diff --git a/.php_cs b/.php_cs new file mode 100644 index 00000000..4846be0b --- /dev/null +++ b/.php_cs @@ -0,0 +1,11 @@ +in([__DIR__.'/app', __DIR__.'/tests']); + +return Config::create() + ->fixers(['-empty_return', 'short_array_syntax', 'ordered_use']) + ->finder($finder); diff --git a/app/TeenQuotes/AdminPanel/AdminPanelServiceProvider.php b/app/TeenQuotes/AdminPanel/AdminPanelServiceProvider.php index 27dc11ac..fab48841 100644 --- a/app/TeenQuotes/AdminPanel/AdminPanelServiceProvider.php +++ b/app/TeenQuotes/AdminPanel/AdminPanelServiceProvider.php @@ -1,66 +1,68 @@ -registerRoutes(); - $this->registerViewComposers(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerRoutes(); + $this->registerViewComposers(); + } - private function registerRoutes() - { - $this->app['router']->pattern('decision', 'approve|unapprove|alert'); + private function registerRoutes() + { + $this->app['router']->pattern('decision', 'approve|unapprove|alert'); - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('/', ['uses' => $this->getController().'@index', 'as' => 'admin.quotes.index']); - $this->app['router']->get('edit/{quote_id}', ['uses' => $this->getController().'@edit', 'as' => 'admin.quotes.edit']); - $this->app['router']->put('update/{quote_id}', ['uses' => $this->getController().'@update', 'as' => 'admin.quotes.update']); - $this->app['router']->post('moderate/{quote_id}/{decision}', ['uses' => $this->getController().'@postModerate', 'as' => 'admin.quotes.moderate']); - }); - } + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('/', ['uses' => $this->getController().'@index', 'as' => 'admin.quotes.index']); + $this->app['router']->get('edit/{quote_id}', ['uses' => $this->getController().'@edit', 'as' => 'admin.quotes.edit']); + $this->app['router']->put('update/{quote_id}', ['uses' => $this->getController().'@update', 'as' => 'admin.quotes.update']); + $this->app['router']->post('moderate/{quote_id}/{decision}', ['uses' => $this->getController().'@postModerate', 'as' => 'admin.quotes.moderate']); + }); + } - private function registerViewComposers() - { - // JS variables used when moderating quotes - $this->app['view']->composer([ - 'admin.index' - ], 'TeenQuotes\AdminPanel\Composers\ModerationIndexComposer'); - } + private function registerViewComposers() + { + // JS variables used when moderating quotes + $this->app['view']->composer([ + 'admin.index', + ], 'TeenQuotes\AdminPanel\Composers\ModerationIndexComposer'); + } - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domainAdmin'), - 'namespace' => 'TeenQuotes\AdminPanel\Controllers', - 'before' => 'admin', - ]; - } + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domainAdmin'), + 'namespace' => 'TeenQuotes\AdminPanel\Controllers', + 'before' => 'admin', + ]; + } - /** - * The controller name to handle requests - * @return string - */ - private function getController() - { - return 'QuotesAdminController'; - } -} \ No newline at end of file + /** + * The controller name to handle requests. + * + * @return string + */ + private function getController() + { + return 'QuotesAdminController'; + } +} diff --git a/app/TeenQuotes/AdminPanel/Composers/ModerationIndexComposer.php b/app/TeenQuotes/AdminPanel/Composers/ModerationIndexComposer.php index c6587d8d..3650c053 100644 --- a/app/TeenQuotes/AdminPanel/Composers/ModerationIndexComposer.php +++ b/app/TeenQuotes/AdminPanel/Composers/ModerationIndexComposer.php @@ -1,36 +1,61 @@ -getData(); - - // The number of days required to publish waiting quotes - $nbDays = $this->getNbdaysToPublishQuotes($data['nbQuotesPending'], $data['nbQuotesPerDay']); - $view->with('nbDays', $nbDays); - - // The page title - $view->with('pageTitle', 'Admin | '.Lang::get('layout.nameWebsite')); - - // Useful JS variables - JavaScript::put([ - 'nbQuotesPerDay' => Config::get('app.quotes.nbQuotesToPublishPerDay'), - 'quotesPlural' => Lang::choice('quotes.quotesText', 2), - 'daysPlural' => Lang::choice('quotes.daysText', 2), - ]); - } - - /** - * Compute the number of days required to publish the current waiting number of quotes - * @param int $nbPending - * @param int $nbPublishedPerDay - * @return int - */ - private function getNbdaysToPublishQuotes($nbPending, $nbPublishedPerDay) - { - return ceil($nbPending / $nbPublishedPerDay); - } -} \ No newline at end of file +colorGenerator = $colorGenerator; + } + + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + + // The number of days required to publish waiting quotes + $nbDays = $this->getNbdaysToPublishQuotes($data['nbQuotesPending'], $data['nbQuotesPerDay']); + $view->with('nbDays', $nbDays); + + // The page title + $view->with('pageTitle', 'Admin | '.Lang::get('layout.nameWebsite')); + + // The color generator + $view->with('colorGenerator', $this->colorGenerator); + + // Useful JS variables + JavaScript::put([ + 'nbQuotesPerDay' => Config::get('app.quotes.nbQuotesToPublishPerDay'), + 'quotesPlural' => Lang::choice('quotes.quotesText', 2), + 'daysPlural' => Lang::choice('quotes.daysText', 2), + ]); + } + + /** + * Compute the number of days required to publish the current waiting number of quotes. + * + * @param int $nbPending + * @param int $nbPublishedPerDay + * + * @return int + */ + private function getNbdaysToPublishQuotes($nbPending, $nbPublishedPerDay) + { + return ceil($nbPending / $nbPublishedPerDay); + } +} diff --git a/app/TeenQuotes/AdminPanel/Controllers/QuotesAdminController.php b/app/TeenQuotes/AdminPanel/Controllers/QuotesAdminController.php index 7c9d16bb..c4e2ae33 100644 --- a/app/TeenQuotes/AdminPanel/Controllers/QuotesAdminController.php +++ b/app/TeenQuotes/AdminPanel/Controllers/QuotesAdminController.php @@ -1,142 +1,156 @@ -quoteRepo = $quoteRepo; - $this->quoteValidator = App::make('TeenQuotes\Quotes\Validation\QuoteValidator'); - $this->userMailer = $userMailer; - } - - /** - * Display a listing of the resource. - * - * @return \Response - */ - public function index() - { - $quotes = $this->quoteRepo->lastWaitingQuotes(); - - $data = [ - 'quotes' => $quotes, - 'colors' => Quote::getRandomColors(), - 'nbQuotesPending' => $this->quoteRepo->nbPending(), - 'nbQuotesPerDay' => Config::get('app.quotes.nbQuotesToPublishPerDay'), - ]; - - return View::make('admin.index', $data); - } - - /** - * Show the form for editing the specified resource. - * - * @param int $id The ID of the quote that we want to edit - * @return \Response - */ - public function edit($id) - { - $quote = $this->quoteRepo->waitingById($id); - - if (is_null($quote)) throw new QuoteNotFoundException; - - return View::make('admin.edit')->withQuote($quote); - } - - /** - * Update the specified resource in storage. - * - * @param int $id The ID of the quote we want to edit - * @return \Response - */ - public function update($id) - { - $quote = $this->quoteRepo->waitingById($id); - - if (is_null($quote)) throw new QuoteNotFoundException; - - $data = [ - 'content' => Input::get('content'), - // Just to use the same validation rules - 'quotesSubmittedToday' => 0, - ]; - - $this->quoteValidator->validatePosting($data); - - // Update the quote - $quote = $this->quoteRepo->updateContentAndApproved($id, $data['content'], Quote::PENDING); - - // Contact the author of the quote - $this->sendMailForQuoteAndModeration($quote, new Moderation('approve')); - - return Redirect::route('admin.quotes.index')->with('success', 'The quote has been edited and approved!'); - } - - /** - * Moderate a quote - * - * @param int $id The ID of the quote - * @param string $type The decision of the moderation: approve|unapprove - * @warning Should be called using Ajax - * @return \Response - */ - public function postModerate($id, $type) - { - $moderation = new Moderation($type); - - if (Request::ajax()) - { - $quote = $this->quoteRepo->waitingById($id); - - // Handle quote not found - if (is_null($quote)) - throw new InvalidArgumentException("Quote ".$id." is not a waiting quote."); - - $approved = $moderation->isApproved() ? Quote::PENDING : Quote::REFUSED; - $quote = $this->quoteRepo->updateApproved($id, $approved); - - // Contact the author of the quote - $this->sendMailForQuoteAndModeration($quote, $moderation); - - return Response::json(['success' => true], 200); - } - } - - /** - * Send an email to the author of quote telling the moderation decision - * @param \TeenQuotes\Quotes\Models\Quote $quote - * @param \TeenQuotes\AdminPanel\Helpers\Moderation $moderation The moderation decision - */ - private function sendMailForQuoteAndModeration($quote, Moderation $moderation) - { - $nbDays = 0; - // Retrieve the number of days before the publication of the quote - if ($moderation->isApproved()) - $nbDays = $this->quoteRepo->nbDaysUntilPublication($quote); - - $this->userMailer->sendModeration($moderation, $quote, $nbDays); - } -} \ No newline at end of file +use View; + +class QuotesAdminController extends BaseController +{ + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Quotes\Validation\QuoteValidator + */ + private $quoteValidator; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + public function __construct(QuoteRepository $quoteRepo, UserMailer $userMailer) + { + $this->quoteRepo = $quoteRepo; + $this->quoteValidator = App::make('TeenQuotes\Quotes\Validation\QuoteValidator'); + $this->userMailer = $userMailer; + } + + /** + * Display a listing of the resource. + * + * @return \Response + */ + public function index() + { + $quotes = $this->quoteRepo->lastWaitingQuotes(); + + $data = [ + 'quotes' => $quotes, + 'nbQuotesPending' => $this->quoteRepo->nbPending(), + 'nbQuotesPerDay' => Config::get('app.quotes.nbQuotesToPublishPerDay'), + ]; + + return View::make('admin.index', $data); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id The ID of the quote that we want to edit + * + * @return \Response + */ + public function edit($id) + { + $quote = $this->quoteRepo->waitingById($id); + + if (is_null($quote)) { + throw new QuoteNotFoundException(); + } + + return View::make('admin.edit')->withQuote($quote); + } + + /** + * Update the specified resource in storage. + * + * @param int $id The ID of the quote we want to edit + * + * @return \Response + */ + public function update($id) + { + $quote = $this->quoteRepo->waitingById($id); + + if (is_null($quote)) { + throw new QuoteNotFoundException(); + } + + $content = Input::get('content'); + + // Validate the quote + $this->quoteValidator->validateModerating(compact('content')); + + // Update the quote + $quote = $this->quoteRepo->updateContentAndApproved($id, $content, Quote::PENDING); + + // Contact the author of the quote + $this->sendMailForQuoteAndModeration($quote, new Moderation('approve')); + + return Redirect::route('admin.quotes.index')->with('success', 'The quote has been edited and approved!'); + } + + /** + * Moderate a quote. + * + * @param int $id The ID of the quote + * @param string $type The decision of the moderation: approve|unapprove + * @warning Should be called using Ajax + * + * @return \Response + */ + public function postModerate($id, $type) + { + $moderation = new Moderation($type); + + if (Request::ajax()) { + $quote = $this->quoteRepo->waitingById($id); + + // Handle quote not found + if (is_null($quote)) { + throw new InvalidArgumentException('Quote '.$id.' is not a waiting quote.'); + } + + $approved = $moderation->isApproved() ? Quote::PENDING : Quote::REFUSED; + $quote = $this->quoteRepo->updateApproved($id, $approved); + + // Contact the author of the quote + $this->sendMailForQuoteAndModeration($quote, $moderation); + + return Response::json(['success' => true], 200); + } + } + + /** + * Send an email to the author of the quote telling the moderation decision. + * + * @param Quote $quote + * @param Moderation $moderation The moderation decision + */ + private function sendMailForQuoteAndModeration(Quote $quote, Moderation $moderation) + { + $nbDays = 0; + // Retrieve the number of days before the publication of the quote + if ($moderation->isApproved()) { + $nbDays = $this->quoteRepo->nbDaysUntilPublication($quote); + } + + $this->userMailer->sendModeration($moderation, $quote, $nbDays); + } +} diff --git a/app/TeenQuotes/AdminPanel/Helpers/Moderation.php b/app/TeenQuotes/AdminPanel/Helpers/Moderation.php index 8846416e..24ff1981 100644 --- a/app/TeenQuotes/AdminPanel/Helpers/Moderation.php +++ b/app/TeenQuotes/AdminPanel/Helpers/Moderation.php @@ -1,71 +1,83 @@ -guardType($type); + /** + * The constructor. + * + * @param string $type The moderation decision + * + * @throws \InvalidArgumentException If the moderation is not supported + */ + public function __construct($type) + { + $this->guardType($type); - $this->type = $type; - } + $this->type = $type; + } - /** - * Tell if the moderation decision was 'approve' - * @return boolean - */ - public function isApproved() - { - return $this->type === 'approve'; - } + /** + * Tell if the moderation decision was 'approve'. + * + * @return bool + */ + public function isApproved() + { + return $this->type === 'approve'; + } - /** - * Get the moderation decision - * @return string - */ - public function getType() - { - return $this->type; - } + /** + * Get the moderation decision. + * + * @return string + */ + public function getType() + { + return $this->type; + } - /** - * Get available types of moderation - * @return array - */ - public static function getAvailableTypes() - { - return ['approve', 'unapprove', 'alert']; - } + /** + * Get available types of moderation. + * + * @return array + */ + public static function getAvailableTypes() + { + return ['approve', 'unapprove', 'alert']; + } - /** - * Present available types of moderation - * @return string - */ - private function presentAvailableTypes() - { - return implode('|', self::getAvailableTypes()); - } + /** + * Present available types of moderation. + * + * @return string + */ + private function presentAvailableTypes() + { + return implode('|', self::getAvailableTypes()); + } - /** - * Guard the moderation decision against available values - * @param string $type The moderation decision to test - * @throws \InvalidArgumentException If the type is not supported - */ - private function guardType($type) - { - $error = "Wrong type. Got ".$type.". Available values: ".$this->presentAvailableTypes(); + /** + * Guard the moderation decision against available values. + * + * @param string $type The moderation decision to test + * + * @throws \InvalidArgumentException If the type is not supported + */ + private function guardType($type) + { + $error = 'Wrong type. Got '.$type.'. Available values: '.$this->presentAvailableTypes(); - if ( ! in_array($type, self::getAvailableTypes())) - throw new InvalidArgumentException($error); - } -} \ No newline at end of file + if (!in_array($type, self::getAvailableTypes())) { + throw new InvalidArgumentException($error); + } + } +} diff --git a/app/TeenQuotes/Api/V1/ApiServiceProvider.php b/app/TeenQuotes/Api/V1/ApiServiceProvider.php index 5b7dd311..4a89dcbb 100644 --- a/app/TeenQuotes/Api/V1/ApiServiceProvider.php +++ b/app/TeenQuotes/Api/V1/ApiServiceProvider.php @@ -1,4 +1,6 @@ -registerErrorHandlers(); - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $this->registerOAuthRoutes(); - $this->registerRoutesPatterns(); - $this->registerBindings(); - - $this->registerCommentsRoutes(); - $this->registerCountriesRoutes(); - $this->registerFavoriteQuotesRoutes(); - $this->registerPasswordRoutes(); - $this->registerQuotesRoutes(); - $this->registerSearchRoutes(); - $this->registerStoriesRoutes(); - $this->registerUsersRoutes(); - } - - private function registerErrorHandlers() - { - $this->app->error(function(ApiNotFoundException $exception, $code) - { - $status = 404; - $error = 'No '.$exception->getMessage().' have been found.'; - - return Response::json(compact('status', 'error'), 404); - }); - } - - private function registerRoutesPatterns() - { - $this->app['router']->pattern('quote_id', '[0-9]+'); - $this->app['router']->pattern('country_id', '[0-9]+'); - $this->app['router']->pattern('story_id', '[0-9]+'); - $this->app['router']->pattern('comment_id', '[0-9]+'); - $this->app['router']->pattern('user_id', '[a-zA-Z0-9_-]+'); - $this->app['router']->pattern('quote_approved_type', 'waiting|refused|pending|published'); - $this->app['router']->pattern('random', 'random'); - $this->app['router']->pattern('tag_name', '[a-z]+'); - } - - private function registerCommentsRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('comments/{quote_id}', ['uses' => 'CommentsController@index']); - $this->app['router']->put('comments/{comment_id}', ['uses' => 'CommentsController@update']); - $this->app['router']->post('comments/{quote_id}', ['uses' => 'CommentsController@store']); - $this->app['router']->delete('comments/{comment_id}', ['uses' => 'CommentsController@destroy']); - $this->app['router']->get('comments/{comment_id}', ['uses' => 'CommentsController@show']); - $this->app['router']->get('comments/users/{user_id}', 'CommentsController@getCommentsForUser'); - }); - } - - private function registerCountriesRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('countries/{country_id?}', ['uses' => 'CountriesController@show']); - }); - } - - private function registerFavoriteQuotesRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->post('favorites/{quote_id}', ['uses' => 'QuotesFavoriteController@postFavorite']); - $this->app['router']->delete('favorites/{quote_id}', ['uses' => 'QuotesFavoriteController@deleteFavorite']); - }); - } - - private function registerPasswordRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->post('password/remind', ['uses' => 'PasswordController@postRemind']); - $this->app['router']->post('password/reset', ['uses' => 'PasswordController@postReset']); - }); - } - - private function registerQuotesRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->post('quotes', ['uses' => 'QuotesController@store']); - $this->app['router']->get('quotes/{quote_id}', ['uses' => 'QuotesController@show']); - $this->app['router']->get('quotes/{random?}', ['uses' => 'QuotesController@index']); - $this->app['router']->get('quotes/top_favorites', ['uses' => 'QuotesController@getTopFavoritedQuotes']); - $this->app['router']->get('quotes/top_comments', ['uses' => 'QuotesController@getTopCommentedQuotes']); - $this->app['router']->get('quotes/favorites/{user_id?}', ['uses' => 'QuotesController@indexFavoritesQuotes']); - $this->app['router']->get('quotes/{quote_approved_type}/{user_id}', ['uses' => 'QuotesController@indexByApprovedQuotes']); - $this->app['router']->get('quotes/search/{query}', ['uses' => 'QuotesController@getSearch']); - $this->app['router']->get('quotes/tags/{tag_name}', ['uses' => 'QuotesController@getQuotesForTag']); - }); - } - - private function registerUsersRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->delete('users',['uses' => 'UsersController@destroy']); - $this->app['router']->post('users', ['uses' => 'UsersController@store']); - $this->app['router']->get('users', ['uses' => 'UsersController@getUsers']); - $this->app['router']->put('users/profile', ['uses' => 'UsersController@putProfile']); - $this->app['router']->get('users/{user_id}', ['uses' => 'UsersController@show']); - $this->app['router']->put('users/password', ['uses' => 'UsersController@putPassword']); - $this->app['router']->put('users/settings', ['uses' => 'UsersController@putSettings']); - $this->app['router']->get('users/countries/{country_id}', ['uses' => 'UsersController@fromCountry']); - $this->app['router']->get('users/search/{query}', ['uses' => 'UsersController@getSearch']); - }); - } - - private function registerSearchRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('search/{query}', ['uses' => 'SearchController@getSearch']); - }); - } - - private function registerStoriesRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('stories', ['uses' => 'StoriesController@index']); - $this->app['router']->post('stories', ['uses' => 'StoriesController@store']); - $this->app['router']->get('stories/{story_id}', ['uses' => 'StoriesController@show']); - }); - } - - private function registerBindings() - { - $this->app->bind(PageBuilderInterface::class, PageBuilder::class); - } - - private function registerOAuthRoutes() - { - $routeGroupParams = $this->getRouteGroupParams(); - // Disable OAuth filter - $routeGroupParams['before'] = 'session.remove'; - // No prefix - array_forget($routeGroupParams, 'prefix'); - - $this->app['router']->group($routeGroupParams, function() { - $this->app['router']->post('oauth', ['uses' => 'APIGlobalController@postOauth']); - $this->app['router']->get('/', ['uses' => 'APIGlobalController@showWelcome']); - }); - } - - /** - * Get the key value parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domainAPI'), - 'before' => 'oauth|session.remove', - 'prefix' => 'v1', - 'namespace' => 'TeenQuotes\Api\V1\Controllers' - ]; - } +class ApiServiceProvider extends ServiceProvider +{ + /** + * Bootstrap the application events. + */ + public function boot() + { + $this->registerErrorHandlers(); + } + + /** + * Register the service provider. + */ + public function register() + { + $this->registerOAuthRoutes(); + $this->registerRoutesPatterns(); + $this->registerBindings(); + + $this->registerCommentsRoutes(); + $this->registerCountriesRoutes(); + $this->registerFavoriteQuotesRoutes(); + $this->registerPasswordRoutes(); + $this->registerQuotesRoutes(); + $this->registerSearchRoutes(); + $this->registerStoriesRoutes(); + $this->registerUsersRoutes(); + } + + private function registerErrorHandlers() + { + $this->app->error(function (ApiNotFoundException $exception, $code) { + $status = 404; + $error = 'No '.$exception->getMessage().' have been found.'; + + return Response::json(compact('status', 'error'), 404); + }); + } + + private function registerRoutesPatterns() + { + $this->app['router']->pattern('quote_id', '[0-9]+'); + $this->app['router']->pattern('country_id', '[0-9]+'); + $this->app['router']->pattern('story_id', '[0-9]+'); + $this->app['router']->pattern('comment_id', '[0-9]+'); + $this->app['router']->pattern('user_id', '[a-zA-Z0-9_-]+'); + $this->app['router']->pattern('quote_approved_type', 'waiting|refused|pending|published'); + $this->app['router']->pattern('random', 'random'); + $this->app['router']->pattern('tag_name', '[a-z]+'); + } + + private function registerCommentsRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('comments/{quote_id}', ['uses' => 'CommentsController@index']); + $this->app['router']->put('comments/{comment_id}', ['uses' => 'CommentsController@update']); + $this->app['router']->post('comments/{quote_id}', ['uses' => 'CommentsController@store']); + $this->app['router']->delete('comments/{comment_id}', ['uses' => 'CommentsController@destroy']); + $this->app['router']->get('comments/{comment_id}', ['uses' => 'CommentsController@show']); + $this->app['router']->get('comments/users/{user_id}', 'CommentsController@getCommentsForUser'); + }); + } + + private function registerCountriesRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('countries/{country_id?}', ['uses' => 'CountriesController@show']); + }); + } + + private function registerFavoriteQuotesRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->post('favorites/{quote_id}', ['uses' => 'QuotesFavoriteController@postFavorite']); + $this->app['router']->delete('favorites/{quote_id}', ['uses' => 'QuotesFavoriteController@deleteFavorite']); + }); + } + + private function registerPasswordRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->post('password/remind', ['uses' => 'PasswordController@postRemind']); + $this->app['router']->post('password/reset', ['uses' => 'PasswordController@postReset']); + }); + } + + private function registerQuotesRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->post('quotes', ['uses' => 'QuotesController@store']); + $this->app['router']->get('quotes/{quote_id}', ['uses' => 'QuotesController@show']); + $this->app['router']->get('quotes/{random?}', ['uses' => 'QuotesController@index']); + $this->app['router']->get('quotes/top_favorites', ['uses' => 'QuotesController@getTopFavoritedQuotes']); + $this->app['router']->get('quotes/top_comments', ['uses' => 'QuotesController@getTopCommentedQuotes']); + $this->app['router']->get('quotes/favorites/{user_id?}', ['uses' => 'QuotesController@indexFavoritesQuotes']); + $this->app['router']->get('quotes/{quote_approved_type}/{user_id}', ['uses' => 'QuotesController@indexByApprovedQuotes']); + $this->app['router']->get('quotes/search/{query}', ['uses' => 'QuotesController@getSearch']); + $this->app['router']->get('quotes/tags/{tag_name}', ['uses' => 'QuotesController@getQuotesForTag']); + }); + } + + private function registerUsersRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->delete('users', ['uses' => 'UsersController@destroy']); + $this->app['router']->post('users', ['uses' => 'UsersController@store']); + $this->app['router']->get('users', ['uses' => 'UsersController@getUsers']); + $this->app['router']->put('users/profile', ['uses' => 'UsersController@putProfile']); + $this->app['router']->get('users/{user_id}', ['uses' => 'UsersController@show']); + $this->app['router']->put('users/password', ['uses' => 'UsersController@putPassword']); + $this->app['router']->put('users/settings', ['uses' => 'UsersController@putSettings']); + $this->app['router']->get('users/countries/{country_id}', ['uses' => 'UsersController@fromCountry']); + $this->app['router']->get('users/search/{query}', ['uses' => 'UsersController@getSearch']); + }); + } + + private function registerSearchRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('search/{query}', ['uses' => 'SearchController@getSearch']); + }); + } + + private function registerStoriesRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('stories', ['uses' => 'StoriesController@index']); + $this->app['router']->post('stories', ['uses' => 'StoriesController@store']); + $this->app['router']->get('stories/{story_id}', ['uses' => 'StoriesController@show']); + }); + } + + private function registerBindings() + { + $this->app->bind(PageBuilderInterface::class, PageBuilder::class); + } + + private function registerOAuthRoutes() + { + $routeGroupParams = $this->getRouteGroupParams(); + // Disable OAuth filter + $routeGroupParams['before'] = 'session.remove'; + // No prefix + array_forget($routeGroupParams, 'prefix'); + + $this->app['router']->group($routeGroupParams, function () { + $this->app['router']->post('oauth', ['uses' => 'APIGlobalController@postOauth']); + $this->app['router']->get('/', ['uses' => 'APIGlobalController@showWelcome']); + }); + } + + /** + * Get the key value parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domainAPI'), + 'before' => 'oauth|session.remove', + 'prefix' => 'v1', + 'namespace' => 'TeenQuotes\Api\V1\Controllers', + ]; + } } diff --git a/app/TeenQuotes/Api/V1/Controllers/APIGlobalController.php b/app/TeenQuotes/Api/V1/Controllers/APIGlobalController.php index 0ee43c80..68a6584b 100644 --- a/app/TeenQuotes/Api/V1/Controllers/APIGlobalController.php +++ b/app/TeenQuotes/Api/V1/Controllers/APIGlobalController.php @@ -1,8 +1,13 @@ -commentRepo = $commentRepo; - $this->countryRepo = $countryRepo; - $this->favQuoteRepo = $favQuoteRepo; - $this->newsletterRepo = $newsletterRepo; - $this->newslettersManager = $newslettersManager; - $this->quoteRepo = $quoteRepo; - $this->settingRepo = $settingRepo; - $this->storyRepo = $storyRepo; - $this->tagRepo = $tagRepo; - $this->userRepo = $userRepo; - $this->pageBuilder = $pageBuilder; - - $this->bootstrap(); - } - - /** - * Bootstrap things we need to do just after the constructor - * has been called - */ - protected function bootstrap() {} - - /** - * @see \TeenQuotes\Api\V1\Interfaces\PageBuilderInterface - */ - public function buildPagesArray($page, $pagesize, $totalPages, $url, $getParams) - { - return $this->pageBuilder->buildPagesArray($page, $pagesize, $totalPages, $url, $getParams); - } - - /** - * Display the welcome message at the root of the API - * - * @return \TeenQuotes\Http\Facades\Response - */ - public function showWelcome() - { - return Response::json([ - 'status' => 'You have arrived', - 'message' => 'Welcome to the Teen Quotes API', - 'version' => '1.0alpha', - 'url_documentation' => 'https://developers.teen-quotes.com', - 'contact' => 'antoine.augusti@teen-quotes.com', - ], 200); - } - - public function postOauth() - { - return AuthorizationServer::performAccessTokenFlow(); - } - - /** - * Paginate content for the API - * - * @param int $page The current page number - * @param int $pagesize The number of items per page - * @param int $totalContent The total number of items for the search - * @param \Illuminate\Support\Collection $content The content - * @param string $contentName The name of the content. Example: quotes|users - * @return array Keys: total_, total_pages, page, pagesize, url, - * has_next_page, has_previous_page[, next_page, previous_page] - */ - public function paginateContent($page, $pagesize, $totalContent, $content, $contentName = 'quotes') - { - $totalPages = ceil($totalContent / $pagesize); - - $data = [ - $contentName => $content, - 'total_'.$contentName => $totalContent, - 'total_pages' => $totalPages, - 'page' => (int) $page, - 'pagesize' => (int) $pagesize, - 'url' => URL::current() - ]; - - $getParams = null; - if (Input::has('quote')) - $getParams = '"e=true'; - - // Get information about previous and next pages - $pagesArray = $this->buildPagesArray($page, $pagesize, $totalPages, $data['url'], $getParams); - - return array_merge($data, $pagesArray); - } - - /** - * Get the current page - * - * @return int - */ - public function getPage() - { - return max(1, Input::get('page', 1)); - } - - /** - * Retrieve the authenticated user from the website or through OAuth - * - * @return \TeenQuotes\Models\Users\User The user object - */ - protected function retrieveUser() - { - // Get the user from OAuth 2 - if (ResourceServer::getOwnerId()) - return $this->userRepo->getById(ResourceServer::getOwnerId()); - - // Get the logged in user - return Auth::user(); - } - - /** - * Determine if a collection contains no results - * - * @param null|\Illuminate\Support\Collection $content - * @return boolean - */ - protected function isNotFound($content) - { - return (is_null($content) OR empty($content) OR $content->count() == 0); - } +use URL; + +class APIGlobalController extends BaseController implements PageBuilderInterface +{ + /** + * @var \TeenQuotes\Countries\Repositories\CountryRepository + */ + protected $countryRepo; + + /** + * @var \TeenQuotes\Comments\Repositories\CommentRepository + */ + protected $commentRepo; + + /** + * @var \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + protected $favQuoteRepo; + + /** + * @var \TeenQuotes\Newsletters\Repositories\NewsletterRepository + */ + protected $newsletterRepo; + + /** + * @var \TeenQuotes\Newsletters\NewslettersManager + */ + protected $newslettersManager; + + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + protected $quoteRepo; + + /** + * @var \TeenQuotes\Settings\Repositories\SettingRepository + */ + protected $settingRepo; + + /** + * @var \TeenQuotes\Stories\Repositories\StoryRepository + */ + protected $storyRepo; + + /** + * @var \TeenQuotes\Tags\Repositories\TagRepository + */ + protected $tagRepo; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + protected $userRepo; + + /** + * @var \TeenQuotes\Api\V1\Interfaces\PageBuilderInterface + */ + protected $pageBuilder; + + public function __construct( + CommentRepository $commentRepo, CountryRepository $countryRepo, + FavoriteQuoteRepository $favQuoteRepo, NewsletterRepository $newsletterRepo, + NewslettersManager $newslettersManager, QuoteRepository $quoteRepo, + SettingRepository $settingRepo, StoryRepository $storyRepo, + TagRepository $tagRepo, UserRepository $userRepo, PageBuilderInterface $pageBuilder) + { + $this->commentRepo = $commentRepo; + $this->countryRepo = $countryRepo; + $this->favQuoteRepo = $favQuoteRepo; + $this->newsletterRepo = $newsletterRepo; + $this->newslettersManager = $newslettersManager; + $this->quoteRepo = $quoteRepo; + $this->settingRepo = $settingRepo; + $this->storyRepo = $storyRepo; + $this->tagRepo = $tagRepo; + $this->userRepo = $userRepo; + $this->pageBuilder = $pageBuilder; + + $this->bootstrap(); + } + + /** + * Bootstrap things we need to do just after the constructor + * has been called. + */ + protected function bootstrap() + { + } + + /** + * @see \TeenQuotes\Api\V1\Interfaces\PageBuilderInterface + */ + public function buildPagesArray($page, $pagesize, $totalPages, $url, $getParams) + { + return $this->pageBuilder->buildPagesArray($page, $pagesize, $totalPages, $url, $getParams); + } + + /** + * Display the welcome message at the root of the API. + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function showWelcome() + { + return Response::json([ + 'status' => 'You have arrived', + 'message' => 'Welcome to the Teen Quotes API', + 'version' => '1.0alpha', + 'url_documentation' => 'https://developers.teen-quotes.com', + 'contact' => 'antoine.augusti@teen-quotes.com', + ], 200); + } + + public function postOauth() + { + return AuthorizationServer::performAccessTokenFlow(); + } + + /** + * Paginate content for the API. + * + * @param int $page The current page number + * @param int $pagesize The number of items per page + * @param int $totalContent The total number of items for the search + * @param \Illuminate\Support\Collection $content The content + * @param string $contentName The name of the content. Example: quotes|users + * + * @return array Keys: total_, total_pages, page, pagesize, url, + * has_next_page, has_previous_page[, next_page, previous_page] + */ + public function paginateContent($page, $pagesize, $totalContent, $content, $contentName = 'quotes') + { + $totalPages = ceil($totalContent / $pagesize); + + $data = [ + $contentName => $content, + 'total_'.$contentName => $totalContent, + 'total_pages' => $totalPages, + 'page' => (int) $page, + 'pagesize' => (int) $pagesize, + 'url' => URL::current(), + ]; + + $getParams = null; + if (Input::has('quote')) { + $getParams = '"e=true'; + } + + // Get information about previous and next pages + $pagesArray = $this->buildPagesArray($page, $pagesize, $totalPages, $data['url'], $getParams); + + return array_merge($data, $pagesArray); + } + + /** + * Get the current page. + * + * @return int + */ + public function getPage() + { + return max(1, Input::get('page', 1)); + } + + /** + * Retrieve the authenticated user from the website or through OAuth. + * + * @return \TeenQuotes\Models\Users\User The user object + */ + protected function retrieveUser() + { + // Get the user from OAuth 2 + if (ResourceServer::getOwnerId()) { + return $this->userRepo->getById(ResourceServer::getOwnerId()); + } + + // Get the logged in user + return Auth::user(); + } + + /** + * Determine if a collection contains no results. + * + * @param null|\Illuminate\Support\Collection $content + * + * @return bool + */ + protected function isNotFound($content) + { + return (is_null($content) or empty($content) or $content->count() == 0); + } } diff --git a/app/TeenQuotes/Api/V1/Controllers/CommentsController.php b/app/TeenQuotes/Api/V1/Controllers/CommentsController.php index 3294c7b7..1d2c1131 100644 --- a/app/TeenQuotes/Api/V1/Controllers/CommentsController.php +++ b/app/TeenQuotes/Api/V1/Controllers/CommentsController.php @@ -1,207 +1,226 @@ -commentValidator = App::make('TeenQuotes\Comments\Validation\CommentValidator'); - } - - public function index($quote_id) - { - $page = $this->getPage(); - $pagesize = $this->getPagesize(); - - // Get comments - if (Input::has('quote')) - $content = $this->commentRepo->indexForQuoteWithQuote($quote_id, $page, $pagesize); - else - $content = $this->commentRepo->indexForQuote($quote_id, $page, $pagesize); - - // Handle no comments found - if ($this->isNotFound($content)) - throw new ApiNotFoundException('comments'); - - // Get the total number of comments for the related quote - $relatedQuote = $this->quoteRepo->getById($quote_id); - $totalComments = $relatedQuote->total_comments; - - $data = $this->paginateContent($page, $pagesize, $totalComments, $content, 'comments'); - - return Response::json($data, 200, [], JSON_NUMERIC_CHECK); - } - - public function getCommentsForUser($user_id) - { - $page = $this->getPage(); - $pagesize = $this->getPagesize(); - - $user = $this->userRepo->getById($user_id); - - // Handle user not found - if (is_null($user)) - return $this->tellUserWasNotFound($user_id); - - // Get comments - $content = $this->commentRepo->findForUser($user, $page, $pagesize); - - // Handle no comments found - $totalComments = 0; - if ($this->isNotFound($content)) - throw new ApiNotFoundException('comments'); - - $totalComments = $this->commentRepo->countForUser($user); - - $data = $this->paginateContent($page, $pagesize, $totalComments, $content, 'comments'); - - return Response::json($data, 200, [], JSON_NUMERIC_CHECK); - } - - public function show($comment_id) - { - if (Input::has('quote')) - $comment = $this->commentRepo->findByIdWithQuote($comment_id); - else - $comment = $this->commentRepo->findById($comment_id); - - // Handle not found - if (is_null($comment)) - return $this->tellCommentWasNotFound($comment_id); - - return Response::json($comment, 200, [], JSON_NUMERIC_CHECK); - } - - public function store($quote_id, $doValidation = true) - { - $user = $this->retrieveUser(); - $content = Input::get('content'); - - if ($doValidation) - $this->commentValidator->validatePosting(compact('content', 'quote_id')); - - $quote = $this->quoteRepo->getById($quote_id); - - // Check if the quote is published - if ( ! $quote->isPublished()) - return Response::json([ - 'status' => 'wrong_quote_id', - 'error' => 'The quote should be published.' - ], 400); - - // Store the comment - $comment = $this->commentRepo->create($quote, $user, $content); - - return Response::json($comment, 201, [], JSON_NUMERIC_CHECK); - } - - public function update($id) - { - $user = $this->retrieveUser(); - $content = Input::get('content'); - $comment = $this->commentRepo->findById($id); - - // Handle not found - if (is_null($comment)) - return $this->tellCommentWasNotFound($id); - - // Check that the user is the owner of the comment - if ( ! $comment->isPostedByUser($user)) - return $this->tellCommentWasNotPostedByUser($id, $user->id); - - // Perform validation - $this->commentValidator->validateEditing(compact('content')); - - // Update the comment - $this->commentRepo->update($id, $content); - - return Response::json([ - 'status' => 'comment_updated', - 'success' => "The comment #".$id." was updated.", - ], 200); - } - - public function destroy($id) - { - $user = $this->retrieveUser(); - $comment = $this->commentRepo->findById($id); - - // Handle not found - if (is_null($comment)) - return $this->tellCommentWasNotFound($id); - - // Check that the user is the owner of the comment - if ( ! $comment->isPostedByUser($user)) - return $this->tellCommentWasNotPostedByUser($id, $user->id); - - // Delete the comment - $this->commentRepo->delete($id); - - return Response::json([ - 'status' => 'comment_deleted', - 'success' => "The comment #".$id." was deleted.", - ], 200); - } - - /** - * Get the pagesize - * - * @return int - */ - public function getPagesize() - { - return Input::get('pagesize', Config::get('app.comments.nbCommentsPerPage')); - } - - /** - * Tell that the comment was not found - * - * @param int $id - * @return \TeenQuotes\Http\Facades\Response - */ - private function tellCommentWasNotFound($id) - { - return Response::json([ - 'status' => 'comment_not_found', - 'error' => "The comment #".$id." was not found.", - ], 404); - } - - /** - * Tell that a comment a comment was not posted by a user - * - * @param int $id The ID of the comment - * @param int $user_id The ID of the user - * @return \TeenQuotes\Http\Facades\Response - */ - private function tellCommentWasNotPostedByUser($id, $user_id) - { - return Response::json([ - 'status' => 'comment_not_self', - 'error' => "The comment #".$id." was not posted by user #".$user_id.".", - ], 400); - } - - /** - * Tell that we can't find a user - * - * @param int $user_id - * @return \TeenQuotes\Http\Facades\Response - */ - private function tellUserWasNotFound($user_id) - { - return Response::json([ - 'status' => 'user_not_found', - 'error' => "The user #".$user_id." was not found.", - ], 400); - } +class CommentsController extends APIGlobalController implements PaginatedContentInterface +{ + /** + * @var \TeenQuotes\Comments\Validation\CommentValidator + */ + private $commentValidator; + + public function bootstrap() + { + $this->commentValidator = App::make('TeenQuotes\Comments\Validation\CommentValidator'); + } + + public function index($quote_id) + { + $page = $this->getPage(); + $pagesize = $this->getPagesize(); + + // Get comments + if (Input::has('quote')) { + $content = $this->commentRepo->indexForQuoteWithQuote($quote_id, $page, $pagesize); + } else { + $content = $this->commentRepo->indexForQuote($quote_id, $page, $pagesize); + } + + // Handle no comments found + if ($this->isNotFound($content)) { + throw new ApiNotFoundException('comments'); + } + + // Get the total number of comments for the related quote + $relatedQuote = $this->quoteRepo->getById($quote_id); + $totalComments = $relatedQuote->total_comments; + + $data = $this->paginateContent($page, $pagesize, $totalComments, $content, 'comments'); + + return Response::json($data, 200, [], JSON_NUMERIC_CHECK); + } + + public function getCommentsForUser($user_id) + { + $page = $this->getPage(); + $pagesize = $this->getPagesize(); + + $user = $this->userRepo->getById($user_id); + + // Handle user not found + if (is_null($user)) { + return $this->tellUserWasNotFound($user_id); + } + + // Get comments + $content = $this->commentRepo->findForUser($user, $page, $pagesize); + + // Handle no comments found + $totalComments = 0; + if ($this->isNotFound($content)) { + throw new ApiNotFoundException('comments'); + } + + $totalComments = $this->commentRepo->countForUser($user); + + $data = $this->paginateContent($page, $pagesize, $totalComments, $content, 'comments'); + + return Response::json($data, 200, [], JSON_NUMERIC_CHECK); + } + + public function show($comment_id) + { + if (Input::has('quote')) { + $comment = $this->commentRepo->findByIdWithQuote($comment_id); + } else { + $comment = $this->commentRepo->findById($comment_id); + } + + // Handle not found + if (is_null($comment)) { + return $this->tellCommentWasNotFound($comment_id); + } + + return Response::json($comment, 200, [], JSON_NUMERIC_CHECK); + } + + public function store($quote_id, $doValidation = true) + { + $user = $this->retrieveUser(); + $content = Input::get('content'); + + if ($doValidation) { + $this->commentValidator->validatePosting(compact('content', 'quote_id')); + } + + $quote = $this->quoteRepo->getById($quote_id); + + // Check if the quote is published + if (!$quote->isPublished()) { + return Response::json([ + 'status' => 'wrong_quote_id', + 'error' => 'The quote should be published.', + ], 400); + } + + // Store the comment + $comment = $this->commentRepo->create($quote, $user, $content); + + return Response::json($comment, 201, [], JSON_NUMERIC_CHECK); + } + + public function update($id) + { + $user = $this->retrieveUser(); + $content = Input::get('content'); + $comment = $this->commentRepo->findById($id); + + // Handle not found + if (is_null($comment)) { + return $this->tellCommentWasNotFound($id); + } + + // Check that the user is the owner of the comment + if (!$comment->isPostedByUser($user)) { + return $this->tellCommentWasNotPostedByUser($id, $user->id); + } + + // Perform validation + $this->commentValidator->validateEditing(compact('content')); + + // Update the comment + $this->commentRepo->update($id, $content); + + return Response::json([ + 'status' => 'comment_updated', + 'success' => 'The comment #'.$id.' was updated.', + ], 200); + } + + public function destroy($id) + { + $user = $this->retrieveUser(); + $comment = $this->commentRepo->findById($id); + + // Handle not found + if (is_null($comment)) { + return $this->tellCommentWasNotFound($id); + } + + // Check that the user is the owner of the comment + if (!$comment->isPostedByUser($user)) { + return $this->tellCommentWasNotPostedByUser($id, $user->id); + } + + // Delete the comment + $this->commentRepo->delete($id); + + return Response::json([ + 'status' => 'comment_deleted', + 'success' => 'The comment #'.$id.' was deleted.', + ], 200); + } + + /** + * Get the pagesize. + * + * @return int + */ + public function getPagesize() + { + return Input::get('pagesize', Config::get('app.comments.nbCommentsPerPage')); + } + + /** + * Tell that the comment was not found. + * + * @param int $id + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function tellCommentWasNotFound($id) + { + return Response::json([ + 'status' => 'comment_not_found', + 'error' => 'The comment #'.$id.' was not found.', + ], 404); + } + + /** + * Tell that a comment a comment was not posted by a user. + * + * @param int $id The ID of the comment + * @param int $user_id The ID of the user + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function tellCommentWasNotPostedByUser($id, $user_id) + { + return Response::json([ + 'status' => 'comment_not_self', + 'error' => 'The comment #'.$id.' was not posted by user #'.$user_id.'.', + ], 400); + } + + /** + * Tell that we can't find a user. + * + * @param int $user_id + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function tellUserWasNotFound($user_id) + { + return Response::json([ + 'status' => 'user_not_found', + 'error' => 'The user #'.$user_id.' was not found.', + ], 400); + } } diff --git a/app/TeenQuotes/Api/V1/Controllers/CountriesController.php b/app/TeenQuotes/Api/V1/Controllers/CountriesController.php index 2e7aa285..cb09174c 100644 --- a/app/TeenQuotes/Api/V1/Controllers/CountriesController.php +++ b/app/TeenQuotes/Api/V1/Controllers/CountriesController.php @@ -1,54 +1,60 @@ -listAll(); - - // Get a single country - $country = $this->countryRepo->findById($country_id); - - // Handle country not found - if ($this->isNotFound($country)) - return $this->countryWasNotFound($country_id); - - return Response::json($country, 200, [], JSON_NUMERIC_CHECK); - } - - /** - * List all countries - * - * @return \TeenQuotes\Http\Facades\Response - */ - private function listAll() - { - $countries = $this->countryRepo->getAll(); - - return Response::json($countries, 200, [], JSON_NUMERIC_CHECK); - } - - /** - * Tell that a country was not found - * - * @param int $id The country's ID - * @return \TeenQuotes\Http\Facades\Response - */ - private function countryWasNotFound($id) - { - return Response::json([ - 'status' => 'country_not_found', - 'error' => "The country #".$id." was not found.", - ], 404); - } -} \ No newline at end of file +class CountriesController extends APIGlobalController +{ + /** + * Show a single or all countries if we don't pass an ID. + * + * @param null|int $country_id + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function show($country_id = null) + { + // List all countries if we haven't got an ID + if (is_null($country_id)) { + return $this->listAll(); + } + + // Get a single country + $country = $this->countryRepo->findById($country_id); + + // Handle country not found + if ($this->isNotFound($country)) { + return $this->countryWasNotFound($country_id); + } + + return Response::json($country, 200, [], JSON_NUMERIC_CHECK); + } + + /** + * List all countries. + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function listAll() + { + $countries = $this->countryRepo->getAll(); + + return Response::json($countries, 200, [], JSON_NUMERIC_CHECK); + } + + /** + * Tell that a country was not found. + * + * @param int $id The country's ID + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function countryWasNotFound($id) + { + return Response::json([ + 'status' => 'country_not_found', + 'error' => 'The country #'.$id.' was not found.', + ], 404); + } +} diff --git a/app/TeenQuotes/Api/V1/Controllers/PasswordController.php b/app/TeenQuotes/Api/V1/Controllers/PasswordController.php index 56cc13ac..229d814d 100644 --- a/app/TeenQuotes/Api/V1/Controllers/PasswordController.php +++ b/app/TeenQuotes/Api/V1/Controllers/PasswordController.php @@ -1,90 +1,90 @@ -subject(Lang::get('auth.passwordReminderEmailSubject')); - }); +use Input; +use Lang; +use Password; +use TeenQuotes\Http\Facades\Response; - switch ($response) { - case Password::INVALID_USER: - $status = 400; - $data = [ - 'status' => 'wrong_user', - 'error' => "The email address doesn't match a user." - ]; - break; +class PasswordController extends APIGlobalController +{ + public function postRemind() + { + $response = Password::remind(Input::only('email'), function ($message) { + $message->subject(Lang::get('auth.passwordReminderEmailSubject')); + }); - case Password::REMINDER_SENT: - $status = 200; - $data = [ - 'status' => 'reminder_sent', - 'success' => "An email was sent to the user." - ]; - } + switch ($response) { + case Password::INVALID_USER: + $status = 400; + $data = [ + 'status' => 'wrong_user', + 'error' => "The email address doesn't match a user.", + ]; + break; - return Response::json($data, $status); - } + case Password::REMINDER_SENT: + $status = 200; + $data = [ + 'status' => 'reminder_sent', + 'success' => 'An email was sent to the user.', + ]; + } - public function postReset() - { - // Here we don't use password_confirmation but we keep it - // to call the reset function - $credentials = [ - 'email' => Input::get('email'), - 'token' => Input::get('token'), - 'password' => Input::get('password'), - 'password_confirmation' => Input::get('password'), - ]; + return Response::json($data, $status); + } - $response = Password::reset($credentials, function($user, $password) - { - // Update the password in database - $user->password = $password; - $user->save(); - }); + public function postReset() + { + // Here we don't use password_confirmation but we keep it + // to call the reset function + $credentials = [ + 'email' => Input::get('email'), + 'token' => Input::get('token'), + 'password' => Input::get('password'), + 'password_confirmation' => Input::get('password'), + ]; - switch ($response) - { - case Password::INVALID_PASSWORD: - $status = 400; - $data = [ - 'status' => 'wrong_password', - 'error' => 'The password is wrong.' - ]; - break; + $response = Password::reset($credentials, function ($user, $password) { + // Update the password in database + $user->password = $password; + $user->save(); + }); - case Password::INVALID_TOKEN: - $status = 400; - $data = [ - 'status' => 'wrong_token', - 'error' => 'The reset token is invalid.' - ]; - break; + switch ($response) { + case Password::INVALID_PASSWORD: + $status = 400; + $data = [ + 'status' => 'wrong_password', + 'error' => 'The password is wrong.', + ]; + break; - case Password::INVALID_USER: - $status = 400; - $data = [ - 'status' => 'wrong_user', - 'error' => "The email address doesn't match a user." - ]; - break; + case Password::INVALID_TOKEN: + $status = 400; + $data = [ + 'status' => 'wrong_token', + 'error' => 'The reset token is invalid.', + ]; + break; + case Password::INVALID_USER: + $status = 400; + $data = [ + 'status' => 'wrong_user', + 'error' => "The email address doesn't match a user.", + ]; + break; - case Password::PASSWORD_RESET: - $status = 200; - $data = [ - 'status' => 'password_reset', - 'success' => "The new password has been set." - ]; - } + case Password::PASSWORD_RESET: + $status = 200; + $data = [ + 'status' => 'password_reset', + 'success' => 'The new password has been set.', + ]; + } - return Response::json($data, $status); - } -} \ No newline at end of file + return Response::json($data, $status); + } +} diff --git a/app/TeenQuotes/Api/V1/Controllers/QuotesController.php b/app/TeenQuotes/Api/V1/Controllers/QuotesController.php index 1031611c..a0aa7b4c 100644 --- a/app/TeenQuotes/Api/V1/Controllers/QuotesController.php +++ b/app/TeenQuotes/Api/V1/Controllers/QuotesController.php @@ -1,295 +1,306 @@ -quoteValidator = App::make('TeenQuotes\Quotes\Validation\QuoteValidator'); - } + /** + * @var \TeenQuotes\Quotes\Validation\QuoteValidator + */ + private $quoteValidator; - public function show($quote_id) - { - $quote = $this->quoteRepo->showQuote($quote_id); + protected function bootstrap() + { + $this->quoteValidator = App::make('TeenQuotes\Quotes\Validation\QuoteValidator'); + } - // Handle not found - if ($this->isNotFound($quote)) - return Response::json([ - 'status' => 'quote_not_found', - 'error' => "The quote #".$quote_id." was not found.", - ], 404); + public function show($quote_id) + { + $quote = $this->quoteRepo->showQuote($quote_id); - // Register the view in the recommendation engine - $quote->registerViewAction(); + // Handle not found + if ($this->isNotFound($quote)) { + return Response::json([ + 'status' => 'quote_not_found', + 'error' => 'The quote #'.$quote_id.' was not found.', + ], 404); + } - return Response::json($quote, 200, [], JSON_NUMERIC_CHECK); - } + // Register the view in the recommendation engine + $quote->registerViewAction(); - public function indexFavoritesQuotes($user_id) - { - $this->relationInvolved = 'users'; + return Response::json($quote, 200, [], JSON_NUMERIC_CHECK); + } - $user = $this->userRepo->getById($user_id); + public function indexFavoritesQuotes($user_id) + { + $this->relationInvolved = 'users'; - // Handle user not found - if (is_null($user)) - return $this->tellUserWasNotFound($user_id); + $user = $this->userRepo->getById($user_id); - // Get the list of favorite quotes - $quotesFavorited = $this->favQuoteRepo->quotesFavoritesForUser($user); + // Handle user not found + if (is_null($user)) { + return $this->tellUserWasNotFound($user_id); + } - $total = count($quotesFavorited); + // Get the list of favorite quotes + $quotesFavorited = $this->favQuoteRepo->quotesFavoritesForUser($user); - $quotes = $this->getQuotesFavorite($this->getPage(), $this->getPagesize(), $quotesFavorited); + $total = count($quotesFavorited); - return $this->buildPaginatedResponse($quotes, $total); - } + $quotes = $this->getQuotesFavorite($this->getPage(), $this->getPagesize(), $quotesFavorited); - public function indexByApprovedQuotes($quote_approved_type, $user_id) - { - $this->relationInvolved = 'users'; + return $this->buildPaginatedResponse($quotes, $total); + } - $user = $this->userRepo->getById($user_id); + public function indexByApprovedQuotes($quote_approved_type, $user_id) + { + $this->relationInvolved = 'users'; - // Handle user not found - if (is_null($user)) - return $this->tellUserWasNotFound($user_id); + $user = $this->userRepo->getById($user_id); - $quotes = $this->getQuotesByApprovedForUser($this->getPage(), $this->getPagesize(), $user, $quote_approved_type); + // Handle user not found + if (is_null($user)) { + return $this->tellUserWasNotFound($user_id); + } - $total = $this->quoteRepo->countQuotesByApprovedForUser($quote_approved_type, $user); + $quotes = $this->getQuotesByApprovedForUser($this->getPage(), $this->getPagesize(), $user, $quote_approved_type); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->quoteRepo->countQuotesByApprovedForUser($quote_approved_type, $user); - public function index() - { - $quotes = $this->getQuotesHome($this->getPage(), $this->getPagesize()); + return $this->buildPaginatedResponse($quotes, $total); + } - $total = $this->quoteRepo->totalPublished(); + public function index() + { + $quotes = $this->getQuotesHome($this->getPage(), $this->getPagesize()); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->quoteRepo->totalPublished(); - public function random() - { - $quotes = $this->getQuotesRandom($this->getPage(), $this->getPagesize()); + return $this->buildPaginatedResponse($quotes, $total); + } - $total = $this->quoteRepo->totalPublished(); + public function random() + { + $quotes = $this->getQuotesRandom($this->getPage(), $this->getPagesize()); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->quoteRepo->totalPublished(); - public function getTopFavoritedQuotes() - { - $ids = $this->favQuoteRepo->getTopQuotes($this->getPage(), $this->getPagesize()); - $quotes = $this->quoteRepo->getForIds($ids, 1, count($ids)); + return $this->buildPaginatedResponse($quotes, $total); + } - $total = $this->quoteRepo->nbQuotesWithFavorites(); + public function getTopFavoritedQuotes() + { + $ids = $this->favQuoteRepo->getTopQuotes($this->getPage(), $this->getPagesize()); + $quotes = $this->quoteRepo->getForIds($ids, 1, count($ids)); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->quoteRepo->nbQuotesWithFavorites(); - public function getTopCommentedQuotes() - { - $ids = $this->commentRepo->getTopQuotes($this->getPage(), $this->getPagesize()); - $quotes = $this->quoteRepo->getForIds($ids, 1, count($ids)); + return $this->buildPaginatedResponse($quotes, $total); + } - $total = $this->quoteRepo->nbQuotesWithComments(); + public function getTopCommentedQuotes() + { + $ids = $this->commentRepo->getTopQuotes($this->getPage(), $this->getPagesize()); + $quotes = $this->quoteRepo->getForIds($ids, 1, count($ids)); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->quoteRepo->nbQuotesWithComments(); - public function getSearch($query) - { - $quotes = $this->getQuotesSearch($this->getPage(), $this->getPagesize(), $query); + return $this->buildPaginatedResponse($quotes, $total); + } - $total = $this->quoteRepo->searchCountPublishedWithQuery($query); + public function getSearch($query) + { + $quotes = $this->getQuotesSearch($this->getPage(), $this->getPagesize(), $query); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->quoteRepo->searchCountPublishedWithQuery($query); - public function getQuotesForTag($tag_name) - { - $tag = $this->tagRepo->getByName($tag_name); + return $this->buildPaginatedResponse($quotes, $total); + } - // Check if the tag has been found - if ($this->isNotFound($tag)) - throw new ApiNotFoundException('tags'); + public function getQuotesForTag($tag_name) + { + $tag = $this->tagRepo->getByName($tag_name); - $quotes = $this->quoteRepo->getQuotesForTag($tag, $this->getPage(), $this->getPagesize()); + // Check if the tag has been found + if ($this->isNotFound($tag)) { + throw new ApiNotFoundException('tags'); + } - $total = $this->tagRepo->totalQuotesForTag($tag); + $quotes = $this->quoteRepo->getQuotesForTag($tag, $this->getPage(), $this->getPagesize()); - return $this->buildPaginatedResponse($quotes, $total); - } + $total = $this->tagRepo->totalQuotesForTag($tag); - public function store($doValidation = true) - { - $user = $this->retrieveUser(); - $content = Input::get('content'); - $quotesSubmittedToday = $this->quoteRepo->submittedTodayForUser($user); + return $this->buildPaginatedResponse($quotes, $total); + } - if ($doValidation) - { - try { - $this->quoteValidator->validateNbSubmittedToday(compact('quotesSubmittedToday')); - } - catch (FormValidationException $e) - { - $errors = [ - 'status' => 'too_much_submitted_quotes', - 'error' => "The maximum number of quotes you can submit is 5 per day." - ]; - - return Response::json($errors, 400); - } - - try { - $this->quoteValidator->validatePosting(compact('content', 'quotesSubmittedToday')); - } - catch (FormValidationException $e) - { - $errors = [ - 'status' => 'wrong_content', - 'error' => 'Content of the quote should be between 50 and 300 characters.' - ]; - - return Response::json($errors, 400); - } - } - - // Store the quote - $quote = $this->quoteRepo->createQuoteForUser($user, $content); - - return Response::json($quote, 201, [], JSON_NUMERIC_CHECK); - } - - public function getPagesize() - { - $relation = $this->relationInvolved; - - switch ($relation) - { - case 'users': - return Input::get('pagesize', Config::get('app.users.nbQuotesPerPage')); - - case 'quotes': - return Input::get('pagesize', $this->getDefaultNbQuotesPerPage()); - } - - $message = "Can't determine pagesize for relation: ".$relation; - - throw new InvalidArgumentException($message); - } - - /** - * Build a paginated response for quotes - * - * @param \Illuminate\Database\Eloquent\Collection $quotes - * @param int $total The total number of results for the ressource - * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no quotes were found - * @return \TeenQuotes\Http\Facades\Response - */ - private function buildPaginatedResponse($quotes, $total) - { - // Handle no quotes found - if ($this->isNotFound($quotes)) - throw new ApiNotFoundException('quotes'); - - $data = $this->paginateContent($this->getPage(), $this->getPagesize(), $total, $quotes, 'quotes'); - - return Response::json($data, 200, [], JSON_NUMERIC_CHECK); - } - - private function getQuotesSearch($page, $pagesize, $query) - { - return $this->quoteRepo->searchPublishedWithQuery($query, $page, $pagesize); - } - - private function getDefaultNbQuotesPerPage() - { - return Config::get('app.quotes.nbQuotesPerPage'); - } - - /** - * List last published quotes - * - * @param int $page The page number - * @param int $pagesize The pagesize - * @return \TeenQuotes\Http\Facades\Response - */ - private function getQuotesHome($page, $pagesize) - { - return $this->quoteRepo->index($page, $pagesize); - } - - - /** - * List last random published quotes - * - * @param int $page The page number - * @param int $pagesize The pagesize - * @return \TeenQuotes\Http\Facades\Response - */ - private function getQuotesRandom($page, $pagesize) - { - return $this->quoteRepo->indexRandom($page, $pagesize); - } - - /** - * List last published quotes - * - * @param int $page The page number - * @param int $pagesize The pagesize - * @param array $quotesFavorited The ID of the quotes we want to grab - * @return \Illuminate\Support\Collection - */ - private function getQuotesFavorite($page, $pagesize, $quotesFavorited) - { - return $this->quoteRepo->getForIds($quotesFavorited, $page, $pagesize); - } - - /** - * Get the latest quotes for a user and an approve type - * - * @param int $page The page number - * @param int $pagesize The pagesize - * @param \TeenQuotes\Users\Models\User $user - * @param string $quote_approved_type The approve type - * @see \TeenQuotes\Quotes\Models\Quote - * @return \Illuminate\Support\Collection - */ - private function getQuotesByApprovedForUser($page, $pagesize, $user, $quote_approved_type) - { - return $this->quoteRepo->getQuotesByApprovedForUser($user, $quote_approved_type, $page, $pagesize); - } - - /** - * Tell that a user was not found - * - * @param int $user_id - * @return \TeenQuotes\Http\Facades\Response - */ - private function tellUserWasNotFound($user_id) - { - $data = [ - 'status' => 'user_not_found', - 'error' => "The user #".$user_id." was not found.", - ]; - - return Response::json($data, 400); - } + public function store($doValidation = true) + { + $user = $this->retrieveUser(); + $content = Input::get('content'); + $quotesSubmittedToday = $this->quoteRepo->submittedTodayForUser($user); + + if ($doValidation) { + try { + $this->quoteValidator->validateNbSubmittedToday(compact('quotesSubmittedToday')); + } catch (FormValidationException $e) { + $errors = [ + 'status' => 'too_much_submitted_quotes', + 'error' => 'The maximum number of quotes you can submit is 5 per day.', + ]; + + return Response::json($errors, 400); + } + + try { + $this->quoteValidator->validatePosting(compact('content', 'quotesSubmittedToday')); + } catch (FormValidationException $e) { + $errors = [ + 'status' => 'wrong_content', + 'error' => 'Content of the quote should be between 50 and 300 characters.', + ]; + + return Response::json($errors, 400); + } + } + + // Store the quote + $quote = $this->quoteRepo->createQuoteForUser($user, $content); + + return Response::json($quote, 201, [], JSON_NUMERIC_CHECK); + } + + public function getPagesize() + { + $relation = $this->relationInvolved; + + switch ($relation) { + case 'users': + return Input::get('pagesize', Config::get('app.users.nbQuotesPerPage')); + + case 'quotes': + return Input::get('pagesize', $this->getDefaultNbQuotesPerPage()); + } + + $message = "Can't determine pagesize for relation: ".$relation; + + throw new InvalidArgumentException($message); + } + + /** + * Build a paginated response for quotes. + * + * @param \Illuminate\Database\Eloquent\Collection $quotes + * @param int $total The total number of results for the ressource + * + * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no quotes were found + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function buildPaginatedResponse($quotes, $total) + { + // Handle no quotes found + if ($this->isNotFound($quotes)) { + throw new ApiNotFoundException('quotes'); + } + + $data = $this->paginateContent($this->getPage(), $this->getPagesize(), $total, $quotes, 'quotes'); + + return Response::json($data, 200, [], JSON_NUMERIC_CHECK); + } + + private function getQuotesSearch($page, $pagesize, $query) + { + return $this->quoteRepo->searchPublishedWithQuery($query, $page, $pagesize); + } + + private function getDefaultNbQuotesPerPage() + { + return Config::get('app.quotes.nbQuotesPerPage'); + } + + /** + * List last published quotes. + * + * @param int $page The page number + * @param int $pagesize The pagesize + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function getQuotesHome($page, $pagesize) + { + return $this->quoteRepo->index($page, $pagesize); + } + + /** + * List last random published quotes. + * + * @param int $page The page number + * @param int $pagesize The pagesize + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function getQuotesRandom($page, $pagesize) + { + return $this->quoteRepo->indexRandom($page, $pagesize); + } + + /** + * List last published quotes. + * + * @param int $page The page number + * @param int $pagesize The pagesize + * @param array $quotesFavorited The ID of the quotes we want to grab + * + * @return \Illuminate\Support\Collection + */ + private function getQuotesFavorite($page, $pagesize, $quotesFavorited) + { + return $this->quoteRepo->getForIds($quotesFavorited, $page, $pagesize); + } + + /** + * Get the latest quotes for a user and an approve type. + * + * @param int $page The page number + * @param int $pagesize The pagesize + * @param \TeenQuotes\Users\Models\User $user + * @param string $quote_approved_type The approve type + * + * @see \TeenQuotes\Quotes\Models\Quote + * + * @return \Illuminate\Support\Collection + */ + private function getQuotesByApprovedForUser($page, $pagesize, $user, $quote_approved_type) + { + return $this->quoteRepo->getQuotesByApprovedForUser($user, $quote_approved_type, $page, $pagesize); + } + + /** + * Tell that a user was not found. + * + * @param int $user_id + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function tellUserWasNotFound($user_id) + { + $data = [ + 'status' => 'user_not_found', + 'error' => 'The user #'.$user_id.' was not found.', + ]; + + return Response::json($data, 400); + } } diff --git a/app/TeenQuotes/Api/V1/Controllers/QuotesFavoriteController.php b/app/TeenQuotes/Api/V1/Controllers/QuotesFavoriteController.php index a7c3d287..5be3367d 100644 --- a/app/TeenQuotes/Api/V1/Controllers/QuotesFavoriteController.php +++ b/app/TeenQuotes/Api/V1/Controllers/QuotesFavoriteController.php @@ -1,109 +1,109 @@ -favQuoteValidator = App::make('TeenQuotes\Quotes\Validation\FavoriteQuoteValidator'); - } - - public function postFavorite($quote_id, $doValidation = true) - { - $user = $this->retrieveUser(); - - if ($doValidation) - { - try { - $this->favQuoteValidator->validatePostForQuote(compact('quote_id')); - } - catch (FormValidationException $e) - { - return $this->tellQuoteWasNotFound($quote_id); - } - - // Check if the quote is published - $quote = $this->quoteRepo->getById($quote_id); - - if ( ! $quote->isPublished()) - return Response::json([ - 'status' => 'quote_not_published', - 'error' => "The quote #".$quote_id." is not published.", - ], 400); - - // Try to find if the user has this quote in favorite from cache - $alreadyFavorited = $this->favQuoteRepo->isFavoriteForUserAndQuote($user, $quote_id); - - if ($alreadyFavorited) - return Response::json([ - 'status' => 'quote_already_favorited', - 'error' => "The quote #".$quote_id." was already favorited.", - ], 400); - } - - // Store the favorite - $favorite = $this->favQuoteRepo->create($user, $quote_id); - - // Register in the recommendation system - $data = [ - 'quote_id' => $quote_id, - 'user_id' => $user->id - ]; - Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@favoriteAQuote', $data); - - return Response::json($favorite, 201, [], JSON_NUMERIC_CHECK); - } - - public function deleteFavorite($quote_id, $doValidation = true) - { - $user = $this->retrieveUser(); - - if ($doValidation) { - - try { - $this->favQuoteValidator->setUserForRemove($user)->validateRemoveForQuote(compact('quote_id')); - } - catch (FormValidationException $e) - { - return $this->tellQuoteWasNotFound($quote_id); - } - } - - // Delete the FavoriteQuote from database - $this->favQuoteRepo->deleteForUserAndQuote($user, $quote_id); - - // Register in the recommendation system - $data = [ - 'quote_id' => $quote_id, - 'user_id' => $user->id - ]; - Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@unfavoriteAQuote', $data); - - return Response::json([ - 'status' => 'favorite_deleted', - 'success' => "The quote #".$quote_id." was deleted from favorites.", - ], 200, [], JSON_NUMERIC_CHECK); - } - - /** - * Tell that a quote was not found - * - * @param int $quote_id - * @return \TeenQuotes\Http\Facades\Response - */ - private function tellQuoteWasNotFound($quote_id) - { - return Response::json([ - 'status' => 'quote_not_found', - 'error' => "The quote #".$quote_id." was not found.", - ], 400); - } -} \ No newline at end of file +class QuotesFavoriteController extends APIGlobalController +{ + /** + * @var \TeenQuotes\Quotes\Validation\FavoriteQuoteValidator + */ + private $favQuoteValidator; + + public function bootstrap() + { + $this->favQuoteValidator = App::make('TeenQuotes\Quotes\Validation\FavoriteQuoteValidator'); + } + + public function postFavorite($quote_id, $doValidation = true) + { + $user = $this->retrieveUser(); + + if ($doValidation) { + try { + $this->favQuoteValidator->validatePostForQuote(compact('quote_id')); + } catch (FormValidationException $e) { + return $this->tellQuoteWasNotFound($quote_id); + } + + // Check if the quote is published + $quote = $this->quoteRepo->getById($quote_id); + + if (!$quote->isPublished()) { + return Response::json([ + 'status' => 'quote_not_published', + 'error' => 'The quote #'.$quote_id.' is not published.', + ], 400); + } + + // Try to find if the user has this quote in favorite from cache + $alreadyFavorited = $this->favQuoteRepo->isFavoriteForUserAndQuote($user, $quote_id); + + if ($alreadyFavorited) { + return Response::json([ + 'status' => 'quote_already_favorited', + 'error' => 'The quote #'.$quote_id.' was already favorited.', + ], 400); + } + } + + // Store the favorite + $favorite = $this->favQuoteRepo->create($user, $quote_id); + + // Register in the recommendation system + $data = [ + 'quote_id' => $quote_id, + 'user_id' => $user->id, + ]; + Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@favoriteAQuote', $data); + + return Response::json($favorite, 201, [], JSON_NUMERIC_CHECK); + } + + public function deleteFavorite($quote_id, $doValidation = true) + { + $user = $this->retrieveUser(); + + if ($doValidation) { + try { + $this->favQuoteValidator->setUserForRemove($user)->validateRemoveForQuote(compact('quote_id')); + } catch (FormValidationException $e) { + return $this->tellQuoteWasNotFound($quote_id); + } + } + + // Delete the FavoriteQuote from database + $this->favQuoteRepo->deleteForUserAndQuote($user, $quote_id); + + // Register in the recommendation system + $data = [ + 'quote_id' => $quote_id, + 'user_id' => $user->id, + ]; + Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@unfavoriteAQuote', $data); + + return Response::json([ + 'status' => 'favorite_deleted', + 'success' => 'The quote #'.$quote_id.' was deleted from favorites.', + ], 200, [], JSON_NUMERIC_CHECK); + } + + /** + * Tell that a quote was not found. + * + * @param int $quote_id + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function tellQuoteWasNotFound($quote_id) + { + return Response::json([ + 'status' => 'quote_not_found', + 'error' => 'The quote #'.$quote_id.' was not found.', + ], 400); + } +} diff --git a/app/TeenQuotes/Api/V1/Controllers/SearchController.php b/app/TeenQuotes/Api/V1/Controllers/SearchController.php index 347cbc60..275b7aae 100644 --- a/app/TeenQuotes/Api/V1/Controllers/SearchController.php +++ b/app/TeenQuotes/Api/V1/Controllers/SearchController.php @@ -1,81 +1,90 @@ -getPage(); - $pagesize = $this->getPagesize(); +class SearchController extends APIGlobalController implements PaginatedContentInterface +{ + public function getSearch($query) + { + $page = $this->getPage(); + $pagesize = $this->getPagesize(); - // Get content - list($quotes, $totalQuotes) = $this->getTotalQuotesAndQuotesForQuery($page, $pagesize, $query); - list($users, $totalUsers) = $this->getTotalUsersAndUsersForQuery($page, $pagesize, $query); + // Get content + list($quotes, $totalQuotes) = $this->getTotalQuotesAndQuotesForQuery($page, $pagesize, $query); + list($users, $totalUsers) = $this->getTotalUsersAndUsersForQuery($page, $pagesize, $query); - // Handle no results - if ($totalQuotes == 0 AND $totalUsers == 0) - throw new ApiNotFoundException('results'); + // Handle no results + if ($totalQuotes == 0 and $totalUsers == 0) { + throw new ApiNotFoundException('results'); + } - return Response::json([ - 'quotes' => $quotes->toArray(), - 'users' => $users->toArray(), - 'total_quotes' => $totalQuotes, - 'total_users' => $totalUsers, - 'pagesize' => (int) $pagesize, - 'url' => URL::current(), - ], 200, [], JSON_NUMERIC_CHECK); - } + return Response::json([ + 'quotes' => $quotes->toArray(), + 'users' => $users->toArray(), + 'total_quotes' => $totalQuotes, + 'total_users' => $totalUsers, + 'pagesize' => (int) $pagesize, + 'url' => URL::current(), + ], 200, [], JSON_NUMERIC_CHECK); + } - public function getPagesize() - { - return Input::get('pagesize', Config::get('app.quotes.nbQuotesPerPage')); - } + public function getPagesize() + { + return Input::get('pagesize', Config::get('app.quotes.nbQuotesPerPage')); + } - /** - * Get the total number of quotes and these objects for a page, - * pagesize and query - * - * @param int $page The page number - * @param int $pagesize The pagesize - * @param string $query The search query - * @return array The first element are the quotes, the second one is - * the total number of quotes - */ - private function getTotalQuotesAndQuotesForQuery($page, $pagesize, $query) - { - $quotes = $this->quoteRepo->searchPublishedWithQuery($query, $page, $pagesize); + /** + * Get the total number of quotes and these objects for a page, + * pagesize and query. + * + * @param int $page The page number + * @param int $pagesize The pagesize + * @param string $query The search query + * + * @return array The first element are the quotes, the second one is + * the total number of quotes + */ + private function getTotalQuotesAndQuotesForQuery($page, $pagesize, $query) + { + $quotes = $this->quoteRepo->searchPublishedWithQuery($query, $page, $pagesize); - $totalQuotes = 0; - // Don't search the total number of items if we have found nothing - if ( ! $this->isNotFound($quotes)) - $totalQuotes = $this->quoteRepo->searchCountPublishedWithQuery($query); + $totalQuotes = 0; + // Don't search the total number of items if we have found nothing + if (!$this->isNotFound($quotes)) { + $totalQuotes = $this->quoteRepo->searchCountPublishedWithQuery($query); + } - return [$quotes, $totalQuotes]; - } + return [$quotes, $totalQuotes]; + } - /** - * Get the total number of users and these objects for a page, - * pagesize and query - * - * @param int $page The page number - * @param int $pagesize The pagesize - * @param string $query The search query - * @return array The first element are the users, the second one is - * the total number of users - */ - private function getTotalUsersAndUsersForQuery($page, $pagesize, $query) - { - $users = $this->userRepo->searchByPartialLogin($query, $page, $pagesize); + /** + * Get the total number of users and these objects for a page, + * pagesize and query. + * + * @param int $page The page number + * @param int $pagesize The pagesize + * @param string $query The search query + * + * @return array The first element are the users, the second one is + * the total number of users + */ + private function getTotalUsersAndUsersForQuery($page, $pagesize, $query) + { + $users = $this->userRepo->searchByPartialLogin($query, $page, $pagesize); - $totalUsers = 0; - // Don't search the total number of items if we have found nothing - if ( ! $this->isNotFound($users)) - $totalUsers = $this->userRepo->countByPartialLogin($query); + $totalUsers = 0; + // Don't search the total number of items if we have found nothing + if (!$this->isNotFound($users)) { + $totalUsers = $this->userRepo->countByPartialLogin($query); + } - return [$users, $totalUsers]; - } -} \ No newline at end of file + return [$users, $totalUsers]; + } +} diff --git a/app/TeenQuotes/Api/V1/Controllers/StoriesController.php b/app/TeenQuotes/Api/V1/Controllers/StoriesController.php index f767edb5..68c47b15 100644 --- a/app/TeenQuotes/Api/V1/Controllers/StoriesController.php +++ b/app/TeenQuotes/Api/V1/Controllers/StoriesController.php @@ -1,80 +1,88 @@ -storyValidator = App::make('TeenQuotes\Stories\Validation\StoryValidator'); - } - - public function index() - { - $page = $this->getPage(); - $pagesize = $this->getPagesize(); - - // Get stories - $stories = $this->storyRepo->index($page, $pagesize); - - // Handle no stories found - if ($this->isNotFound($stories)) - throw new ApiNotFoundException('stories'); - - $data = $this->paginateContent($page, $pagesize, $this->storyRepo->total(), $stories, 'stories'); - - return Response::json($data, 200, [], JSON_NUMERIC_CHECK); - } - - public function show($story_id) - { - $story = $this->storyRepo->findById($story_id); - - // Handle not found - if ($this->isNotFound($story)) - return $this->tellStoryWasNotFound($story_id); - - return Response::json($story, 200, [], JSON_NUMERIC_CHECK); - } - - public function store($doValidation = true) - { - $user = $this->retrieveUser(); - $data = Input::only(['frequence_txt', 'represent_txt']); - - if ($doValidation) - $this->storyValidator->validatePosting($data); - - // Store the new story - $story = $this->storyRepo->create($user, $data['represent_txt'], $data['frequence_txt']); - - return Response::json($story, 201, [], JSON_NUMERIC_CHECK); - } - - public function getPagesize() - { - return Input::get('pagesize', Config::get('app.stories.nbStoriesPerPage')); - } - - /** - * Tell that a story was not found - * - * @param int $story_id - * @return \TeenQuotes\Http\Facades\Response - */ - private function tellStoryWasNotFound($story_id) - { - return Response::json([ - 'status' => 'story_not_found', - 'error' => "The story #".$story_id." was not found.", - ], 404); - } +class StoriesController extends APIGlobalController implements PaginatedContentInterface +{ + /** + * @var \TeenQuotes\Stories\Validation\StoryValidator + */ + private $storyValidator; + + protected function bootstrap() + { + $this->storyValidator = App::make('TeenQuotes\Stories\Validation\StoryValidator'); + } + + public function index() + { + $page = $this->getPage(); + $pagesize = $this->getPagesize(); + + // Get stories + $stories = $this->storyRepo->index($page, $pagesize); + + // Handle no stories found + if ($this->isNotFound($stories)) { + throw new ApiNotFoundException('stories'); + } + + $data = $this->paginateContent($page, $pagesize, $this->storyRepo->total(), $stories, 'stories'); + + return Response::json($data, 200, [], JSON_NUMERIC_CHECK); + } + + public function show($story_id) + { + $story = $this->storyRepo->findById($story_id); + + // Handle not found + if ($this->isNotFound($story)) { + return $this->tellStoryWasNotFound($story_id); + } + + return Response::json($story, 200, [], JSON_NUMERIC_CHECK); + } + + public function store($doValidation = true) + { + $user = $this->retrieveUser(); + $data = Input::only(['frequence_txt', 'represent_txt']); + + if ($doValidation) { + $this->storyValidator->validatePosting($data); + } + + // Store the new story + $story = $this->storyRepo->create($user, $data['represent_txt'], $data['frequence_txt']); + + return Response::json($story, 201, [], JSON_NUMERIC_CHECK); + } + + public function getPagesize() + { + return Input::get('pagesize', Config::get('app.stories.nbStoriesPerPage')); + } + + /** + * Tell that a story was not found. + * + * @param int $story_id + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function tellStoryWasNotFound($story_id) + { + return Response::json([ + 'status' => 'story_not_found', + 'error' => 'The story #'.$story_id.' was not found.', + ], 404); + } } diff --git a/app/TeenQuotes/Api/V1/Controllers/UsersController.php b/app/TeenQuotes/Api/V1/Controllers/UsersController.php index d9947387..d1ea84d4 100644 --- a/app/TeenQuotes/Api/V1/Controllers/UsersController.php +++ b/app/TeenQuotes/Api/V1/Controllers/UsersController.php @@ -1,9 +1,13 @@ -userValidator = App::make(UserValidator::class); - $this->localisationDetector = App::make(Detector::class); - } - - /** - * Destroy the account of the logged in user - * @return \TeenQuotes\Http\Facades\Response - */ - public function destroy() - { - $this->userRepo->destroy($this->retrieveUser()); - - return Response::json([ - 'status' => 'user_deleted', - 'success' => 'The user has been deleted.' - ], 200); - } - - - /** - * Show information about the logged in user - * @return \TeenQuotes\Http\Facades\Response - */ - public function getUsers() - { - $u = $this->retrieveUser(); - - return $this->show($u->id); - } - - /** - * Create a new account - * @param boolean $doValidation Do we need to perform validation? - * @return \TeenQuotes\Http\Facades\Response - */ - public function store($doValidation = true) - { - $data = Input::only(['login', 'password', 'email']); - - if ($doValidation) - $this->userValidator->validateSignup($data); - - // Store the new user - // If the new user has got a Gravatar, set the avatar - $avatar = null; - if (Gravatar::exists($data['email'])) - $avatar = Gravatar::src($data['email'], 150); - - // Try to detect the city and the country from the request - $request = Input::instance(); - $country = $this->localisationDetector->detectCountry($request); - $city = $this->localisationDetector->detectCity($request); - - $user = $this->userRepo->create($data['login'], $data['email'], $data['password'], - $_SERVER['REMOTE_ADDR'], Carbon::now()->toDateTimeString(), - $country, $city, $avatar - ); - - // Send a welcome e-mail and subscribe the user to the - // weekly newsletter thanks to its observer - - return Response::json($user, 201, [], JSON_NUMERIC_CHECK); - } - - /** - * Show a user's profile - * @param int $user_id The ID of the user - * @return \TeenQuotes\Http\Facades\Response - */ - public function show($user_id) - { - $user = $this->userRepo->showByLoginOrId($user_id); - - // User not found - if ($this->isNotFound($user)) - return Response::json([ - 'status' => 404, - 'error' => 'User not found.' - ], 404); - - $data = $user->toArray(); - foreach (User::$appendsFull as $key) - { - $method = Str::camel('get_'.$key); - $data[$key] = $user->$method(); - } - - $user->registerViewUserProfile(); - - return Response::json($data, 200, [], JSON_NUMERIC_CHECK); - } - - /** - * Search users without an hidden profile from a partial username - * @param string $query - * @return \TeenQuotes\Http\Facades\Response - * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no users were found - */ - public function getSearch($query) - { - // Get users - $users = $this->getUsersSearch($this->getPage(), $this->getPagesize(), $query); - - // Count the total number of results - $totalUsers = $this->userRepo->countByPartialLogin($query); - - return $this->buildPaginatedResponse($users, $totalUsers); - } - - /** - * Update a user's profile - * @param boolean $doValidation Do we perform validation? - * @return \TeenQuotes\Http\Facades\Response - */ - public function putProfile($doValidation = true) - { - $data = [ - 'gender' => Input::get('gender'), - 'birthdate' => Input::get('birthdate'), - 'country' => Input::get('country'), - 'city' => Input::get('city'), - 'about_me' => Input::get('about_me'), - 'avatar' => Input::file('avatar'), - ]; - - if ($doValidation) - $this->userValidator->validateUpdateProfile($data); - - // Everything went fine, update the user - $user = $this->retrieveUser(); - - $this->userRepo->updateProfile($user, $data['gender'], $data['country'], - $data['city'], $data['about_me'], $data['birthdate'], - $data['avatar']); - - // Move the avatar if required - if ( ! is_null($data['avatar'])) - $this->cropAndMoveAvatar($user, $data['avatar']); - - return Response::json([ - 'status' => 'profile_updated', - 'success' => 'The profile has been updated.' - ], 200); - } - - /** - * Update the password of the logged in user - * @return \TeenQuotes\Http\Facades\Response - */ - public function putPassword() - { - $user = $this->retrieveUser(); - - $data = Input::only(['password', 'password_confirmation']); - - $this->userValidator->validateUpdatePassword($data); - - // Update the new password - $this->userRepo->updatePassword($user, $data['password']); - - return Response::json([ - 'status' => 'password_updated', - 'success' => 'The new password has been set.', - ], 200, [], JSON_NUMERIC_CHECK); - } - - /** - * Update the user's settings - * @param \TeenQuotes\Users\Models\User|null $userInstance - * @return \TeenQuotes\Http\Facades\Response - */ - public function putSettings($userInstance = null) - { - if (is_null($userInstance)) - $user = $this->retrieveUser(); - else - $user = $userInstance; - - // We just want booleans - $data = [ - 'notification_comment_quote' => Input::has('notification_comment_quote') ? filter_var(Input::get('notification_comment_quote'), FILTER_VALIDATE_BOOLEAN) : false, - 'hide_profile' => Input::has('hide_profile') ? filter_var(Input::get('hide_profile'), FILTER_VALIDATE_BOOLEAN) : false, - 'weekly_newsletter' => Input::has('weekly_newsletter') ? filter_var(Input::get('weekly_newsletter'), FILTER_VALIDATE_BOOLEAN) : false, - 'daily_newsletter' => Input::has('daily_newsletter') ? filter_var(Input::get('daily_newsletter'), FILTER_VALIDATE_BOOLEAN) : false, - 'colors' => Input::get('colors'), - ]; - - $this->userRepo->updateSettings($user, $data['notification_comment_quote'], $data['hide_profile']); - - // Update daily / weekly newsletters - foreach (Newsletter::getPossibleTypes() as $newsletterType) - { - // The user wants the newsletter - if ($data[$newsletterType.'_newsletter']) - { - // He was NOT already subscribed, store this in storage - if ( ! $user->isSubscribedToNewsletter($newsletterType)) - $this->newslettersManager->createForUserAndType($user, $newsletterType); - - // He was already subscribed, do nothing - } - // The user doesn't want the newsletter - else { - // He was subscribed, delete this from storage - if ($user->isSubscribedToNewsletter($newsletterType)) - $this->newslettersManager->deleteForUserAndType($user, $newsletterType); - - // He was not subscribed, do nothing - } - } - - // Update colors for quotes - if ( ! in_array($data['colors'], Config::get('app.users.colorsAvailableQuotesPublished'))) - return $this->colorIsNotAllowed(); - - $this->settingRepo->updateOrCreate($user, 'colorsQuotesPublished', $data['colors']); - - return Response::json([ - 'status' => 'profile_updated', - 'success' => 'The profile has been updated.' - ], 200); - } - - /** - * Get users from a given country - * @param int $country_id The ID of the country - * @return \TeenQuotes\Http\Facades\Response - * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no users were found - */ - public function fromCountry($country_id) - { - $country = $this->countryRepo->findById($country_id); - - if ($this->isNotFound($country)) - return $this->countryWasNotFound($country_id); - - $users = $this->userRepo->fromCountry($country, $this->getPage(), $this->getPagesize()); - - $totalUsers = $this->userRepo->countFromCountry($country); - - return $this->buildPaginatedResponse($users, $totalUsers); - } - - /** - * Retrieve users from a partial username for a given page and pagesize - * @param int $page - * @param int $pagesize - * @param string $query - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getUsersSearch($page, $pagesize, $query) - { - return $this->userRepo->searchByPartialLogin($query, $page, $pagesize); - } - - /** - * Get the pagesize - * @return int - */ - public function getPagesize() - { - return Input::get('pagesize', Config::get('app.quotes.nbQuotesPerPage')); - } - - private function cropAndMoveAvatar(User $user, $avatar) - { - $filename = $user->id.'.'.$avatar->getClientOriginalExtension(); - $filepath = Config::get('app.users.avatarPath').'/'.$filename; - - // Save to the final location - Input::file('avatar')->move(Config::get('app.users.avatarPath'), $filename); - - // Crop the image and save it - $center = new CropEntropy($filepath); - $croppedImage = $center->resizeAndCrop(Config::get('app.users.avatarWidth'), Config::get('app.users.avatarHeight')); - $croppedImage->writeimage($filepath); - } - - /** - * Tell that a country was not found - * - * @param int $id The country's ID - * @return \TeenQuotes\Http\Facades\Response - */ - private function countryWasNotFound($id) - { - return Response::json([ - 'status' => 'country_not_found', - 'error' => "The country #".$id." was not found.", - ], 404); - } - - /** - * Tell that a color is not allowed - * @return \TeenQuotes\Http\Facades\Response - */ - private function colorIsNotAllowed() - { - return Response::json([ - 'status' => 'wrong_color', - 'error' => 'This color is not allowed.' - ], 400); - } - - /** - * Build a paginated response for users - * - * @param \Illuminate\Database\Eloquent\Collection $users - * @param int $total The total number of results for the ressource - * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no users were found - * @return \TeenQuotes\Http\Facades\Response - */ - private function buildPaginatedResponse($users, $total) - { - // Handle no users found - if ($this->isNotFound($users)) - throw new ApiNotFoundException('users'); - - $data = $this->paginateContent($this->getPage(), $this->getPagesize(), $total, $users, 'users'); - - return Response::json($data, 200, [], JSON_NUMERIC_CHECK); - } +class UsersController extends APIGlobalController implements PaginatedContentInterface +{ + /** + * @var \TeenQuotes\Users\Validation\UserValidator + */ + private $userValidator; + + /** + * @var \TeenQuotes\Countries\Localisation\Detector + */ + private $localisationDetector; + + protected function bootstrap() + { + $this->userValidator = App::make(UserValidator::class); + $this->localisationDetector = App::make(Detector::class); + } + + /** + * Destroy the account of the logged in user. + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function destroy() + { + $this->userRepo->destroy($this->retrieveUser()); + + return Response::json([ + 'status' => 'user_deleted', + 'success' => 'The user has been deleted.', + ], 200); + } + + /** + * Show information about the logged in user. + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function getUsers() + { + $u = $this->retrieveUser(); + + return $this->show($u->id); + } + + /** + * Create a new account. + * + * @param bool $doValidation Do we need to perform validation? + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function store($doValidation = true) + { + $data = Input::only(['login', 'password', 'email']); + + if ($doValidation) { + $this->userValidator->validateSignup($data); + } + + // Store the new user + // If the new user has got a Gravatar, set the avatar + $avatar = null; + if (Gravatar::exists($data['email'])) { + $avatar = Gravatar::src($data['email'], 150); + } + + // Try to detect the city and the country from the request + $request = Input::instance(); + $country = $this->localisationDetector->detectCountry($request); + $city = $this->localisationDetector->detectCity($request); + + $user = $this->userRepo->create($data['login'], $data['email'], $data['password'], + $_SERVER['REMOTE_ADDR'], Carbon::now()->toDateTimeString(), + $country, $city, $avatar + ); + + // Send a welcome e-mail and subscribe the user to the + // weekly newsletter thanks to its observer + + return Response::json($user, 201, [], JSON_NUMERIC_CHECK); + } + + /** + * Show a user's profile. + * + * @param int $user_id The ID of the user + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function show($user_id) + { + $user = $this->userRepo->showByLoginOrId($user_id); + + // User not found + if ($this->isNotFound($user)) { + return Response::json([ + 'status' => 404, + 'error' => 'User not found.', + ], 404); + } + + $data = $user->toArray(); + foreach (User::$appendsFull as $key) { + $method = Str::camel('get_'.$key); + $data[$key] = $user->$method(); + } + + $user->registerViewUserProfile(); + + return Response::json($data, 200, [], JSON_NUMERIC_CHECK); + } + + /** + * Search users without an hidden profile from a partial username. + * + * @param string $query + * + * @return \TeenQuotes\Http\Facades\Response + * + * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no users were found + */ + public function getSearch($query) + { + // Get users + $users = $this->getUsersSearch($this->getPage(), $this->getPagesize(), $query); + + // Count the total number of results + $totalUsers = $this->userRepo->countByPartialLogin($query); + + return $this->buildPaginatedResponse($users, $totalUsers); + } + + /** + * Update a user's profile. + * + * @param bool $doValidation Do we perform validation? + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function putProfile($doValidation = true) + { + $data = [ + 'gender' => Input::get('gender'), + 'birthdate' => Input::get('birthdate'), + 'country' => Input::get('country'), + 'city' => Input::get('city'), + 'about_me' => Input::get('about_me'), + 'avatar' => Input::file('avatar'), + ]; + + if ($doValidation) { + $this->userValidator->validateUpdateProfile($data); + } + + // Everything went fine, update the user + $user = $this->retrieveUser(); + + $this->userRepo->updateProfile($user, $data['gender'], $data['country'], + $data['city'], $data['about_me'], $data['birthdate'], + $data['avatar']); + + // Move the avatar if required + if (!is_null($data['avatar'])) { + $this->cropAndMoveAvatar($user, $data['avatar']); + } + + return Response::json([ + 'status' => 'profile_updated', + 'success' => 'The profile has been updated.', + ], 200); + } + + /** + * Update the password of the logged in user. + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function putPassword() + { + $user = $this->retrieveUser(); + + $data = Input::only(['password', 'password_confirmation']); + + $this->userValidator->validateUpdatePassword($data); + + // Update the new password + $this->userRepo->updatePassword($user, $data['password']); + + return Response::json([ + 'status' => 'password_updated', + 'success' => 'The new password has been set.', + ], 200, [], JSON_NUMERIC_CHECK); + } + + /** + * Update the user's settings. + * + * @param \TeenQuotes\Users\Models\User|null $userInstance + * + * @return \TeenQuotes\Http\Facades\Response + */ + public function putSettings($userInstance = null) + { + if (is_null($userInstance)) { + $user = $this->retrieveUser(); + } else { + $user = $userInstance; + } + + // We just want booleans + $data = [ + 'notification_comment_quote' => Input::has('notification_comment_quote') ? filter_var(Input::get('notification_comment_quote'), FILTER_VALIDATE_BOOLEAN) : false, + 'hide_profile' => Input::has('hide_profile') ? filter_var(Input::get('hide_profile'), FILTER_VALIDATE_BOOLEAN) : false, + 'weekly_newsletter' => Input::has('weekly_newsletter') ? filter_var(Input::get('weekly_newsletter'), FILTER_VALIDATE_BOOLEAN) : false, + 'daily_newsletter' => Input::has('daily_newsletter') ? filter_var(Input::get('daily_newsletter'), FILTER_VALIDATE_BOOLEAN) : false, + 'colors' => Input::get('colors'), + ]; + + $this->userRepo->updateSettings($user, $data['notification_comment_quote'], $data['hide_profile']); + + // Update daily / weekly newsletters + foreach (Newsletter::getPossibleTypes() as $newsletterType) { + // The user wants the newsletter + if ($data[$newsletterType.'_newsletter']) { + // He was NOT already subscribed, store this in storage + if (!$user->isSubscribedToNewsletter($newsletterType)) { + $this->newslettersManager->createForUserAndType($user, $newsletterType); + } + + // He was already subscribed, do nothing + } + // The user doesn't want the newsletter + else { + // He was subscribed, delete this from storage + if ($user->isSubscribedToNewsletter($newsletterType)) { + $this->newslettersManager->deleteForUserAndType($user, $newsletterType); + } + + // He was not subscribed, do nothing + } + } + + // Update colors for quotes + if (!in_array($data['colors'], Config::get('app.users.colorsAvailableQuotesPublished'))) { + return $this->colorIsNotAllowed(); + } + + $this->settingRepo->updateOrCreate($user, 'colorsQuotesPublished', $data['colors']); + + return Response::json([ + 'status' => 'profile_updated', + 'success' => 'The profile has been updated.', + ], 200); + } + + /** + * Get users from a given country. + * + * @param int $country_id The ID of the country + * + * @return \TeenQuotes\Http\Facades\Response + * + * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no users were found + */ + public function fromCountry($country_id) + { + $country = $this->countryRepo->findById($country_id); + + if ($this->isNotFound($country)) { + return $this->countryWasNotFound($country_id); + } + + $users = $this->userRepo->fromCountry($country, $this->getPage(), $this->getPagesize()); + + $totalUsers = $this->userRepo->countFromCountry($country); + + return $this->buildPaginatedResponse($users, $totalUsers); + } + + /** + * Retrieve users from a partial username for a given page and pagesize. + * + * @param int $page + * @param int $pagesize + * @param string $query + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getUsersSearch($page, $pagesize, $query) + { + return $this->userRepo->searchByPartialLogin($query, $page, $pagesize); + } + + /** + * Get the pagesize. + * + * @return int + */ + public function getPagesize() + { + return Input::get('pagesize', Config::get('app.quotes.nbQuotesPerPage')); + } + + private function cropAndMoveAvatar(User $user, $avatar) + { + $filename = $user->id.'.'.$avatar->getClientOriginalExtension(); + $filepath = Config::get('app.users.avatarPath').'/'.$filename; + + // Save to the final location + Input::file('avatar')->move(Config::get('app.users.avatarPath'), $filename); + + // Crop the image and save it + $center = new CropEntropy($filepath); + $croppedImage = $center->resizeAndCrop(Config::get('app.users.avatarWidth'), Config::get('app.users.avatarHeight')); + $croppedImage->writeimage($filepath); + } + + /** + * Tell that a country was not found. + * + * @param int $id The country's ID + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function countryWasNotFound($id) + { + return Response::json([ + 'status' => 'country_not_found', + 'error' => 'The country #'.$id.' was not found.', + ], 404); + } + + /** + * Tell that a color is not allowed. + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function colorIsNotAllowed() + { + return Response::json([ + 'status' => 'wrong_color', + 'error' => 'This color is not allowed.', + ], 400); + } + + /** + * Build a paginated response for users. + * + * @param \Illuminate\Database\Eloquent\Collection $users + * @param int $total The total number of results for the ressource + * + * @throws \TeenQuotes\Exceptions\ApiNotFoundException If no users were found + * + * @return \TeenQuotes\Http\Facades\Response + */ + private function buildPaginatedResponse($users, $total) + { + // Handle no users found + if ($this->isNotFound($users)) { + throw new ApiNotFoundException('users'); + } + + $data = $this->paginateContent($this->getPage(), $this->getPagesize(), $total, $users, 'users'); + + return Response::json($data, 200, [], JSON_NUMERIC_CHECK); + } } diff --git a/app/TeenQuotes/Api/V1/Interfaces/PageBuilderInterface.php b/app/TeenQuotes/Api/V1/Interfaces/PageBuilderInterface.php index ccc23534..2656b2fb 100644 --- a/app/TeenQuotes/Api/V1/Interfaces/PageBuilderInterface.php +++ b/app/TeenQuotes/Api/V1/Interfaces/PageBuilderInterface.php @@ -1,16 +1,19 @@ -buildNextPage($page, $pagesize, $totalPages, $url, $getParams); +use TeenQuotes\Api\V1\Interfaces\PageBuilderInterface; - // Add previous page URL - list($has_previous_page, $previous_page) = $this->buildPreviousPage($page, $pagesize, $url, $getParams); +class PageBuilder implements PageBuilderInterface +{ + /** + * Build page parameters for a paginated response. + * + * @param int $page The current page + * @param int $pagesize The number of elements per page + * @param int $totalPages The total number of pages + * @param string $url The URL of the endpoint + * @param string $getParams Additional get parameters + * + * @return array Keys: has_next_page, has_previous_page[, next_page, previous_page] + */ + public function buildPagesArray($page, $pagesize, $totalPages, $url, $getParams) + { + // Add next page URL + list($has_next_page, $next_page) = $this->buildNextPage($page, $pagesize, $totalPages, $url, $getParams); - $pagesArray = compact('has_next_page', 'next_page', 'has_previous_page', 'previous_page'); + // Add previous page URL + list($has_previous_page, $previous_page) = $this->buildPreviousPage($page, $pagesize, $url, $getParams); - // Remove null values from the array - return array_filter($pagesArray, [$this, 'notNull']); - } + $pagesArray = compact('has_next_page', 'next_page', 'has_previous_page', 'previous_page'); - /** - * Return true if the value is not null - * - * @param mixed $v - * @return boolean - */ - private function notNull($v) - { - return ! is_null($v); - } + // Remove null values from the array + return array_filter($pagesArray, [$this, 'notNull']); + } - /** - * Build "next page" parameters for a paginated response - * - * @param int $page The current page - * @param int $pagesize The number of elements per page - * @param int $totalPages The total number of pages - * @param string $url The URL of the endpoint - * @param string $getParams Additional get parameters - * @return array The first element is a boolean. The second element, - * is the next page's URL if we've got a next page - */ - private function buildNextPage($page, $pagesize, $totalPages, $url, $getParams) - { - $hasNextPage = ($page < $totalPages); - $nextPage = null; + /** + * Return true if the value is not null. + * + * @param mixed $v + * + * @return bool + */ + private function notNull($v) + { + return !is_null($v); + } - if ($hasNextPage) - $nextPage = $url.'?page='.($page + 1).'&pagesize='.$pagesize.$getParams; + /** + * Build "next page" parameters for a paginated response. + * + * @param int $page The current page + * @param int $pagesize The number of elements per page + * @param int $totalPages The total number of pages + * @param string $url The URL of the endpoint + * @param string $getParams Additional get parameters + * + * @return array The first element is a boolean. The second element, + * is the next page's URL if we've got a next page + */ + private function buildNextPage($page, $pagesize, $totalPages, $url, $getParams) + { + $hasNextPage = ($page < $totalPages); + $nextPage = null; - return [$hasNextPage, $nextPage]; - } + if ($hasNextPage) { + $nextPage = $url.'?page='.($page + 1).'&pagesize='.$pagesize.$getParams; + } - /** - * Build "previous page" parameters for a paginated response - * - * @param int $page The current page - * @param int $pagesize The number of elements per page - * @param string $url The URL of the endpoint - * @param string $getParams Additional get parameters - * @return array The first element is a boolean. The second element, - * is the previous page's URL if we've got a previous page - */ - private function buildPreviousPage($page, $pagesize, $url, $getParams) - { - $hasPreviousPage = ($page >= 2); - $previousPage = null; + return [$hasNextPage, $nextPage]; + } - if ($hasPreviousPage) - $previousPage = $url.'?page='.($page - 1).'&pagesize='.$pagesize.$getParams; + /** + * Build "previous page" parameters for a paginated response. + * + * @param int $page The current page + * @param int $pagesize The number of elements per page + * @param string $url The URL of the endpoint + * @param string $getParams Additional get parameters + * + * @return array The first element is a boolean. The second element, + * is the previous page's URL if we've got a previous page + */ + private function buildPreviousPage($page, $pagesize, $url, $getParams) + { + $hasPreviousPage = ($page >= 2); + $previousPage = null; - return [$hasPreviousPage, $previousPage]; - } + if ($hasPreviousPage) { + $previousPage = $url.'?page='.($page - 1).'&pagesize='.$pagesize.$getParams; + } + return [$hasPreviousPage, $previousPage]; + } } diff --git a/app/TeenQuotes/Auth/AuthServiceProvider.php b/app/TeenQuotes/Auth/AuthServiceProvider.php index c27838fd..93e2de48 100644 --- a/app/TeenQuotes/Auth/AuthServiceProvider.php +++ b/app/TeenQuotes/Auth/AuthServiceProvider.php @@ -1,99 +1,100 @@ -registerAuthRoutes(); - $this->registerAuthViewComposers(); - - // Reminders - $this->registerReminderRoutes(); - $this->registerReminderViewComposers(); - } - - private function registerAuthRoutes() - { - $controller = 'AuthController'; - - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) { - $this->app['router']->get('signin', ['as' => 'signin', 'uses' => $controller.'@getSignin']); - $this->app['router']->get('logout', ['as' => 'logout', 'uses' => $controller.'@getLogout']); - $this->app['router']->post('signin', $controller.'@postSignin'); - }); - } - - private function registerAuthViewComposers() - { - // Send event to GA when not logged in - $this->app['view']->composer([ - 'auth.signin' - ], $this->getNamespaceComposers().'SigninComposer'); - - // When signing up - $this->app['view']->composer([ - 'auth.signup' - ], $this->getNamespaceComposers().'SignupComposer'); - - // For deeps link - $this->app['view']->composer([ - 'auth.signin', - 'auth.signup' - ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); - } - - private function registerReminderRoutes() - { - $controller = 'RemindersController'; - - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) { - $this->app['router']->get('password/remind', ['as' => 'password.remind', 'uses' => $controller.'@getRemind']); - $this->app['router']->post('password/remind', ['as' => 'password.remind', 'uses' => $controller.'@postRemind']); - $this->app['router']->get('password/reset', ['as' => 'password.reset', 'uses' => $controller.'@getReset']); - $this->app['router']->post('password/reset', ['as' => 'password.reset', 'uses' => $controller.'@postReset']); - }); - } - - private function registerReminderViewComposers() - { - // Reset a password with a token - $this->app['view']->composer([ - 'password.reset' - ], $this->getNamespaceComposers().'ResetComposer'); - - // For deeps link - $this->app['view']->composer([ - 'password.remind' - ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); - } - - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domainAccount'), - 'namespace' => 'TeenQuotes\Auth\Controllers' - ]; - } +class AuthServiceProvider extends ServiceProvider +{ + use NamespaceTrait; + + /** + * Indicates if loading of the provider is deferred. + * + * @var bool + */ + protected $defer = false; + + /** + * Register the service provider. + */ + public function register() + { + // Authentification + $this->registerAuthRoutes(); + $this->registerAuthViewComposers(); + + // Reminders + $this->registerReminderRoutes(); + $this->registerReminderViewComposers(); + } + + private function registerAuthRoutes() + { + $controller = 'AuthController'; + + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->get('signin', ['as' => 'signin', 'uses' => $controller.'@getSignin']); + $this->app['router']->get('logout', ['as' => 'logout', 'uses' => $controller.'@getLogout']); + $this->app['router']->post('signin', $controller.'@postSignin'); + }); + } + + private function registerAuthViewComposers() + { + // Send event to GA when not logged in + $this->app['view']->composer([ + 'auth.signin', + ], $this->getNamespaceComposers().'SigninComposer'); + + // When signing up + $this->app['view']->composer([ + 'auth.signup', + ], $this->getNamespaceComposers().'SignupComposer'); + + // For deeps link + $this->app['view']->composer([ + 'auth.signin', + 'auth.signup', + ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); + } + + private function registerReminderRoutes() + { + $controller = 'RemindersController'; + + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->get('password/remind', ['as' => 'password.remind', 'uses' => $controller.'@getRemind']); + $this->app['router']->post('password/remind', ['as' => 'password.remind', 'uses' => $controller.'@postRemind']); + $this->app['router']->get('password/reset', ['as' => 'password.reset', 'uses' => $controller.'@getReset']); + $this->app['router']->post('password/reset', ['as' => 'password.reset', 'uses' => $controller.'@postReset']); + }); + } + + private function registerReminderViewComposers() + { + // Reset a password with a token + $this->app['view']->composer([ + 'password.reset', + ], $this->getNamespaceComposers().'ResetComposer'); + + // For deeps link + $this->app['view']->composer([ + 'password.remind', + ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); + } + + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domainAccount'), + 'namespace' => 'TeenQuotes\Auth\Controllers', + ]; + } } diff --git a/app/TeenQuotes/Auth/Composers/ResetComposer.php b/app/TeenQuotes/Auth/Composers/ResetComposer.php index fe7294af..c0b6e12e 100644 --- a/app/TeenQuotes/Auth/Composers/ResetComposer.php +++ b/app/TeenQuotes/Auth/Composers/ResetComposer.php @@ -1,16 +1,22 @@ -getData(); - $token = $data['token']; +class ResetComposer extends AbstractDeepLinksComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + $token = $data['token']; - // For deep links - $view->with('deepLinksArray', $this->createDeepLinks('password/reset?token='.$token)); - } -} \ No newline at end of file + // For deep links + $view->with('deepLinksArray', $this->createDeepLinks('password/reset?token='.$token)); + } +} diff --git a/app/TeenQuotes/Auth/Composers/SigninComposer.php b/app/TeenQuotes/Auth/Composers/SigninComposer.php index 49afac49..e419b8e3 100644 --- a/app/TeenQuotes/Auth/Composers/SigninComposer.php +++ b/app/TeenQuotes/Auth/Composers/SigninComposer.php @@ -1,18 +1,26 @@ -getData(); +class SigninComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); - if ($data['requireLoggedInAddQuote']) - JavaScript::put([ - 'eventCategory' => 'addquote', - 'eventAction' => 'not-logged-in', - 'eventLabel' => 'signin-page' - ]); - } -} \ No newline at end of file + if ($data['requireLoggedInAddQuote']) { + JavaScript::put([ + 'eventCategory' => 'addquote', + 'eventAction' => 'not-logged-in', + 'eventLabel' => 'signin-page', + ]); + } + } +} diff --git a/app/TeenQuotes/Auth/Composers/SignupComposer.php b/app/TeenQuotes/Auth/Composers/SignupComposer.php index e3104cac..bbaffb10 100644 --- a/app/TeenQuotes/Auth/Composers/SignupComposer.php +++ b/app/TeenQuotes/Auth/Composers/SignupComposer.php @@ -1,18 +1,28 @@ - Lang::get('auth.didYouMean'), - 'mailAddressInvalid' => Lang::get('auth.mailAddressInvalid'), - 'mailAddressValid' => Lang::get('auth.mailAddressValid'), - 'mailAddressUpdated' => Lang::get('auth.mailAddressUpdated'), - 'mailgunPubKey' => Config::get('services.mailgun.pubkey'), - 'urlLoginValidator' => URL::route('users.loginValidator', [], true), - ]); - } -} \ No newline at end of file +class SignupComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + JavaScript::put([ + 'didYouMean' => Lang::get('auth.didYouMean'), + 'mailAddressInvalid' => Lang::get('auth.mailAddressInvalid'), + 'mailAddressValid' => Lang::get('auth.mailAddressValid'), + 'mailAddressUpdated' => Lang::get('auth.mailAddressUpdated'), + 'mailgunPubKey' => Config::get('services.mailgun.pubkey'), + 'urlLoginValidator' => URL::route('users.loginValidator', [], true), + ]); + } +} diff --git a/app/TeenQuotes/Auth/Controllers/AuthController.php b/app/TeenQuotes/Auth/Controllers/AuthController.php index dd32c2e1..fcc47576 100644 --- a/app/TeenQuotes/Auth/Controllers/AuthController.php +++ b/app/TeenQuotes/Auth/Controllers/AuthController.php @@ -1,108 +1,111 @@ -beforeFilter('guest', ['only' => 'getSignin']); - $this->beforeFilter('auth', ['only' => 'getLogout']); - - $this->userRepo = $userRepo; - $this->userValidator = $userValidator; - } - - /** - * Displays the signin form - * - * @return \Response - */ - public function getSignin() - { - $data = [ - 'pageTitle' => Lang::get('auth.signinPageTitle'), - 'pageDescription' => Lang::get('auth.signinPageDescription'), - 'requireLoggedInAddQuote' => Session::has('requireLoggedInAddQuote'), - ]; - - return View::make('auth.signin', $data); - } - - /** - * Handles the signin form submission - * - * @return \Response - */ - public function postSignin() - { - $data = Input::only(['login', 'password']); - - try { - $this->userValidator->validateSignin($data); - } - catch (FormValidationException $e) - { - return Redirect::route('signin') - ->withErrors($e->getErrors()) - ->withInput(Input::except('password')); - } - - // Try to log the user in. - if (Auth::attempt($data, true)) - { - $user = Auth::user(); - $user->last_visit = Carbon::now()->toDateTimeString(); - $user->save(); - - return Redirect::intended(route('home'))->with('success', Lang::get('auth.loginSuccessfull', ['login' => $data['login']])); - } - // Maybe the user uses the old hash method - else - { - $user = $this->userRepo->getByLogin($data['login']); - - if ( ! is_null($user) AND ($user->password == User::oldHashMethod($data))) - { - // Update the password in database - $user->password = $data['password']; - $user->last_visit = Carbon::now()->toDateTimeString(); - $user->save(); - - Auth::login($user, true); - - return Redirect::intended(route('home'))->with('success', Lang::get('auth.loginSuccessfull', ['login' => $data['login']])); - } - - return Redirect::route('signin')->withErrors(array('password' => Lang::get('auth.passwordInvalid')))->withInput(Input::except('password')); - } - } - - /** - * Log a user out - * - * @return \Response - */ - public function getLogout() - { - $login = Auth::user()->login; - Auth::logout(); - - return Redirect::route('home')->with('success', Lang::get('auth.logoutSuccessfull', compact('login'))); - } +use View; + +class AuthController extends BaseController +{ + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + /** + * @var \TeenQuotes\Users\Validation\UserValidator + */ + private $userValidator; + + public function __construct(UserRepository $userRepo, UserValidator $userValidator) + { + $this->beforeFilter('guest', ['only' => 'getSignin']); + $this->beforeFilter('auth', ['only' => 'getLogout']); + + $this->userRepo = $userRepo; + $this->userValidator = $userValidator; + } + + /** + * Displays the signin form. + * + * @return \Response + */ + public function getSignin() + { + $data = [ + 'pageTitle' => Lang::get('auth.signinPageTitle'), + 'pageDescription' => Lang::get('auth.signinPageDescription'), + 'requireLoggedInAddQuote' => Session::has('requireLoggedInAddQuote'), + ]; + + return View::make('auth.signin', $data); + } + + /** + * Handles the signin form submission. + * + * @return \Response + */ + public function postSignin() + { + $data = Input::only(['login', 'password']); + + try { + $this->userValidator->validateSignin($data); + } catch (FormValidationException $e) { + return Redirect::route('signin') + ->withErrors($e->getErrors()) + ->withInput(Input::except('password')); + } + + // Try to log the user in. + if (Auth::attempt($data, true)) { + $user = Auth::user(); + $user->last_visit = Carbon::now()->toDateTimeString(); + $user->save(); + + return Redirect::intended(route('home'))->with('success', Lang::get('auth.loginSuccessfull', ['login' => $data['login']])); + } + // Maybe the user uses the old hash method + else { + $user = $this->userRepo->getByLogin($data['login']); + + if (!is_null($user) and ($user->password == User::oldHashMethod($data))) { + // Update the password in database + $user->password = $data['password']; + $user->last_visit = Carbon::now()->toDateTimeString(); + $user->save(); + + Auth::login($user, true); + + return Redirect::intended(route('home'))->with('success', Lang::get('auth.loginSuccessfull', ['login' => $data['login']])); + } + + return Redirect::route('signin')->withErrors(['password' => Lang::get('auth.passwordInvalid')])->withInput(Input::except('password')); + } + } + + /** + * Log a user out. + * + * @return \Response + */ + public function getLogout() + { + $login = Auth::user()->login; + Auth::logout(); + + return Redirect::route('home')->with('success', Lang::get('auth.logoutSuccessfull', compact('login'))); + } } diff --git a/app/TeenQuotes/Auth/Controllers/RemindersController.php b/app/TeenQuotes/Auth/Controllers/RemindersController.php index fd702ec5..b0aebb41 100644 --- a/app/TeenQuotes/Auth/Controllers/RemindersController.php +++ b/app/TeenQuotes/Auth/Controllers/RemindersController.php @@ -1,106 +1,111 @@ -beforeFilter('guest'); - } - - /** - * Display the password reminder view. - * - * @return \Response - */ - public function getRemind() - { - return View::make('password.remind'); - } - - /** - * Handle a POST request to remind a user of their password. - * - * @return \Response - */ - public function postRemind() - { - $response = Password::remind(Input::only('email'), function($message) - { - $message->subject(Lang::get('auth.passwordReminderEmailSubject')); - }); - - switch ($response) - { - case Password::INVALID_USER: - return Redirect::back()->with('error', Lang::get($response))->withInput(Input::only('email')); - - case Password::REMINDER_SENT: - return Redirect::back()->with('success', Lang::get($response)); - } - } - - /** - * Display the password reset view for the given token. - * - * @return \Response - */ - public function getReset() - { - $token = Input::get('token', null); - - if (is_null($token)) - throw new TokenNotFoundException; - - $data = [ - 'token' => $token, - 'contactHumanTitle' => Lang::get('auth.contactHumanTitle'), - 'contactHumanContent' => Lang::get('auth.contactHumanContent', ['url' => URL::route('contact')]), - 'pageTitle' => Lang::get('auth.resetPasswordPageTitle'), - 'pageDescription' => Lang::get('auth.resetPasswordPageDescription'), - ]; - - return View::make('password.reset', $data); - } - - /** - * Handle a POST request to reset a user's password. - * - * @return \Response - */ - public function postReset() - { - // Here we don't use password_confirmation but we keep it - // to call the reset function - $credentials = [ - 'email' => Input::get('email'), - 'token' => Input::get('token'), - 'password' => Input::get('password'), - 'password_confirmation' => Input::get('password'), - ]; - - $response = Password::reset($credentials, function($user, $password) - { - // Update the password in database - $user->password = $password; - $user->save(); - - // Log in the user - Auth::login($user); - }); - - switch ($response) - { - case Password::INVALID_PASSWORD: - case Password::INVALID_TOKEN: - case Password::INVALID_USER: - return Redirect::back()->with('warning', Lang::get($response))->withInput(Input::only('email', 'token')); - - case Password::PASSWORD_RESET: - return Redirect::route('home')->with('success', Lang::get('auth.welcomeBackPasswordChanged', ['login' => Auth::user()->login])); - } - } -} \ No newline at end of file +use Auth; +use BaseController; +use Input; +use Lang; +use Password; +use Redirect; +use TeenQuotes\Exceptions\TokenNotFoundException; +use URL; +use View; + +class RemindersController extends BaseController +{ + public function __construct() + { + $this->beforeFilter('guest'); + } + + /** + * Display the password reminder view. + * + * @return \Response + */ + public function getRemind() + { + return View::make('password.remind'); + } + + /** + * Handle a POST request to remind a user of their password. + * + * @return \Response + */ + public function postRemind() + { + $response = Password::remind(Input::only('email'), function ($message) { + $message->subject(Lang::get('auth.passwordReminderEmailSubject')); + }); + + switch ($response) { + case Password::INVALID_USER: + return Redirect::back()->with('error', Lang::get($response))->withInput(Input::only('email')); + + case Password::REMINDER_SENT: + return Redirect::back()->with('success', Lang::get($response)); + } + } + + /** + * Display the password reset view for the given token. + * + * @return \Response + */ + public function getReset() + { + $token = Input::get('token', null); + + if (is_null($token)) { + throw new TokenNotFoundException(); + } + + $data = [ + 'token' => $token, + 'contactHumanTitle' => Lang::get('auth.contactHumanTitle'), + 'contactHumanContent' => Lang::get('auth.contactHumanContent', ['url' => URL::route('contact')]), + 'pageTitle' => Lang::get('auth.resetPasswordPageTitle'), + 'pageDescription' => Lang::get('auth.resetPasswordPageDescription'), + ]; + + return View::make('password.reset', $data); + } + + /** + * Handle a POST request to reset a user's password. + * + * @return \Response + */ + public function postReset() + { + // Here we don't use password_confirmation but we keep it + // to call the reset function + $credentials = [ + 'email' => Input::get('email'), + 'token' => Input::get('token'), + 'password' => Input::get('password'), + 'password_confirmation' => Input::get('password'), + ]; + + $response = Password::reset($credentials, function ($user, $password) { + // Update the password in database + $user->password = $password; + $user->save(); + + // Log in the user + Auth::login($user); + }); + + switch ($response) { + case Password::INVALID_PASSWORD: + case Password::INVALID_TOKEN: + case Password::INVALID_USER: + return Redirect::back()->with('warning', Lang::get($response))->withInput(Input::only('email', 'token')); + + case Password::PASSWORD_RESET: + return Redirect::route('home')->with('success', Lang::get('auth.welcomeBackPasswordChanged', ['login' => Auth::user()->login])); + } + } +} diff --git a/app/TeenQuotes/Comments/CommentsServiceProvider.php b/app/TeenQuotes/Comments/CommentsServiceProvider.php index afe1db8a..ac7a6521 100644 --- a/app/TeenQuotes/Comments/CommentsServiceProvider.php +++ b/app/TeenQuotes/Comments/CommentsServiceProvider.php @@ -1,4 +1,6 @@ -registerObserver(); - } + /** + * Bootstrap the application events. + */ + public function boot() + { + $this->registerObserver(); + } - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $this->registerBindings(); - $this->registerComposers(); - $this->registerRoutes(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerBindings(); + $this->registerComposers(); + $this->registerRoutes(); + } - private function registerBindings() - { - $namespace = 'TeenQuotes\Comments\Repositories'; + private function registerBindings() + { + $namespace = 'TeenQuotes\Comments\Repositories'; - $this->app->bind(CommentRepository::class, function() - { - $eloquentRepo = new DbCommentRepository; + $this->app->bind(CommentRepository::class, function () { + $eloquentRepo = new DbCommentRepository(); - return new CachingCommentRepository($eloquentRepo); - }); - } + return new CachingCommentRepository($eloquentRepo); + }); + } - private function registerComposers() - { - $namespace = 'TeenQuotes\Comments\Composers'; + private function registerComposers() + { + $namespace = 'TeenQuotes\Comments\Composers'; - // When editing a comment - $this->app['view']->composer([ - 'comments.edit' - ], $namespace.'\EditComposer'); - } + // When editing a comment + $this->app['view']->composer([ + 'comments.edit', + ], $namespace.'\EditComposer'); + } - private function registerObserver() - { - Comment::observe(new CommentObserver); - } + private function registerObserver() + { + Comment::observe(new CommentObserver()); + } - private function registerRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->resource('comments', 'CommentsController', ['only' => ['store', 'destroy', 'update', 'edit']]); - }); - } + private function registerRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->resource('comments', 'CommentsController', ['only' => ['store', 'destroy', 'update', 'edit']]); + }); + } - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - 'namespace' => 'TeenQuotes\Comments\Controllers', - ]; - } -} \ No newline at end of file + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + 'namespace' => 'TeenQuotes\Comments\Controllers', + ]; + } +} diff --git a/app/TeenQuotes/Comments/Composers/EditComposer.php b/app/TeenQuotes/Comments/Composers/EditComposer.php index 2aa86f89..c78c08e3 100644 --- a/app/TeenQuotes/Comments/Composers/EditComposer.php +++ b/app/TeenQuotes/Comments/Composers/EditComposer.php @@ -1,15 +1,23 @@ - Lang::get('comments.contentShortHint'), - 'contentGreatHint' => Lang::get('comments.contentGreatHint'), - ]); - } -} \ No newline at end of file +class EditComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + // Put some useful variables for the JS + JavaScript::put([ + 'contentShortHisnt' => Lang::get('comments.contentShortHint'), + 'contentGreatHint' => Lang::get('comments.contentGreatHint'), + ]); + } +} diff --git a/app/TeenQuotes/Comments/Controllers/CommentsController.php b/app/TeenQuotes/Comments/Controllers/CommentsController.php index 690e4591..faa566f4 100644 --- a/app/TeenQuotes/Comments/Controllers/CommentsController.php +++ b/app/TeenQuotes/Comments/Controllers/CommentsController.php @@ -1,103 +1,116 @@ -beforeFilter('auth'); - $this->api = App::make('TeenQuotes\Api\V1\Controllers\CommentsController'); - $this->commentValidator = App::make('TeenQuotes\Comments\Validation\CommentValidator'); - } - - /** - * Store a newly created resource in storage. - * - * @return \Response - */ - public function store() - { - $data = Input::only('content', 'quote_id'); - - $this->commentValidator->validatePosting($data); - - // Call the API - skip the API validator - $response = $this->api->store($data['quote_id'], false); - if ($response->getStatusCode() == 201) - return Redirect::route('quotes.show', $data['quote_id'])->with('success', Lang::get('comments.commentAddedSuccessfull')); - } - - /** - * Show the form to edit a comment - * - * @param int $id - * @return \Response - */ - public function edit($id) - { - $comment = $this->api->show($id)->getOriginalData(); - - // If the comment was not found or is not posted by the user - if (is_null($comment) OR ! $comment->isPostedBySelf()) - return Redirect::home()->with('warning', Lang::get('comments.cantEditThisComment')); - - $data = compact('comment'); - $data['pageTitle'] = Lang::get('comments.updateCommentPageTitle'); - - return View::make('comments.edit', $data); - } - - /** - * Edit a comment - * - * @param int $id - * @return \Response - */ - public function update($id) - { - $data = Input::only('content', 'quote_id'); - - $this->commentValidator->validateEditing($data); - - // Call the API - $response = $this->api->update($id); - if ($response->getStatusCode() != 200) - return Redirect::route('quotes.show', $data['quote_id'])->with('warning', Lang::get('comments.cantEditThisComment')); - - return Redirect::route('quotes.show', $data['quote_id'])->with('success', Lang::get('comments.commentEditSuccessfull')); - } - - /** - * Remove the specified resource from storage. - * - * @param int $id - * @return \Response - */ - public function destroy($id) - { - if (Request::ajax()) - { - $response = $this->api->destroy($id); - - return Response::json([ - 'success' => ($response->getStatusCode() == ResponseClass::HTTP_OK) - ]); - } - } - -} \ No newline at end of file +use View; + +class CommentsController extends BaseController +{ + /** + * The API controller. + * + * @var \TeenQuotes\Api\V1\Controllers\CommentsController + */ + private $api; + + /** + * @var \TeenQuotes\Comments\Validation\CommentValidator + */ + private $commentValidator; + + public function __construct() + { + $this->beforeFilter('auth'); + $this->api = App::make('TeenQuotes\Api\V1\Controllers\CommentsController'); + $this->commentValidator = App::make('TeenQuotes\Comments\Validation\CommentValidator'); + } + + /** + * Store a newly created resource in storage. + * + * @return \Response + */ + public function store() + { + $data = Input::only('content', 'quote_id'); + + $this->commentValidator->validatePosting($data); + + // Call the API - skip the API validator + $response = $this->api->store($data['quote_id'], false); + if ($response->getStatusCode() == 201) { + return Redirect::route('quotes.show', $data['quote_id'])->with('success', Lang::get('comments.commentAddedSuccessfull')); + } + } + + /** + * Show the form to edit a comment. + * + * @param int $id + * + * @return \Response + */ + public function edit($id) + { + $comment = $this->api->show($id)->getOriginalData(); + + // If the comment was not found or is not posted by the user + if (is_null($comment) or !$comment->isPostedBySelf()) { + return Redirect::home()->with('warning', Lang::get('comments.cantEditThisComment')); + } + + $data = compact('comment'); + $data['pageTitle'] = Lang::get('comments.updateCommentPageTitle'); + + return View::make('comments.edit', $data); + } + + /** + * Edit a comment. + * + * @param int $id + * + * @return \Response + */ + public function update($id) + { + $data = Input::only('content', 'quote_id'); + + $this->commentValidator->validateEditing($data); + + // Call the API + $response = $this->api->update($id); + if ($response->getStatusCode() != 200) { + return Redirect::route('quotes.show', $data['quote_id'])->with('warning', Lang::get('comments.cantEditThisComment')); + } + + return Redirect::route('quotes.show', $data['quote_id'])->with('success', Lang::get('comments.commentEditSuccessfull')); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * + * @return \Response + */ + public function destroy($id) + { + if (Request::ajax()) { + $response = $this->api->destroy($id); + + return Response::json([ + 'success' => ($response->getStatusCode() == ResponseClass::HTTP_OK), + ]); + } + } +} diff --git a/app/TeenQuotes/Comments/Models/Comment.php b/app/TeenQuotes/Comments/Models/Comment.php index 0b3ba927..f6a50aec 100644 --- a/app/TeenQuotes/Comments/Models/Comment.php +++ b/app/TeenQuotes/Comments/Models/Comment.php @@ -1,30 +1,34 @@ -user_id == Auth::id(); + public function isPostedBySelf() + { + if (Auth::check()) { + return $this->user_id == Auth::id(); + } - return false; - } + return false; + } - public function isPostedByUser(User $u) - { - return $this->user_id == $u->id; - } -} \ No newline at end of file + public function isPostedByUser(User $u) + { + return $this->user_id == $u->id; + } +} diff --git a/app/TeenQuotes/Comments/Models/Relations/CommentTrait.php b/app/TeenQuotes/Comments/Models/Relations/CommentTrait.php index 987f1099..324a5bc4 100644 --- a/app/TeenQuotes/Comments/Models/Relations/CommentTrait.php +++ b/app/TeenQuotes/Comments/Models/Relations/CommentTrait.php @@ -1,17 +1,19 @@ -belongsTo(User::class); - } +trait CommentTrait +{ + public function user() + { + return $this->belongsTo(User::class); + } - public function quote() - { - return $this->belongsTo(Quote::class); - } -} \ No newline at end of file + public function quote() + { + return $this->belongsTo(Quote::class); + } +} diff --git a/app/TeenQuotes/Comments/Models/Scopes/CommentTrait.php b/app/TeenQuotes/Comments/Models/Scopes/CommentTrait.php index c0c17c96..79e0e577 100644 --- a/app/TeenQuotes/Comments/Models/Scopes/CommentTrait.php +++ b/app/TeenQuotes/Comments/Models/Scopes/CommentTrait.php @@ -1,21 +1,23 @@ -orderBy('created_at', 'DESC'); - } +trait CommentTrait +{ + public function scopeOrderDescending($query) + { + return $query->orderBy('created_at', 'DESC'); + } - public function scopeForQuoteId($query, $id) - { - return $query->where('quote_id', '=', $id); - } + public function scopeForQuoteId($query, $id) + { + return $query->where('quote_id', '=', $id); + } - public function scopeForQuote($query, Quote $q) - { - return $query->where('quote_id', '=', $q->id); - } -} \ No newline at end of file + public function scopeForQuote($query, Quote $q) + { + return $query->where('quote_id', '=', $q->id); + } +} diff --git a/app/TeenQuotes/Comments/Observers/CommentObserver.php b/app/TeenQuotes/Comments/Observers/CommentObserver.php index 73116cf1..e6d4bbf9 100644 --- a/app/TeenQuotes/Comments/Observers/CommentObserver.php +++ b/app/TeenQuotes/Comments/Observers/CommentObserver.php @@ -1,51 +1,54 @@ -quoteRepo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); - $this->userMailer = App::make('TeenQuotes\Mail\UserMailer'); - } - - /** - * Will be triggered when a model is created - * - * @param \TeenQuotes\Comments\Models\Comment $comment - */ - public function created($comment) - { - $quote = $this->quoteRepo->getByIdWithUser($comment->quote_id); - - // Send an email to the author of the quote if he wants it - if ($this->needToWarnByEmail($quote, $comment)) - $this->sendEmailToQuoteAuthor($quote); - } - - private function sendEmailToQuoteAuthor($quote) - { - $author = $quote->user; - - $this->userMailer->warnAuthorAboutCommentPosted($author, $quote); - } - - private function needToWarnByEmail($quote, $comment) - { - // Do not send an e-mail if the author of the comment - // is the author of the quote - return $quote->user->wantsEmailComment() AND $comment->user_id != $quote->user->id; - } -} \ No newline at end of file +class CommentObserver +{ + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + public function __construct() + { + $this->quoteRepo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); + $this->userMailer = App::make('TeenQuotes\Mail\UserMailer'); + } + + /** + * Will be triggered when a model is created. + * + * @param \TeenQuotes\Comments\Models\Comment $comment + */ + public function created($comment) + { + $quote = $this->quoteRepo->getByIdWithUser($comment->quote_id); + + // Send an email to the author of the quote if he wants it + if ($this->needToWarnByEmail($quote, $comment)) { + $this->sendEmailToQuoteAuthor($quote); + } + } + + private function sendEmailToQuoteAuthor($quote) + { + $author = $quote->user; + + $this->userMailer->warnAuthorAboutCommentPosted($author, $quote); + } + + private function needToWarnByEmail($quote, $comment) + { + // Do not send an e-mail if the author of the comment + // is the author of the quote + return $quote->user->wantsEmailComment() and $comment->user_id != $quote->user->id; + } +} diff --git a/app/TeenQuotes/Comments/Presenters/CommentPresenter.php b/app/TeenQuotes/Comments/Presenters/CommentPresenter.php index ac370074..2648f022 100644 --- a/app/TeenQuotes/Comments/Presenters/CommentPresenter.php +++ b/app/TeenQuotes/Comments/Presenters/CommentPresenter.php @@ -1,11 +1,13 @@ -created_at->diffForHumans(); - } -} \ No newline at end of file +class CommentPresenter extends Presenter +{ + public function commentAge() + { + return $this->created_at->diffForHumans(); + } +} diff --git a/app/TeenQuotes/Comments/Repositories/CachingCommentRepository.php b/app/TeenQuotes/Comments/Repositories/CachingCommentRepository.php index ac8bbd2e..abaccdad 100644 --- a/app/TeenQuotes/Comments/Repositories/CachingCommentRepository.php +++ b/app/TeenQuotes/Comments/Repositories/CachingCommentRepository.php @@ -1,128 +1,131 @@ -comments = $comments; - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function findById($id) - { - return $this->comments->findById($id); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function findByIdWithQuote($id) - { - return $this->comments->findByIdWithQuote($id); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function indexForQuote($quote_id, $page, $pagesize) - { - return $this->comments->indexForQuote($quote_id, $page, $pagesize); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function indexForQuoteWithQuote($quote_id, $page, $pagesize) - { - return $this->comments->indexForQuoteWithQuote($quote_id, $page, $pagesize); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function findForUser(User $user, $page, $pagesize) - { - return $this->comments->findForUser($user, $page, $pagesize); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function countForUser(User $user) - { - return $this->comments->countForUser($user); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function create(Quote $q, User $u, $content) - { - $cacheKey = $this->getCountKeyForQuote($q); - - if (Cache::has($cacheKey)) - Cache::increment($cacheKey); - - return $this->comments->create($q, $u, $content); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function update($c, $content) - { - return $this->comments->update($c, $content); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function delete($id) - { - $comment = $this->findByIdWithQuote($id); - - $cacheKey = $this->getCountKeyForQuote($comment->quote); - - if (Cache::has($cacheKey)) - Cache::decrement($cacheKey); - - return $this->comments->delete($id); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function getTopQuotes($page, $pagesize) - { - return $this->comments->getTopQuotes($page, $pagesize); - } - - /** - * @see \TeenQuotes\Comments\Repositories\CommentRepository - */ - public function nbCommentsForQuote(Quote $q) - { - $callback = (function() use ($q) - { - return $this->comments->nbCommentsForQuote($q); - }); - - return Cache::remember($this->getCountKeyForQuote($q), 10, $callback); - } - - private function getCountKeyForQuote(Quote $q) - { - return 'comments.quote-'.$q->id.'.count'; - } -} \ No newline at end of file +class CachingCommentRepository implements CommentRepository +{ + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + private $comments; + + public function __construct(CommentRepository $comments) + { + $this->comments = $comments; + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function findById($id) + { + return $this->comments->findById($id); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function findByIdWithQuote($id) + { + return $this->comments->findByIdWithQuote($id); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function indexForQuote($quote_id, $page, $pagesize) + { + return $this->comments->indexForQuote($quote_id, $page, $pagesize); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function indexForQuoteWithQuote($quote_id, $page, $pagesize) + { + return $this->comments->indexForQuoteWithQuote($quote_id, $page, $pagesize); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function findForUser(User $user, $page, $pagesize) + { + return $this->comments->findForUser($user, $page, $pagesize); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function countForUser(User $user) + { + return $this->comments->countForUser($user); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function create(Quote $q, User $u, $content) + { + $cacheKey = $this->getCountKeyForQuote($q); + + if (Cache::has($cacheKey)) { + Cache::increment($cacheKey); + } + + return $this->comments->create($q, $u, $content); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function update($c, $content) + { + return $this->comments->update($c, $content); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function delete($id) + { + $comment = $this->findByIdWithQuote($id); + + $cacheKey = $this->getCountKeyForQuote($comment->quote); + + if (Cache::has($cacheKey)) { + Cache::decrement($cacheKey); + } + + return $this->comments->delete($id); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function getTopQuotes($page, $pagesize) + { + return $this->comments->getTopQuotes($page, $pagesize); + } + + /** + * @see \TeenQuotes\Comments\Repositories\CommentRepository + */ + public function nbCommentsForQuote(Quote $q) + { + $callback = (function () use ($q) { + return $this->comments->nbCommentsForQuote($q); + }); + + return Cache::remember($this->getCountKeyForQuote($q), 10, $callback); + } + + private function getCountKeyForQuote(Quote $q) + { + return 'comments.quote-'.$q->id.'.count'; + } +} diff --git a/app/TeenQuotes/Comments/Repositories/CommentRepository.php b/app/TeenQuotes/Comments/Repositories/CommentRepository.php index ae281ead..d34bbd5c 100644 --- a/app/TeenQuotes/Comments/Repositories/CommentRepository.php +++ b/app/TeenQuotes/Comments/Repositories/CommentRepository.php @@ -1,94 +1,118 @@ -withSmallUser() - ->first(); - } - - /** - * Retrieve a comment thanks to its ID and add the related quote - * @param int $id - * @return \TeenQuotes\Comments\Models\Comment - */ - public function findByIdWithQuote($id) - { - return Comment::where('id', '=', $id) - ->withSmallUser() - ->with('quote') - ->first(); - } - - /** - * List quotes for a given quote, page and pagesize - * @param int $quote_id - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function indexForQuote($quote_id, $page, $pagesize) - { - return Comment::forQuoteId($quote_id) - ->withSmallUser() - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * List quotes for a given quote, page and pagesize and add the related quotes - * @param int $quote_id - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function indexForQuoteWithQuote($quote_id, $page, $pagesize) - { - return Comment::forQuoteId($quote_id) - ->withSmallUser() - ->with('quote') - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Retrieve comments posted by a user for a page and a pagesize - * @param \TeenQuotes\Users\Models\User $user - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function findForUser(User $user, $page, $pagesize) - { - return $user->comments() - ->withSmallUser() - ->with('quote') - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Count the number of posted comments for a user - * @param \TeenQuotes\Users\Models\User $user - * @return int - */ - public function countForUser(User $user) - { - return $user->getTotalComments(); - } - - /** - * Post a comment on a quote - * @param \TeenQuotes\Quotes\Models\Quote $q - * @param \TeenQuotes\Users\Models\User $u - * @param string $content - * @return \TeenQuotes\Comments\Models\Comment - */ - public function create(Quote $q, User $u, $content) - { - $comment = new Comment; - $comment->content = $content; - $comment->quote_id = $q->id; - $comment->user_id = $u->id; - $comment->save(); - - return $comment; - } - - /** - * Update the content of a comment - * @param \TeenQuotes\Comments\Models\Comment|int $c - * @param string $content - * @return \TeenQuotes\Comments\Models\Comment - */ - public function update($c, $content) - { - $c = $this->retrieveComment($c); - - $c->content = $content; - $c->save(); - - return $c; - } - - /** - * Delete a comment - * @param int $id - * @return \TeenQuotes\Comments\Models\Comment - */ - public function delete($id) - { - return Comment::find($id)->delete(); - } - - /** - * Get a top of quotes by the number of comments, in descending order - * @param int $page - * @param int $pagesize - * @return array The ID of the quotes - */ - public function getTopQuotes($page, $pagesize) - { - $countKey = 'comment_count'; - - return Comment::select(DB::raw('count(*) as '.$countKey.', quote_id')) - ->groupBy('quote_id') - ->orderBy($countKey, 'DESC') - ->having($countKey, '>=', 1) - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->lists('quote_id'); - } - - /** - * Get the number of comments for a quote - * @param \TeenQuotes\Quotes\Models\Quote $q - * @return int - */ - public function nbCommentsForQuote(Quote $q) - { - return Comment::forQuoteId($q->id)->count(); - } - - /** - * Retrieve a comment by its ID or by its instance - * @param \TeenQuotes\Comments\Models\Comment|int $c - * @return \TeenQuotes\Comments\Models\Comment - * @throws \InvalidArgumentException If we can't retrieve a comment with the given data - */ - private function retrieveComment($c) - { - if (is_numeric($c)) - return $this->findById($c); - - if ($c instanceof Comment) - return $c; - - throw new InvalidArgumentException("The given instance is not a comment"); - } - - private function computeSkip($page, $pagesize) - { - return $pagesize * ($page - 1); - } -} \ No newline at end of file +class DbCommentRepository implements CommentRepository +{ + /** + * Retrieve a comment thanks to its ID. + * + * @param int $id + * + * @return \TeenQuotes\Comments\Models\Comment + */ + public function findById($id) + { + return Comment::where('id', '=', $id) + ->withSmallUser() + ->first(); + } + + /** + * Retrieve a comment thanks to its ID and add the related quote. + * + * @param int $id + * + * @return \TeenQuotes\Comments\Models\Comment + */ + public function findByIdWithQuote($id) + { + return Comment::where('id', '=', $id) + ->withSmallUser() + ->with('quote') + ->first(); + } + + /** + * List quotes for a given quote, page and pagesize. + * + * @param int $quote_id + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function indexForQuote($quote_id, $page, $pagesize) + { + return Comment::forQuoteId($quote_id) + ->withSmallUser() + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * List quotes for a given quote, page and pagesize and add the related quotes. + * + * @param int $quote_id + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function indexForQuoteWithQuote($quote_id, $page, $pagesize) + { + return Comment::forQuoteId($quote_id) + ->withSmallUser() + ->with('quote') + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Retrieve comments posted by a user for a page and a pagesize. + * + * @param \TeenQuotes\Users\Models\User $user + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function findForUser(User $user, $page, $pagesize) + { + return $user->comments() + ->withSmallUser() + ->with('quote') + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Count the number of posted comments for a user. + * + * @param \TeenQuotes\Users\Models\User $user + * + * @return int + */ + public function countForUser(User $user) + { + return $user->getTotalComments(); + } + + /** + * Post a comment on a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * @param \TeenQuotes\Users\Models\User $u + * @param string $content + * + * @return \TeenQuotes\Comments\Models\Comment + */ + public function create(Quote $q, User $u, $content) + { + $comment = new Comment(); + $comment->content = $content; + $comment->quote_id = $q->id; + $comment->user_id = $u->id; + $comment->save(); + + return $comment; + } + + /** + * Update the content of a comment. + * + * @param \TeenQuotes\Comments\Models\Comment|int $c + * @param string $content + * + * @return \TeenQuotes\Comments\Models\Comment + */ + public function update($c, $content) + { + $c = $this->retrieveComment($c); + + $c->content = $content; + $c->save(); + + return $c; + } + + /** + * Delete a comment. + * + * @param int $id + * + * @return \TeenQuotes\Comments\Models\Comment + */ + public function delete($id) + { + return Comment::find($id)->delete(); + } + + /** + * Get a top of quotes by the number of comments, in descending order. + * + * @param int $page + * @param int $pagesize + * + * @return array The ID of the quotes + */ + public function getTopQuotes($page, $pagesize) + { + $countKey = 'comment_count'; + + return Comment::select(DB::raw('count(*) as '.$countKey.', quote_id')) + ->groupBy('quote_id') + ->orderBy($countKey, 'DESC') + ->having($countKey, '>=', 1) + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->lists('quote_id'); + } + + /** + * Get the number of comments for a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * + * @return int + */ + public function nbCommentsForQuote(Quote $q) + { + return Comment::forQuoteId($q->id)->count(); + } + + /** + * Retrieve a comment by its ID or by its instance. + * + * @param \TeenQuotes\Comments\Models\Comment|int $c + * + * @return \TeenQuotes\Comments\Models\Comment + * + * @throws \InvalidArgumentException If we can't retrieve a comment with the given data + */ + private function retrieveComment($c) + { + if (is_numeric($c)) { + return $this->findById($c); + } + + if ($c instanceof Comment) { + return $c; + } + + throw new InvalidArgumentException('The given instance is not a comment'); + } + + private function computeSkip($page, $pagesize) + { + return $pagesize * ($page - 1); + } +} diff --git a/app/TeenQuotes/Comments/Validation/CommentValidator.php b/app/TeenQuotes/Comments/Validation/CommentValidator.php index 6152a139..0271244e 100644 --- a/app/TeenQuotes/Comments/Validation/CommentValidator.php +++ b/app/TeenQuotes/Comments/Validation/CommentValidator.php @@ -1,23 +1,27 @@ - 'required|min:10|max:500', - 'quote_id' => 'required|exists:quotes,id', - ]; +class CommentValidator extends BaseValidator +{ + /** + * The validation rules when adding a comment. + * + * @var array + */ + protected $rulesPosting = [ + 'content' => 'required|min:10|max:500', + 'quote_id' => 'required|exists:quotes,id', + ]; - /** - * The validation rules when editing a comment - * @var array - */ - protected $rulesEditing = [ - 'content' => 'required|min:10|max:500', - ]; -} \ No newline at end of file + /** + * The validation rules when editing a comment. + * + * @var array + */ + protected $rulesEditing = [ + 'content' => 'required|min:10|max:500', + ]; +} diff --git a/app/TeenQuotes/Countries/Console/MostCommonCountryCommand.php b/app/TeenQuotes/Countries/Console/MostCommonCountryCommand.php index 5dd27789..209c571d 100644 --- a/app/TeenQuotes/Countries/Console/MostCommonCountryCommand.php +++ b/app/TeenQuotes/Countries/Console/MostCommonCountryCommand.php @@ -1,113 +1,115 @@ -countryRepo = $countryRepo; - $this->userRepo = $userRepo; - } - - /** - * When a command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return \Indatus\Dispatcher\Scheduling\Schedulable - */ - public function schedule(Schedulable $scheduler) - { - return $scheduler - ->daily() - ->hours(18) - ->minutes(00); - } - - /** - * Choose the environment(s) where the command should run - * @return array Array of environments' name - */ - public function environment() - { - return ['production', 'staging']; - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function fire() - { - $currentMostCommonCountryID = Country::getDefaultCountry(); - - // Get the most common country in the users' table - $mostCommonCountryID = $this->userRepo->mostCommonCountryId(); - - // The value was different, update it - if ($currentMostCommonCountryID != $mostCommonCountryID) { - - $country = $this->countryRepo->findById($mostCommonCountryID); - Log::info("Most common country updated. This is now ".$country->name."."); - - LaraSetting::set('countries.defaultCountry', $mostCommonCountryID); - } - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return []; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } +class MostCommonCountryCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'countries:mostCommon'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Compute the most common country ID and update it in settings.json.'; + + /** + * @var \TeenQuotes\Countries\Repositories\CountryRepository + */ + private $countryRepo; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + /** + * Create a new command instance. + */ + public function __construct(CountryRepository $countryRepo, UserRepository $userRepo) + { + parent::__construct(); + + $this->countryRepo = $countryRepo; + $this->userRepo = $userRepo; + } + + /** + * When a command should run. + * + * @param \Indatus\Dispatcher\Scheduling\Schedulable + * + * @return \Indatus\Dispatcher\Scheduling\Schedulable + */ + public function schedule(Schedulable $scheduler) + { + return $scheduler + ->daily() + ->hours(18) + ->minutes(00); + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production', 'staging']; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + $currentMostCommonCountryID = Country::getDefaultCountry(); + + // Get the most common country in the users' table + $mostCommonCountryID = $this->userRepo->mostCommonCountryId(); + + // The value was different, update it + if ($currentMostCommonCountryID != $mostCommonCountryID) { + $country = $this->countryRepo->findById($mostCommonCountryID); + Log::info('Most common country updated. This is now '.$country->name.'.'); + + LaraSetting::set('countries.defaultCountry', $mostCommonCountryID); + } + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } } diff --git a/app/TeenQuotes/Countries/CountriesServiceProvider.php b/app/TeenQuotes/Countries/CountriesServiceProvider.php index 65eb06b1..26bddc1a 100644 --- a/app/TeenQuotes/Countries/CountriesServiceProvider.php +++ b/app/TeenQuotes/Countries/CountriesServiceProvider.php @@ -1,77 +1,73 @@ -registerBindings(); - $this->registerCommands(); - } - - private function registerBindings() - { - $this->app->bind(CountryRepository::class, function() - { - $eloquentRepo = new DbCountryRepository; - - return new CachingCountryRepository($eloquentRepo); - }); - - $geoIP = $this->app['geoip']; - - $this->app->bind(CityDetector::class, function() use($geoIP) - { - return new GeoIPCityDetector($geoIP); - }); - - $this->app->bind(CountryDetector::class, function() use($geoIP) - { - $countriesRepo = $this->app->make(CountryRepository::class); - - $array = $countriesRepo->listNameAndId(); - $default = Country::getDefaultCountry(); - - $instance = new GeoIPCountryDetector(array_keys($array), array_values($array), $geoIP); - $instance->setDefault($default); - - return $instance; - }); - } - - private function registerCommands() - { - $commandName = $this->getBaseNamespace().'Console\MostCommonCountryCommand'; - - $this->app->bindShared('countries.console.mostCommonCountry', function($app) use($commandName) - { - return $app->make($commandName); - }); - - $this->commands('countries.console.mostCommonCountry'); - } -} \ No newline at end of file +class CountriesServiceProvider extends ServiceProvider +{ + use NamespaceTrait; + + /** + * Indicates if loading of the provider is deferred. + * + * @var bool + */ + protected $defer = false; + + /** + * Register the service provider. + */ + public function register() + { + $this->registerBindings(); + $this->registerCommands(); + } + + private function registerBindings() + { + $this->app->bind(CountryRepository::class, function () { + $eloquentRepo = new DbCountryRepository(); + + return new CachingCountryRepository($eloquentRepo); + }); + + $geoIP = $this->app['geoip']; + + $this->app->bind(CityDetector::class, function () use ($geoIP) { + return new GeoIPCityDetector($geoIP); + }); + + $this->app->bind(CountryDetector::class, function () use ($geoIP) { + $countriesRepo = $this->app->make(CountryRepository::class); + + $array = $countriesRepo->listNameAndId(); + $default = Country::getDefaultCountry(); + + $instance = new GeoIPCountryDetector(array_keys($array), array_values($array), $geoIP); + $instance->setDefault($default); + + return $instance; + }); + } + + private function registerCommands() + { + $commandName = $this->getBaseNamespace().'Console\MostCommonCountryCommand'; + + $this->app->bindShared('countries.console.mostCommonCountry', function ($app) use ($commandName) { + return $app->make($commandName); + }); + + $this->commands('countries.console.mostCommonCountry'); + } +} diff --git a/app/TeenQuotes/Countries/Localisation/CityDetector.php b/app/TeenQuotes/Countries/Localisation/CityDetector.php index 193a17a3..99a5b90d 100644 --- a/app/TeenQuotes/Countries/Localisation/CityDetector.php +++ b/app/TeenQuotes/Countries/Localisation/CityDetector.php @@ -1,16 +1,20 @@ -cityDetector = $cityDetector; - $this->countryDetector = $countryDetector; - } + public function __construct(CityDetector $cityDetector, CountryDetector $countryDetector) + { + $this->cityDetector = $cityDetector; + $this->countryDetector = $countryDetector; + } - public function detectCountry(Request $request) - { - return $this->countryDetector->detectCountry($request); - } + public function detectCountry(Request $request) + { + return $this->countryDetector->detectCountry($request); + } - public function detectCity(Request $request) - { - return $this->cityDetector->detectCity($request); - } -} \ No newline at end of file + public function detectCity(Request $request) + { + return $this->cityDetector->detectCity($request); + } +} diff --git a/app/TeenQuotes/Countries/Localisation/GeoIPCityDetector.php b/app/TeenQuotes/Countries/Localisation/GeoIPCityDetector.php index 802332c1..cfe3d874 100644 --- a/app/TeenQuotes/Countries/Localisation/GeoIPCityDetector.php +++ b/app/TeenQuotes/Countries/Localisation/GeoIPCityDetector.php @@ -1,38 +1,43 @@ -detector = $detector; + } - public function __construct(GeoIP $detector) - { - $this->detector = $detector; - } + /** + * Detect the city for a HTTP request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @see \TeenQuotes\Countries\Models\Country + * + * @return string|null The name of the detected city + * If we can't find a match, return null + */ + public function detectCity(Request $request) + { + $this->detector->setIP($request->getClientIp()); - /** - * Detect the city for a HTTP request - * - * @param \Symfony\Component\HttpFoundation\Request $request - * @see \TeenQuotes\Countries\Models\Country - * @return string|null The name of the detected city - * If we can't find a match, return null - */ - public function detectCity(Request $request) - { - $this->detector->setIP($request->getClientIp()); + try { + $cityDetected = $this->detector->getCity(); - try { - $cityDetected = $this->detector->getCity(); - return $cityDetected; - } catch (Exception $e) { - return null; - } - } -} \ No newline at end of file + return $cityDetected; + } catch (Exception $e) { + return null; + } + } +} diff --git a/app/TeenQuotes/Countries/Localisation/GeoIPCountryDetector.php b/app/TeenQuotes/Countries/Localisation/GeoIPCountryDetector.php index 4317bf76..6db531ca 100644 --- a/app/TeenQuotes/Countries/Localisation/GeoIPCountryDetector.php +++ b/app/TeenQuotes/Countries/Localisation/GeoIPCountryDetector.php @@ -1,88 +1,101 @@ -ids = $ids; - $this->countries = $countries; - $this->detector = $detector; - } - - /** - * Detect the country for a HTTP request - * - * @param \Symfony\Component\HttpFoundation\Request $request - * @see \TeenQuotes\Countries\Models\Country - * @return int|null The ID of the detected country - * If we can't find a match, return null - */ - public function detectCountry(Request $request) - { - $this->detector->setIP($request->getClientIp()); - - try { - $detectedCountry = $this->detector->getCountry(); - } catch (Exception $e) { - $detectedID = $this->defaultID; - } - - // Create a key value pair for each country - $countries = array_combine($this->ids, $this->countries); - - // If the detected country in the possible countries, we will select it - if ( ! isset($detectedID) AND in_array($detectedCountry, $this->countries)) - $detectedID = array_search($detectedCountry, $this->countries); - else - $detectedID = $this->defaultID; - - return $detectedID; - } - - /** - * Set the default ID to return if we don't match something - * @param int $id - */ - public function setDefault($id) - { - if (! is_integer($id)) - throw new InvalidArgumentException($id." is not an integer."); - - if ($this->isProduction() AND ! in_array($id, $this->ids)) - throw new InvalidArgumentException($id." was not in the list of all IDs."); - - $this->defaultID = $id; - } - - private function isProduction() - { - return App::environment() === 'production'; - } -} \ No newline at end of file +class GeoIPCountryDetector implements CountryDetector +{ + /** + * The IDs of available countries. + * + * @var array + */ + private $ids; + + /** + * The name of available of countries. + * + * @var array + */ + private $countries; + + /** + * The default country if we can't find a match. + * + * @var null|int + */ + private $defaultID = null; + + /** + * @var \Buonzz\GeoIP\GeoIP + */ + private $detector; + + public function __construct($ids, $countries, GeoIP $detector) + { + $this->ids = $ids; + $this->countries = $countries; + $this->detector = $detector; + } + + /** + * Detect the country for a HTTP request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @see \TeenQuotes\Countries\Models\Country + * + * @return int|null The ID of the detected country + * If we can't find a match, return null + */ + public function detectCountry(Request $request) + { + $this->detector->setIP($request->getClientIp()); + + try { + $detectedCountry = $this->detector->getCountry(); + } catch (Exception $e) { + $detectedID = $this->defaultID; + } + + // Create a key value pair for each country + $countries = array_combine($this->ids, $this->countries); + + // If the detected country in the possible countries, we will select it + if (!isset($detectedID) and in_array($detectedCountry, $this->countries)) { + $detectedID = array_search($detectedCountry, $this->countries); + } else { + $detectedID = $this->defaultID; + } + + return $detectedID; + } + + /** + * Set the default ID to return if we don't match something. + * + * @param int $id + */ + public function setDefault($id) + { + if (!is_integer($id)) { + throw new InvalidArgumentException($id.' is not an integer.'); + } + + if ($this->isProduction() and !in_array($id, $this->ids)) { + throw new InvalidArgumentException($id.' was not in the list of all IDs.'); + } + + $this->defaultID = $id; + } + + private function isProduction() + { + return App::environment() === 'production'; + } +} diff --git a/app/TeenQuotes/Countries/Models/Country.php b/app/TeenQuotes/Countries/Models/Country.php index 1f79e4f4..f4d70826 100644 --- a/app/TeenQuotes/Countries/Models/Country.php +++ b/app/TeenQuotes/Countries/Models/Country.php @@ -1,50 +1,59 @@ -hasMany(User::class, 'country', 'id'); - } -} \ No newline at end of file +trait CountryTrait +{ + public function users() + { + return $this->hasMany(User::class, 'country', 'id'); + } +} diff --git a/app/TeenQuotes/Countries/Presenters/CountryPresenter.php b/app/TeenQuotes/Countries/Presenters/CountryPresenter.php index 59d7a004..1f1f272d 100644 --- a/app/TeenQuotes/Countries/Presenters/CountryPresenter.php +++ b/app/TeenQuotes/Countries/Presenters/CountryPresenter.php @@ -1,24 +1,27 @@ -entity->country_code); +class CountryPresenter extends Presenter +{ + /** + * The CSS class used to display the flag associated with + * the country. + * + * @return string + */ + public function countryCodeClass() + { + $countryCode = strtolower($this->entity->country_code); - return 'flag-'.$countryCode; - } + return 'flag-'.$countryCode; + } - public function searchUsers() - { - return URL::route('search.users.country', $this->entity->id); - } -} \ No newline at end of file + public function searchUsers() + { + return URL::route('search.users.country', $this->entity->id); + } +} diff --git a/app/TeenQuotes/Countries/Repositories/CachingCountryRepository.php b/app/TeenQuotes/Countries/Repositories/CachingCountryRepository.php index 8df461ba..ccb7f5d5 100644 --- a/app/TeenQuotes/Countries/Repositories/CachingCountryRepository.php +++ b/app/TeenQuotes/Countries/Repositories/CachingCountryRepository.php @@ -1,56 +1,55 @@ -countries = $countries; - } - - /** - * @see \TeenQuotes\Countries\Repositories\CountryRepository - */ - public function findById($id) - { - $keyName = $this->getCacheKeyNameForId($id); - - return Cache::rememberForever($keyName, function() use($id) - { - return $this->countries->findById($id); - }); - } - - /** - * @see \TeenQuotes\Countries\Repositories\CountryRepository - */ - public function listNameAndId() - { - return Cache::rememberForever('countries.all.list', function() - { - return $this->countries->listNameAndId(); - }); - } - - /** - * @see \TeenQuotes\Countries\Repositories\CountryRepository - */ - public function getAll() - { - return Cache::rememberForever('countries.all', function() - { - return $this->countries->getAll(); - }); - } - - private function getCacheKeyNameForId($id) - { - return 'countries.'.$id; - } -} \ No newline at end of file +class CachingCountryRepository implements CountryRepository +{ + /** + * @var \TeenQuotes\Countries\Repositories\CountryRepository + */ + private $countries; + + public function __construct(CountryRepository $countries) + { + $this->countries = $countries; + } + + /** + * @see \TeenQuotes\Countries\Repositories\CountryRepository + */ + public function findById($id) + { + $keyName = $this->getCacheKeyNameForId($id); + + return Cache::rememberForever($keyName, function () use ($id) { + return $this->countries->findById($id); + }); + } + + /** + * @see \TeenQuotes\Countries\Repositories\CountryRepository + */ + public function listNameAndId() + { + return Cache::rememberForever('countries.all.list', function () { + return $this->countries->listNameAndId(); + }); + } + + /** + * @see \TeenQuotes\Countries\Repositories\CountryRepository + */ + public function getAll() + { + return Cache::rememberForever('countries.all', function () { + return $this->countries->getAll(); + }); + } + + private function getCacheKeyNameForId($id) + { + return 'countries.'.$id; + } +} diff --git a/app/TeenQuotes/Countries/Repositories/CountryRepository.php b/app/TeenQuotes/Countries/Repositories/CountryRepository.php index dab0ab72..fc3b8065 100644 --- a/app/TeenQuotes/Countries/Repositories/CountryRepository.php +++ b/app/TeenQuotes/Countries/Repositories/CountryRepository.php @@ -1,26 +1,29 @@ -with([$source => function($q) - { - $q->addSelect(['id', 'login', 'avatar', 'hide_profile']); - }]); - } -} \ No newline at end of file +class Toloquent extends Eloquent +{ + /** + * Get a model small user's info. + * + * @param \Illuminate\Database\Eloquent\Builder $query The original query + * @param string $source Where we can access the user's info. Default to 'user' + * + * @return \Illuminate\Database\Query\Builder The modified query + */ + public function scopeWithSmallUser($query, $source = 'user') + { + return $query->with([$source => function ($q) { + $q->addSelect(['id', 'login', 'avatar', 'hide_profile']); + }]); + } +} diff --git a/app/TeenQuotes/Exceptions/ApiNotFoundException.php b/app/TeenQuotes/Exceptions/ApiNotFoundException.php index cd68a299..3fc0dc1b 100644 --- a/app/TeenQuotes/Exceptions/ApiNotFoundException.php +++ b/app/TeenQuotes/Exceptions/ApiNotFoundException.php @@ -1,7 +1,9 @@ -originalData = $data; + /** + * Constructor. + * + * @param mixed $data + * @param int $status + * @param array $headers + * @param int $options + */ + public function __construct($data = null, $status = 200, $headers = [], $options = 0) + { + // We just need to be able to retrieve the original data + $this->originalData = $data; - if ($data instanceof ArrayableInterface) - $data = $data->toArray(); + if ($data instanceof ArrayableInterface) { + $data = $data->toArray(); + } - parent::__construct($data, $status, $headers, $options); - } + parent::__construct($data, $status, $headers, $options); + } - public function getOriginalData() - { - return $this->originalData; - } -} \ No newline at end of file + public function getOriginalData() + { + return $this->originalData; + } +} diff --git a/app/TeenQuotes/Mail/Composers/IndexQuotesComposer.php b/app/TeenQuotes/Mail/Composers/IndexQuotesComposer.php new file mode 100644 index 00000000..7121147a --- /dev/null +++ b/app/TeenQuotes/Mail/Composers/IndexQuotesComposer.php @@ -0,0 +1,28 @@ +colorGenerator = $colorGenerator; + } + + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $view->with('colorGenerator', $this->colorGenerator); + } +} diff --git a/app/TeenQuotes/Mail/Composers/WelcomeViewComposer.php b/app/TeenQuotes/Mail/Composers/WelcomeViewComposer.php index 69eb628b..67b08e55 100644 --- a/app/TeenQuotes/Mail/Composers/WelcomeViewComposer.php +++ b/app/TeenQuotes/Mail/Composers/WelcomeViewComposer.php @@ -1,25 +1,29 @@ -getData(); - $login = $viewData['login']; +class WelcomeViewComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $viewData = $view->getData(); + $login = $viewData['login']; - // Construct a URL to track with Google Analytics - $urlProfile = URL::route('users.show', $login); - $urlCampaignProfile = TextTools::linkCampaign($urlProfile, 'callToProfile', 'email', 'welcome', 'linkBodyEmail'); + // Construct a URL to track with Google Analytics + $urlProfile = URL::route('users.show', $login); + $urlCampaignProfile = TextTools::linkCampaign($urlProfile, 'callToProfile', 'email', 'welcome', 'linkBodyEmail'); - $data = [ - 'login' => $login, - 'urlCampaignProfile' => $urlCampaignProfile, - 'urlProfile' => $urlProfile, - ]; + $data = compact('login', 'urlCampaignProfile', 'urlProfile'); - // Content - $view->with('data', $data); - } -} \ No newline at end of file + // Content + $view->with('data', $data); + } +} diff --git a/app/TeenQuotes/Mail/Facades/MandrillClient.php b/app/TeenQuotes/Mail/Facades/MandrillClient.php index f6e203b7..9fe72e30 100644 --- a/app/TeenQuotes/Mail/Facades/MandrillClient.php +++ b/app/TeenQuotes/Mail/Facades/MandrillClient.php @@ -1,11 +1,13 @@ -registerViewComposers(); - - $this->app->bindShared('mailer', function($app) use ($me) - { - $me->registerSwiftMailer(); - - // Once we have create the mailer instance, we will set a container instance - // on the mailer. This allows us to resolve mailer classes via containers - // for maximum testability on said classes instead of passing Closures. - $mailer = new Mailer( - $app['view'], $app['swift.mailer'], $app['events'] - ); - - $this->setMailerDependencies($mailer, $app); - - // If a "from" address is set, we will set it on the mailer so that all mail - // messages sent by the applications will utilize the same "from" address - // on each one, which makes the developer's life a lot more convenient. - $from = $app['config']['mail.from']; - - if (is_array($from) && isset($from['address'])) - { - $mailer->alwaysFrom($from['address'], $from['name']); - } - - // Here we will determine if the mailer should be in "pretend" mode for this - // environment, which will simply write out e-mail to the logs instead of - // sending it over the web, which is useful for local dev environments. - $pretend = $app['config']->get('mail.pretend', false); - - $mailer->pretend($pretend); - - return $mailer; - }); - } - - /** - * Register the Mandrill Swift Transport instance. - * - * @param array $config - * @return void - */ - protected function registerMandrillTransport($config) - { - $mandrill = $this->app['config']->get('services.mandrill', array()); - - $this->app->bindShared('swift.transport', function() use ($mandrill) - { - return new MandrillTransport($mandrill['secret']); - }); - } - - private function registerViewComposers() - { - // Welcome email - $this->app['view']->composer([ - 'emails.welcome' - ], 'TeenQuotes\Mail\Composers\WelcomeViewComposer'); - } -} \ No newline at end of file +class MailServiceProvider extends \Illuminate\Mail\MailServiceProvider +{ + public function register() + { + $me = $this; + + $this->registerViewComposers(); + + $this->app->bindShared('mailer', function ($app) use ($me) { + $me->registerSwiftMailer(); + + // Once we have create the mailer instance, we will set a container instance + // on the mailer. This allows us to resolve mailer classes via containers + // for maximum testability on said classes instead of passing Closures. + $mailer = new Mailer( + $app['view'], $app['swift.mailer'], $app['events'] + ); + + $this->setMailerDependencies($mailer, $app); + + // If a "from" address is set, we will set it on the mailer so that all mail + // messages sent by the applications will utilize the same "from" address + // on each one, which makes the developer's life a lot more convenient. + $from = $app['config']['mail.from']; + + if (is_array($from) && isset($from['address'])) { + $mailer->alwaysFrom($from['address'], $from['name']); + } + + // Here we will determine if the mailer should be in "pretend" mode for this + // environment, which will simply write out e-mail to the logs instead of + // sending it over the web, which is useful for local dev environments. + $pretend = $app['config']->get('mail.pretend', false); + + $mailer->pretend($pretend); + + return $mailer; + }); + } + + /** + * Register the Mandrill Swift Transport instance. + * + * @param array $config + */ + protected function registerMandrillTransport($config) + { + $mandrill = $this->app['config']->get('services.mandrill', []); + + $this->app->bindShared('swift.transport', function () use ($mandrill) { + return new MandrillTransport($mandrill['secret']); + }); + } + + private function registerViewComposers() + { + // Welcome email + $this->app['view']->composer([ + 'emails.welcome', + ], 'TeenQuotes\Mail\Composers\WelcomeViewComposer'); + + // When listing multiple quotes + $this->app['view']->composer([ + 'emails.quotes.multiple', + ], 'TeenQuotes\Mail\Composers\IndexQuotesComposer'); + } +} diff --git a/app/TeenQuotes/Mail/MailSwitcher.php b/app/TeenQuotes/Mail/MailSwitcher.php index 45eb1d11..c6a42827 100644 --- a/app/TeenQuotes/Mail/MailSwitcher.php +++ b/app/TeenQuotes/Mail/MailSwitcher.php @@ -1,103 +1,120 @@ -isTestingEnvironment()) return; +class MailSwitcher +{ + /** + * Constructor. + * + * @param string $driver The new mail driver + * + * @throws InvalidArgumentException If the driver is not supported + */ + public function __construct($driver) + { + // Do not change the configuration on a testing environment + if ($this->isTestingEnvironment()) { + return null; + } - self::guardDriver($driver); + self::guardDriver($driver); - // Postfix is not always installed on developers' computer - // We will fallback to SMTP - if (App::environment() == 'local') $driver = 'smtp'; + // Postfix is not always installed on developers' computer + // We will fallback to SMTP + if (App::environment() == 'local') { + $driver = 'smtp'; + } - if ($this->driverNeedsChange($driver)) - { - // Update the configuration - switch (strtolower($driver)) - { - case 'smtp': - // Switch to SMTP - Config::set('mail.driver', 'smtp'); - Config::set('mail.from', Config::get('mail.from.smtp')); - break; + if ($this->driverNeedsChange($driver)) { + // Update the configuration + switch (strtolower($driver)) { + case 'smtp': + // Switch to SMTP + Config::set('mail.driver', 'smtp'); + Config::set('mail.from', Config::get('mail.from.smtp')); + break; - case 'mandrill': - // Switch to Postfix - Config::set('mail.driver', 'mandrill'); - Config::set('mail.from', Config::get('mail.from')); - break; - } + case 'mandrill': + // Switch to Mandrill + Config::set('mail.driver', 'mandrill'); + Config::set('mail.from', Config::get('mail.from')); + break; + } - // Since we have changed the transport layer, - // we need to register again the service provider - App::register('TeenQuotes\Mail\MailServiceProvider'); - } - } + // Since we have changed the transport layer, + // we need to register again the service provider + App::register('TeenQuotes\Mail\MailServiceProvider'); + } + } - /** - * Get the available mail drivers - * @return array - */ - public static function getAvailableDrivers() - { - return ['smtp', 'mandrill']; - } + /** + * Get the available mail drivers. + * + * @return array + */ + public static function getAvailableDrivers() + { + return ['smtp', 'mandrill']; + } - /** - * Present available mail drivers - * @return string - */ - public static function presentAvailableDrivers() - { - return implode('|', self::getAvailableDrivers()); - } + /** + * Present available mail drivers. + * + * @return string + */ + public static function presentAvailableDrivers() + { + return implode('|', self::getAvailableDrivers()); + } - /** - * Check if the driver is supported - * @param string $driver - * @throws \InvalidArgumentException If the driver is not supported - */ - public static function guardDriver($driver) - { - if ( ! in_array($driver, self::getAvailableDrivers())) - throw new InvalidArgumentException("Unknown driver. Got ".$driver.". Possible values are: ".self::presentAvailableDrivers()); - } + /** + * Check if the driver is supported. + * + * @param string $driver + * + * @throws InvalidArgumentException If the driver is not supported + */ + public static function guardDriver($driver) + { + if (!in_array($driver, self::getAvailableDrivers())) { + throw new InvalidArgumentException('Unknown driver. Got '.$driver.'. Possible values are: '.self::presentAvailableDrivers()); + } + } - /** - * Determine if we are in a testing environment - * @return boolean - */ - private function isTestingEnvironment() - { - return in_array(App::environment(), ['testing', 'codeception', 'codeceptionMysql']); - } + /** + * Determine if we are in a testing environment. + * + * @return bool + */ + private function isTestingEnvironment() + { + return in_array(App::environment(), ['testing', 'codeception', 'codeceptionMysql']); + } - /** - * Determine if the mail driver needs to be updated - * @param string $newDriver - * @return boolean - */ - private function driverNeedsChange($newDriver) - { - return $newDriver != $this->getCurrentDriver(); - } + /** + * Determine if the mail driver needs to be updated. + * + * @param string $newDriver + * + * @return bool + */ + private function driverNeedsChange($newDriver) + { + return $newDriver != $this->getCurrentDriver(); + } - /** - * Get the current mail driver - * @return string - */ - private function getCurrentDriver() - { - return Config::get('mail.driver'); - } -} \ No newline at end of file + /** + * Get the current mail driver. + * + * @return string + */ + private function getCurrentDriver() + { + return Config::get('mail.driver'); + } +} diff --git a/app/TeenQuotes/Mail/Mailer.php b/app/TeenQuotes/Mail/Mailer.php index 8819cc8a..a6dfa6df 100644 --- a/app/TeenQuotes/Mail/Mailer.php +++ b/app/TeenQuotes/Mail/Mailer.php @@ -1,28 +1,31 @@ -views->make($view, $data)->render(); + $view = $this->views->make($view, $data)->render(); - // Inline CSS - $cssInline->setUseInlineStylesBlock(); - $cssInline->setStripOriginalStyleTags(); - $cssInline->setCleanup(); - $cssInline->setHTML($view); + // Inline CSS + $cssInline->setUseInlineStylesBlock(); + $cssInline->setStripOriginalStyleTags(); + $cssInline->setCleanup(); + $cssInline->setHTML($view); - return $cssInline->convert(); - } -} \ No newline at end of file + return $cssInline->convert(); + } +} diff --git a/app/TeenQuotes/Mail/Mandrill.php b/app/TeenQuotes/Mail/Mandrill.php index 9612d81f..31a12f00 100644 --- a/app/TeenQuotes/Mail/Mandrill.php +++ b/app/TeenQuotes/Mail/Mandrill.php @@ -1,65 +1,71 @@ -api = $api; - $this->userRepo = $userRepo; - } + public function __construct(M $api, UserRepository $userRepo) + { + $this->api = $api; + $this->userRepo = $userRepo; + } - /** - * Get email addresses that have already have an hard bounce - * @return array - */ - public function getHardBouncedEmails() - { - $result = $this->api->rejects->getList("", false); - $collection = new Collection($result); + /** + * Get email addresses that have already have an hard bounce. + * + * @return array + */ + public function getHardBouncedEmails() + { + $result = $this->api->rejects->getList('', false); + $collection = new Collection($result); - $hardBounced = $collection->filter(function($a) - { - return $a['reason'] == 'hard-bounce'; - }); + $hardBounced = $collection->filter(function ($a) { + return $a['reason'] == 'hard-bounce'; + }); - return $hardBounced->lists('email'); - } + return $hardBounced->lists('email'); + } - /** - * Get users that have already been affected by an hard bounce - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getHardBouncedUsers() - { - return $this->userRepo->getByEmails( - $this->getHardBouncedEmails() - ); - } + /** + * Get users that have already been affected by an hard bounce. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getHardBouncedUsers() + { + return $this->userRepo->getByEmails( + $this->getHardBouncedEmails() + ); + } - /** - * Delete an email address from the rejection list - * @param string $email - * @return boolean Whether the address was deleted successfully - */ - public function deleteEmailFromRejection($email) - { - $result = $this->api->rejects->delete($email); + /** + * Delete an email address from the rejection list. + * + * @param string $email + * + * @return bool Whether the address was deleted successfully + */ + public function deleteEmailFromRejection($email) + { + $result = $this->api->rejects->delete($email); - return $result['deleted']; - } -} \ No newline at end of file + return $result['deleted']; + } +} diff --git a/app/TeenQuotes/Mail/MandrillServiceProvider.php b/app/TeenQuotes/Mail/MandrillServiceProvider.php index bc33fe31..3a1deaa3 100644 --- a/app/TeenQuotes/Mail/MandrillServiceProvider.php +++ b/app/TeenQuotes/Mail/MandrillServiceProvider.php @@ -1,49 +1,47 @@ -app->bind('mandrill', function() - { - $mandrillSecret = $this->app['config']->get('services.mandrill.secret'); - $mandrillAPI = new BaseMandrill($mandrillSecret); + /** + * Register the service provider. + */ + public function register() + { + $this->app->bind('mandrill', function () { + $mandrillSecret = $this->app['config']->get('services.mandrill.secret'); + $mandrillAPI = new BaseMandrill($mandrillSecret); - return new Mandrill($mandrillAPI, $this->app->make('TeenQuotes\Users\Repositories\UserRepository')); - }); - } + return new Mandrill($mandrillAPI, $this->app->make('TeenQuotes\Users\Repositories\UserRepository')); + }); + } - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return ['mandrill']; - } -} \ No newline at end of file + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return ['mandrill']; + } +} diff --git a/app/TeenQuotes/Mail/Transport/MandrillTransport.php b/app/TeenQuotes/Mail/Transport/MandrillTransport.php index 528cd88d..de9bec19 100644 --- a/app/TeenQuotes/Mail/Transport/MandrillTransport.php +++ b/app/TeenQuotes/Mail/Transport/MandrillTransport.php @@ -1,21 +1,23 @@ -getHttpClient(); +class MandrillTransport extends BaseMandrillTransport +{ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $client = $this->getHttpClient(); - $client->post('https://mandrillapp.com/api/1.0/messages/send-raw.json', [ - 'body' => [ - 'key' => $this->key, - 'raw_message' => (string) $message, - // see https://mandrillapp.com/api/docs/messages.JSON.html#method=send-raw - 'async' => true, - ], - ]); - } -} \ No newline at end of file + $client->post('https://mandrillapp.com/api/1.0/messages/send-raw.json', [ + 'body' => [ + 'key' => $this->key, + 'raw_message' => (string) $message, + // see https://mandrillapp.com/api/docs/messages.JSON.html#method=send-raw + 'async' => true, + ], + ]); + } +} diff --git a/app/TeenQuotes/Mail/UserMailer.php b/app/TeenQuotes/Mail/UserMailer.php index 373fe5fb..13b3a899 100644 --- a/app/TeenQuotes/Mail/UserMailer.php +++ b/app/TeenQuotes/Mail/UserMailer.php @@ -1,287 +1,296 @@ -config = $config; - $this->queue = $queue; - $this->userRepo = $userRepo; - } - - /** - * Send a mail to a user - * - * @param string $viewName The name of the view - * @param \TeenQuotes\Users\Models\User $user - * @param array $data Data to pass the email view - * @param string $subject The subject of the email - * @param string $driver The name of the driver that we will use to send the email - */ - public function send($viewName, User $user, $data, $subject, $driver = null) - { - $this->switchDriverIfNeeded($driver); - - // Send the email - $this->mail->send($viewName, $data, function ($m) use($user, $subject) - { - $m->to($user->email, $user->login)->subject($subject); - }); - } - - /** - * Send a delayed mail to a user - * - * @param string $viewName The name of the view - * @param \TeenQuotes\Users\Models\User $user - * @param array $data Data to pass the email view - * @param string $subject The subject of the email - * @param string $driver The name of the driver that we will use to send the email - * @param \DateTime|int $delay - */ - public function sendLater($viewName, User $user, $data, $subject, $driver = null, $delay = 0) - { - $data = compact('viewName', 'user', 'data', 'subject', 'driver'); - - // Queue the email - $this->queue->later($delay, get_class($this).'@dispatchToSend', $data); - } - - /** - * Send an email with a job - * - * @param \Illuminate\Queue\Jobs\Job $job - * @param array $data Required keys: viewName, user, data, subject and driver. - */ - public function dispatchToSend($job, $data) - { - extract($data); - - // Retrieve the user - $user = $this->getUserFromId($user['id']); - - // It is possible that the user has deleted its account - // while an e-mail was queued so we do a quick check - if ( ! is_null($user)) - $this->send($viewName, $user, $data, $subject, $driver); - } - - /** - * Tell an author of a quote that a comment was posted on one of - * its quote - * - * @param \TeenQuotes\Users\Models\User $author The author of the quote - * @param \TeenQuotes\Quotes\Models\Quote $quote The quote - */ - public function warnAuthorAboutCommentPosted(User $author, Quote $quote) - { - $subject = Lang::get('comments.commentAddedSubjectEmail', ['id' => $quote->id]); - - $this->send('emails.comments.posted', - $author, - compact('quote'), - $subject - ); - } - - /** - * Tell a user that he was subscribed from our newsletters - * - * @param \TeenQuotes\Users\Models\User $user - */ - public function unsubscribeUserFromNewsletter(User $user) - { - $this->send('emails.newsletters.unsubscribe', - $user, - compact('user'), - Lang::get('email.unsubscribeNewsletterSubject') - ); - } - - /** - * Tell the author of a quote that its quote was published - * - * @param \TeenQuotes\Quotes\Models\Quote $quote - */ - public function tellQuoteWasPublished(Quote $quote) - { - $this->send('emails.quotes.published', - $quote->user, // The author of the quote - compact('quote'), - Lang::get('quotes.quotePublishedSubjectEmail') - ); - } - - /** - * Wish happy birthday to a user - * - * @param \TeenQuotes\Users\Models\User $user - */ - public function wishHappyBirthday(User $user) - { - $this->send('emails.events.birthday', - $user, - compact('user'), - Lang::get('email.happyBirthdaySubjectEmail') - ); - } - - /** - * Send the welcome email to a user - * - * @param \TeenQuotes\Users\Models\User $user - */ - public function sendWelcome(User $user) - { - // Data for the view - $data = [ - 'login' => $user->login, - 'email' => $user->email, - ]; - - $subject = Lang::get('auth.subjectWelcomeEmail', ['login' => $data['login']]); - - $this->sendLater('emails.welcome', - $user, - $data, - $subject, - null, // Use the default driver - Carbon::now()->addMinutes(10) // Defer the email - ); - } - - /** - * Send a moderation decision for a quote to its author - * - * @param \TeenQuotes\AdminPanel\Helpers\Moderation $moderation The moderation decision - * @param \TeenQuotes\Quotes\Models\Quote $quote - * @param int $nbDays The number of days before the publication of the quote - */ - public function sendModeration(Moderation $moderation, $quote, $nbDays) - { - $type = $moderation->getType(); - - $this->send('emails.quotes.'.$type, - $quote->user, - compact('quote', 'nbDays'), - Lang::get('quotes.quote'.ucfirst($type).'SubjectEmail') - ); - } - - /** - * Schedule an e-mail to send about an event for a user - * - * @param string $event - * @param \TeenQuotes\Users\Models\User $user - * @param string $driver The e-mail driver to use - * @param \DateTime $delay When we should send the e-mail - */ - public function sendEvent($event, $user, $driver, $delay) - { - $this->sendLater('emails.events.'.$event, // View - $user, - ['login' => $user->login], // Data - Lang::get('email.event'.ucfirst($event).'SubjectEmail'), // Subject - $driver, - $delay - ); - } - - /** - * Queue an e-mail to request feedback for a user after 5 days - * - * @param \TeenQuotes\Users\Models\User $user - */ - public function scheduleSigningUpFeedBack(User $user) - { - $this->sendLater('emails.feedback.welcome', // View - $user, - ['login' => $user->login], // Data - Lang::get('feedback.welcomeSubject'), // Subject - null, // Default driver - Carbon::now()->addDays(5) - ); - } - - /** - * Retrieve an user by its ID - * - * @param int $id - * @return \TeenQuotes\Users\Models\User - */ - private function getUserFromId($id) - { - return $this->userRepo->getById($id); - } - - private function switchDriverIfNeeded($driver) - { - if (is_null($driver)) $driver = $this->getCurrentDriver(); - - $this->guardDriver($driver); - - // Ask to use this driver - new MailSwitcher($driver); - - $this->registerMailDriver(); - } - - private function getCurrentDriver() - { - return $this->config->get('mail.driver'); - } - - private function registerMailDriver() - { - $this->mail = App::make('mailer'); - } - - private function guardDriver($driver) - { - if (! $this->isTestingEnvironment()) - MailSwitcher::guardDriver($driver); - } - - private function isTestingEnvironment() - { - return in_array(App::environment(), ['testing', 'codeception', 'codeceptionMysql']); - } - - private function getAvailableDrivers() - { - return MailSwitcher::getAvailableDrivers(); - } - - private function presentAvailableDrivers() - { - return MailSwitcher::presentAvailableDrivers(); - } -} \ No newline at end of file +class UserMailer +{ + /** + * @var Config + */ + private $config; + + /** + * @var \Illuminate\Mail\Mailer + */ + private $mail; + + /** + * @var Queue + */ + private $queue; + + /** + * @var UserRepository + */ + private $userRepo; + + public function __construct(Config $config, Queue $queue, UserRepository $userRepo) + { + $this->config = $config; + $this->queue = $queue; + $this->userRepo = $userRepo; + } + + /** + * Send a mail to a user. + * + * @param string $viewName The name of the view + * @param User $user + * @param array $data Data to pass the email view + * @param string $subject The subject of the email + * @param string $driver The name of the driver that we will use to send the email + */ + public function send($viewName, User $user, $data, $subject, $driver = null) + { + $this->switchDriverIfNeeded($driver); + + // Send the email + $this->mail->send($viewName, $data, function ($m) use ($user, $subject) { + $m->to($user->email, $user->login)->subject($subject); + }); + } + + /** + * Send a delayed mail to a user. + * + * @param string $viewName The name of the view + * @param User $user + * @param array $data Data to pass the email view + * @param string $subject The subject of the email + * @param string $driver The name of the driver that we will use to send the email + * @param \DateTime|int $delay + */ + public function sendLater($viewName, User $user, $data, $subject, $driver = null, $delay = 0) + { + $data = compact('viewName', 'user', 'data', 'subject', 'driver'); + + // Queue the email + $this->queue->later($delay, get_class($this).'@dispatchToSend', $data); + } + + /** + * Send an email with a job. + * + * @param Job $job + * @param array $data Required keys: viewName, user, data, subject and driver. + */ + public function dispatchToSend(Job $job, $data) + { + extract($data); + + // Retrieve the user + $user = $this->getUserFromId($user['id']); + + // It is possible that the user has deleted its account + // while an e-mail was queued so we do a quick check + if (!is_null($user)) { + $this->send($viewName, $user, $data, $subject, $driver); + } + } + + /** + * Tell an author of a quote that a comment was posted on one of + * its quote. + * + * @param User $author The author of the quote + * @param Quote $quote The quote + */ + public function warnAuthorAboutCommentPosted(User $author, Quote $quote) + { + $subject = Lang::get('comments.commentAddedSubjectEmail', ['id' => $quote->id]); + + $this->send('emails.comments.posted', + $author, + compact('quote'), + $subject + ); + } + + /** + * Tell a user that he was subscribed from our newsletters. + * + * @param User $user + */ + public function unsubscribeUserFromNewsletter(User $user) + { + $this->send('emails.newsletters.unsubscribe', + $user, + compact('user'), + Lang::get('email.unsubscribeNewsletterSubject') + ); + } + + /** + * Tell the author of a quote that its quote was published. + * + * @param Quote $quote + */ + public function tellQuoteWasPublished(Quote $quote) + { + $this->send('emails.quotes.published', + $quote->user, // The author of the quote + compact('quote'), + Lang::get('quotes.quotePublishedSubjectEmail') + ); + } + + /** + * Wish happy birthday to a user. + * + * @param User $user + */ + public function wishHappyBirthday(User $user) + { + $this->send('emails.events.birthday', + $user, + compact('user'), + Lang::get('email.happyBirthdaySubjectEmail') + ); + } + + /** + * Send the welcome email to a user. + * + * @param User $user + */ + public function sendWelcome(User $user) + { + // Data for the view + $data = [ + 'login' => $user->login, + 'email' => $user->email, + ]; + + $subject = Lang::get('auth.subjectWelcomeEmail', ['login' => $data['login']]); + + $this->sendLater('emails.welcome', + $user, + $data, + $subject, + null, // Use the default driver + Carbon::now()->addMinutes(10) // Defer the email + ); + } + + /** + * Send a moderation decision for a quote to its author. + * + * @param Moderation $moderation The moderation decision + * @param Quote $quote + * @param int $nbDays The number of days before the publication of the quote + */ + public function sendModeration(Moderation $moderation, $quote, $nbDays) + { + $type = $moderation->getType(); + + $this->send('emails.quotes.'.$type, + $quote->user, + compact('quote', 'nbDays'), + Lang::get('quotes.quote'.ucfirst($type).'SubjectEmail') + ); + } + + /** + * Schedule an e-mail to send about an event for a user. + * + * @param string $event + * @param User $user + * @param string $driver The e-mail driver to use + * @param \DateTime $delay When we should send the e-mail + */ + public function sendEvent($event, $user, $driver, $delay) + { + $this->sendLater('emails.events.'.$event, // View + $user, + ['login' => $user->login], // Data + Lang::get('email.event'.ucfirst($event).'SubjectEmail'), // Subject + $driver, + $delay + ); + } + + /** + * Queue an e-mail to request feedback for a user after 5 days. + * + * @param User $user + */ + public function scheduleSigningUpFeedBack(User $user) + { + $this->sendLater('emails.feedback.welcome', // View + $user, + ['login' => $user->login], // Data + Lang::get('feedback.welcomeSubject'), // Subject + null, // Default driver + Carbon::now()->addDays(5) + ); + } + + /** + * Retrieve an user by its ID. + * + * @param int $id + * + * @return User + */ + private function getUserFromId($id) + { + return $this->userRepo->getById($id); + } + + private function switchDriverIfNeeded($driver) + { + if (is_null($driver)) { + $driver = $this->getCurrentDriver(); + } + + $this->guardDriver($driver); + + // Ask to use this driver + new MailSwitcher($driver); + + $this->registerMailDriver(); + } + + private function getCurrentDriver() + { + return $this->config->get('mail.driver'); + } + + private function registerMailDriver() + { + $this->mail = App::make('mailer'); + } + + private function guardDriver($driver) + { + if (!$this->isTestingEnvironment()) { + MailSwitcher::guardDriver($driver); + } + } + + private function isTestingEnvironment() + { + return in_array(App::environment(), ['testing', 'codeception', 'codeceptionMysql']); + } + + private function getAvailableDrivers() + { + return MailSwitcher::getAvailableDrivers(); + } + + private function presentAvailableDrivers() + { + return MailSwitcher::presentAvailableDrivers(); + } +} diff --git a/app/TeenQuotes/Newsletters/Console/SendNewsletterCommand.php b/app/TeenQuotes/Newsletters/Console/SendNewsletterCommand.php index b0353d26..622602fc 100644 --- a/app/TeenQuotes/Newsletters/Console/SendNewsletterCommand.php +++ b/app/TeenQuotes/Newsletters/Console/SendNewsletterCommand.php @@ -1,177 +1,202 @@ -quoteRepo = $quoteRepo; - $this->newsletterList = $newsletterList; - } - - /** - * When a command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return array - */ - public function schedule(Schedulable $scheduler) - { - return [ - $scheduler - ->args(['daily']) - ->daily() - ->hours(12) - ->minutes(0), - - $scheduler - ->args(['weekly']) - ->daysOfTheWeek([ - Scheduler::MONDAY]) - ->hours(12) - ->minutes(15), - ]; - } - - /** - * Choose the environment(s) where the command should run - * @return array Array of environments' name - */ - public function environment() - { - return ['production']; - } - - /** - * Execute the console command. - * - */ - public function fire() - { - if ($this->eventTypeIsValid()) { - $type = $this->getType(); - - $quotes = ($type == 'weekly') ? $this->retrieveWeeklyQuotes() : $this->retrieveDailyQuotes(); - - // Send the newsletter only if we have at least 1 quote - if ( ! $quotes->isEmpty()) { - $this->newsletterList->sendCampaign( - $type.'Newsletter', - Lang::get('newsletters.'.$type.'SubjectEmail'), - 'Teen Quotes\' member', - 'emails.newsletters.'.$type, - compact('quotes') - ); - } - } - } - - private function retrieveWeeklyQuotes() - { - return $this->quoteRepo->randomPublished($this->getNbQuotes()); - } - - private function retrieveDailyQuotes() - { - return $this->quoteRepo->randomPublishedToday($this->getNbQuotes()); - } - - private function getType() - { - return $this->argument('type'); - } - - private function getNbQuotes() - { - $type = $this->getType(); - - // Get the number of quotes to publish - $nbQuotes = is_null($this->argument('nb_quotes')) ? Config::get('app.newsletters.nbQuotesToSend'.ucfirst($type)) : $this->argument('nb_quotes'); - - return $nbQuotes; - } - - private function eventTypeIsValid() - { - $type = $this->getType(); - - if (is_null($type) OR ! in_array($type, $this->possibleTypes)) { - $this->error('Wrong type for the newsletter! Can only be '.$this->presentPossibleTypes().'. '.$type.' was given.'); - return false; - } - - return true; - } - - private function presentPossibleTypes() - { - return implode('|', $this->possibleTypes); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return [ - ['type', InputArgument::REQUIRED, 'The type of newsletter we will send. '.$this->presentPossibleTypes()], - ['nb_quotes', InputArgument::OPTIONAL, 'The number of quotes to send.'], - ]; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } -} \ No newline at end of file +class SendNewsletterCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'newsletter:send'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Send a newsletter to the subscribed users.'; + + /** + * Allowed event types. + * + * @var array + */ + private $possibleTypes = ['daily', 'weekly']; + + /** + * @var QuoteRepository + */ + private $quoteRepo; + + /** + * @var NewsletterList + */ + private $newsletterList; + + /** + * @param QuoteRepository $quoteRepo + * @param NewsletterList $newsletterList + */ + public function __construct(QuoteRepository $quoteRepo, NewsletterList $newsletterList) + { + parent::__construct(); + + $this->quoteRepo = $quoteRepo; + $this->newsletterList = $newsletterList; + } + + /** + * When a command should run. + * + * @param Schedulable + * + * @return array + */ + public function schedule(Schedulable $scheduler) + { + return [ + $scheduler + ->args(['daily']) + ->daily() + ->hours(12) + ->minutes(0), + + $scheduler + ->args(['weekly']) + ->daysOfTheWeek([ + Scheduler::MONDAY, ]) + ->hours(12) + ->minutes(15), + ]; + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production']; + } + + /** + * Execute the console command. + */ + public function fire() + { + if ($this->eventTypeIsValid()) { + $type = $this->getType(); + + $quotes = ($type == 'weekly') ? $this->retrieveWeeklyQuotes() : $this->retrieveDailyQuotes(); + + // Send the newsletter only if we have at least 1 quote + if (!$quotes->isEmpty()) { + $this->newsletterList->sendCampaign( + $type.'Newsletter', + Lang::get('newsletters.'.$type.'SubjectEmail'), + 'Teen Quotes\' member', + 'emails.newsletters.'.$type, + compact('quotes') + ); + } + } + } + + /** + * Get some random published quotes. + * + * @return \Illuminate\Support\Collection + */ + private function retrieveWeeklyQuotes() + { + return $this->quoteRepo->randomPublished($this->getNbQuotes()); + } + + /** + * Get some quotes that were published today. + * + * @return \Illuminate\Support\Collection + */ + private function retrieveDailyQuotes() + { + return $this->quoteRepo->randomPublishedToday($this->getNbQuotes()); + } + + /** + * Get the type given when the command was launched. + * + * @return string + */ + private function getType() + { + return $this->argument('type'); + } + + /** + * Get the number of quotes to send. + * + * @return int + */ + private function getNbQuotes() + { + $type = $this->getType(); + + // Get the number of quotes to publish + $nbQuotes = is_null($this->argument('nb_quotes')) ? Config::get('app.newsletters.nbQuotesToSend'.ucfirst($type)) : $this->argument('nb_quotes'); + + return $nbQuotes; + } + + private function eventTypeIsValid() + { + $type = $this->getType(); + + if (is_null($type) or !in_array($type, $this->possibleTypes)) { + $this->error('Wrong type for the newsletter! Can only be '.$this->presentPossibleTypes().'. '.$type.' was given.'); + + return false; + } + + return true; + } + + private function presentPossibleTypes() + { + return implode('|', $this->possibleTypes); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['type', InputArgument::REQUIRED, 'The type of newsletter we will send. '.$this->presentPossibleTypes()], + ['nb_quotes', InputArgument::OPTIONAL, 'The number of quotes to send.'], + ]; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } +} diff --git a/app/TeenQuotes/Newsletters/Console/UnsubscribeUsersCommand.php b/app/TeenQuotes/Newsletters/Console/UnsubscribeUsersCommand.php index 3577305e..a83d29eb 100644 --- a/app/TeenQuotes/Newsletters/Console/UnsubscribeUsersCommand.php +++ b/app/TeenQuotes/Newsletters/Console/UnsubscribeUsersCommand.php @@ -1,154 +1,153 @@ -newslettersManager = $newslettersManager; - $this->userMailer = $userMailer; - $this->userRepo = $userRepo; - } - - /** - * When a command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return \Indatus\Dispatcher\Scheduling\Schedulable - */ - public function schedule(Schedulable $scheduler) - { - return $scheduler - ->daily() - ->hours(17) - ->minutes(30); - } - - /** - * Choose the environment(s) where the command should run - * - * @return array Array of environments' name - */ - public function environment() - { - return ['production']; - } - - /** - * Execute the console command. - * - */ - public function fire() - { - // Retrieve inactive users - $nonActiveUsers = $this->userRepo->getNonActiveHavingNewsletter(); - - $hardBouncedUsers = $this->getHardBouncedUsers(); - - // Merge all users that need to be unsubscribed from newsletters - $allUsers = $nonActiveUsers->merge($hardBouncedUsers); - - // Unsubscribe these users from newsletters - $this->newslettersManager->deleteForUsers($allUsers); - - // Send an email to each user to notice them - $nonActiveUsers->each(function($user) - { - // Log this info - $this->writeToLog("Unsubscribing user from newsletters: ".$user->login." - ".$user->email); - - // Send the actual email - $this->userMailer->unsubscribeUserFromNewsletter($user); - }); - } - - /** - * Get users that have already been affected by a hard bounce - * - * @return \Illuminate\Database\Eloquent\Collection - */ - private function getHardBouncedUsers() - { - $users = MandrillClient::getHardBouncedUsers(); - - // Delete each user from the existing rejection list - $instance = $this; - $users->each(function($user) use ($instance) - { - MandrillClient::deleteEmailFromRejection($user->email); - - // Log this info - $instance->writeToLog("Removing user from the rejection list: ".$user->login." - ".$user->email); - }); - - return $users; - } - - private function writeToLog($line) - { - $this->info($line); - Log::info($line); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return []; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } +class UnsubscribeUsersCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'newsletter:deleteUsers'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Unsubscribe users from newsletters.'; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + /** + * @var \TeenQuotes\Newsletters\NewslettersManager + */ + private $newslettersManager; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + /** + * Create a new command instance. + */ + public function __construct(UserRepository $userRepo, NewslettersManager $newslettersManager, UserMailer $userMailer) + { + parent::__construct(); + + $this->newslettersManager = $newslettersManager; + $this->userMailer = $userMailer; + $this->userRepo = $userRepo; + } + + /** + * When a command should run. + * + * @param \Indatus\Dispatcher\Scheduling\Schedulable + * + * @return \Indatus\Dispatcher\Scheduling\Schedulable + */ + public function schedule(Schedulable $scheduler) + { + return $scheduler + ->daily() + ->hours(17) + ->minutes(30); + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production']; + } + + /** + * Execute the console command. + */ + public function fire() + { + // Retrieve inactive users + $nonActiveUsers = $this->userRepo->getNonActiveHavingNewsletter(); + + $hardBouncedUsers = $this->getHardBouncedUsers(); + + // Merge all users that need to be unsubscribed from newsletters + $allUsers = $nonActiveUsers->merge($hardBouncedUsers); + + // Unsubscribe these users from newsletters + $this->newslettersManager->deleteForUsers($allUsers); + + // Send an email to each user to notice them + $nonActiveUsers->each(function ($user) { + // Log this info + $this->writeToLog('Unsubscribing user from newsletters: '.$user->login.' - '.$user->email); + + // Send the actual email + $this->userMailer->unsubscribeUserFromNewsletter($user); + }); + } + + /** + * Get users that have already been affected by a hard bounce. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + private function getHardBouncedUsers() + { + $users = MandrillClient::getHardBouncedUsers(); + + // Delete each user from the existing rejection list + $instance = $this; + $users->each(function ($user) use ($instance) { + MandrillClient::deleteEmailFromRejection($user->email); + + // Log this info + $instance->writeToLog('Removing user from the rejection list: '.$user->login.' - '.$user->email); + }); + + return $users; + } + + private function writeToLog($line) + { + $this->info($line); + Log::info($line); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } } diff --git a/app/TeenQuotes/Newsletters/Controllers/MailchimpWebhook.php b/app/TeenQuotes/Newsletters/Controllers/MailchimpWebhook.php index d72a4664..91476dd2 100644 --- a/app/TeenQuotes/Newsletters/Controllers/MailchimpWebhook.php +++ b/app/TeenQuotes/Newsletters/Controllers/MailchimpWebhook.php @@ -1,99 +1,147 @@ -userRepo = $userRepo; - $this->newsletterRepo = $newsletterRepo; - $this->newsletterList = $newsletterList; - } - - public function listen() - { - $this->checkKey(Input::get('key')); - - $type = Input::get('type'); - - switch ($type) - { - // Unsubscribe from Mailchimp website - case 'unsubscribe': - $this->unsubscribe(Input::get('data')); - break; - - // Update of the email address - case 'upemail': - $this->changeEmail(Input::get('data')); - break; - - // Hard bounce or spam complaint - case 'cleaned': - $this->bounce(Input::get('data')); - break; - } - - return Response::make('DONE', 200); - } - - private function bounce($data) - { - $user = $this->userRepo->getByEmail($data['email']); - - if (! is_null($user)) - $this->newsletterRepo->deleteForUser($user); - } - - private function unsubscribe($data) - { - $type = $this->getTypeFromListId($data['list_id']); - - $user = $this->userRepo->getByLogin($data['merges']['LOGIN']); - - if (! is_null($user)) - $this->newsletterRepo->deleteForUserAndType($user, $type); - } - - private function changeEmail($data) - { - $oldEmail = $data['old_email']; - $newEmail = $data['new_email']; - - $user = $this->userRepo->getByEmail($oldEmail); - - if (! is_null($user)) - $this->userRepo->updateEmail($user, $newEmail); - } - - private function getTypeFromListId($listId) - { - return str_replace('Newsletter', '', $this->newsletterList->getNameFromListId($listId)); - } - - private function checkKey($key) - { - if ($key != Config::get('services.mailchimp.secret')) - throw new InvalidArgumentException("The secret key is not valid. Got ".$key); - } -} \ No newline at end of file +class MailchimpWebhook extends BaseController +{ + /** + * @var NewsletterRepository + */ + private $newsletterRepo; + + /** + * @var UserRepository + */ + private $userRepo; + + /** + * @var NewsletterList + */ + private $newsletterList; + + /** + * @param UserRepository $userRepo + * @param NewsletterRepository $newsletterRepo + * @param NewsletterList $newsletterList + */ + public function __construct(UserRepository $userRepo, NewsletterRepository $newsletterRepo, + NewsletterList $newsletterList) + { + $this->userRepo = $userRepo; + $this->newsletterRepo = $newsletterRepo; + $this->newsletterList = $newsletterList; + } + + /** + * Listen for the incoming webhooks and handle them. + * + * @return Response + */ + public function listen() + { + $this->checkKey(Input::get('key')); + + $type = Input::get('type'); + + switch ($type) { + // Unsubscribe from Mailchimp website + case 'unsubscribe': + $this->unsubscribe(Input::get('data')); + break; + + // Update of the email address + case 'upemail': + $this->changeEmail(Input::get('data')); + break; + + // Hard bounce or spam complaint + case 'cleaned': + $this->bounce(Input::get('data')); + break; + } + + return Response::make('DONE', 200); + } + + /** + * Handle the bounce event. + * + * @param array $data + */ + private function bounce(array $data) + { + $user = $this->userRepo->getByEmail($data['email']); + + if (!is_null($user)) { + $this->newsletterRepo->deleteForUser($user); + } + } + + /** + * Handle the unsubscribe event. + * + * @param array $data + */ + private function unsubscribe(array $data) + { + $type = $this->getTypeFromListId($data['list_id']); + + $user = $this->userRepo->getByLogin($data['merges']['LOGIN']); + + if (!is_null($user)) { + $this->newsletterRepo->deleteForUserAndType($user, $type); + } + } + + /** + * Handle the event when an user has changed its email address. + * + * @param array $data + */ + private function changeEmail(array $data) + { + $oldEmail = $data['old_email']; + $newEmail = $data['new_email']; + + $user = $this->userRepo->getByEmail($oldEmail); + + if (!is_null($user)) { + $this->userRepo->updateEmail($user, $newEmail); + } + } + + /** + * Get the type of a newsletter from its list ID. + * + * @param string $listId + * + * @return string + */ + private function getTypeFromListId($listId) + { + return str_replace('Newsletter', '', $this->newsletterList->getNameFromListId($listId)); + } + + /** + * Check the given secret key. + * + * @param string $key + * + * @throws InvalidArgumentException The key was wrong + */ + private function checkKey($key) + { + if ($key != Config::get('services.mailchimp.secret')) { + throw new InvalidArgumentException('The secret key is not valid. Got '.$key); + } + } +} diff --git a/app/TeenQuotes/Newsletters/Mailchimp/NewsletterList.php b/app/TeenQuotes/Newsletters/Mailchimp/NewsletterList.php index 0e2f66b4..a33b4b27 100644 --- a/app/TeenQuotes/Newsletters/Mailchimp/NewsletterList.php +++ b/app/TeenQuotes/Newsletters/Mailchimp/NewsletterList.php @@ -1,4 +1,6 @@ - 'd22415c1ea', - 'dailyNewsletter' => 'f9e52170f4', - ]; - - function __construct(View $view, Config $config, UserRepository $userRepo) - { - $this->mailchimp = App::make('MailchimpClient'); - $this->view = $view; - $this->config = $config; - $this->userRepo = $userRepo; - } - - /** - * Subscribe a user to a Mailchimp list - * - * @param string $listName - * @param \TeenQuotes\Users\Models\User $email - * @return mixed - */ - public function subscribeTo($listName, User $user) - { - return $this->mailchimp->lists->subscribe( - $this->getListIdFromName($listName), - ['email' => $user->email], - $this->getMergeVarsForUser($user), // Merge vars - 'html', // Email type - false, // Require double opt in? - true // Update existing customers? - ); - } - - /** - * Subscribe multiple users to a newsletter - * - * @param string $listName - * @param \Illuminate\Support\Collection $collection A collection of users - * @return mixed - */ - public function subscribeUsersTo($listName, Collection $collection) - { - $batch = $this->extractBatchSubscribe($collection); - - return $this->mailchimp->lists->batchSubscribe( - $this->getListIdFromName($listName), - $batch, - false, // Require double opt in? - true, // Update existing customers. - true // Replace interest - ); - } - - /** - * Unsubscribe a user from a Mailchimp list - * - * @param string $listName - * @param \TeenQuotes\Users\Models\User $email - * @return mixed - */ - public function unsubscribeFrom($listName, User $user) - { - return $this->mailchimp->lists->unsubscribe( - $this->getListIdFromName($listName), - ['email' => $user->email], - false, // Delete the member permanently - false, // Send goodbye email? - false // Send unsubscribe notification email? - ); - } - - /** - * Unsubscribe multiple users from a newsletter - * - * @param string $listName - * @param \Illuminate\Support\Collection $collection A collection of users - * @return mixed - */ - public function unsubscribeUsersFrom($listName, Collection $collection) - { - $batch = $this->extractBatchUnsubscribe($collection); - - return $this->mailchimp->lists->batchUnsubscribe( - $this->getListIdFromName($listName), - $batch, - true, // Delete member - false, // Send goodbye - false // Send notify - ); - } - - /** - * Send a campaign to a list - * - * @param string $listName - * @param string $subject - * @param string $toName - * @param string $viewName - * @param array $viewData - * @return mixed - */ - public function sendCampaign($listName, $subject, $toName, $viewName, $viewData) - { - $from = $this->config->get('mail.from'); - - $options = [ - 'list_id' => $this->getListIdFromName($listName), - 'subject' => $subject, - 'to_name' => $toName, - 'from_email' => $from['address'], - 'from_name' => $from['name'], - 'generate_text' => true, // Auto generate the plain text version - 'inline_css' => true, // Automatically inline CSS - ]; - - $html = $this->view->make($viewName, $viewData)->render(); - $content = compact('html'); - - $campaign = $this->mailchimp->campaigns->create('regular', $options, $content); - - return $this->mailchimp->campaigns->send($campaign['id']); - } - - /** - * Get users who unsubscribed from a list - * - * @param string $listName - * @return \Illuminate\Support\Collection $collection A collection of users - */ - public function getUnsubscribesFromList($listName) - { - $emails = $this->getEmailsUnsubscribedFromList($listName); - - return $this->userRepo->getByEmails($emails); - } - - /** - * Get a mailing list ID from its user-friendly name - * @param string $name - * @return string - */ - public function getListIdFromName($name) - { - return $this->lists[$name]; - } - - /** - * Get the user-friendly name of a mailing list from its ID - * @param string $listId - * @return string - */ - public function getNameFromListId($listId) - { - return array_search($listId, $this->lists); - } - - private function getEmailsUnsubscribedFromList($listName) - { - $emails = []; - - $out = $this->mailchimp->lists->members( - $this->getListIdFromName($listName), - 'unsubscribed', // Status: subscribed|unsubscribed|cleaned - null // Options - ); - - foreach ($out['data'] as $user) - $emails[] = $user['email']; - - return $emails; - } - - private function extractBatchSubscribe(Collection $c) - { - $batch = []; - - foreach ($c as $user) - { - $out['email'] = ['email' => $user->email]; - $out['email_type'] = 'html'; - $out['merge_vars'] = $this->getMergeVarsForUser($user); - - $batch[] = $out; - } - - return $batch; - } - - private function extractBatchUnsubscribe(Collection $c) - { - $batch = []; - - foreach ($c as $user) - { - $batch[] = ['email' => $user->email]; - } - - return $batch; - } - - private function getMergeVarsForUser(User $u) - { - return [ - 'LOGIN' => $u->login, - ]; - } -} \ No newline at end of file +class NewsletterList implements NewsletterListInterface +{ + /** + * @var Mailchimp + */ + protected $mailchimp; + + /** + * @var View + */ + protected $view; + + /** + * @var Config + */ + protected $config; + + /** + * @var UserRepository + */ + protected $userRepo; + + /** + * @var array + */ + protected $lists = [ + 'weeklyNewsletter' => 'd22415c1ea', + 'dailyNewsletter' => 'f9e52170f4', + ]; + + /** + * @param View $view + * @param Config $config + * @param UserRepository $userRepo + */ + public function __construct(View $view, Config $config, UserRepository $userRepo) + { + $this->mailchimp = App::make('MailchimpClient'); + $this->view = $view; + $this->config = $config; + $this->userRepo = $userRepo; + } + + /** + * Subscribe a user to a Mailchimp list. + * + * @param string $listName + * @param User $email + * + * @return mixed + */ + public function subscribeTo($listName, User $user) + { + return $this->mailchimp->lists->subscribe( + $this->getListIdFromName($listName), + ['email' => $user->email], + $this->getMergeVarsForUser($user), // Merge vars + 'html', // Email type + false, // Require double opt in? + true // Update existing customers? + ); + } + + /** + * Subscribe multiple users to a newsletter. + * + * @param string $listName + * @param \Illuminate\Support\Collection $collection A collection of users + * + * @return mixed + */ + public function subscribeUsersTo($listName, Collection $collection) + { + $batch = $this->extractBatchSubscribe($collection); + + return $this->mailchimp->lists->batchSubscribe( + $this->getListIdFromName($listName), + $batch, + false, // Require double opt in? + true, // Update existing customers. + true // Replace interest + ); + } + + /** + * Unsubscribe a user from a Mailchimp list. + * + * @param string $listName + * @param User $email + * + * @return mixed + */ + public function unsubscribeFrom($listName, User $user) + { + return $this->mailchimp->lists->unsubscribe( + $this->getListIdFromName($listName), + ['email' => $user->email], + false, // Delete the member permanently + false, // Send goodbye email? + false // Send unsubscribe notification email? + ); + } + + /** + * Unsubscribe multiple users from a newsletter. + * + * @param string $listName + * @param \Illuminate\Support\Collection $collection A collection of users + * + * @return mixed + */ + public function unsubscribeUsersFrom($listName, Collection $collection) + { + $batch = $this->extractBatchUnsubscribe($collection); + + return $this->mailchimp->lists->batchUnsubscribe( + $this->getListIdFromName($listName), + $batch, + true, // Delete member + false, // Send goodbye + false // Send notify + ); + } + + /** + * Send a campaign to a list. + * + * @param string $listName + * @param string $subject + * @param string $toName + * @param string $viewName + * @param array $viewData + * + * @return mixed + */ + public function sendCampaign($listName, $subject, $toName, $viewName, $viewData) + { + $from = $this->config->get('mail.from'); + + $options = [ + 'list_id' => $this->getListIdFromName($listName), + 'subject' => $subject, + 'to_name' => $toName, + 'from_email' => $from['address'], + 'from_name' => $from['name'], + 'generate_text' => true, // Auto generate the plain text version + 'inline_css' => true, // Automatically inline CSS + ]; + + $html = $this->view->make($viewName, $viewData)->render(); + $content = compact('html'); + + $campaign = $this->mailchimp->campaigns->create('regular', $options, $content); + + return $this->mailchimp->campaigns->send($campaign['id']); + } + + /** + * Get users who unsubscribed from a list. + * + * @param string $listName + * + * @return Collection $collection A collection of users + */ + public function getUnsubscribesFromList($listName) + { + $emails = $this->getEmailsUnsubscribedFromList($listName); + + return $this->userRepo->getByEmails($emails); + } + + /** + * Get a mailing list ID from its user-friendly name. + * + * @param string $name + * + * @return string + */ + public function getListIdFromName($name) + { + return $this->lists[$name]; + } + + /** + * Get the user-friendly name of a mailing list from its ID. + * + * @param string $listId + * + * @return string + */ + public function getNameFromListId($listId) + { + return array_search($listId, $this->lists); + } + + private function getEmailsUnsubscribedFromList($listName) + { + $emails = []; + + $out = $this->mailchimp->lists->members( + $this->getListIdFromName($listName), + 'unsubscribed', // Status: subscribed|unsubscribed|cleaned + null // Options + ); + + foreach ($out['data'] as $user) { + $emails[] = $user['email']; + } + + return $emails; + } + + private function extractBatchSubscribe(Collection $c) + { + $batch = []; + + foreach ($c as $user) { + $out['email'] = ['email' => $user->email]; + $out['email_type'] = 'html'; + $out['merge_vars'] = $this->getMergeVarsForUser($user); + + $batch[] = $out; + } + + return $batch; + } + + private function extractBatchUnsubscribe(Collection $c) + { + $batch = []; + + foreach ($c as $user) { + $batch[] = ['email' => $user->email]; + } + + return $batch; + } + + private function getMergeVarsForUser(User $u) + { + return [ + 'LOGIN' => $u->login, + ]; + } +} diff --git a/app/TeenQuotes/Newsletters/Models/Newsletter.php b/app/TeenQuotes/Newsletters/Models/Newsletter.php index 4e3bc895..a0d837ff 100644 --- a/app/TeenQuotes/Newsletters/Models/Newsletter.php +++ b/app/TeenQuotes/Newsletters/Models/Newsletter.php @@ -1,37 +1,50 @@ -type == self::DAILY); - } - - public function isWeekly() - { - return ($this->type == self::WEEKLY); - } - - /** - * Get available types of newsletters - * @return array - */ - public static function getPossibleTypes() - { - return [self::WEEKLY, self::DAILY]; - } -} \ No newline at end of file +class Newsletter extends Eloquent +{ + use NewsletterRelationsTrait, NewsletterScopesTrait; + + /** + * Constants associated with the newletter type. + */ + const DAILY = 'daily'; + const WEEKLY = 'weekly'; + + protected $fillable = []; + + /** + * Tell if it's the daily newsletter. + * + * @return bool + */ + public function isDaily() + { + return ($this->type == self::DAILY); + } + + /** + * Tell if it's the weekly newsletter. + * + * @return bool + */ + public function isWeekly() + { + return ($this->type == self::WEEKLY); + } + + /** + * Get available types of newsletters. + * + * @return array + */ + public static function getPossibleTypes() + { + return [self::WEEKLY, self::DAILY]; + } +} diff --git a/app/TeenQuotes/Newsletters/Models/Relations/NewsletterTrait.php b/app/TeenQuotes/Newsletters/Models/Relations/NewsletterTrait.php index 8992369e..97f4e8e9 100644 --- a/app/TeenQuotes/Newsletters/Models/Relations/NewsletterTrait.php +++ b/app/TeenQuotes/Newsletters/Models/Relations/NewsletterTrait.php @@ -1,11 +1,13 @@ -belongsTo(User::class); - } -} \ No newline at end of file +trait NewsletterTrait +{ + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/TeenQuotes/Newsletters/Models/Scopes/NewsletterTrait.php b/app/TeenQuotes/Newsletters/Models/Scopes/NewsletterTrait.php index fe890838..11a9267b 100644 --- a/app/TeenQuotes/Newsletters/Models/Scopes/NewsletterTrait.php +++ b/app/TeenQuotes/Newsletters/Models/Scopes/NewsletterTrait.php @@ -1,20 +1,23 @@ -whereType($type); - } + return $query->whereType($type); + } - public function scopeForUser($query, User $user) - { - return $query->where('user_id', '=', $user->id); - } -} \ No newline at end of file + public function scopeForUser($query, User $user) + { + return $query->where('user_id', '=', $user->id); + } +} diff --git a/app/TeenQuotes/Newsletters/NewsletterList.php b/app/TeenQuotes/Newsletters/NewsletterList.php index e597eedf..433c3d34 100644 --- a/app/TeenQuotes/Newsletters/NewsletterList.php +++ b/app/TeenQuotes/Newsletters/NewsletterList.php @@ -1,77 +1,89 @@ -app; +class NewsletterListServiceProvider extends ServiceProvider +{ + /** + * Register binding in IoC container. + */ + public function register() + { + $app = $this->app; - $this->app->singleton('MailchimpClient', function() use ($app) - { - return new Mailchimp($app['config']->get('services.mailchimp.secret')); - }); + $this->app->singleton('MailchimpClient', function () use ($app) { + return new Mailchimp($app['config']->get('services.mailchimp.secret')); + }); - $app->bind( - NewsletterList::class, - MailchimpNewsletterList::class - ); - } -} \ No newline at end of file + $app->bind( + NewsletterList::class, + MailchimpNewsletterList::class + ); + } +} diff --git a/app/TeenQuotes/Newsletters/NewslettersManager.php b/app/TeenQuotes/Newsletters/NewslettersManager.php index 7a32040b..1e52215a 100644 --- a/app/TeenQuotes/Newsletters/NewslettersManager.php +++ b/app/TeenQuotes/Newsletters/NewslettersManager.php @@ -1,64 +1,100 @@ -newslettersRepo = $newslettersRepo; - $this->newslettersList = $newslettersList; - } + /** + * @param NewsletterRepository $newslettersRepo + * @param NewsletterList $newslettersList + */ + public function __construct(NewsletterRepository $newslettersRepo, NewsletterList $newslettersList) + { + $this->newslettersRepo = $newslettersRepo; + $this->newslettersList = $newslettersList; + } - public function createForUserAndType(User $user, $type) - { - $this->newslettersRepo->createForUserAndType($user, $type); + /** + * Subscribe a user to a newsletter. + * + * @param User $user + * @param string $type The newsletter's type + */ + public function createForUserAndType(User $user, $type) + { + $this->newslettersRepo->createForUserAndType($user, $type); - if ($this->shouldCallAPI()) - $this->newslettersList->subscribeTo($this->getListNameFromType($type), $user); - } + if ($this->shouldCallAPI()) { + $this->newslettersList->subscribeTo($this->getListNameFromType($type), $user); + } + } - public function deleteForUserAndType(User $u, $type) - { - if ($this->shouldCallAPI()) - $this->newslettersList->unsubscribeFrom($this->getListNameFromType($type), $u); + /** + * Unsubscribe a user from a newsletter. + * + * @param User $u + * @param string $type The newsletter's type + */ + public function deleteForUserAndType(User $u, $type) + { + if ($this->shouldCallAPI()) { + $this->newslettersList->unsubscribeFrom($this->getListNameFromType($type), $u); + } - return $this->newslettersRepo->deleteForUserAndType($u, $type); - } + return $this->newslettersRepo->deleteForUserAndType($u, $type); + } - public function deleteForUsers(Collection $users) - { - if ($this->shouldCallAPI()) - { - foreach (Newsletter::getPossibleTypes() as $type) - $this->newslettersList->unsubscribeUsersFrom($this->getListNameFromType($type), $users); - } + /** + * Unsubscribe multiple users from all newsletters. + * + * @param Collection $users + */ + public function deleteForUsers(Collection $users) + { + if ($this->shouldCallAPI()) { + foreach (Newsletter::getPossibleTypes() as $type) { + $this->newslettersList->unsubscribeUsersFrom($this->getListNameFromType($type), $users); + } + } - return $this->newslettersRepo->deleteForUsers($users); - } + return $this->newslettersRepo->deleteForUsers($users); + } - private function shouldCallAPI() - { - return App::environment() == 'production'; - } + /** + * Determine if we should call the API. + * + * @return bool + */ + private function shouldCallAPI() + { + return App::environment() == 'production'; + } - private function getListNameFromType($type) - { - return $type.'Newsletter'; - } -} \ No newline at end of file + /** + * Get the name of a newsletter's list for a given type. + * + * @param string $type + * + * @return string + */ + private function getListNameFromType($type) + { + return $type.'Newsletter'; + } +} diff --git a/app/TeenQuotes/Newsletters/NewslettersServiceProvider.php b/app/TeenQuotes/Newsletters/NewslettersServiceProvider.php index f877aab4..4f18c9a6 100644 --- a/app/TeenQuotes/Newsletters/NewslettersServiceProvider.php +++ b/app/TeenQuotes/Newsletters/NewslettersServiceProvider.php @@ -1,75 +1,74 @@ -registerBindings(); - $this->registerCommands(); - $this->registerWebhooks(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerBindings(); + $this->registerCommands(); + $this->registerWebhooks(); + } - private function registerWebhooks() - { - $controller = 'MailchimpWebhook'; + private function registerWebhooks() + { + $controller = 'MailchimpWebhook'; - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) { - $this->app['router']->match(['GET', 'POST'],'mailchimp/webhook', ['as' => 'mailchimp.webhook', 'uses' => $controller.'@listen']); - }); - } + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->match(['GET', 'POST'], 'mailchimp/webhook', ['as' => 'mailchimp.webhook', 'uses' => $controller.'@listen']); + }); + } - private function registerBindings() - { - $this->app->bind( - $this->getNamespaceRepositories().'NewsletterRepository', - $this->getNamespaceRepositories().'DbNewsletterRepository' - ); - } + private function registerBindings() + { + $this->app->bind( + $this->getNamespaceRepositories().'NewsletterRepository', + $this->getNamespaceRepositories().'DbNewsletterRepository' + ); + } - private function registerCommands() - { - $commands = [ - 'newsletters.console.sendNewsletter' => $this->getNamespaceConsole().'SendNewsletterCommand', - 'newsletters.console.unsubscribeUsers' => $this->getNamespaceConsole().'UnsubscribeUsersCommand', - ]; + private function registerCommands() + { + $commands = [ + 'newsletters.console.sendNewsletter' => $this->getNamespaceConsole().'SendNewsletterCommand', + 'newsletters.console.unsubscribeUsers' => $this->getNamespaceConsole().'UnsubscribeUsersCommand', + ]; - foreach ($commands as $key => $class) - { - $this->app->bindShared($key, function($app) use($class) - { - return $app->make($class); - }); + foreach ($commands as $key => $class) { + $this->app->bindShared($key, function ($app) use ($class) { + return $app->make($class); + }); - $this->commands($key); - } - } + $this->commands($key); + } + } - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - 'namespace' => $this->getBaseNamespace().'Controllers', - ]; - } -} \ No newline at end of file + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + 'namespace' => $this->getBaseNamespace().'Controllers', + ]; + } +} diff --git a/app/TeenQuotes/Newsletters/Repositories/DbNewsletterRepository.php b/app/TeenQuotes/Newsletters/Repositories/DbNewsletterRepository.php index a57117a5..96767df3 100644 --- a/app/TeenQuotes/Newsletters/Repositories/DbNewsletterRepository.php +++ b/app/TeenQuotes/Newsletters/Repositories/DbNewsletterRepository.php @@ -1,101 +1,120 @@ -guardType($type); +class DbNewsletterRepository implements NewsletterRepository +{ + /** + * Tells if a user if subscribed to a newsletter type. + * + * @param User $u The given user + * @param string $type The newsletter's type + * + * @return bool + * + * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() + */ + public function userIsSubscribedToNewsletterType(User $u, $type) + { + $this->guardType($type); - return Newsletter::forUser($u) - ->type($type) - ->count() > 0; - } + return Newsletter::forUser($u) + ->type($type) + ->count() > 0; + } - /** - * Retrieve newsletters for a given type - * @param string $type - * @return \Illuminate\Database\Eloquent\Collection - * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() - */ - public function getForType($type) - { - $this->guardType($type); + /** + * Retrieve newsletters for a given type. + * + * @param string $type + * + * @return Collection + * + * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() + */ + public function getForType($type) + { + $this->guardType($type); - return Newsletter::whereType($type) - ->with('user') - ->get(); - } + return Newsletter::whereType($type) + ->with('user') + ->get(); + } - /** - * Create a newsletter item for the given user - * @var \TeenQuotes\Users\Models\User $user The user instance - * @var string $type The type of the newsletter : weekly|daily - * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() - */ - public function createForUserAndType(User $user, $type) - { - $this->guardType($type); + /** + * Create a newsletter item for the given user. + * + * @var \TeenQuotes\Users\Models\User The user instance + * @var string The type of the newsletter : weekly|daily + * + * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() + */ + public function createForUserAndType(User $user, $type) + { + $this->guardType($type); - if ($this->userIsSubscribedToNewsletterType($user, $type)) return; + if ($this->userIsSubscribedToNewsletterType($user, $type)) { + return null; + } - $newsletter = new Newsletter; - $newsletter->type = $type; - $newsletter->user_id = $user->id; - $newsletter->save(); - } + $newsletter = new Newsletter(); + $newsletter->type = $type; + $newsletter->user_id = $user->id; + $newsletter->save(); + } - /** - * Delete a newsletter item for the given user - * @var \TeenQuotes\Users\Models\User $user The user instance - * @var string $type The type of the newsletter : weekly|daily - * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() - */ - public function deleteForUserAndType(User $u, $type) - { - $this->guardType($type); + /** + * Delete a newsletter item for the given user. + * + * @var \TeenQuotes\Users\Models\User The user instance + * @var string The type of the newsletter : weekly|daily + * + * @see \TeenQuotes\Newsletters\Models\Newsletter::getPossibleTypes() + */ + public function deleteForUserAndType(User $u, $type) + { + $this->guardType($type); - return Newsletter::forUser($u) - ->type($type) - ->delete(); - } + return Newsletter::forUser($u) + ->type($type) + ->delete(); + } - /** - * Delete all newsletters for a given user - * @param \TeenQuotes\Users\Models\User $u - * @return int The number of affected rows - */ - public function deleteForUser(User $u) - { - return Newsletter::where('user_id', $u->id)->delete(); - } + /** + * Delete all newsletters for a given user. + * + * @param User $u + * + * @return int The number of affected rows + */ + public function deleteForUser(User $u) + { + return Newsletter::where('user_id', $u->id)->delete(); + } - /** - * Delete newsletters for a list of users - * @param \Illuminate\Support\Collection $users The collection of users - * @return int The number of affected rows - */ - public function deleteForUsers(Collection $users) - { - return Newsletter::whereIn('user_id', $users->lists('id'))->delete(); - } + /** + * Delete newsletters for a list of users. + * + * @param Collection $users The collection of users + * + * @return int The number of affected rows + */ + public function deleteForUsers(Collection $users) + { + return Newsletter::whereIn('user_id', $users->lists('id'))->delete(); + } - private function guardType($type) - { - $possibleTypes = Newsletter::getPossibleTypes(); + private function guardType($type) + { + $possibleTypes = Newsletter::getPossibleTypes(); - if ( ! in_array($type, $possibleTypes)) - throw new InvalidArgumentException($type." was given. Possible types: ".implode('|', $possibleTypes)); - } -} \ No newline at end of file + if (!in_array($type, $possibleTypes)) { + throw new InvalidArgumentException($type.' was given. Possible types: '.implode('|', $possibleTypes)); + } + } +} diff --git a/app/TeenQuotes/Newsletters/Repositories/NewsletterRepository.php b/app/TeenQuotes/Newsletters/Repositories/NewsletterRepository.php index 72237185..6bbc3f45 100644 --- a/app/TeenQuotes/Newsletters/Repositories/NewsletterRepository.php +++ b/app/TeenQuotes/Newsletters/Repositories/NewsletterRepository.php @@ -1,54 +1,70 @@ -app->bind('TeenQuotes\Notifiers\AdminNotifier', function($app) - { - $config = $this->app['config']; +class AdminNotifierServiceProvider extends ServiceProvider +{ + /** + * Register binding in IoC container. + */ + public function register() + { + $this->app->bind('TeenQuotes\Notifiers\AdminNotifier', function ($app) { + $config = $this->app['config']; - $lang = $this->app['translator']; - $apiKey = $config->get('services.pushbullet.apiKey'); - $deviceIden = $config->get('services.pushbullet.deviceIden'); + $lang = $this->app['translator']; + $apiKey = $config->get('services.pushbullet.apiKey'); + $deviceIden = $config->get('services.pushbullet.deviceIden'); - return new PushbulletAdminNotifier($lang, $apiKey, $deviceIden); - }); - } -} \ No newline at end of file + return new PushbulletAdminNotifier($lang, $apiKey, $deviceIden); + }); + } +} diff --git a/app/TeenQuotes/Notifiers/Pushbullet/PushbulletAdminNotifier.php b/app/TeenQuotes/Notifiers/Pushbullet/PushbulletAdminNotifier.php index 233e6e8b..ead24957 100644 --- a/app/TeenQuotes/Notifiers/Pushbullet/PushbulletAdminNotifier.php +++ b/app/TeenQuotes/Notifiers/Pushbullet/PushbulletAdminNotifier.php @@ -1,45 +1,50 @@ -apiKey = $apiKey; - $this->deviceIden = $deviceIden; - $this->lang = $lang; - } - - /** - * Notify an administrator about an event - * @param string $message - */ - public function notify($message) - { - $title = $this->lang->get('layout.nameWebsite'); - - $p = new Pushbullet($this->apiKey); - - $p->pushNote($this->deviceIden, $title, $message); - } -} \ No newline at end of file +class PushbulletAdminNotifier implements AdminNotifier +{ + /** + * The API key of Pushbullet. + * + * @var string + */ + private $apiKey; + + /** + * The ID of the device we will send the notification on. + * + * @var string + */ + private $deviceIden; + + /** + * @var \Illuminate\Translation\Translator + */ + private $lang; + + public function __construct(Lang $lang, $apiKey, $deviceIden) + { + $this->apiKey = $apiKey; + $this->deviceIden = $deviceIden; + $this->lang = $lang; + } + + /** + * Notify an administrator about an event. + * + * @param string $message + */ + public function notify($message) + { + $title = $this->lang->get('layout.nameWebsite'); + + $p = new Pushbullet($this->apiKey); + + $p->pushNote($this->deviceIden, $title, $message); + } +} diff --git a/app/TeenQuotes/Notifiers/Sms/SmsAdminNotifier.php b/app/TeenQuotes/Notifiers/Sms/SmsAdminNotifier.php index 4c3d8b77..3dad3b33 100644 --- a/app/TeenQuotes/Notifiers/Sms/SmsAdminNotifier.php +++ b/app/TeenQuotes/Notifiers/Sms/SmsAdminNotifier.php @@ -1,64 +1,70 @@ -url = $url; - $this->user = $user; - $this->password = $password; - } + public function __construct($url, $user, $password) + { + $this->url = $url; + $this->user = $user; + $this->password = $password; + } - /** - * Notify an administrator about an event - * @param string $message - */ - public function notify($message) - { - $data = $this->constructData($message); + /** + * Notify an administrator about an event. + * + * @param string $message + */ + public function notify($message) + { + $data = $this->constructData($message); - $this->sendRequest($this->url, $data); - } + $this->sendRequest($this->url, $data); + } - private function sendRequest($url, $data) - { - $ch = curl_init(); - $full = $url.'?'.http_build_query($data, '', '&', PHP_QUERY_RFC3986); + private function sendRequest($url, $data) + { + $ch = curl_init(); + $full = $url.'?'.http_build_query($data, '', '&', PHP_QUERY_RFC3986); - curl_setopt($ch, CURLOPT_URL, $full); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_URL, $full); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $output = curl_exec($ch); + $output = curl_exec($ch); - curl_close($ch); - } + curl_close($ch); + } - private function constructData($message) - { - return [ - 'user' => $this->user, - 'pass' => $this->password, - 'msg' => $message - ]; - } -} \ No newline at end of file + private function constructData($message) + { + return [ + 'user' => $this->user, + 'pass' => $this->password, + 'msg' => $message, + ]; + } +} diff --git a/app/TeenQuotes/Pages/Composers/AppsComposer.php b/app/TeenQuotes/Pages/Composers/AppsComposer.php index 042b267c..a0ccda1a 100644 --- a/app/TeenQuotes/Pages/Composers/AppsComposer.php +++ b/app/TeenQuotes/Pages/Composers/AppsComposer.php @@ -1,16 +1,24 @@ - 'apps', - 'eventAction' => 'download-page', - 'eventLabel' => Agent::platform().' - '.Agent::device() - ]); - } -} \ No newline at end of file +class AppsComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + // Data for Google Analytics + JavaScript::put([ + 'eventCategory' => 'apps', + 'eventAction' => 'download-page', + 'eventLabel' => Agent::platform().' - '.Agent::device(), + ]); + } +} diff --git a/app/TeenQuotes/Pages/Controllers/AppsController.php b/app/TeenQuotes/Pages/Controllers/AppsController.php index 12d9e006..ce932dd5 100644 --- a/app/TeenQuotes/Pages/Controllers/AppsController.php +++ b/app/TeenQuotes/Pages/Controllers/AppsController.php @@ -1,73 +1,81 @@ - Lang::get('apps.'.$device.'Title'), - 'titleIcon' => $this->getIconTitle($device), - 'deviceType' => $device, - 'content' => Lang::get('apps.'.$devicesInfo[$device]['text-key'], ['url' => URL::route('contact')]), - 'devicesInfo' => $devicesInfo, - 'pageTitle' => Lang::get('apps.'.$device.'Title').' | '.Lang::get('layout.nameWebsite'), - 'pageDescription' => Lang::get('apps.pageDescription'), - ]; + $data = [ + 'title' => Lang::get('apps.'.$device.'Title'), + 'titleIcon' => $this->getIconTitle($device), + 'deviceType' => $device, + 'content' => Lang::get('apps.'.$devicesInfo[$device]['text-key'], ['url' => URL::route('contact')]), + 'devicesInfo' => $devicesInfo, + 'pageTitle' => Lang::get('apps.'.$device.'Title').' | '.Lang::get('layout.nameWebsite'), + 'pageDescription' => Lang::get('apps.pageDescription'), + ]; - return View::make('apps.download', $data); - } + return View::make('apps.download', $data); + } - private function getIconTitle($device) - { - switch ($device) - { - case 'android': - case 'ios': - case 'mobile': - $result = 'fa-mobile'; - break; + private function getIconTitle($device) + { + switch ($device) { + case 'android': + case 'ios': + case 'mobile': + $result = 'fa-mobile'; + break; - case 'tablet': - $result = 'fa-tablet'; - break; - case 'desktop': - $result = 'fa-desktop'; - break; - } + case 'tablet': + $result = 'fa-tablet'; + break; + case 'desktop': + $result = 'fa-desktop'; + break; + } - return $result; - } -} \ No newline at end of file + return $result; + } +} diff --git a/app/TeenQuotes/Pages/Controllers/ContactController.php b/app/TeenQuotes/Pages/Controllers/ContactController.php index db5cfa31..e821f866 100644 --- a/app/TeenQuotes/Pages/Controllers/ContactController.php +++ b/app/TeenQuotes/Pages/Controllers/ContactController.php @@ -1,28 +1,34 @@ - Lang::get('contact.chooseYourWeapon'), - 'contactTitle' => Lang::get('contact.contactTitle'), - 'emailAddress' => Lang::get('contact.emailAddress'), - 'pageDescription' => Lang::get('contact.pageDescription'), - 'pageTitle' => Lang::get('contact.pageTitle'), - 'stayInTouchContent' => Lang::get('contact.stayInTouchContent'), - 'stayInTouchTitle' => Lang::get('contact.stayInTouchTitle'), - 'teamMembers' => LaraSetting::get('team'), - 'teamTitle' => Lang::get('contact.teamTitle'), - 'twitterAccount' => Lang::get('layout.twitterUsername'), - ]; +class ContactController extends BaseController +{ + public function index() + { + $data = [ + 'chooseYourWeapon' => Lang::get('contact.chooseYourWeapon'), + 'contactTitle' => Lang::get('contact.contactTitle'), + 'emailAddress' => Lang::get('contact.emailAddress'), + 'pageDescription' => Lang::get('contact.pageDescription'), + 'pageTitle' => Lang::get('contact.pageTitle'), + 'stayInTouchContent' => Lang::get('contact.stayInTouchContent'), + 'stayInTouchTitle' => Lang::get('contact.stayInTouchTitle'), + 'teamMembers' => LaraSetting::get('team'), + 'teamTitle' => Lang::get('contact.teamTitle'), + 'twitterAccount' => Lang::get('layout.twitterUsername'), + ]; - // Add description for each team member - foreach ($data['teamMembers'] as $teamName) - $data['teamDescription'.$teamName['firstName']] = Lang::get('contact.teamDescription'.$teamName['firstName']); + // Add description for each team member + foreach ($data['teamMembers'] as $teamName) { + $data['teamDescription'.$teamName['firstName']] = Lang::get('contact.teamDescription'.$teamName['firstName']); + } - return View::make('contact.show', $data); - } -} \ No newline at end of file + return View::make('contact.show', $data); + } +} diff --git a/app/TeenQuotes/Pages/Controllers/LegalController.php b/app/TeenQuotes/Pages/Controllers/LegalController.php index f6409c37..d1f8b24d 100644 --- a/app/TeenQuotes/Pages/Controllers/LegalController.php +++ b/app/TeenQuotes/Pages/Controllers/LegalController.php @@ -1,33 +1,40 @@ - Lang::get('legal.termsOfUseTitle'), - 'privacy' => Lang::get('legal.privacyPolicyTitle'), - ]; + $arianeLineLinks = [ + 'tos' => Lang::get('legal.termsOfUseTitle'), + 'privacy' => Lang::get('legal.privacyPolicyTitle'), + ]; - $data = [ - 'title' => Lang::get('legal.'.$displayName.'Title'), - 'content' => Lang::get('legal.'.$displayName.'Content'), - 'pageTitle' => Lang::get('legal.'.$displayName.'Title')." | ".Lang::get('layout.nameWebsite'), - 'pageDescription' => Lang::get('legal.pageDescription'), - 'arianeLineLinks' => $arianeLineLinks, - ]; + $data = [ + 'title' => Lang::get('legal.'.$displayName.'Title'), + 'content' => Lang::get('legal.'.$displayName.'Content'), + 'pageTitle' => Lang::get('legal.'.$displayName.'Title').' | '.Lang::get('layout.nameWebsite'), + 'pageDescription' => Lang::get('legal.pageDescription'), + 'arianeLineLinks' => $arianeLineLinks, + ]; - return View::make('legal.show', $data); - } -} \ No newline at end of file + return View::make('legal.show', $data); + } +} diff --git a/app/TeenQuotes/Pages/PagesServiceProvider.php b/app/TeenQuotes/Pages/PagesServiceProvider.php index 09ec199f..59f41369 100644 --- a/app/TeenQuotes/Pages/PagesServiceProvider.php +++ b/app/TeenQuotes/Pages/PagesServiceProvider.php @@ -1,101 +1,102 @@ -registerAppsPages(); - $this->registerAppsViewComposers(); - - // Contact - $this->registerContactPage(); - $this->registerContactViewComposers(); - - // Legal - $this->registerLegalPages(); - $this->registerLegalViewComposers(); - } - - private function registerAppsPages() - { - $this->app['router']->pattern('device_type', 'tablet|ios|android|mobile|desktop'); - - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('apps', ['as' => 'apps', 'uses' => 'AppsController@index']); - $this->app['router']->get('app', ['uses' => 'AppsController@redirectPlural']); - $this->app['router']->get('apps/{device_type}', ['as' => 'apps.device', 'uses' => 'AppsController@getDevice']); - }); - } - - private function registerAppsViewComposers() - { - // Apps download page - $this->app['view']->composer([ - 'apps.download' - ], 'TeenQuotes\Pages\Composers\AppsComposer'); - - // For deeps link - $this->app['view']->composer([ - 'apps.download' - ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); - } - - private function registerContactViewComposers() - { - // For deeps link - $this->app['view']->composer([ - 'contact.show' - ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); - } - - private function registerLegalViewComposers() - { - // For deeps link - $this->app['view']->composer([ - 'legal.show' - ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); - } - - private function registerContactPage() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('contact', ['as' => 'contact', 'uses' => 'ContactController@index']); - }); - } - - private function registerLegalPages() - { - $this->app['router']->pattern('legal_page', 'tos|privacy'); - - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('legal/{legal_page?}', ['as' => 'legal.show', 'uses' => 'LegalController@show']); - }); - } - - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - 'namespace' => 'TeenQuotes\Pages\Controllers', - ]; - } -} \ No newline at end of file +class PagesServiceProvider extends ServiceProvider +{ + /** + * Indicates if loading of the provider is deferred. + * + * @var bool + */ + protected $defer = false; + + /** + * Register the service provider. + */ + public function register() + { + // Apps + $this->registerAppsPages(); + $this->registerAppsViewComposers(); + + // Contact + $this->registerContactPage(); + $this->registerContactViewComposers(); + + // Legal + $this->registerLegalPages(); + $this->registerLegalViewComposers(); + } + + private function registerAppsPages() + { + $this->app['router']->pattern('device_type', 'tablet|ios|android|mobile|desktop'); + + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('apps', ['as' => 'apps', 'uses' => 'AppsController@index']); + $this->app['router']->get('app', ['uses' => 'AppsController@redirectPlural']); + $this->app['router']->get('apps/{device_type}', ['as' => 'apps.device', 'uses' => 'AppsController@getDevice']); + }); + } + + private function registerAppsViewComposers() + { + // Apps download page + $this->app['view']->composer([ + 'apps.download', + ], 'TeenQuotes\Pages\Composers\AppsComposer'); + + // For deeps link + $this->app['view']->composer([ + 'apps.download', + ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); + } + + private function registerContactViewComposers() + { + // For deeps link + $this->app['view']->composer([ + 'contact.show', + ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); + } + + private function registerLegalViewComposers() + { + // For deeps link + $this->app['view']->composer([ + 'legal.show', + ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); + } + + private function registerContactPage() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('contact', ['as' => 'contact', 'uses' => 'ContactController@index']); + }); + } + + private function registerLegalPages() + { + $this->app['router']->pattern('legal_page', 'tos|privacy'); + + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('legal/{legal_page?}', ['as' => 'legal.show', 'uses' => 'LegalController@show']); + }); + } + + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + 'namespace' => 'TeenQuotes\Pages\Controllers', + ]; + } +} diff --git a/app/TeenQuotes/Queues/QueuesServiceProvider.php b/app/TeenQuotes/Queues/QueuesServiceProvider.php index cbc6cf8c..51fb4892 100644 --- a/app/TeenQuotes/Queues/QueuesServiceProvider.php +++ b/app/TeenQuotes/Queues/QueuesServiceProvider.php @@ -1,36 +1,38 @@ -registerRoutes(); - } +class QueuesServiceProvider extends ServiceProvider +{ + /** + * Register binding in IoC container. + */ + public function register() + { + $this->registerRoutes(); + } - public function registerRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->post('queues/work', function() - { - return Queue::marshal(); - }); - }); - } + public function registerRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->post('queues/work', function () { + return Queue::marshal(); + }); + }); + } - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - ]; - } -} \ No newline at end of file + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + ]; + } +} diff --git a/app/TeenQuotes/Queues/Workers/EasyrecWorker.php b/app/TeenQuotes/Queues/Workers/EasyrecWorker.php index 958b06b9..ad6effbd 100644 --- a/app/TeenQuotes/Queues/Workers/EasyrecWorker.php +++ b/app/TeenQuotes/Queues/Workers/EasyrecWorker.php @@ -1,102 +1,117 @@ -app = $app; - } + public function __construct(App $app) + { + $this->app = $app; + } - /** - * Register the view of a quote - * @param \Illuminate\Queue\Jobs\Job $job - * @param array $data Required keys: quote_id and user_id. - */ - public function viewQuote($job, $data) - { - if (! $this->isEnabled()) return; + /** + * Register the view of a quote. + * + * @param \Illuminate\Queue\Jobs\Job $job + * @param array $data Required keys: quote_id and user_id. + */ + public function viewQuote($job, $data) + { + if (!$this->isEnabled()) { + return null; + } - Easyrec::view($data['quote_id'], - "Quote ".$data['quote_id'], - URL::route("quotes.show", $data['quote_id'], false), - $data['user_id'], - null, // No image URL - null, // Current timestamp - "QUOTE" - ); - } + Easyrec::view($data['quote_id'], + 'Quote '.$data['quote_id'], + URL::route('quotes.show', $data['quote_id'], false), + $data['user_id'], + null, // No image URL + null, // Current timestamp + 'QUOTE' + ); + } - /** - * Register the view of a user profile - * @param \Illuminate\Queue\Jobs\Job $job - * @param array $data Required keys: viewer_user_id, user_login and user_id. - */ - public function viewUserProfile($job, $data) - { - if (! $this->isEnabled()) return; + /** + * Register the view of a user profile. + * + * @param \Illuminate\Queue\Jobs\Job $job + * @param array $data Required keys: viewer_user_id, user_login and user_id. + */ + public function viewUserProfile($job, $data) + { + if (!$this->isEnabled()) { + return null; + } - Easyrec::view($data['user_id'], - "User ".$data['user_id'], - URL::route("users.show", $data['user_login'], false), - $data['viewer_user_id'], - null, // No image URL - null, // Current timestamp - "USERPROFILE" - ); - } + Easyrec::view($data['user_id'], + 'User '.$data['user_id'], + URL::route('users.show', $data['user_login'], false), + $data['viewer_user_id'], + null, // No image URL + null, // Current timestamp + 'USERPROFILE' + ); + } - /** - * Add a quote to the favorites - * @param \Illuminate\Queue\Jobs\Job $job [ription] - * @param array $data Required keys: quote_id, user_id - */ - public function favoriteAQuote($job, $data) - { - if (! $this->isEnabled()) return; + /** + * Add a quote to the favorites. + * + * @param \Illuminate\Queue\Jobs\Job $job [ription] + * @param array $data Required keys: quote_id, user_id + */ + public function favoriteAQuote($job, $data) + { + if (!$this->isEnabled()) { + return null; + } - Easyrec::sendAction($data['quote_id'], - "Quote ".$data['quote_id'], - URL::route("quotes.show", $data['quote_id'], false), - "FAVORITE", - null, // Action value - $data['user_id'], - null, // No image URL - null, // Current timestamp - "QUOTE" - ); - } + Easyrec::sendAction($data['quote_id'], + 'Quote '.$data['quote_id'], + URL::route('quotes.show', $data['quote_id'], false), + 'FAVORITE', + null, // Action value + $data['user_id'], + null, // No image URL + null, // Current timestamp + 'QUOTE' + ); + } - /** - * Remove a quote from the favorites - * @param \Illuminate\Queue\Jobs\Job $job [ription] - * @param array $data Required keys: quote_id, user_id - */ - public function unfavoriteAQuote($job, $data) - { - if (! $this->isEnabled()) return; + /** + * Remove a quote from the favorites. + * + * @param \Illuminate\Queue\Jobs\Job $job [ription] + * @param array $data Required keys: quote_id, user_id + */ + public function unfavoriteAQuote($job, $data) + { + if (!$this->isEnabled()) { + return null; + } - Easyrec::sendAction($data['quote_id'], - "Quote ".$data['quote_id'], - URL::route("quotes.show", $data['quote_id'], false), - "UNFAVORITE", - null, // Action value - $data['user_id'], - null, // No image URL - null, // Current timestamp - "QUOTE" - ); - } + Easyrec::sendAction($data['quote_id'], + 'Quote '.$data['quote_id'], + URL::route('quotes.show', $data['quote_id'], false), + 'UNFAVORITE', + null, // Action value + $data['user_id'], + null, // No image URL + null, // Current timestamp + 'QUOTE' + ); + } - private function isEnabled() - { - return $this->app->environment() == 'production'; - } -} \ No newline at end of file + private function isEnabled() + { + return $this->app->environment() == 'production'; + } +} diff --git a/app/TeenQuotes/Queues/Workers/ProfileVisitorWorker.php b/app/TeenQuotes/Queues/Workers/ProfileVisitorWorker.php index e24e0e48..1d31217d 100644 --- a/app/TeenQuotes/Queues/Workers/ProfileVisitorWorker.php +++ b/app/TeenQuotes/Queues/Workers/ProfileVisitorWorker.php @@ -1,27 +1,29 @@ -repo = $repo; - } + public function __construct(ProfileVisitorRepository $repo) + { + $this->repo = $repo; + } - /** - * View a user profile - * - * @param \Illuminate\Queue\Jobs\SyncJob $job - * @param array $data Required keys: visitor_id and user_id. - */ - public function viewProfile($job, $data) - { - $this->repo->addVisitor($data['user_id'], $data['visitor_id']); - } -} \ No newline at end of file + /** + * View a user profile. + * + * @param \Illuminate\Queue\Jobs\SyncJob $job + * @param array $data Required keys: visitor_id and user_id. + */ + public function viewProfile($job, $data) + { + $this->repo->addVisitor($data['user_id'], $data['visitor_id']); + } +} diff --git a/app/TeenQuotes/Quotes/Composers/AddComposer.php b/app/TeenQuotes/Quotes/Composers/AddComposer.php index 0c1668ee..fbea49bf 100644 --- a/app/TeenQuotes/Quotes/Composers/AddComposer.php +++ b/app/TeenQuotes/Quotes/Composers/AddComposer.php @@ -1,17 +1,25 @@ - Lang::get('quotes.contentShortHint'), - 'contentGreatHint' => Lang::get('quotes.contentGreatHint'), - 'eventCategory' => 'addquote', - 'eventAction' => 'logged-in', - 'eventLabel' => 'addquote-page' - ]); - } -} \ No newline at end of file +class AddComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + JavaScript::put([ + 'contentShortHint' => Lang::get('quotes.contentShortHint'), + 'contentGreatHint' => Lang::get('quotes.contentGreatHint'), + 'eventCategory' => 'addquote', + 'eventAction' => 'logged-in', + 'eventLabel' => 'addquote-page', + ]); + } +} diff --git a/app/TeenQuotes/Quotes/Composers/IndexComposer.php b/app/TeenQuotes/Quotes/Composers/IndexComposer.php index 6789be06..4b5eeafd 100644 --- a/app/TeenQuotes/Quotes/Composers/IndexComposer.php +++ b/app/TeenQuotes/Quotes/Composers/IndexComposer.php @@ -1,93 +1,108 @@ -getData(); - - // The AdBlock disclaimer - JavaScript::put([ - 'moneyDisclaimer' => Lang::get('quotes.adblockDisclaimer'), - ]); - - // Build the associative array #quote->id => "color" - // and store it in session - $view->with('colors', $this->extractAndStoreColors($data['quotes'])); - - // If we have an available promotion, display it - $shouldDisplayPromotion = $this->shouldDisplayPromotion(); - $view->with('shouldDisplayPromotion', $shouldDisplayPromotion); - if ($shouldDisplayPromotion) - $view = $this->addPromotionToData($view); - } - - private function addPromotionToData($view) - { - $data = $this->getDataPromotion(); - - foreach ($data as $key => $value) { - $view->with($key, $value); - } - - return $view; - } - - public function extractAndStoreColors($quotes) - { - $colors = Quote::storeQuotesColors($quotes->lists('id')); - - return $colors; - } - - private function getDataPromotion() - { - if ($this->shouldDisplaySignupPromotion()) - return $this->getDataSignupPromotion(); - - if ($this->shouldDisplaySharingPromotion()) - return $this->getDataSharingPromotion(); - } - - private function getDataSharingPromotion() - { - return [ - 'promotionTitle' => Lang::get('quotes.sharePromotionTitle'), - 'promotionText' => Lang::get('quotes.sharePromotion'), - 'promotionIcon' => 'fa-heart-o', - ]; - } - - private function getDataSignupPromotion() - { - return [ - 'promotionTitle' => Lang::get('quotes.signupPromotionTitle'), - 'promotionText' => Lang::get('quotes.signupPromotion', ['url' => URL::route('signup')]), - 'promotionIcon' => 'fa-smile-o', - ]; - } - - private function shouldDisplaySharingPromotion() - { - if (is_null(self::$shouldDisplaySharingPromotion)) - self::$shouldDisplaySharingPromotion = (rand(1, 100) == 42); - - return self::$shouldDisplaySharingPromotion; - } - - private function shouldDisplaySignupPromotion() - { - return Auth::guest() AND Input::get('page') >= 2; - } - - private function shouldDisplayPromotion() - { - return $this->shouldDisplaySharingPromotion() OR $this->shouldDisplaySignupPromotion(); - } -} \ No newline at end of file +use URL; + +class IndexComposer implements QuotesColorsExtractor +{ + private static $shouldDisplaySharingPromotion = null; + + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + + // The AdBlock disclaimer + JavaScript::put([ + 'moneyDisclaimer' => Lang::get('quotes.adblockDisclaimer'), + ]); + + // Build the associative array #quote->id => "color" + // and store it in session + $view->with('colors', $this->extractAndStoreColors($data['quotes'])); + + // If we have an available promotion, display it + $shouldDisplayPromotion = $this->shouldDisplayPromotion(); + $view->with('shouldDisplayPromotion', $shouldDisplayPromotion); + if ($shouldDisplayPromotion) { + $view = $this->addPromotionToData($view); + } + } + + private function addPromotionToData($view) + { + $data = $this->getDataPromotion(); + + foreach ($data as $key => $value) { + $view->with($key, $value); + } + + return $view; + } + + public function extractAndStoreColors($quotes) + { + $colors = Quote::storeQuotesColors($quotes->lists('id')); + + return $colors; + } + + private function getDataPromotion() + { + if ($this->shouldDisplaySignupPromotion()) { + return $this->getDataSignupPromotion(); + } + + if ($this->shouldDisplaySharingPromotion()) { + return $this->getDataSharingPromotion(); + } + } + + private function getDataSharingPromotion() + { + return [ + 'promotionTitle' => Lang::get('quotes.sharePromotionTitle'), + 'promotionText' => Lang::get('quotes.sharePromotion'), + 'promotionIcon' => 'fa-heart-o', + ]; + } + + private function getDataSignupPromotion() + { + return [ + 'promotionTitle' => Lang::get('quotes.signupPromotionTitle'), + 'promotionText' => Lang::get('quotes.signupPromotion', ['url' => URL::route('signup')]), + 'promotionIcon' => 'fa-smile-o', + ]; + } + + private function shouldDisplaySharingPromotion() + { + if (is_null(self::$shouldDisplaySharingPromotion)) { + self::$shouldDisplaySharingPromotion = (rand(1, 100) == 42); + } + + return self::$shouldDisplaySharingPromotion; + } + + private function shouldDisplaySignupPromotion() + { + return Auth::guest() and Input::get('page') >= 2; + } + + private function shouldDisplayPromotion() + { + return $this->shouldDisplaySharingPromotion() or $this->shouldDisplaySignupPromotion(); + } +} diff --git a/app/TeenQuotes/Quotes/Composers/IndexForTagComposer.php b/app/TeenQuotes/Quotes/Composers/IndexForTagComposer.php index ebc3f6b4..4872780c 100644 --- a/app/TeenQuotes/Quotes/Composers/IndexForTagComposer.php +++ b/app/TeenQuotes/Quotes/Composers/IndexForTagComposer.php @@ -1,15 +1,22 @@ -with('tagName', Route::input('tag_name')); +class IndexForTagComposer extends IndexComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + // Bind to the view the name of the tag + $view->with('tagName', Route::input('tag_name')); - // Delegate the difficult stuff to the parent - parent::compose($view); - } -} \ No newline at end of file + // Delegate the difficult stuff to the parent + parent::compose($view); + } +} diff --git a/app/TeenQuotes/Quotes/Composers/IndexForTopsComposer.php b/app/TeenQuotes/Quotes/Composers/IndexForTopsComposer.php index 7cff11a4..e5fc231b 100644 --- a/app/TeenQuotes/Quotes/Composers/IndexForTopsComposer.php +++ b/app/TeenQuotes/Quotes/Composers/IndexForTopsComposer.php @@ -1,45 +1,52 @@ -with('possibleTopTypes', $this->getPossibleTopTypes()); - $view = $this->buildIconsForTops($view); - - // Delegate the difficult stuff to the parent - parent::compose($view); - } - - private function buildIconsForTops($view) - { - foreach ($this->getPossibleTopTypes() as $topType) - $view->with('iconForTop'.ucfirst($topType), $this->getIconForTopType($topType)); +namespace TeenQuotes\Quotes\Composers; - return $view; - } - - private function getIconForTopType($topType) - { - switch ($topType) - { - case 'favorites': - return 'fa-heart'; - - case 'comments': - return 'fa-comments'; - } - - $message = "Can't find icon for top type: ".$topType; - - throw new InvalidArgumentException($message); - } +use InvalidArgumentException; - private function getPossibleTopTypes() - { - return ['favorites', 'comments']; - } -} \ No newline at end of file +class IndexForTopsComposer extends IndexComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + // Add stuff related to tops + $view->with('possibleTopTypes', $this->getPossibleTopTypes()); + $view = $this->buildIconsForTops($view); + + // Delegate the difficult stuff to the parent + parent::compose($view); + } + + private function buildIconsForTops($view) + { + foreach ($this->getPossibleTopTypes() as $topType) { + $view->with('iconForTop'.ucfirst($topType), $this->getIconForTopType($topType)); + } + + return $view; + } + + private function getIconForTopType($topType) + { + switch ($topType) { + case 'favorites': + return 'fa-heart'; + + case 'comments': + return 'fa-comments'; + } + + $message = "Can't find icon for top type: ".$topType; + + throw new InvalidArgumentException($message); + } + + private function getPossibleTopTypes() + { + return ['favorites', 'comments']; + } +} diff --git a/app/TeenQuotes/Quotes/Composers/ResultsComposer.php b/app/TeenQuotes/Quotes/Composers/ResultsComposer.php index 3145f899..646e8521 100644 --- a/app/TeenQuotes/Quotes/Composers/ResultsComposer.php +++ b/app/TeenQuotes/Quotes/Composers/ResultsComposer.php @@ -1,21 +1,28 @@ -getData(); - public function compose($view) - { - $data = $view->getData(); + $view->with('colors', $this->extractAndStoreColors($data['quotes'])); + } - $view->with('colors', $this->extractAndStoreColors($data['quotes'])); - } + public function extractAndStoreColors($quotes) + { + $colors = Quote::storeQuotesColors($quotes->lists('id')); - public function extractAndStoreColors($quotes) - { - $colors = Quote::storeQuotesColors($quotes->lists('id')); - - return $colors; - } -} \ No newline at end of file + return $colors; + } +} diff --git a/app/TeenQuotes/Quotes/Composers/ShowComposer.php b/app/TeenQuotes/Quotes/Composers/ShowComposer.php index e869b6c7..51d7dfe4 100644 --- a/app/TeenQuotes/Quotes/Composers/ShowComposer.php +++ b/app/TeenQuotes/Quotes/Composers/ShowComposer.php @@ -1,58 +1,66 @@ -getData(); - - // The ID of the current quote - $id = $data['quote']->id; - - // Put some useful variables for the JS - JavaScript::put([ - 'contentShortHint' => Lang::get('comments.contentShortHint'), - 'contentGreatHint' => Lang::get('comments.contentGreatHint'), - ]); - - // Load colors for the quote - if (Session::has('colors.quote') AND array_key_exists($id, Session::get('colors.quote'))) - $colors = Session::get('colors.quote'); - else - { - // Fall back to the default color - $colors = []; - $colors[$id] = 'color-1'; - } - - $view->with('colors', $colors); - - // Deep links - $view->with('deepLinksArray', $this->createDeepLinks('quotes/'.$id)); - - // Perform translation on tags - $view->with('tagsName', $this->transformTags($data['quote'])); - } - - /** - * Transform a list of tags for a quote - * - * @param \TeenQuotes\Quotes\Model\Quote $quote - * @return array A key value array like ['love' => 'Love'] - */ - private function transformTags(Quote $quote) - { - $tagsName = []; - - foreach($quote->tagsList as $tag) - { - $tagsName[$tag] = Lang::get('tags.'.$tag); - } - - return $tagsName; - } -} \ No newline at end of file +class ShowComposer extends AbstractDeepLinksComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + + // The ID of the current quote + $id = $data['quote']->id; + + // Put some useful variables for the JS + JavaScript::put([ + 'contentShortHint' => Lang::get('comments.contentShortHint'), + 'contentGreatHint' => Lang::get('comments.contentGreatHint'), + ]); + + // Load colors for the quote + if (Session::has('colors.quote') and array_key_exists($id, Session::get('colors.quote'))) { + $colors = Session::get('colors.quote'); + } else { + // Fall back to the default color + $colors = []; + $colors[$id] = 'color-1'; + } + + $view->with('colors', $colors); + + // Deep links + $view->with('deepLinksArray', $this->createDeepLinks('quotes/'.$id)); + + // Perform translation on tags + $view->with('tagsName', $this->transformTags($data['quote'])); + } + + /** + * Transform a list of tags for a quote. + * + * @param \TeenQuotes\Quotes\Model\Quote $quote + * + * @return array A key value array like ['love' => 'Love'] + */ + private function transformTags(Quote $quote) + { + $tagsName = []; + + foreach ($quote->tagsList as $tag) { + $tagsName[$tag] = Lang::get('tags.'.$tag); + } + + return $tagsName; + } +} diff --git a/app/TeenQuotes/Quotes/Composers/SingleComposer.php b/app/TeenQuotes/Quotes/Composers/SingleComposer.php index 151d9c79..1de39113 100644 --- a/app/TeenQuotes/Quotes/Composers/SingleComposer.php +++ b/app/TeenQuotes/Quotes/Composers/SingleComposer.php @@ -1,14 +1,22 @@ - URL::route('quotes.favoritesInfo'), - ]); - } -} \ No newline at end of file +class SingleComposer extends AbstractDeepLinksComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + JavaScript::put([ + 'urlFavoritesInfo' => URL::route('quotes.favoritesInfo'), + ]); + } +} diff --git a/app/TeenQuotes/Quotes/Console/QuotesPublishCommand.php b/app/TeenQuotes/Quotes/Console/QuotesPublishCommand.php index 2067dcf3..03afb64c 100644 --- a/app/TeenQuotes/Quotes/Console/QuotesPublishCommand.php +++ b/app/TeenQuotes/Quotes/Console/QuotesPublishCommand.php @@ -1,183 +1,188 @@ -quoteRepo = $quoteRepo; - $this->userMailer = $userMailer; - $this->adminNotifier = $adminNotifier; - } - - /** - * When a command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return \Indatus\Dispatcher\Scheduling\Schedulable - */ - public function schedule(Schedulable $scheduler) - { - return $scheduler - ->daily() - ->hours(11) - ->minutes(0); - } - - /** - * Choose the environment(s) where the command should run - * @return array Array of environments' name - */ - public function environment() - { - return ['production']; - } - - private function getNbQuotesArgument() - { - if (is_null($this->argument('nb_quotes'))) - return Config::get('app.quotes.nbQuotesToPublishPerDay'); - - return $this->argument('nb_quotes'); - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function fire() - { - // Get the quotes that will be published today - $quotes = $this->quoteRepo->lastPendingQuotes($this->getNbQuotesArgument()); - - // Remember the effective number of published quotes - $this->nbQuotesPublished = $quotes->count(); - - $quotes->each(function($quote) - { - // Save the quote in storage - $this->quoteRepo->updateApproved($quote->id, Quote::PUBLISHED); - - $this->users[] = $quote->user; - - // Log this info - $this->log("Published quote #".$quote->id); - - // Send an email to the author - $this->userMailer->tellQuoteWasPublished($quote); - }); - - // Notify the administrator about the remaining - // number of days to published queued quotes - $this->notifyAdministrator(); - } - - private function notifyAdministrator() - { - $nbDays = $this->getNbRemainingDaysPublication(); - - $message = 'Number of days with quotes waiting to be published: '.$nbDays; - - $this->adminNotifier->notify($message); - } - - /** - * Compute the number of days required to publish - * quotes waiting to be published - * - * @return int - */ - private function getNbRemainingDaysPublication() - { - $nbQuotesPending = $this->quoteRepo->nbPending(); - $quotesPerDay = Config::get('app.quotes.nbQuotesToPublishPerDay'); - - return ceil($nbQuotesPending / $quotesPerDay); - } - - private function log($string) - { - $this->info($string); - Log::info($string); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return [ - ['nb_quotes', InputArgument::OPTIONAL, 'The number of quotes to publish.'], - ]; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } +class QuotesPublishCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'quotes:publish'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Publish quotes for today.'; + + /** + * Users that have published quotes. + * + * @var array + */ + protected $users = []; + + /** + * Effective number of quotes published today. + * + * @var int + */ + protected $nbQuotesPublished = 0; + + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + /** + * @var \TeenQuotes\Notifiers\AdminNotifier + */ + private $adminNotifier; + + /** + * Create a new command instance. + */ + public function __construct(QuoteRepository $quoteRepo, UserMailer $userMailer, + AdminNotifier $adminNotifier) + { + parent::__construct(); + + $this->quoteRepo = $quoteRepo; + $this->userMailer = $userMailer; + $this->adminNotifier = $adminNotifier; + } + + /** + * When a command should run. + * + * @param \Indatus\Dispatcher\Scheduling\Schedulable + * + * @return \Indatus\Dispatcher\Scheduling\Schedulable + */ + public function schedule(Schedulable $scheduler) + { + return $scheduler + ->daily() + ->hours(11) + ->minutes(0); + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production']; + } + + private function getNbQuotesArgument() + { + if (is_null($this->argument('nb_quotes'))) { + return Config::get('app.quotes.nbQuotesToPublishPerDay'); + } + + return $this->argument('nb_quotes'); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Get the quotes that will be published today + $quotes = $this->quoteRepo->lastPendingQuotes($this->getNbQuotesArgument()); + + // Remember the effective number of published quotes + $this->nbQuotesPublished = $quotes->count(); + + $quotes->each(function ($quote) { + // Save the quote in storage + $this->quoteRepo->updateApproved($quote->id, Quote::PUBLISHED); + + $this->users[] = $quote->user; + + // Log this info + $this->log('Published quote #'.$quote->id); + + // Send an email to the author + $this->userMailer->tellQuoteWasPublished($quote); + }); + + // Notify the administrator about the remaining + // number of days to published queued quotes + $this->notifyAdministrator(); + } + + private function notifyAdministrator() + { + $nbDays = $this->getNbRemainingDaysPublication(); + + $message = 'Number of days with quotes waiting to be published: '.$nbDays; + + $this->adminNotifier->notify($message); + } + + /** + * Compute the number of days required to publish + * quotes waiting to be published. + * + * @return int + */ + private function getNbRemainingDaysPublication() + { + $nbQuotesPending = $this->quoteRepo->nbPending(); + $quotesPerDay = Config::get('app.quotes.nbQuotesToPublishPerDay'); + + return ceil($nbQuotesPending / $quotesPerDay); + } + + private function log($string) + { + $this->info($string); + Log::info($string); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['nb_quotes', InputArgument::OPTIONAL, 'The number of quotes to publish.'], + ]; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } } diff --git a/app/TeenQuotes/Quotes/Console/WaitingQuotesCommand.php b/app/TeenQuotes/Quotes/Console/WaitingQuotesCommand.php index 2a746903..0f63cdff 100644 --- a/app/TeenQuotes/Quotes/Console/WaitingQuotesCommand.php +++ b/app/TeenQuotes/Quotes/Console/WaitingQuotesCommand.php @@ -1,4 +1,6 @@ -quoteRepo = $quoteRepo; - $this->adminNotifier = $adminNotifier; - } - - /** - * When the command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return \Indatus\Dispatcher\Scheduling\Schedulable - */ - public function schedule(Schedulable $scheduler) - { - return $scheduler - ->daily() - ->hours(12) - ->minutes(0); - } - - /** - * Choose the environment(s) where the command should run - * - * @return array Array of environments' name - */ - public function environment() - { - return ['production']; - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function fire() - { - // Retrieve data - $waitingToday = $this->getWaitingToday(); - $totalWaiting = $this->getTotalWaiting(); - - // Warn the administrator - $this->sendStatsToAdministrator($waitingToday, $totalWaiting); - } - - /** - * Send some statistics to the administrator - * - * @param int $waitingToday The number of quotes submitted today - * @param int $totalWaiting The number of quotes waiting moderation - */ - private function sendStatsToAdministrator($waitingToday, $totalWaiting) - { - $message = "Number of quotes submitted today: ".$waitingToday." Total: ".$totalWaiting; - - $this->adminNotifier->notify($message); - } - - /** - * Get the number of quotes submitted in the last 24 hours - * - * @return int - */ - private function getWaitingToday() - { - $yesterday = Carbon::now()->subDay(); - - return $this->quoteRepo->countWaitingQuotesSince($yesterday); - } - - /** - * Get the number of quotes waiting moderation - * - * @return int - */ - private function getTotalWaiting() - { - return $this->quoteRepo->nbWaiting(); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return []; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } -} \ No newline at end of file +class WaitingQuotesCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'quotes:waiting'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Get some statistics about waiting quotes.'; + + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Notifiers\AdminNotifier + */ + private $adminNotifier; + + /** + * Create a new command instance. + */ + public function __construct(QuoteRepository $quoteRepo, AdminNotifier $adminNotifier) + { + parent::__construct(); + + $this->quoteRepo = $quoteRepo; + $this->adminNotifier = $adminNotifier; + } + + /** + * When the command should run. + * + * @param \Indatus\Dispatcher\Scheduling\Schedulable + * + * @return \Indatus\Dispatcher\Scheduling\Schedulable + */ + public function schedule(Schedulable $scheduler) + { + return $scheduler + ->daily() + ->hours(12) + ->minutes(0); + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production']; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Retrieve data + $waitingToday = $this->getWaitingToday(); + $totalWaiting = $this->getTotalWaiting(); + + // Warn the administrator + $this->sendStatsToAdministrator($waitingToday, $totalWaiting); + } + + /** + * Send some statistics to the administrator. + * + * @param int $waitingToday The number of quotes submitted today + * @param int $totalWaiting The number of quotes waiting moderation + */ + private function sendStatsToAdministrator($waitingToday, $totalWaiting) + { + $message = 'Number of quotes submitted today: '.$waitingToday.' Total: '.$totalWaiting; + + $this->adminNotifier->notify($message); + } + + /** + * Get the number of quotes submitted in the last 24 hours. + * + * @return int + */ + private function getWaitingToday() + { + $yesterday = Carbon::now()->subDay(); + + return $this->quoteRepo->countWaitingQuotesSince($yesterday); + } + + /** + * Get the number of quotes waiting moderation. + * + * @return int + */ + private function getTotalWaiting() + { + return $this->quoteRepo->nbWaiting(); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } +} diff --git a/app/TeenQuotes/Quotes/Controllers/FavoriteQuoteController.php b/app/TeenQuotes/Quotes/Controllers/FavoriteQuoteController.php index 28ee50fe..d178fb8d 100644 --- a/app/TeenQuotes/Quotes/Controllers/FavoriteQuoteController.php +++ b/app/TeenQuotes/Quotes/Controllers/FavoriteQuoteController.php @@ -1,77 +1,80 @@ -api = App::make('TeenQuotes\Api\V1\Controllers\QuotesFavoriteController'); - $this->favQuoteValidator = App::make('TeenQuotes\Quotes\Validation\FavoriteQuoteValidator'); - } + public function __construct() + { + $this->api = App::make('TeenQuotes\Api\V1\Controllers\QuotesFavoriteController'); + $this->favQuoteValidator = App::make('TeenQuotes\Quotes\Validation\FavoriteQuoteValidator'); + } - /** - * Store a newly created resource in storage. - * - * @return \Response - */ - public function store($quote_id) - { - if (Request::ajax()) - { - // Call the API to store the favorite - $response = $this->api->postFavorite($quote_id); + /** + * Store a newly created resource in storage. + * + * @return \Response + */ + public function store($quote_id) + { + if (Request::ajax()) { + // Call the API to store the favorite + $response = $this->api->postFavorite($quote_id); - return Response::json(['success' => ($response->getStatusCode() == 201)], 200); - } - } + return Response::json(['success' => ($response->getStatusCode() == 201)], 200); + } + } - /** - * Remove the specified resource from storage. - * - * @param int $id - * @return \Response - */ - public function destroy($quote_id) - { - if (Request::ajax()) - { - $user = Auth::user(); - $data = [ - 'quote_id' => $quote_id, - 'user_id' => $user->id, - ]; + /** + * Remove the specified resource from storage. + * + * @param int $id + * + * @return \Response + */ + public function destroy($quote_id) + { + if (Request::ajax()) { + $user = Auth::user(); + $data = [ + 'quote_id' => $quote_id, + 'user_id' => $user->id, + ]; - try { - $this->favQuoteValidator->validateRemove($data); - } - catch (FormValidationException $e) - { - return Response::json([ - 'success' => false, - 'errors' => $e->getErrors() - ]); - } + try { + $this->favQuoteValidator->validateRemove($data); + } catch (FormValidationException $e) { + return Response::json([ + 'success' => false, + 'errors' => $e->getErrors(), + ]); + } - // Call the API to delete the favorite - $response = $this->api->deleteFavorite($quote_id, false); + // Call the API to delete the favorite + $response = $this->api->deleteFavorite($quote_id, false); - if ($response->getStatusCode() == 200) - return Response::json(['success' => true], 200); - } - } -} \ No newline at end of file + if ($response->getStatusCode() == 200) { + return Response::json(['success' => true], 200); + } + } + } +} diff --git a/app/TeenQuotes/Quotes/Controllers/QuotesController.php b/app/TeenQuotes/Quotes/Controllers/QuotesController.php index dd1b9d3a..41b7ad7e 100644 --- a/app/TeenQuotes/Quotes/Controllers/QuotesController.php +++ b/app/TeenQuotes/Quotes/Controllers/QuotesController.php @@ -1,291 +1,305 @@ -beforeFilter('auth', ['on' => 'store']); - $this->api = App::make('TeenQuotes\Api\V1\Controllers\QuotesController'); - $this->quoteRepo = $quoteRepo; - $this->quoteValidator = App::make('TeenQuotes\Quotes\Validation\QuoteValidator'); - } - - /** - * Redirect to the new URL schema - * - * @param int $id ID of the quote - * @return \Response - */ - public function redirectOldUrl($id) - { - return Redirect::route('quotes.show', $id, 301); - } - - public function redirectTop() - { - return Redirect::route('quotes.top.favorites', null, 301); - } - - /** - * Display last quotes - * - * @return \Response - */ - public function index() - { - $response = $this->retrieveLastQuotes(); - - return $this->buildIndexResponse('quotes.index', $response); - } - - /** - * Display random quotes - * - * @return \Response - */ - public function random() - { - $response = $this->retrieveRandomQuotes(); - - return $this->buildIndexResponse('quotes.index', $response); - } - - /** - * Display top favorited quotes - * - * @return \Response - */ - public function topFavorites() - { - $response = $this->retrieveTopFavorites(); - - return $this->buildIndexResponse('quotes.top.favorites', $response); - } - - /** - * Display top commented quotes - * - * @return \Response - */ - public function topComments() - { - $response = $this->retrieveTopComments(); - - return $this->buildIndexResponse('quotes.top.comments', $response); - } - - /** - * Index quotes for a given tag name - * - * @param string $tagName The name of the tag - * @return \Response - */ - public function indexForTag($tagName) - { - $response = $this->retrieveQuotesForTag($tagName); - - return $this->buildIndexResponse('quotes.tags.index', $response); - } - - /** - * Store a new quote in storage - * - * @return \Response - */ - public function store() - { - $user = Auth::user(); - - $data = [ - 'content' => Input::get('content'), - 'quotesSubmittedToday' => $this->quoteRepo->submittedTodayForUser($user), - ]; - - $this->quoteValidator->validatePosting($data); - - // Call the API to store the quote - $response = $this->api->store(false); - if ($response->getStatusCode() == 201) - return Redirect::route('home')->with('success', Lang::get('quotes.quoteAddedSuccessfull', ['login' => $user->login])); - - App::abort(500, "Can't create quote."); - } - - /** - * Display the form to add a quote - * - * @return \Response - */ - public function create() - { - $data = [ - 'pageTitle' => Lang::get('quotes.addquotePageTitle'), - 'pageDescription' => Lang::get('quotes.addquotePageDescription'), - ]; - - return View::make('quotes.addquote', $data); - } - - /** - * Display the specified resource. - * - * @param int $id - * @return \Response - */ - public function show($id) - { - $response = $this->api->show($id); - - $this->guardAgainstNotFound($response); - - $quote = $response->getOriginalData(); - - // If the user was not logged in, we store the current URL in its session - // After sign in / sign up, he will be redirected here - if (Auth::guest()) - Session::put('url.intended', URL::route('quotes.show', $id)); - - $data = [ - 'quote' => $quote, - 'pageTitle' => Lang::get('quotes.singleQuotePageTitle', compact('id')), - 'pageDescription' => $quote->content, - ]; - - // JS variables and colors are set in a view composer - - return View::make('quotes.show', $data); - } - - public function getDataFavoritesInfo() - { - $quote = $this->quoteRepo->getById(Input::get('id')); - $data = $quote->present()->favoritesData; - - $translate = Lang::choice('quotes.favoritesText', $data['nbFavorites'], $data); - - return Response::json(compact('translate'), 200); - } - - private function buildIndexResponse($viewName, $response) - { - $quotes = $response['quotes']; - - $data = [ - 'quotes' => $quotes, - 'pageTitle' => Lang::get('quotes.'.$this->cleanLangKey(Route::currentRouteName().'PageTitle')), - 'pageDescription' => Lang::get('quotes.'.$this->cleanLangKey(Route::currentRouteName().'PageDescription')), - 'paginator' => Paginator::make($quotes->toArray(), $response['total_quotes'], $response['pagesize']), - ]; - - return View::make($viewName, $data); - } - - private function cleanLangKey($key) - { - return lcfirst(str_replace(' ', '', ucwords(str_replace('.', ' ', $key)))); - } - - private function retrieveTopFavorites() - { - try { - $apiResponse = $this->api->getTopFavoritedQuotes(); - } - catch (ApiNotFoundException $e) { - throw new QuoteNotFoundException; - } - - return $apiResponse->getOriginalData(); - } - - private function retrieveTopComments() - { - try { - $apiResponse = $this->api->getTopCommentedQuotes(); - } - catch (ApiNotFoundException $e) { - throw new QuoteNotFoundException; - } - - return $apiResponse->getOriginalData(); - } - - private function retrieveLastQuotes() - { - try { - $apiResponse = $this->api->index(); - } - catch (ApiNotFoundException $e) { - throw new QuoteNotFoundException; - } - - return $apiResponse->getOriginalData(); - } - - private function retrieveRandomQuotes() - { - try { - $apiResponse = $this->api->random(); - } - catch (ApiNotFoundException $e) { - throw new QuoteNotFoundException; - } - - return $apiResponse->getOriginalData(); - } - - private function retrieveQuotesForTag($tagName) - { - try { - $apiResponse = $this->api->getQuotesForTag($tagName); - } - catch (ApiNotFoundException $e) { - switch ($e->getMessage()) - { - case 'quotes': - throw new QuoteNotFoundException; - - case 'tags': - throw new TagNotFoundException; - } - } - - return $apiResponse->getOriginalData(); - } - - /** - * Throw an exception if the given response is a not found response - * - * @param JsonResponse $response the response - * @return void|\TeenQuotes\Exceptions\QuoteNotFoundException - */ - private function guardAgainstNotFound(JsonResponse $response) - { - if ($this->responseIsNotFound($response)) - throw new QuoteNotFoundException; - } -} \ No newline at end of file +use URL; +use View; + +class QuotesController extends BaseController +{ + /** + * The API controller. + * + * @var \TeenQuotes\Api\V1\Controllers\QuotesController + */ + private $api; + + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Quotes\Validation\QuoteValidator + */ + private $quoteValidator; + + public function __construct(QuoteRepository $quoteRepo) + { + $this->beforeFilter('auth', ['on' => 'store']); + $this->api = App::make('TeenQuotes\Api\V1\Controllers\QuotesController'); + $this->quoteRepo = $quoteRepo; + $this->quoteValidator = App::make('TeenQuotes\Quotes\Validation\QuoteValidator'); + } + + /** + * Redirect to the new URL schema. + * + * @param int $id ID of the quote + * + * @return \Response + */ + public function redirectOldUrl($id) + { + return Redirect::route('quotes.show', $id, 301); + } + + public function redirectTop() + { + return Redirect::route('quotes.top.favorites', null, 301); + } + + /** + * Display last quotes. + * + * @return \Response + */ + public function index() + { + $response = $this->retrieveLastQuotes(); + + return $this->buildIndexResponse('quotes.index', $response); + } + + /** + * Display random quotes. + * + * @return \Response + */ + public function random() + { + $response = $this->retrieveRandomQuotes(); + + return $this->buildIndexResponse('quotes.index', $response); + } + + /** + * Display top favorited quotes. + * + * @return \Response + */ + public function topFavorites() + { + $response = $this->retrieveTopFavorites(); + + return $this->buildIndexResponse('quotes.top.favorites', $response); + } + + /** + * Display top commented quotes. + * + * @return \Response + */ + public function topComments() + { + $response = $this->retrieveTopComments(); + + return $this->buildIndexResponse('quotes.top.comments', $response); + } + + /** + * Index quotes for a given tag name. + * + * @param string $tagName The name of the tag + * + * @return \Response + */ + public function indexForTag($tagName) + { + $response = $this->retrieveQuotesForTag($tagName); + + return $this->buildIndexResponse('quotes.tags.index', $response); + } + + /** + * Store a new quote in storage. + * + * @return \Response + */ + public function store() + { + $user = Auth::user(); + + $data = [ + 'content' => Input::get('content'), + 'quotesSubmittedToday' => $this->quoteRepo->submittedTodayForUser($user), + ]; + + $this->quoteValidator->validatePosting($data); + + // Call the API to store the quote + $response = $this->api->store(false); + if ($response->getStatusCode() == 201) { + return Redirect::route('home')->with('success', Lang::get('quotes.quoteAddedSuccessfull', ['login' => $user->login])); + } + + App::abort(500, "Can't create quote."); + } + + /** + * Display the form to add a quote. + * + * @return \Response + */ + public function create() + { + $data = [ + 'pageTitle' => Lang::get('quotes.addquotePageTitle'), + 'pageDescription' => Lang::get('quotes.addquotePageDescription'), + ]; + + return View::make('quotes.addquote', $data); + } + + /** + * Display the specified resource. + * + * @param int $id + * + * @return \Response + */ + public function show($id) + { + $response = $this->api->show($id); + + $this->guardAgainstNotFound($response); + + $quote = $response->getOriginalData(); + + // If the user was not logged in, we store the current URL in its session + // After sign in / sign up, he will be redirected here + if (Auth::guest()) { + Session::put('url.intended', URL::route('quotes.show', $id)); + } + + $data = [ + 'quote' => $quote, + 'pageTitle' => Lang::get('quotes.singleQuotePageTitle', compact('id')), + 'pageDescription' => $quote->content, + ]; + + // JS variables and colors are set in a view composer + + return View::make('quotes.show', $data); + } + + public function getDataFavoritesInfo() + { + $quote = $this->quoteRepo->getById(Input::get('id')); + $data = $quote->present()->favoritesData; + + $translate = Lang::choice('quotes.favoritesText', $data['nbFavorites'], $data); + + return Response::json(compact('translate'), 200); + } + + private function buildIndexResponse($viewName, $response) + { + $quotes = $response['quotes']; + + $data = [ + 'quotes' => $quotes, + 'pageTitle' => Lang::get('quotes.'.$this->cleanLangKey(Route::currentRouteName().'PageTitle')), + 'pageDescription' => Lang::get('quotes.'.$this->cleanLangKey(Route::currentRouteName().'PageDescription')), + 'paginator' => Paginator::make($quotes->toArray(), $response['total_quotes'], $response['pagesize']), + ]; + + return View::make($viewName, $data); + } + + private function cleanLangKey($key) + { + return lcfirst(str_replace(' ', '', ucwords(str_replace('.', ' ', $key)))); + } + + private function retrieveTopFavorites() + { + try { + $apiResponse = $this->api->getTopFavoritedQuotes(); + } catch (ApiNotFoundException $e) { + throw new QuoteNotFoundException(); + } + + return $apiResponse->getOriginalData(); + } + + private function retrieveTopComments() + { + try { + $apiResponse = $this->api->getTopCommentedQuotes(); + } catch (ApiNotFoundException $e) { + throw new QuoteNotFoundException(); + } + + return $apiResponse->getOriginalData(); + } + + private function retrieveLastQuotes() + { + try { + $apiResponse = $this->api->index(); + } catch (ApiNotFoundException $e) { + throw new QuoteNotFoundException(); + } + + return $apiResponse->getOriginalData(); + } + + private function retrieveRandomQuotes() + { + try { + $apiResponse = $this->api->random(); + } catch (ApiNotFoundException $e) { + throw new QuoteNotFoundException(); + } + + return $apiResponse->getOriginalData(); + } + + private function retrieveQuotesForTag($tagName) + { + try { + $apiResponse = $this->api->getQuotesForTag($tagName); + } catch (ApiNotFoundException $e) { + switch ($e->getMessage()) { + case 'quotes': + throw new QuoteNotFoundException(); + + case 'tags': + throw new TagNotFoundException(); + } + } + + return $apiResponse->getOriginalData(); + } + + /** + * Throw an exception if the given response is a not found response. + * + * @param JsonResponse $response the response + * + * @return void|\TeenQuotes\Exceptions\QuoteNotFoundException + */ + private function guardAgainstNotFound(JsonResponse $response) + { + if ($this->responseIsNotFound($response)) { + throw new QuoteNotFoundException(); + } + } +} diff --git a/app/TeenQuotes/Quotes/Controllers/SearchController.php b/app/TeenQuotes/Quotes/Controllers/SearchController.php index 57f97b7c..a286cffe 100644 --- a/app/TeenQuotes/Quotes/Controllers/SearchController.php +++ b/app/TeenQuotes/Quotes/Controllers/SearchController.php @@ -1,190 +1,218 @@ -beforeFilter('search.isValid', ['only' => ['getResults', 'dispatcher']]); - - $this->countryRepo = $countryRepo; - $this->quoteRepo = $quoteRepo; - $this->userRepo = $userRepo; - } - - /** - * Dispatch the search form to search results - * @return \Response - */ - public function dispatcher() - { - // filter search.isValid before - return Redirect::route('search.results', Input::get('search')); - } - - /** - * Show the search form - * @return \Response - */ - public function showForm() - { - $data = [ - 'pageTitle' => Lang::get('search.formPageTitle'), - 'pageDescription' => Lang::get('search.formPageDescription'), - ]; - - return View::make('search.form', $data); - } - - /** - * Show results after a search - * @var string $query The search query - * @return \Response - */ - public function getResults($query) - { - $nbResultsPerCategory = $this->nbOfResultsPerCategory(); - - // Search quotes - $nbQuotes = $this->quoteRepo->searchCountPublishedWithQuery($query); - $quotes = $this->quoteRepo->searchPublishedWithQuery($query, 1, $nbResultsPerCategory); - - // Search users - $nbUsers = 0; - $users = null; - if ($this->shouldSearchForUsers($query)) - { - $nbUsers = $this->userRepo->countByPartialLogin($query); - $users = $this->userRepo->searchByPartialLogin($query, 1, $nbResultsPerCategory); - } - - // Handle no results - if ($this->resultsAreEmpty($quotes, $users)) - return Redirect::route('search.form')->with('warning', Lang::get('search.noResultsAtAll')); - - $data = compact('quotes', 'users', 'nbQuotes', 'nbUsers', 'query'); - $data['maxNbResultPerCategory'] = Config::get('app.search.maxResultsPerCategory'); - $data['pageTitle'] = Lang::get('search.resultsPageTitle', compact('query')); - $data['pageDescription'] = Lang::get('search.resultsPageDescription', compact('query')); - - return View::make('search.results', $data); - } - - /** - * Search users coming from a given country - * @param int $country_id The ID of the country - * @throws \TeenQuotes\Exceptions\CountryNotFoundException If the country was not found - * @throws \TeenQuotes\Exceptions\UserNotFoundException If no users were found - * @return \Response - */ - public function usersFromCountry($country_id) - { - $country = $this->countryRepo->findById($country_id); - - // Handle country not found - if (is_null($country)) - throw new CountryNotFoundException; - - $page = Input::get('page', 1); - $pagesize = $this->nbOfResultsPerCategory(); - - $users = $this->userRepo->fromCountry($country, $page, $pagesize); - if ($users->isEmpty() AND $this->countryIsMostCommon($country_id)) - throw new UserNotFoundException; - elseif ($users->isEmpty()) - return $this->redirectToDefaultCountrySearch(); - - $totalResults = $this->userRepo->countFromCountry($country); - - $paginator = Paginator::make($users->toArray(), $totalResults, $pagesize); - $data = compact('users', 'paginator', 'country'); - - return View::make('search.users', $data); - } - - /** - * Redirect to results from the most common country with a warning - * @return \Response - */ - private function redirectToDefaultCountrySearch() - { - return Redirect::route('search.users.country', Country::getDefaultCountry(), 302) - ->with('redirectedToMostCommonCountry', true); - } - - /** - * Get the most common country ID for our users - * @return int - */ - private function getMostCommonCountryID() - { - return Country::getDefaultCountry(); - } - - /** - * Tell if the given ID is the most common country - * @param int $countryID - * @return boolean - */ - private function countryIsMostCommon($countryID) - { - return $countryID === $this->getMostCommonCountryID(); - } - - /** - * Return the number of results per category - * @return int - */ - private function nbOfResultsPerCategory() - { - return Config::get('app.search.maxResultsPerCategory'); - } - - /** - * Tell if search results are empty - * @param \Illuminate\Database\Eloquent\Collection $quotes - * @param null|\Illuminate\Database\Eloquent\Collection $users - * @return boolean - */ - private function resultsAreEmpty($quotes, $users) - { - return $quotes->isEmpty() AND (is_null($users) OR $users->isEmpty()); - } - - /** - * Determine if we should search for users from a search query - * @param string $query - * @return boolean - */ - private function shouldSearchForUsers($query) - { - return $this->stringIsSingleWord($query); - } - - /** - * Tell if a string is only a single word - * @param string $string - * @return boolean - */ - private function stringIsSingleWord($string) - { - return (str_word_count($string) == 1); - } -} \ No newline at end of file +use View; + +class SearchController extends BaseController +{ + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + public function __construct(CountryRepository $countryRepo, QuoteRepository $quoteRepo, UserRepository $userRepo) + { + $this->beforeFilter('search.isValid', ['only' => ['getResults', 'dispatcher']]); + + $this->countryRepo = $countryRepo; + $this->quoteRepo = $quoteRepo; + $this->userRepo = $userRepo; + } + + /** + * Dispatch the search form to search results. + * + * @return \Response + */ + public function dispatcher() + { + // filter search.isValid before + return Redirect::route('search.results', Input::get('search')); + } + + /** + * Show the search form. + * + * @return \Response + */ + public function showForm() + { + $data = [ + 'pageTitle' => Lang::get('search.formPageTitle'), + 'pageDescription' => Lang::get('search.formPageDescription'), + ]; + + return View::make('search.form', $data); + } + + /** + * Show results after a search. + * + * @var string The search query + * + * @return \Response + */ + public function getResults($query) + { + $nbResultsPerCategory = $this->nbOfResultsPerCategory(); + + // Search quotes + $nbQuotes = $this->quoteRepo->searchCountPublishedWithQuery($query); + $quotes = $this->quoteRepo->searchPublishedWithQuery($query, 1, $nbResultsPerCategory); + + // Search users + $nbUsers = 0; + $users = null; + if ($this->shouldSearchForUsers($query)) { + $nbUsers = $this->userRepo->countByPartialLogin($query); + $users = $this->userRepo->searchByPartialLogin($query, 1, $nbResultsPerCategory); + } + + // Handle no results + if ($this->resultsAreEmpty($quotes, $users)) { + return Redirect::route('search.form')->with('warning', Lang::get('search.noResultsAtAll')); + } + + $data = compact('quotes', 'users', 'nbQuotes', 'nbUsers', 'query'); + $data['maxNbResultPerCategory'] = Config::get('app.search.maxResultsPerCategory'); + $data['pageTitle'] = Lang::get('search.resultsPageTitle', compact('query')); + $data['pageDescription'] = Lang::get('search.resultsPageDescription', compact('query')); + + return View::make('search.results', $data); + } + + /** + * Search users coming from a given country. + * + * @param int $country_id The ID of the country + * + * @throws \TeenQuotes\Exceptions\CountryNotFoundException If the country was not found + * @throws \TeenQuotes\Exceptions\UserNotFoundException If no users were found + * + * @return \Response + */ + public function usersFromCountry($country_id) + { + $country = $this->countryRepo->findById($country_id); + + // Handle country not found + if (is_null($country)) { + throw new CountryNotFoundException(); + } + + $page = Input::get('page', 1); + $pagesize = $this->nbOfResultsPerCategory(); + + $users = $this->userRepo->fromCountry($country, $page, $pagesize); + if ($users->isEmpty() and $this->countryIsMostCommon($country_id)) { + throw new UserNotFoundException(); + } elseif ($users->isEmpty()) { + return $this->redirectToDefaultCountrySearch(); + } + + $totalResults = $this->userRepo->countFromCountry($country); + + $paginator = Paginator::make($users->toArray(), $totalResults, $pagesize); + $data = compact('users', 'paginator', 'country'); + + return View::make('search.users', $data); + } + + /** + * Redirect to results from the most common country with a warning. + * + * @return \Response + */ + private function redirectToDefaultCountrySearch() + { + return Redirect::route('search.users.country', Country::getDefaultCountry(), 302) + ->with('redirectedToMostCommonCountry', true); + } + + /** + * Get the most common country ID for our users. + * + * @return int + */ + private function getMostCommonCountryID() + { + return Country::getDefaultCountry(); + } + + /** + * Tell if the given ID is the most common country. + * + * @param int $countryID + * + * @return bool + */ + private function countryIsMostCommon($countryID) + { + return $countryID === $this->getMostCommonCountryID(); + } + + /** + * Return the number of results per category. + * + * @return int + */ + private function nbOfResultsPerCategory() + { + return Config::get('app.search.maxResultsPerCategory'); + } + + /** + * Tell if search results are empty. + * + * @param \Illuminate\Database\Eloquent\Collection $quotes + * @param null|\Illuminate\Database\Eloquent\Collection $users + * + * @return bool + */ + private function resultsAreEmpty($quotes, $users) + { + return $quotes->isEmpty() and (is_null($users) or $users->isEmpty()); + } + + /** + * Determine if we should search for users from a search query. + * + * @param string $query + * + * @return bool + */ + private function shouldSearchForUsers($query) + { + return $this->stringIsSingleWord($query); + } + + /** + * Tell if a string is only a single word. + * + * @param string $string + * + * @return bool + */ + private function stringIsSingleWord($string) + { + return (str_word_count($string) == 1); + } +} diff --git a/app/TeenQuotes/Quotes/Models/FavoriteQuote.php b/app/TeenQuotes/Quotes/Models/FavoriteQuote.php index 5472e96c..453e0d6b 100644 --- a/app/TeenQuotes/Quotes/Models/FavoriteQuote.php +++ b/app/TeenQuotes/Quotes/Models/FavoriteQuote.php @@ -1,14 +1,16 @@ -favQuoteRepo = App::make('TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository'); - $this->commentRepo = App::make('TeenQuotes\Comments\Repositories\CommentRepository'); - $this->tagsRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); - } - - /** - * Store colors that will be use to display quotes in an associative array: quote_id => css_class_name. This array is stored in session to be used when displaying a single quote. - * @param array $quotesIDs IDs of the quotes - * @param string $colors If we want to use different colors, give a string here. Example: orange|blue|red.. - * @return array The associative array: quote_id => color - */ - public static function storeQuotesColors($quotesIDs, $color = null) - { - $colors = []; - - // We will build an array if we have at least one quote - if (count($quotesIDs) >= 1) { - $func = function($value) use ($color) { - if (is_null($color)) - return 'color-'.$value; - else - return 'color-'.$color.'-'.$value; - }; - - $colors = array_map($func, range(1, count($quotesIDs))); - $colors = array_combine($quotesIDs, $colors); - } - - // Store it in session - Session::set('colors.quote', $colors); - - return $colors; - } - - /** - * Get the total number of comments - * - * @return int - */ - public function getTotalCommentsAttribute() - { - // If the quote is not published, obviously we have no comments - if ( ! $this->isPublished()) - return 0; - - return $this->commentRepo->nbCommentsForQuote($this); - } - - /** - * Tell if the quote has comment - * - * @return boolean - */ - public function getHasFavoritesAttribute() - { - return ($this->total_favorites > 0); - } - - /** - * Get the total number of favorites - * - * @return integer - */ - public function getTotalFavoritesAttribute() - { - // If the quote is not published, obviously we have no favorites - if ( ! $this->isPublished()) - return 0; - - return $this->favQuoteRepo->nbFavoritesForQuote($this->id); - } - - /** - * Tell if the quote has comments - * - * @return boolean - */ - public function getHasCommentsAttribute() - { - return ($this->total_comments > 0); - } - - /** - * Tell if the quote is favorited for the current logged-in user - * - * @return boolean - */ - public function getIsFavoriteAttribute() - { - return $this->isFavoriteForCurrentUser(); - } - - /** - * Get the list of tags for the quote - * - * @return array - */ - public function getTagsListAttribute() - { - return $this->tagsRepo->tagsForQuote($this); - } - - public static function getRandomColors() - { - $colors = self::$colors; - - shuffle($colors); - - return $colors; - } - - public function isFavoriteForCurrentUser() - { - $idUserApi = ResourceServer::getOwnerId(); - - if (Auth::check() OR ! empty($idUserApi)) - { - $id = Auth::check() ? Auth::id() : $idUserApi; - - return $this->favQuoteRepo->isFavoriteForUserAndQuote($id, $this->id); - } - - return false; - } - - public function isPublished() - { - return ($this->approved == self::PUBLISHED); - } - - public function isPending() - { - return ($this->approved == self::PENDING); - } - - public function isWaiting() - { - return ($this->approved == self::WAITING); - } - - public function isRefused() - { - return ($this->approved == self::REFUSED); - } - - /** - * Register a view action in the Easyrec recommendation engine - */ - public function registerViewAction() - { - if ( ! in_array(App::environment(), ['testing', 'codeception'])) { - // Try to retrieve the ID of the user - if (Auth::guest()) { - $idUserApi = ResourceServer::getOwnerId(); - $userRecommendation = ! empty($idUserApi) ? $idUserApi : null; - } - else - $userRecommendation = Auth::id(); - - // Register in the recommendation system - $data = [ - 'quote_id' => $this->id, - 'user_id' => $userRecommendation, - ]; - - Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@viewQuote', $data); - } - } - - /** - * Lighten or darken a color from an hexadecimal code - * @author http://stackoverflow.com/questions/3512311/how-to-generate-lighter-darker-color-with-php - * @param string $hex The color in hexadecimal - * @param int $steps Steps should be between -255 and 255. Negative = darker, positive = lighter - * @return string The computed hexadecimal color - */ - public static function adjustBrightness($hex, $steps) - { - $steps = max(-255, min(255, $steps)); - - // Format the hex color string - $hex = str_replace('#', '', $hex); - if (strlen($hex) == 3) - $hex = str_repeat(substr($hex, 0, 1), 2).str_repeat(substr($hex, 1, 1), 2).str_repeat(substr($hex, 2, 1), 2); - - // Get decimal values - $r = hexdec(substr($hex, 0, 2)); - $g = hexdec(substr($hex, 2, 2)); - $b = hexdec(substr($hex, 4, 2)); - - // Adjust number of steps and keep it inside 0 to 255 - $r = max(0, min(255, $r + $steps)); - $g = max(0, min(255, $g + $steps)); - $b = max(0, min(255, $b + $steps)); - - $r_hex = str_pad(dechex($r), 2, '0', STR_PAD_LEFT); - $g_hex = str_pad(dechex($g), 2, '0', STR_PAD_LEFT); - $b_hex = str_pad(dechex($b), 2, '0', STR_PAD_LEFT); - - return '#'.$r_hex.$g_hex.$b_hex; - } +use Toloquent; + +class Quote extends Toloquent +{ + use PresentableTrait, QuoteRelationsTrait, QuoteScopesTrait; + + protected $presenter = 'TeenQuotes\Quotes\Presenters\QuotePresenter'; + + /** + * Constants associated with the approved field of the quote. + */ + const REFUSED = -1; + const WAITING = 0; + const PUBLISHED = 1; + const PENDING = 2; + + protected $fillable = []; + + protected $hidden = ['updated_at']; + + /** + * Adding customs attributes to the object. + * + * @var array + */ + protected $appends = ['tags_list', 'has_comments', 'total_comments', 'is_favorite', 'total_favorites']; + + /** + * The colors that will be used for quotes on the admin page. + * + * @var array + */ + public static $colors = [ + '#27ae60', '#16a085', '#d35400', '#e74c3c', '#8e44ad', '#F9690E', '#2c3e50', '#f1c40f', '#65C6BB', '#E08283', + ]; + + /** + * @var \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + private $favQuoteRepo; + + /** + * @var \TeenQuotes\Comments\Repositories\CommentRepository + */ + private $commentRepo; + + /** + * @var \TeenQuotes\Tags\Repositories\TagRepository + */ + private $tagsRepo; + + public function __construct($attributes = []) + { + parent::__construct($attributes); + + $this->favQuoteRepo = App::make('TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository'); + $this->commentRepo = App::make('TeenQuotes\Comments\Repositories\CommentRepository'); + $this->tagsRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); + } + + /** + * Store colors that will be use to display quotes in an associative array: quote_id => css_class_name. This array is stored in session to be used when displaying a single quote. + * + * @param array $quotesIDs IDs of the quotes + * @param string $colors If we want to use different colors, give a string here. Example: orange|blue|red.. + * + * @return array The associative array: quote_id => color + */ + public static function storeQuotesColors($quotesIDs, $color = null) + { + $colors = []; + + // We will build an array if we have at least one quote + if (count($quotesIDs) >= 1) { + $func = function ($value) use ($color) { + if (is_null($color)) { + return 'color-'.$value; + } else { + return 'color-'.$color.'-'.$value; + } + }; + + $colors = array_map($func, range(1, count($quotesIDs))); + $colors = array_combine($quotesIDs, $colors); + } + + // Store it in session + Session::set('colors.quote', $colors); + + return $colors; + } + + /** + * Get the total number of comments. + * + * @return int + */ + public function getTotalCommentsAttribute() + { + // If the quote is not published, obviously we have no comments + if (!$this->isPublished()) { + return 0; + } + + return $this->commentRepo->nbCommentsForQuote($this); + } + + /** + * Tell if the quote has comment. + * + * @return bool + */ + public function getHasFavoritesAttribute() + { + return ($this->total_favorites > 0); + } + + /** + * Get the total number of favorites. + * + * @return int + */ + public function getTotalFavoritesAttribute() + { + // If the quote is not published, obviously we have no favorites + if (!$this->isPublished()) { + return 0; + } + + return $this->favQuoteRepo->nbFavoritesForQuote($this->id); + } + + /** + * Tell if the quote has comments. + * + * @return bool + */ + public function getHasCommentsAttribute() + { + return ($this->total_comments > 0); + } + + /** + * Tell if the quote is favorited for the current logged-in user. + * + * @return bool + */ + public function getIsFavoriteAttribute() + { + return $this->isFavoriteForCurrentUser(); + } + + /** + * Get the list of tags for the quote. + * + * @return array + */ + public function getTagsListAttribute() + { + return $this->tagsRepo->tagsForQuote($this); + } + + public function isFavoriteForCurrentUser() + { + $idUserApi = ResourceServer::getOwnerId(); + + if (Auth::check() or !empty($idUserApi)) { + $id = Auth::check() ? Auth::id() : $idUserApi; + + return $this->favQuoteRepo->isFavoriteForUserAndQuote($id, $this->id); + } + + return false; + } + + public function isPublished() + { + return ($this->approved == self::PUBLISHED); + } + + public function isPending() + { + return ($this->approved == self::PENDING); + } + + public function isWaiting() + { + return ($this->approved == self::WAITING); + } + + public function isRefused() + { + return ($this->approved == self::REFUSED); + } + + /** + * Register a view action in the Easyrec recommendation engine. + */ + public function registerViewAction() + { + if (!in_array(App::environment(), ['testing', 'codeception'])) { + // Try to retrieve the ID of the user + if (Auth::guest()) { + $idUserApi = ResourceServer::getOwnerId(); + $userRecommendation = !empty($idUserApi) ? $idUserApi : null; + } else { + $userRecommendation = Auth::id(); + } + + // Register in the recommendation system + $data = [ + 'quote_id' => $this->id, + 'user_id' => $userRecommendation, + ]; + + Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@viewQuote', $data); + } + } } diff --git a/app/TeenQuotes/Quotes/Models/Relations/FavoriteQuoteTrait.php b/app/TeenQuotes/Quotes/Models/Relations/FavoriteQuoteTrait.php index 2c293a25..2f340fa0 100644 --- a/app/TeenQuotes/Quotes/Models/Relations/FavoriteQuoteTrait.php +++ b/app/TeenQuotes/Quotes/Models/Relations/FavoriteQuoteTrait.php @@ -1,17 +1,19 @@ -belongsTo(User::class); - } +trait FavoriteQuoteTrait +{ + public function user() + { + return $this->belongsTo(User::class); + } - public function quote() - { - return $this->belongsTo(Quote::class); - } -} \ No newline at end of file + public function quote() + { + return $this->belongsTo(Quote::class); + } +} diff --git a/app/TeenQuotes/Quotes/Models/Relations/QuoteTrait.php b/app/TeenQuotes/Quotes/Models/Relations/QuoteTrait.php index fbcb4d2f..8ab677c0 100644 --- a/app/TeenQuotes/Quotes/Models/Relations/QuoteTrait.php +++ b/app/TeenQuotes/Quotes/Models/Relations/QuoteTrait.php @@ -1,29 +1,31 @@ -belongsTo(User::class, 'user_id', 'id'); - } +trait QuoteTrait +{ + public function user() + { + return $this->belongsTo(User::class, 'user_id', 'id'); + } - public function comments() - { - return $this->hasMany(Comment::class); - } + public function comments() + { + return $this->hasMany(Comment::class); + } - public function favorites() - { - return $this->hasMany(FavoriteQuote::class)->orderBy('id', 'DESC'); - } + public function favorites() + { + return $this->hasMany(FavoriteQuote::class)->orderBy('id', 'DESC'); + } - public function tags() - { - return $this->belongsToMany(Tag::class, 'quote_tag', 'quote_id', 'tag_id'); - } -} \ No newline at end of file + public function tags() + { + return $this->belongsToMany(Tag::class, 'quote_tag', 'quote_id', 'tag_id'); + } +} diff --git a/app/TeenQuotes/Quotes/Models/Scopes/FavoriteQuoteTrait.php b/app/TeenQuotes/Quotes/Models/Scopes/FavoriteQuoteTrait.php index 660b4097..4224ce58 100644 --- a/app/TeenQuotes/Quotes/Models/Scopes/FavoriteQuoteTrait.php +++ b/app/TeenQuotes/Quotes/Models/Scopes/FavoriteQuoteTrait.php @@ -1,37 +1,46 @@ -where('user_id', '=', Auth::id()); - } + return $query->where('user_id', '=', Auth::id()); + } - /** - * Get FavoriteQuote for a given user - * @param Illuminate\Database\Query\Builder $query - * @param mixed $user int|User User's ID or User object - * @return \Illuminate\Database\Query\Builder - */ - public function scopeForUser($query, $user) - { - if (is_numeric($user)) - { - $user_id = (int) $user; - return $query->where('user_id', '=', $user_id); - } + /** + * Get FavoriteQuote for a given user. + * + * @param Illuminate\Database\Query\Builder $query + * @param mixed $user int|User User's ID or User object + * + * @return \Illuminate\Database\Query\Builder + */ + public function scopeForUser($query, $user) + { + if (is_numeric($user)) { + $user_id = (int) $user; - return $query->where('user_id', '=', $user->id); - } -} \ No newline at end of file + return $query->where('user_id', '=', $user_id); + } + + return $query->where('user_id', '=', $user->id); + } +} diff --git a/app/TeenQuotes/Quotes/Models/Scopes/QuoteTrait.php b/app/TeenQuotes/Quotes/Models/Scopes/QuoteTrait.php index a98b25fb..3288b57b 100644 --- a/app/TeenQuotes/Quotes/Models/Scopes/QuoteTrait.php +++ b/app/TeenQuotes/Quotes/Models/Scopes/QuoteTrait.php @@ -1,136 +1,153 @@ -whereBetween('created_at', [Carbon::today(), Carbon::today()->addDay()]); - } +trait QuoteTrait +{ + /** + * Get quotes created today. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeCreatedToday($query) + { + return $query->whereBetween('created_at', [Carbon::today(), Carbon::today()->addDay()]); + } - /** - * Get quotes updated today - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeUpdatedToday($query) - { - return $query->whereBetween('updated_at', [Carbon::today(), Carbon::today()->addDay()]); - } + /** + * Get quotes updated today. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeUpdatedToday($query) + { + return $query->whereBetween('updated_at', [Carbon::today(), Carbon::today()->addDay()]); + } - /** - * Get quotes waiting to be published - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeWaiting($query) - { - return $query->where('approved', '=', self::WAITING); - } + /** + * Get quotes waiting to be published. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeWaiting($query) + { + return $query->where('approved', '=', self::WAITING); + } - /** - * Get quotes that have been refused - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeRefused($query) - { - return $query->where('approved', '=', self::REFUSED); - } + /** + * Get quotes that have been refused. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeRefused($query) + { + return $query->where('approved', '=', self::REFUSED); + } - /** - * Get quotes that are pending moderation - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopePending($query) - { - return $query->where('approved', '=', self::PENDING); - } + /** + * Get quotes that are pending moderation. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopePending($query) + { + return $query->where('approved', '=', self::PENDING); + } - /** - * Get published quotes - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopePublished($query) - { - return $query->where('approved', '=', self::PUBLISHED); - } + /** + * Get published quotes. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopePublished($query) + { + return $query->where('approved', '=', self::PUBLISHED); + } - /** - * Get quotes added by a given user - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \TeenQuotes\Users\Models\User $user - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeForUser($query, User $user) - { - return $query->where('user_id', '=', $user->id); - } + /** + * Get quotes added by a given user. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \TeenQuotes\Users\Models\User $user + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeForUser($query, User $user) + { + return $query->where('user_id', '=', $user->id); + } - /** - * Order quotes by descending order - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeOrderDescending($query) - { - return $query->orderBy('created_at', 'DESC'); - } + /** + * Order quotes by descending order. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeOrderDescending($query) + { + return $query->orderBy('created_at', 'DESC'); + } - /** - * Order quotes by ascending order - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeOrderAscending($query) - { - return $query->orderBy('created_at', 'ASC'); - } + /** + * Order quotes by ascending order. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeOrderAscending($query) + { + return $query->orderBy('created_at', 'ASC'); + } - /** - * Get random quotes - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeRandom($query) - { - if (Config::get('database.default') != 'mysql') - return $query; + /** + * Get random quotes. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeRandom($query) + { + if (Config::get('database.default') != 'mysql') { + return $query; + } - // Here we use a constant in the MySQL RAND function - // so that quotes will be always be in the same "order" - // even if they are not ordered - // ref: http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand - return $query->orderBy(DB::raw('RAND(42)')); - } + // Here we use a constant in the MySQL RAND function + // so that quotes will be always be in the same "order" + // even if they are not ordered + // ref: http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand + return $query->orderBy(DB::raw('RAND(42)')); + } - /** - * Get quotes that have been created after a given date - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Carbon\Carbon $date - * @return \Illuminate\Database\Eloquent\Builder - */ - public function scopeCreatedAfter($query, Carbon $date) - { - return $query->where('created_at', '>=', $date); - } -} \ No newline at end of file + /** + * Get quotes that have been created after a given date. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Carbon\Carbon $date + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeCreatedAfter($query, Carbon $date) + { + return $query->where('created_at', '>=', $date); + } +} diff --git a/app/TeenQuotes/Quotes/Presenters/QuotePresenter.php b/app/TeenQuotes/Quotes/Presenters/QuotePresenter.php index 2dd8d293..85fc18c3 100644 --- a/app/TeenQuotes/Quotes/Presenters/QuotePresenter.php +++ b/app/TeenQuotes/Quotes/Presenters/QuotePresenter.php @@ -1,93 +1,100 @@ -content; - $maxLength = 115; - $twitterUsername = Lang::get('layout.twitterUsername'); - $maxLengthAddTwitterUsername = $maxLength - strlen($twitterUsername); - - if (strlen($content) > $maxLength) - { - $content = substr($content, 0, $maxLength); - $lastSpace = strrpos($content, " "); - - // After the space, add … - $content = substr($content, 0, $lastSpace).'…'; - } - elseif (strlen($content) <= $maxLengthAddTwitterUsername) - $content .= ' '.$twitterUsername; - - return urlencode($content.' '.URL::route('quotes.show', array($this->id), true)); - } - - /** - * Return the text for the Twitter Card. Displayed on single quote page. - * @return The text for the Twitter Card - */ - public function textTwitterCard() - { - $content = $this->content; - $maxLength = 197; - - if (strlen($content) > $maxLength) - { - $content = substr($content, 0, $maxLength); - $lastSpace = strrpos($content, " "); - - // After the space, add … - $content = substr($content, 0, $lastSpace).'…'; - } - - return $content; - } - - /** - * Returns information about people who favorited a quote - * @return array Keys: name{0,1,2}, nbFavorites, nbRemaining - */ - public function favoritesData() - { - $nbFavorites = count($this->favorites); - $data = compact('nbFavorites'); - - // We have got too much people who favorited this quote - if ($nbFavorites > 3) - $data['nbRemaining'] = $nbFavorites - 3; - - // Collect a maximum of 3 users - $i = 0; - $favorites = $this->favorites; - - while ($i < 3 AND ! $favorites->isEmpty()) - { - $fav = $favorites->shift(); - $data['name'.$i] = $this->linkForUser($fav->user); - $i++; - } - - return $data; - } - - /** - * Returns a link to a user's profile or just its login if its profile is hidden - * @param \TeenQuotes\Users\Models\User $user The User object - * @return string - */ - public function linkForUser($user) - { - if ($user->isHiddenProfile()) - return $user->login; - - return "login)."'>".$user->login.""; - } -} \ No newline at end of file +use Lang; +use Laracasts\Presenter\Presenter; +use URL; + +class QuotePresenter extends Presenter +{ + /** + * The text that will be tweeted. Given to the Twitter sharer. + * + * @return The text for the Twitter sharer + */ + public function textTweet() + { + $content = $this->content; + $maxLength = 115; + $twitterUsername = Lang::get('layout.twitterUsername'); + $maxLengthAddTwitterUsername = $maxLength - strlen($twitterUsername); + + if (strlen($content) > $maxLength) { + $content = substr($content, 0, $maxLength); + $lastSpace = strrpos($content, ' '); + + // After the space, add … + $content = substr($content, 0, $lastSpace).'…'; + } elseif (strlen($content) <= $maxLengthAddTwitterUsername) { + $content .= ' '.$twitterUsername; + } + + return urlencode($content.' '.URL::route('quotes.show', [$this->id], true)); + } + + /** + * Return the text for the Twitter Card. Displayed on single quote page. + * + * @return The text for the Twitter Card + */ + public function textTwitterCard() + { + $content = $this->content; + $maxLength = 197; + + if (strlen($content) > $maxLength) { + $content = substr($content, 0, $maxLength); + $lastSpace = strrpos($content, ' '); + + // After the space, add … + $content = substr($content, 0, $lastSpace).'…'; + } + + return $content; + } + + /** + * Returns information about people who favorited a quote. + * + * @return array Keys: name{0,1,2}, nbFavorites, nbRemaining + */ + public function favoritesData() + { + $nbFavorites = count($this->favorites); + $data = compact('nbFavorites'); + + // We have got too much people who favorited this quote + if ($nbFavorites > 3) { + $data['nbRemaining'] = $nbFavorites - 3; + } + + // Collect a maximum of 3 users + $i = 0; + $favorites = $this->favorites; + + while ($i < 3 and !$favorites->isEmpty()) { + $fav = $favorites->shift(); + $data['name'.$i] = $this->linkForUser($fav->user); + $i++; + } + + return $data; + } + + /** + * Returns a link to a user's profile or just its login if its profile is hidden. + * + * @param \TeenQuotes\Users\Models\User $user The User object + * + * @return string + */ + public function linkForUser($user) + { + if ($user->isHiddenProfile()) { + return $user->login; + } + + return "login)."'>".$user->login.''; + } +} diff --git a/app/TeenQuotes/Quotes/QuotesServiceProvider.php b/app/TeenQuotes/Quotes/QuotesServiceProvider.php index 5968c806..b9396b83 100644 --- a/app/TeenQuotes/Quotes/QuotesServiceProvider.php +++ b/app/TeenQuotes/Quotes/QuotesServiceProvider.php @@ -1,4 +1,6 @@ -registerFavoriteQuoteRoutes(); - $this->registerFavoriteQuoteBindings(); - - // Quotes - $this->registerQuoteRoutes(); - $this->registerQuotesComposers(); - $this->registerQuotesBindings(); - $this->registerQuotesCommands(); - - // Search - $this->registerSearchRoutes(); - $this->registerSearchComposers(); - } - - private function registerQuotesCommands() - { - $commands = [ - 'quotesPublish' => 'QuotesPublishCommand', - 'quotesWaiting' => 'WaitingQuotesCommand', - ]; - - foreach ($commands as $key => $class) - { - $commandName = $this->getBaseNamespace().'Console\\'.$class; - - $this->app->bindShared('quotes.console.'.$key, function($app) use($commandName) - { - return $app->make($commandName); - }); - - $this->commands('quotes.console.'.$key); - } - } - - private function registerFavoriteQuoteBindings() - { - $this->app->bind(FavoriteQuoteRepository::class, function() - { - $eloquentRepo = new DbFavoriteQuoteRepository; - - return new CachingFavoriteQuoteRepository($eloquentRepo); - }); - } - - private function registerQuotesBindings() - { - $this->app->bind(QuoteRepository::class, function() - { - $eloquentRepo = new DbQuoteRepository; - - return new CachingQuoteRepository($eloquentRepo); - }); - } - - private function registerFavoriteQuoteRoutes() - { - $controller = 'FavoriteQuoteController'; - - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) { - $this->app['router']->post('favorite/{quote_id}', ['as' => 'favorite', 'before' => 'auth', 'uses' => $controller.'@store']); - $this->app['router']->post('unfavorite/{quote_id}', ['as' => 'unfavorite', 'before' => 'auth', 'uses' => $controller.'@destroy']); - }); - } - - private function registerQuoteRoutes() - { - $controller = 'QuotesController'; - - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) { - $this->app['router']->get('/', ['as' => 'home', 'uses' => $controller.'@index']); - $this->app['router']->get('tags/{tag_name}', ['as' => 'quotes.tags.index', 'uses' => $controller.'@indexForTag']); - $this->app['router']->get('top', ['as' => 'quotes.top', 'uses' => $controller.'@redirectTop']); - $this->app['router']->get('top/favorites', ['as' => 'quotes.top.favorites', 'uses' => $controller.'@topFavorites']); - $this->app['router']->get('top/comments', ['as' => 'quotes.top.comments', 'uses' => $controller.'@topComments']); - $this->app['router']->get('random', ['as' => 'random', 'uses' => $controller.'@random']); - $this->app['router']->get('addquote', ['as' => 'addquote', 'before' => 'auth', 'uses' => $controller.'@create']); - $this->app['router']->get('quote-{quote_id}', ['uses' => $controller.'@redirectOldUrl']); - $this->app['router']->post('quotes/favorites-info', ['as' => 'quotes.favoritesInfo', 'uses' => $controller.'@getDataFavoritesInfo']); - $this->app['router']->resource('quotes', $controller, ['only' => ['index', 'show', 'store']]); - }); - } - - private function registerSearchRoutes() - { - $controller = 'SearchController'; - - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) { - $this->app['router']->get('search', ['as' => 'search.form', 'uses' => $controller.'@showForm']); - $this->app['router']->post('search', ['as' => 'search.dispatcher', 'uses' => $controller.'@dispatcher']); - $this->app['router']->get('search/{query}', ['as' => 'search.results', 'uses' => $controller.'@getResults']); - }); - } - - private function registerQuotesComposers() - { - $composersNamespace = $this->getNamespaceComposers(); - - // When indexing quotes - $this->app['view']->composer([ - 'quotes.partials.multiple', - ], $composersNamespace.'IndexComposer'); - - $this->app['view']->composer([ - 'quotes.tags.index', - ], $composersNamespace.'IndexForTagComposer'); - - $this->app['view']->composer([ - 'quotes.top.comments', - 'quotes.top.favorites', - ], $composersNamespace.'IndexForTopsComposer'); - - // When adding a quote - $this->app['view']->composer([ - 'quotes.addquote' - ], $composersNamespace.'AddComposer'); - - // When adding a comment on a single quote - $this->app['view']->composer([ - 'quotes.show' - ], $composersNamespace.'ShowComposer'); - - // View a single quote - $this->app['view']->composer([ - 'quotes.partials.singleQuote' - ], $composersNamespace.'SingleComposer'); - - // For deeps link - $this->app['view']->composer([ - 'quotes.index', - 'quotes.addquote' - ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); - } - - private function registerSearchComposers() - { - // When showing search results - $this->app['view']->composer([ - 'search.results' - ], $this->getNamespaceComposers().'ResultsComposer'); - } - - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - 'namespace' => $this->getBaseNamespace().'Controllers', - ]; - } -} \ No newline at end of file +class QuotesServiceProvider extends ServiceProvider +{ + use NamespaceTrait; + + /** + * Indicates if loading of the provider is deferred. + * + * @var bool + */ + protected $defer = false; + + /** + * Bootstrap the application events. + */ + public function boot() + { + // + } + + /** + * Register the service provider. + */ + public function register() + { + // FavoriteQuote + $this->registerFavoriteQuoteRoutes(); + $this->registerFavoriteQuoteBindings(); + + // Quotes + $this->registerQuoteRoutes(); + $this->registerQuotesComposers(); + $this->registerQuotesBindings(); + $this->registerQuotesCommands(); + + // Search + $this->registerSearchRoutes(); + $this->registerSearchComposers(); + } + + private function registerQuotesCommands() + { + $commands = [ + 'quotesPublish' => 'QuotesPublishCommand', + 'quotesWaiting' => 'WaitingQuotesCommand', + ]; + + foreach ($commands as $key => $class) { + $commandName = $this->getBaseNamespace().'Console\\'.$class; + + $this->app->bindShared('quotes.console.'.$key, function ($app) use ($commandName) { + return $app->make($commandName); + }); + + $this->commands('quotes.console.'.$key); + } + } + + private function registerFavoriteQuoteBindings() + { + $this->app->bind(FavoriteQuoteRepository::class, function () { + $eloquentRepo = new DbFavoriteQuoteRepository(); + + return new CachingFavoriteQuoteRepository($eloquentRepo); + }); + } + + private function registerQuotesBindings() + { + $this->app->bind(QuoteRepository::class, function () { + $eloquentRepo = new DbQuoteRepository(); + + return new CachingQuoteRepository($eloquentRepo); + }); + } + + private function registerFavoriteQuoteRoutes() + { + $controller = 'FavoriteQuoteController'; + + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->post('favorite/{quote_id}', ['as' => 'favorite', 'before' => 'auth', 'uses' => $controller.'@store']); + $this->app['router']->post('unfavorite/{quote_id}', ['as' => 'unfavorite', 'before' => 'auth', 'uses' => $controller.'@destroy']); + }); + } + + private function registerQuoteRoutes() + { + $controller = 'QuotesController'; + + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->get('/', ['as' => 'home', 'uses' => $controller.'@index']); + $this->app['router']->get('tags/{tag_name}', ['as' => 'quotes.tags.index', 'uses' => $controller.'@indexForTag']); + $this->app['router']->get('top', ['as' => 'quotes.top', 'uses' => $controller.'@redirectTop']); + $this->app['router']->get('top/favorites', ['as' => 'quotes.top.favorites', 'uses' => $controller.'@topFavorites']); + $this->app['router']->get('top/comments', ['as' => 'quotes.top.comments', 'uses' => $controller.'@topComments']); + $this->app['router']->get('random', ['as' => 'random', 'uses' => $controller.'@random']); + $this->app['router']->get('addquote', ['as' => 'addquote', 'before' => 'auth', 'uses' => $controller.'@create']); + $this->app['router']->get('quote-{quote_id}', ['uses' => $controller.'@redirectOldUrl']); + $this->app['router']->post('quotes/favorites-info', ['as' => 'quotes.favoritesInfo', 'uses' => $controller.'@getDataFavoritesInfo']); + $this->app['router']->resource('quotes', $controller, ['only' => ['index', 'show', 'store']]); + }); + } + + private function registerSearchRoutes() + { + $controller = 'SearchController'; + + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->get('search', ['as' => 'search.form', 'uses' => $controller.'@showForm']); + $this->app['router']->post('search', ['as' => 'search.dispatcher', 'uses' => $controller.'@dispatcher']); + $this->app['router']->get('search/{query}', ['as' => 'search.results', 'uses' => $controller.'@getResults']); + }); + } + + private function registerQuotesComposers() + { + $composersNamespace = $this->getNamespaceComposers(); + + // When indexing quotes + $this->app['view']->composer([ + 'quotes.partials.multiple', + ], $composersNamespace.'IndexComposer'); + + $this->app['view']->composer([ + 'quotes.tags.index', + ], $composersNamespace.'IndexForTagComposer'); + + $this->app['view']->composer([ + 'quotes.top.comments', + 'quotes.top.favorites', + ], $composersNamespace.'IndexForTopsComposer'); + + // When adding a quote + $this->app['view']->composer([ + 'quotes.addquote', + ], $composersNamespace.'AddComposer'); + + // When adding a comment on a single quote + $this->app['view']->composer([ + 'quotes.show', + ], $composersNamespace.'ShowComposer'); + + // View a single quote + $this->app['view']->composer([ + 'quotes.partials.singleQuote', + ], $composersNamespace.'SingleComposer'); + + // For deeps link + $this->app['view']->composer([ + 'quotes.index', + 'quotes.addquote', + ], 'TeenQuotes\Tools\Composers\DeepLinksComposer'); + } + + private function registerSearchComposers() + { + // When showing search results + $this->app['view']->composer([ + 'search.results', + ], $this->getNamespaceComposers().'ResultsComposer'); + } + + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + 'namespace' => $this->getBaseNamespace().'Controllers', + ]; + } +} diff --git a/app/TeenQuotes/Quotes/Repositories/CachingFavoriteQuoteRepository.php b/app/TeenQuotes/Quotes/Repositories/CachingFavoriteQuoteRepository.php index bb552b20..e262e7d1 100644 --- a/app/TeenQuotes/Quotes/Repositories/CachingFavoriteQuoteRepository.php +++ b/app/TeenQuotes/Quotes/Repositories/CachingFavoriteQuoteRepository.php @@ -1,141 +1,149 @@ -favQuotes = $favQuotes; - } - - /** - * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository - */ - public function isFavoriteForUserAndQuote($u, $quote_id) - { - return in_array($quote_id, $this->quotesFavoritesForUser($u)); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository - */ - public function deleteForUserAndQuote($u, $quote_id) - { - $cacheKeyUser = $this->getCacheKeyForUser($u); - $cacheKeyQuote = $this->getCacheKeyForQuote($quote_id); - - $quotes = Cache::get($cacheKeyUser, null); - if (! is_null($quotes)) - { - $quotes = $this->arrayDelete($quotes, $quote_id); - Cache::put($cacheKeyUser, $quotes, 10); - } - - if (Cache::has($cacheKeyQuote)) - Cache::decrement($cacheKeyQuote); - - return $this->favQuotes->deleteForUserAndQuote($u, $quote_id); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository - */ - public function nbFavoritesForQuotes($idsQuotes) - { - return $this->favQuotes->nbFavoritesForQuotes($idsQuotes); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository - */ - public function quotesFavoritesForUser($u) - { - $cacheKey = $this->getCacheKeyForUser($u); - $quotes = Cache::get($cacheKey, null); - - if (! is_null($quotes)) - return $quotes; - - return Cache::remember($cacheKey, 10, function() use($u) - { - return $this->favQuotes->quotesFavoritesForUser($u); - }); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository - */ - public function create(User $u, $quote_id) - { - $cacheKeyUser = $this->getCacheKeyForUser($u); - $cacheKeyQuote = $this->getCacheKeyForQuote($quote_id); - - $quotes = Cache::get($cacheKeyUser, null); - if (! is_null($quotes)) - { - $quotes[] = $quote_id; - Cache::put($cacheKeyUser, $quotes, 10); - } - - if (Cache::has($cacheKeyQuote)) - Cache::increment($cacheKeyQuote); - - return $this->favQuotes->create($u, $quote_id); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository - */ - public function getTopQuotes($page, $pagesize) - { - return $this->favQuotes->getTopQuotes($page, $pagesize); - } - - /** - * Get the number of favorites for a quote - * @param int $quote_id - * @return int - */ - public function nbFavoritesForQuote($quote_id) - { - $nb = Cache::get($this->getCacheKeyForQuote($quote_id), null); - - if (! is_null($nb)) - return $nb; - - return $this->favQuotes->nbFavoritesForQuote($quote_id); - } - - private function arrayDelete($array, $element) - { - return array_diff($array, [$element]); - } - - private function getCacheKeyForUser($u) - { - return 'favorites.user-'.$this->getUserId($u); - } - - private function getCacheKeyForQuote($id) - { - return 'favorites.quote-'.$id; - } - - private function getUserId($u) - { - if (is_numeric($u)) - return $u; - - if ($u instanceof User) - return $u->id; - - throw new InvalidArgumentException($u." is not a user or an ID"); - } -} \ No newline at end of file +class CachingFavoriteQuoteRepository implements FavoriteQuoteRepository +{ + /** + * @var \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + private $favQuotes; + + public function __construct(FavoriteQuoteRepository $favQuotes) + { + $this->favQuotes = $favQuotes; + } + + /** + * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + public function isFavoriteForUserAndQuote($u, $quote_id) + { + return in_array($quote_id, $this->quotesFavoritesForUser($u)); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + public function deleteForUserAndQuote($u, $quote_id) + { + $cacheKeyUser = $this->getCacheKeyForUser($u); + $cacheKeyQuote = $this->getCacheKeyForQuote($quote_id); + + $quotes = Cache::get($cacheKeyUser, null); + if (!is_null($quotes)) { + $quotes = $this->arrayDelete($quotes, $quote_id); + Cache::put($cacheKeyUser, $quotes, 10); + } + + if (Cache::has($cacheKeyQuote)) { + Cache::decrement($cacheKeyQuote); + } + + return $this->favQuotes->deleteForUserAndQuote($u, $quote_id); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + public function nbFavoritesForQuotes($idsQuotes) + { + return $this->favQuotes->nbFavoritesForQuotes($idsQuotes); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + public function quotesFavoritesForUser($u) + { + $cacheKey = $this->getCacheKeyForUser($u); + $quotes = Cache::get($cacheKey, null); + + if (!is_null($quotes)) { + return $quotes; + } + + return Cache::remember($cacheKey, 10, function () use ($u) { + return $this->favQuotes->quotesFavoritesForUser($u); + }); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + public function create(User $u, $quote_id) + { + $cacheKeyUser = $this->getCacheKeyForUser($u); + $cacheKeyQuote = $this->getCacheKeyForQuote($quote_id); + + $quotes = Cache::get($cacheKeyUser, null); + if (!is_null($quotes)) { + $quotes[] = $quote_id; + Cache::put($cacheKeyUser, $quotes, 10); + } + + if (Cache::has($cacheKeyQuote)) { + Cache::increment($cacheKeyQuote); + } + + return $this->favQuotes->create($u, $quote_id); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + public function getTopQuotes($page, $pagesize) + { + return $this->favQuotes->getTopQuotes($page, $pagesize); + } + + /** + * Get the number of favorites for a quote. + * + * @param int $quote_id + * + * @return int + */ + public function nbFavoritesForQuote($quote_id) + { + $nb = Cache::get($this->getCacheKeyForQuote($quote_id), null); + + if (!is_null($nb)) { + return $nb; + } + + return $this->favQuotes->nbFavoritesForQuote($quote_id); + } + + private function arrayDelete($array, $element) + { + return array_diff($array, [$element]); + } + + private function getCacheKeyForUser($u) + { + return 'favorites.user-'.$this->getUserId($u); + } + + private function getCacheKeyForQuote($id) + { + return 'favorites.quote-'.$id; + } + + private function getUserId($u) + { + if (is_numeric($u)) { + return $u; + } + + if ($u instanceof User) { + return $u->id; + } + + throw new InvalidArgumentException($u.' is not a user or an ID'); + } +} diff --git a/app/TeenQuotes/Quotes/Repositories/CachingQuoteRepository.php b/app/TeenQuotes/Quotes/Repositories/CachingQuoteRepository.php index a7d05190..37d6ce41 100644 --- a/app/TeenQuotes/Quotes/Repositories/CachingQuoteRepository.php +++ b/app/TeenQuotes/Quotes/Repositories/CachingQuoteRepository.php @@ -1,328 +1,333 @@ -quotes = $quotes; - // We shouldn't inject big dependencies, like Cache or Config - // Because it would take a massive space when serializing - // every classes when caching a result - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function lastWaitingQuotes() - { - return $this->quotes->lastWaitingQuotes(); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function nbPending() - { - return $this->quotes->nbPending(); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function nbWaiting() - { - return $this->quotes->nbWaiting(); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function lastPendingQuotes($nb) - { - return $this->quotes->lastPendingQuotes($nb); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function getById($id) - { - return $this->quotes->getById($id); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function getByIdWithUser($id) - { - return $this->quotes->getByIdWithUser($id); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function waitingById($id) - { - return $this->quotes->waitingById($id); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function showQuote($id) - { - return $this->quotes->showQuote($id); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function countQuotesByApprovedForUser($approved, User $u) - { - return $this->quotes->countQuotesByApprovedForUser($approved, $u); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function updateContentAndApproved($id, $content, $approved) - { - return $this->quotes->updateContentAndApproved($id, $content, $approved); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function updateApproved($id, $approved) - { - if ($approved == Quote::PUBLISHED) - $this->flushQuotesForQuote($id); - - return $this->quotes->updateApproved($id, $approved); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function totalPublished() - { - $quotes = $this->quotes; - - return Cache::remember('quotes.totalPublished', 10, function() use($quotes) - { - return $quotes->totalPublished(); - }); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function searchCountPublishedWithQuery($query) - { - return $this->quotes->searchCountPublishedWithQuery($query); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function submittedTodayForUser(User $u) - { - return $this->quotes->submittedTodayForUser($u); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function createQuoteForUser(User $u, $content) - { - return $this->quotes->createQuoteForUser($u, $content); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function index($page, $pagesize) - { - $quotes = $this->quotes; - - // Use caching only with the default pagesize - if (! $this->isDefaultPagesize($pagesize)) - return $this->quotes->index($page, $pagesize); - - return Cache::remember('quotes.published.'.$page, 1, function() use ($quotes, $page, $pagesize) - { - return $quotes->index($page, $pagesize); - }); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function randomPublished($nb) - { - return $this->quotes->randomPublished($nb); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function randomPublishedToday($nb) - { - return $this->quotes->randomPublishedToday($nb); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function indexRandom($page, $pagesize) - { - $quotes = $this->quotes; - - // Use caching only with the default pagesize - if (! $this->isDefaultPagesize($pagesize)) - return $this->quotes->indexRandom($page, $pagesize); - - return Cache::remember('quotes.random.'.$page, 1, function() use ($quotes, $page, $pagesize) - { - return $quotes->indexRandom($page, $pagesize); - }); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function listPublishedIdsForUser(User $u) - { - return $this->quotes->listPublishedIdsForUser($u); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function nbPublishedForUser(User $u) - { - $quotes = $this->quotes; - - return Cache::remember('quotes.user-'.$u->id.'.nbPublished', 10, function() use($quotes, $u) - { - return $quotes->nbPublishedForUser($u); - }); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function getForIds($ids, $page, $pagesize) - { - return $this->quotes->getForIds($ids, $page, $pagesize); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function searchPublishedWithQuery($query, $page, $pagesize) - { - return $this->quotes->searchPublishedWithQuery($query, $page, $pagesize); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function getQuotesByApprovedForUser(User $u, $approved, $page, $pagesize) - { - $quotes = $this->quotes; - - $callback = (function() use ($quotes, $u, $approved, $page, $pagesize) - { - return $quotes->getQuotesByApprovedForUser($u, $approved, $page, $pagesize); - }); - - $cacheTags = $this->getCacheNameForUserAndApproved($u, $approved); - - return Cache::tags($cacheTags)->remember($page, 5, $callback); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function nbDaysUntilPublication($q) - { - return $this->quotes->nbDaysUntilPublication($q); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function nbQuotesWithFavorites() - { - return $this->quotes->nbQuotesWithFavorites(); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function nbQuotesWithComments() - { - return $this->quotes->nbQuotesWithComments(); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function getQuotesForTag(Tag $t, $page, $pagesize) - { - return $this->quotes->getQuotesForTag($t, $page, $pagesize); - } - - /** - * @see \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - public function countWaitingQuotesSince(Carbon $date) - { - return $this->quotes->countWaitingQuotesSince($date); - } - - private function flushQuotesForQuote($id) - { - $quote = $this->getByIdWithUser($id); - $author = $quote->user; - - // Increment the number of published quotes for the author - if (Cache::has('quotes.user-'.$author->id.'.nbPublished')) - Cache::increment('quotes.user-'.$author->id.'.nbPublished'); - - // Update the number of published quotes - if (Cache::has('quotes.totalPublished')) - Cache::increment('quotes.totalPublished'); - - // Delete published and waiting quotes for the author - Cache::tags($this->getCacheNameForUserAndApproved($author, Quote::WAITING))->flush(); - Cache::tags($this->getCacheNameForUserAndApproved($author, Quote::PUBLISHED))->flush(); - } - - private function getCacheNameForUserAndApproved(User $u, $approve) - { - return ['quotes', 'user', $u->id, $approve]; - } - - /** - * Tells if the pagesize is the default value - * - * @param int $pagesize - * @return boolean - */ - private function isDefaultPagesize($pagesize) - { - return $pagesize == Config::get('app.quotes.nbQuotesPerPage'); - } -} \ No newline at end of file +class CachingQuoteRepository implements QuoteRepository +{ + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quotes; + + public function __construct(QuoteRepository $quotes) + { + $this->quotes = $quotes; + // We shouldn't inject big dependencies, like Cache or Config + // Because it would take a massive space when serializing + // every classes when caching a result + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function lastWaitingQuotes() + { + return $this->quotes->lastWaitingQuotes(); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function nbPending() + { + return $this->quotes->nbPending(); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function nbWaiting() + { + return $this->quotes->nbWaiting(); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function lastPendingQuotes($nb) + { + return $this->quotes->lastPendingQuotes($nb); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function getById($id) + { + return $this->quotes->getById($id); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function getByIdWithUser($id) + { + return $this->quotes->getByIdWithUser($id); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function waitingById($id) + { + return $this->quotes->waitingById($id); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function showQuote($id) + { + return $this->quotes->showQuote($id); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function countQuotesByApprovedForUser($approved, User $u) + { + return $this->quotes->countQuotesByApprovedForUser($approved, $u); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function updateContentAndApproved($id, $content, $approved) + { + return $this->quotes->updateContentAndApproved($id, $content, $approved); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function updateApproved($id, $approved) + { + if ($approved == Quote::PUBLISHED) { + $this->flushQuotesForQuote($id); + } + + return $this->quotes->updateApproved($id, $approved); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function totalPublished() + { + $quotes = $this->quotes; + + return Cache::remember('quotes.totalPublished', 10, function () use ($quotes) { + return $quotes->totalPublished(); + }); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function searchCountPublishedWithQuery($query) + { + return $this->quotes->searchCountPublishedWithQuery($query); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function submittedTodayForUser(User $u) + { + return $this->quotes->submittedTodayForUser($u); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function createQuoteForUser(User $u, $content) + { + return $this->quotes->createQuoteForUser($u, $content); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function index($page, $pagesize) + { + $quotes = $this->quotes; + + // Use caching only with the default pagesize + if (!$this->isDefaultPagesize($pagesize)) { + return $this->quotes->index($page, $pagesize); + } + + return Cache::remember('quotes.published.'.$page, 1, function () use ($quotes, $page, $pagesize) { + return $quotes->index($page, $pagesize); + }); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function randomPublished($nb) + { + return $this->quotes->randomPublished($nb); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function randomPublishedToday($nb) + { + return $this->quotes->randomPublishedToday($nb); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function indexRandom($page, $pagesize) + { + $quotes = $this->quotes; + + // Use caching only with the default pagesize + if (!$this->isDefaultPagesize($pagesize)) { + return $this->quotes->indexRandom($page, $pagesize); + } + + return Cache::remember('quotes.random.'.$page, 1, function () use ($quotes, $page, $pagesize) { + return $quotes->indexRandom($page, $pagesize); + }); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function listPublishedIdsForUser(User $u) + { + return $this->quotes->listPublishedIdsForUser($u); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function nbPublishedForUser(User $u) + { + $quotes = $this->quotes; + + return Cache::remember('quotes.user-'.$u->id.'.nbPublished', 10, function () use ($quotes, $u) { + return $quotes->nbPublishedForUser($u); + }); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function getForIds($ids, $page, $pagesize) + { + return $this->quotes->getForIds($ids, $page, $pagesize); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function searchPublishedWithQuery($query, $page, $pagesize) + { + return $this->quotes->searchPublishedWithQuery($query, $page, $pagesize); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function getQuotesByApprovedForUser(User $u, $approved, $page, $pagesize) + { + $quotes = $this->quotes; + + $callback = (function () use ($quotes, $u, $approved, $page, $pagesize) { + return $quotes->getQuotesByApprovedForUser($u, $approved, $page, $pagesize); + }); + + $cacheTags = $this->getCacheNameForUserAndApproved($u, $approved); + + return Cache::tags($cacheTags)->remember($page, 5, $callback); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function nbDaysUntilPublication($q) + { + return $this->quotes->nbDaysUntilPublication($q); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function nbQuotesWithFavorites() + { + return $this->quotes->nbQuotesWithFavorites(); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function nbQuotesWithComments() + { + return $this->quotes->nbQuotesWithComments(); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function getQuotesForTag(Tag $t, $page, $pagesize) + { + return $this->quotes->getQuotesForTag($t, $page, $pagesize); + } + + /** + * @see \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + public function countWaitingQuotesSince(Carbon $date) + { + return $this->quotes->countWaitingQuotesSince($date); + } + + private function flushQuotesForQuote($id) + { + $quote = $this->getByIdWithUser($id); + $author = $quote->user; + + // Increment the number of published quotes for the author + if (Cache::has('quotes.user-'.$author->id.'.nbPublished')) { + Cache::increment('quotes.user-'.$author->id.'.nbPublished'); + } + + // Update the number of published quotes + if (Cache::has('quotes.totalPublished')) { + Cache::increment('quotes.totalPublished'); + } + + // Delete published and waiting quotes for the author + Cache::tags($this->getCacheNameForUserAndApproved($author, Quote::WAITING))->flush(); + Cache::tags($this->getCacheNameForUserAndApproved($author, Quote::PUBLISHED))->flush(); + } + + private function getCacheNameForUserAndApproved(User $u, $approve) + { + return ['quotes', 'user', $u->id, $approve]; + } + + /** + * Tells if the pagesize is the default value. + * + * @param int $pagesize + * + * @return bool + */ + private function isDefaultPagesize($pagesize) + { + return $pagesize == Config::get('app.quotes.nbQuotesPerPage'); + } +} diff --git a/app/TeenQuotes/Quotes/Repositories/DbFavoriteQuoteRepository.php b/app/TeenQuotes/Quotes/Repositories/DbFavoriteQuoteRepository.php index 562a1e65..ad1e7a5c 100644 --- a/app/TeenQuotes/Quotes/Repositories/DbFavoriteQuoteRepository.php +++ b/app/TeenQuotes/Quotes/Repositories/DbFavoriteQuoteRepository.php @@ -1,113 +1,129 @@ -forUser($u) - ->count() == 1; - } +class DbFavoriteQuoteRepository implements FavoriteQuoteRepository +{ + /** + * Tells if a quote is in the user's favorites. + * + * @param int|\TeenQuotes\Users\Models\User $u The user + * @param int $quote_id + * + * @return bool + */ + public function isFavoriteForUserAndQuote($u, $quote_id) + { + return FavoriteQuote::where('quote_id', '=', $quote_id) + ->forUser($u) + ->count() == 1; + } - /** - * Delete a favorite for a user and a quote - * @param int|\TeenQuotes\Users\Models\User $u The user - * @param int $quote_id - * @return \TeenQuotes\Quotes\Models\FavoriteQuote - */ - public function deleteForUserAndQuote($u, $quote_id) - { - // We can't chain all our methods, otherwise the deleted event - // will not be fired - $fav = FavoriteQuote::where('quote_id', '=' , $quote_id) - ->forUser($u) - ->first(); + /** + * Delete a favorite for a user and a quote. + * + * @param int|\TeenQuotes\Users\Models\User $u The user + * @param int $quote_id + * + * @return \TeenQuotes\Quotes\Models\FavoriteQuote + */ + public function deleteForUserAndQuote($u, $quote_id) + { + // We can't chain all our methods, otherwise the deleted event + // will not be fired + $fav = FavoriteQuote::where('quote_id', '=', $quote_id) + ->forUser($u) + ->first(); - $fav->delete(); - } + $fav->delete(); + } - /** - * Count the number of favorites for an array of quotes - * @param array $idsQuotes - * @return int - */ - public function nbFavoritesForQuotes($idsQuotes) - { - return FavoriteQuote::whereIn('quote_id', $idsQuotes) - ->count(); - } + /** + * Count the number of favorites for an array of quotes. + * + * @param array $idsQuotes + * + * @return int + */ + public function nbFavoritesForQuotes($idsQuotes) + { + return FavoriteQuote::whereIn('quote_id', $idsQuotes) + ->count(); + } - /** - * List all quotes IDs of the user's favorites - * @param int|\TeenQuotes\Users\Models\User $u The user - * @return array - */ - public function quotesFavoritesForUser($u) - { - return FavoriteQuote::forUser($u) - ->select('quote_id') - ->orderBy('id', 'DESC') - ->get() - ->lists('quote_id'); - } + /** + * List all quotes IDs of the user's favorites. + * + * @param int|\TeenQuotes\Users\Models\User $u The user + * + * @return array + */ + public function quotesFavoritesForUser($u) + { + return FavoriteQuote::forUser($u) + ->select('quote_id') + ->orderBy('id', 'DESC') + ->get() + ->lists('quote_id'); + } - /** - * Mark a quote as favorited for a user - * @param int|\TeenQuotes\Users\Models\User $u - * @param int $quote_id - * @return \TeenQuotes\Quotes\Models\FavoriteQuote - */ - public function create(User $u, $quote_id) - { - $favorite = new FavoriteQuote; - $favorite->user_id = $u->id; - $favorite->quote_id = $quote_id; - $favorite->save(); + /** + * Mark a quote as favorited for a user. + * + * @param int|\TeenQuotes\Users\Models\User $u + * @param int $quote_id + * + * @return \TeenQuotes\Quotes\Models\FavoriteQuote + */ + public function create(User $u, $quote_id) + { + $favorite = new FavoriteQuote(); + $favorite->user_id = $u->id; + $favorite->quote_id = $quote_id; + $favorite->save(); - return $favorite; - } + return $favorite; + } - /** - * Get a top of quotes by the number of favorites, in descending order - * @param int $page - * @param int $pagesize - * @return array The ID of the quotes - */ - public function getTopQuotes($page, $pagesize) - { - $countKey = 'fav_count'; + /** + * Get a top of quotes by the number of favorites, in descending order. + * + * @param int $page + * @param int $pagesize + * + * @return array The ID of the quotes + */ + public function getTopQuotes($page, $pagesize) + { + $countKey = 'fav_count'; - return FavoriteQuote::select(DB::raw('count(*) as '.$countKey.', quote_id')) - ->groupBy('quote_id') - ->orderBy($countKey, 'DESC') - ->having($countKey, '>=', 1) - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->lists('quote_id'); - } + return FavoriteQuote::select(DB::raw('count(*) as '.$countKey.', quote_id')) + ->groupBy('quote_id') + ->orderBy($countKey, 'DESC') + ->having($countKey, '>=', 1) + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->lists('quote_id'); + } - /** - * Get the number of favorites for a quote - * @param int $quote_id - * @return int - */ - public function nbFavoritesForQuote($quote_id) - { - return FavoriteQuote::where('quote_id', $quote_id)->count(); - } + /** + * Get the number of favorites for a quote. + * + * @param int $quote_id + * + * @return int + */ + public function nbFavoritesForQuote($quote_id) + { + return FavoriteQuote::where('quote_id', $quote_id)->count(); + } - private function computeSkip($page, $pagesize) - { - return $pagesize * ($page - 1); - } -} \ No newline at end of file + private function computeSkip($page, $pagesize) + { + return $pagesize * ($page - 1); + } +} diff --git a/app/TeenQuotes/Quotes/Repositories/DbQuoteRepository.php b/app/TeenQuotes/Quotes/Repositories/DbQuoteRepository.php index 603e009f..1bc93b96 100644 --- a/app/TeenQuotes/Quotes/Repositories/DbQuoteRepository.php +++ b/app/TeenQuotes/Quotes/Repositories/DbQuoteRepository.php @@ -1,471 +1,537 @@ -orderAscending() - ->get(); - } - - /** - * Get the number of quotes waiting to be published - * @return int - */ - public function nbPending() - { - return Quote::pending()->count(); - } - - /** - * Get the number of quotes waiting moderation - * @return int - */ - public function nbWaiting() - { - return Quote::waiting()->count(); - } - - /** - * Grab pending quotes - * @param int $nb The number of quotes to grab - * @return \Illuminate\Database\Eloquent\Collection - */ - public function lastPendingQuotes($nb) - { - return Quote::pending() - ->orderAscending() - ->take($nb) - ->with('user') - ->get(); - } - - /** - * Retrieve a quote by its ID - * @param int $id - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function getById($id) - { - return Quote::find($id); - } - - /** - * Retrieve a quote by its ID - * @param int $id - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function getByIdWithUser($id) - { - return Quote::whereId($id) - ->with('user') - ->first(); - } - - /** - * Retrieve a waiting quote by its ID - * @param int $id - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function waitingById($id) - { - return Quote::waiting() - ->where('id', '=', $id) - ->with('user') - ->first(); - } - - /** - * Get full information about a quote given its ID - * @param int $id - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function showQuote($id) - { - return Quote::whereId($id) - ->with('comments') - ->withSmallUser('comments.user') - ->withSmallUser('favorites.user') - ->withSmallUser() - ->first(); - } - - /** - * Count the number of quotes by approved type for a user - * @param string $approved - * @param \TeenQuotes\Users\Models\User $u - * @return int - */ - public function countQuotesByApprovedForUser($approved, User $u) - { - $this->guardApprovedScope($approved); - - return Quote::$approved() - ->forUser($u) - ->count(); - } - - /** - * Update the content and the approved type for a quote - * @param int $id - * @param string $content - * @param int $approved - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function updateContentAndApproved($id, $content, $approved) - { - $this->guardApproved($approved); - - $q = $this->getById($id); - $q->content = $content; - $q->approved = $approved; - $q->save(); - - return $q; - } - - /** - * Update the approved type for a quote - * @param int $id - * @param int $approved - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function updateApproved($id, $approved) - { - $this->guardApproved($approved); - - $q = $this->getById($id); - $q->approved = $approved; - $q->save(); - - return $q; - } - - /** - * Get the number of published quotes - * @return int - */ - public function totalPublished() - { - return Quote::published()->count(); - } - - /** - * Get the number of results for a query against published quotes - * @param string $query - * @return int - */ - public function searchCountPublishedWithQuery($query) - { - return Quote::whereRaw("MATCH(content) AGAINST(?)", array($query)) - // $query will NOT be bind here - // it will be bind when calling setBindings - ->where('approved', '=', Quote::PUBLISHED) - // WARNING 1 corresponds to approved = 1 - // We need to bind it again - ->setBindings([$query, Quote::PUBLISHED]) - ->count(); - } - - /** - * Get the number of quotes submitted today for a user - * @param \TeenQuotes\Users\Models\User $u - * @return int - */ - public function submittedTodayForUser(User $u) - { - return Quote::createdToday() - ->forUser($u) - ->count(); - } - - /** - * Create a quote for a user - * @param \TeenQuotes\Users\Models\User $u - * @param string $content - * @return \TeenQuotes\Quotes\Models\Quote - */ - public function createQuoteForUser(User $u, $content) - { - $quote = new Quote; - $quote->content = $content; - $u->quotes()->save($quote); - - return $quote; - } - - /** - * List published quotes for a given page and pagesize - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function index($page, $pagesize) - { - return Quote::published() - ->withSmallUser() - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Retrieve some random published quotes - * @param int $nb - * @return \Illuminate\Database\Eloquent\Collection - */ - public function randomPublished($nb) - { - return Quote::published() - ->with('user') - ->random() - ->take($nb) - ->get(); - } - - /** - * Retrieve some random published quotes, published today - * @param int $nb - * @return \Illuminate\Database\Eloquent\Collection - */ - public function randomPublishedToday($nb) - { - return Quote::published() - ->updatedToday() - ->random() - ->with('user') - ->take($nb) - ->get(); - } - - /** - * List published random quotes for a given page and pagesize - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function indexRandom($page, $pagesize) - { - return Quote::published() - ->withSmallUser() - ->random() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * List IDs of published quotes for a user - * @param \TeenQuotes\Users\Models\User $u - * @return array - */ - public function listPublishedIdsForUser(User $u) - { - return Quote::forUser($u) - ->published() - ->lists('id'); - } - - /** - * Get the number of published quotes for a user - * @param \TeenQuotes\Users\Models\User $u - * @return int - */ - public function nbPublishedForUser(User $u) - { - return Quote::forUser($u) - ->published() - ->count(); - } - - /** - * Retrieve quotes for given IDs, page and pagesize - * @param array $ids - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getForIds($ids, $page, $pagesize) - { - if (empty($ids)) return new Collection; - - $query = Quote::whereIn('id', $ids) - ->withSmallUser() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)); - - if (Config::get('database.default') == 'mysql') - $query = $query->orderBy(DB::raw("FIELD(id, ".implode(',', $ids).")")); - - return $query->get(); - } - - /** - * Search published quote with a query - * @param string $query - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function searchPublishedWithQuery($query, $page, $pagesize) - { - return Quote::select('id', 'content', 'user_id', 'approved', 'created_at', 'updated_at', DB::raw("MATCH(content) AGAINST(?) AS `rank`")) - // $search will NOT be bind here - // it will be bind when calling setBindings - ->whereRaw("MATCH(content) AGAINST(?)", array($query)) - ->where('approved', '=', 1) - ->orderBy('rank', 'DESC') - ->withSmallUser() - ->skip($this->computeSkip($page, $pagesize)) - ->take($pagesize) - // WARNING 1 corresponds to approved = 1 - // We need to bind it again - ->setBindings([$query, $query, 1]) - ->get(); - } - - /** - * Get quotes by approved type for a user - * @param \TeenQuotes\Users\Models\User $u - * @param string $approved - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getQuotesByApprovedForUser(User $u, $approved, $page, $pagesize) - { - $this->guardApprovedScope($approved); - - return Quote::$approved() - ->withSmallUser() - ->forUser($u) - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Compute the number of days before publication for a quote waiting to be published. - * @param \TeenQuotes\Quotes\Models\Quote|int $q - * @return int - * @throws \InvalidArgumentException If the quote is not waiting to be published - */ - public function nbDaysUntilPublication($q) - { - $q = $this->getQuote($q); - - if (! $q->isPending()) - throw new InvalidArgumentException("Quote #".$q->id." is not waiting to be published."); - - return ceil($this->getNbQuotesToPublishBefore($q) / $this->getNbQuotesToPublishPerDay()); - } - - /** - * Get the number of quotes having at least a favorite - * @return int - */ - public function nbQuotesWithFavorites() - { - return Quote::has('favorites')->count(); - } - - /** - * Get quotes having a given tag, for a page and a pagesize - * @param \TeenQuotes\Tags\Models\Tag $t - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getQuotesForTag(Tag $t, $page, $pagesize) - { - return $t->quotes() - ->withSmallUser() - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Get the number of quotes having at least a comment - * @return int - */ - public function nbQuotesWithComments() - { - return Quote::has('comments')->count(); - } - - /** - * Get the number of waiting quotes submitted after a given date - * @param \Carbon\Carbon $date - * @return int - */ - public function countWaitingQuotesSince(Carbon $date) - { - return Quote::waiting() - ->createdAfter($date) - ->count(); - } - - private function getNbQuotesToPublishBefore(Quote $q) - { - $pending = $this->lastPendingQuotes(1000); - - $id = $q->id; - - $nbToPublishedBefore = $pending->filter(function($quote) use($id) - { - return $quote->id <= $id; - })->count(); - - return $nbToPublishedBefore; - } - - /** - * Get a quote object - * @param \TeenQuotes\Quotes\Models\Quote|int $q - * @return \TeenQuotes\Quotes\Models\Quote - */ - private function getQuote($q) - { - if ($q instanceof Quote) - return $q; - - return $this->getById($q); - } - - private function getNbQuotesToPublishPerDay() - { - return Config::get('app.quotes.nbQuotesToPublishPerDay'); - } - - private function guardApprovedScope($approved) - { - if (! in_array($approved, ['pending', 'refused', 'waiting', 'published'])) - throw new InvalidArgumentException("Wrong approved type. Got ".$approved); - } - - private function guardApproved($approved) - { - if (! in_array($approved, [Quote::PENDING, Quote::REFUSED, Quote::WAITING, Quote::PUBLISHED])) - throw new InvalidArgumentException("Wrong approved type. Got ".$approved); - } - - private function computeSkip($page, $pagesize) - { - return $pagesize * ($page - 1); - } -} \ No newline at end of file +class DbQuoteRepository implements QuoteRepository +{ + /** + * Retrieve last waiting quotes. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function lastWaitingQuotes() + { + return Quote::waiting() + ->orderAscending() + ->get(); + } + + /** + * Get the number of quotes waiting to be published. + * + * @return int + */ + public function nbPending() + { + return Quote::pending()->count(); + } + + /** + * Get the number of quotes waiting moderation. + * + * @return int + */ + public function nbWaiting() + { + return Quote::waiting()->count(); + } + + /** + * Grab pending quotes. + * + * @param int $nb The number of quotes to grab + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function lastPendingQuotes($nb) + { + return Quote::pending() + ->orderAscending() + ->take($nb) + ->with('user') + ->get(); + } + + /** + * Retrieve a quote by its ID. + * + * @param int $id + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function getById($id) + { + return Quote::find($id); + } + + /** + * Retrieve a quote by its ID. + * + * @param int $id + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function getByIdWithUser($id) + { + return Quote::whereId($id) + ->with('user') + ->first(); + } + + /** + * Retrieve a waiting quote by its ID. + * + * @param int $id + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function waitingById($id) + { + return Quote::waiting() + ->where('id', '=', $id) + ->with('user') + ->first(); + } + + /** + * Get full information about a quote given its ID. + * + * @param int $id + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function showQuote($id) + { + return Quote::whereId($id) + ->with('comments') + ->withSmallUser('comments.user') + ->withSmallUser('favorites.user') + ->withSmallUser() + ->first(); + } + + /** + * Count the number of quotes by approved type for a user. + * + * @param string $approved + * @param \TeenQuotes\Users\Models\User $u + * + * @return int + */ + public function countQuotesByApprovedForUser($approved, User $u) + { + $this->guardApprovedScope($approved); + + return Quote::$approved() + ->forUser($u) + ->count(); + } + + /** + * Update the content and the approved type for a quote. + * + * @param int $id + * @param string $content + * @param int $approved + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function updateContentAndApproved($id, $content, $approved) + { + $this->guardApproved($approved); + + $q = $this->getById($id); + $q->content = $content; + $q->approved = $approved; + $q->save(); + + return $q; + } + + /** + * Update the approved type for a quote. + * + * @param int $id + * @param int $approved + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function updateApproved($id, $approved) + { + $this->guardApproved($approved); + + $q = $this->getById($id); + $q->approved = $approved; + $q->save(); + + return $q; + } + + /** + * Get the number of published quotes. + * + * @return int + */ + public function totalPublished() + { + return Quote::published()->count(); + } + + /** + * Get the number of results for a query against published quotes. + * + * @param string $query + * + * @return int + */ + public function searchCountPublishedWithQuery($query) + { + return Quote::whereRaw('MATCH(content) AGAINST(?)', [$query]) + // $query will NOT be bind here + // it will be bind when calling setBindings + ->where('approved', '=', Quote::PUBLISHED) + // WARNING 1 corresponds to approved = 1 + // We need to bind it again + ->setBindings([$query, Quote::PUBLISHED]) + ->count(); + } + + /** + * Get the number of quotes submitted today for a user. + * + * @param \TeenQuotes\Users\Models\User $u + * + * @return int + */ + public function submittedTodayForUser(User $u) + { + return Quote::createdToday() + ->forUser($u) + ->count(); + } + + /** + * Create a quote for a user. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $content + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + public function createQuoteForUser(User $u, $content) + { + $quote = new Quote(); + $quote->content = $content; + $u->quotes()->save($quote); + + return $quote; + } + + /** + * List published quotes for a given page and pagesize. + * + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function index($page, $pagesize) + { + return Quote::published() + ->withSmallUser() + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Retrieve some random published quotes. + * + * @param int $nb + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function randomPublished($nb) + { + return Quote::published() + ->with('user') + ->random() + ->take($nb) + ->get(); + } + + /** + * Retrieve some random published quotes, published today. + * + * @param int $nb + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function randomPublishedToday($nb) + { + return Quote::published() + ->updatedToday() + ->random() + ->with('user') + ->take($nb) + ->get(); + } + + /** + * List published random quotes for a given page and pagesize. + * + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function indexRandom($page, $pagesize) + { + return Quote::published() + ->withSmallUser() + ->random() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * List IDs of published quotes for a user. + * + * @param \TeenQuotes\Users\Models\User $u + * + * @return array + */ + public function listPublishedIdsForUser(User $u) + { + return Quote::forUser($u) + ->published() + ->lists('id'); + } + + /** + * Get the number of published quotes for a user. + * + * @param \TeenQuotes\Users\Models\User $u + * + * @return int + */ + public function nbPublishedForUser(User $u) + { + return Quote::forUser($u) + ->published() + ->count(); + } + + /** + * Retrieve quotes for given IDs, page and pagesize. + * + * @param array $ids + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getForIds($ids, $page, $pagesize) + { + if (empty($ids)) { + return new Collection(); + } + + $query = Quote::whereIn('id', $ids) + ->withSmallUser() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)); + + if (Config::get('database.default') == 'mysql') { + $query = $query->orderBy(DB::raw('FIELD(id, '.implode(',', $ids).')')); + } + + return $query->get(); + } + + /** + * Search published quote with a query. + * + * @param string $query + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function searchPublishedWithQuery($query, $page, $pagesize) + { + return Quote::select('id', 'content', 'user_id', 'approved', 'created_at', 'updated_at', DB::raw('MATCH(content) AGAINST(?) AS `rank`')) + // $search will NOT be bind here + // it will be bind when calling setBindings + ->whereRaw('MATCH(content) AGAINST(?)', [$query]) + ->where('approved', '=', 1) + ->orderBy('rank', 'DESC') + ->withSmallUser() + ->skip($this->computeSkip($page, $pagesize)) + ->take($pagesize) + // WARNING 1 corresponds to approved = 1 + // We need to bind it again + ->setBindings([$query, $query, 1]) + ->get(); + } + + /** + * Get quotes by approved type for a user. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $approved + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getQuotesByApprovedForUser(User $u, $approved, $page, $pagesize) + { + $this->guardApprovedScope($approved); + + return Quote::$approved() + ->withSmallUser() + ->forUser($u) + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Compute the number of days before publication for a quote waiting to be published. + * + * @param \TeenQuotes\Quotes\Models\Quote|int $q + * + * @return int + * + * @throws \InvalidArgumentException If the quote is not waiting to be published + */ + public function nbDaysUntilPublication($q) + { + $q = $this->getQuote($q); + + if (!$q->isPending()) { + throw new InvalidArgumentException('Quote #'.$q->id.' is not waiting to be published.'); + } + + return ceil($this->getNbQuotesToPublishBefore($q) / $this->getNbQuotesToPublishPerDay()); + } + + /** + * Get the number of quotes having at least a favorite. + * + * @return int + */ + public function nbQuotesWithFavorites() + { + return Quote::has('favorites')->count(); + } + + /** + * Get quotes having a given tag, for a page and a pagesize. + * + * @param \TeenQuotes\Tags\Models\Tag $t + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getQuotesForTag(Tag $t, $page, $pagesize) + { + return $t->quotes() + ->withSmallUser() + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Get the number of quotes having at least a comment. + * + * @return int + */ + public function nbQuotesWithComments() + { + return Quote::has('comments')->count(); + } + + /** + * Get the number of waiting quotes submitted after a given date. + * + * @param \Carbon\Carbon $date + * + * @return int + */ + public function countWaitingQuotesSince(Carbon $date) + { + return Quote::waiting() + ->createdAfter($date) + ->count(); + } + + private function getNbQuotesToPublishBefore(Quote $q) + { + $pending = $this->lastPendingQuotes(1000); + + $id = $q->id; + + $nbToPublishedBefore = $pending->filter(function ($quote) use ($id) { + return $quote->id <= $id; + })->count(); + + return $nbToPublishedBefore; + } + + /** + * Get a quote object. + * + * @param \TeenQuotes\Quotes\Models\Quote|int $q + * + * @return \TeenQuotes\Quotes\Models\Quote + */ + private function getQuote($q) + { + if ($q instanceof Quote) { + return $q; + } + + return $this->getById($q); + } + + private function getNbQuotesToPublishPerDay() + { + return Config::get('app.quotes.nbQuotesToPublishPerDay'); + } + + private function guardApprovedScope($approved) + { + if (!in_array($approved, ['pending', 'refused', 'waiting', 'published'])) { + throw new InvalidArgumentException('Wrong approved type. Got '.$approved); + } + } + + private function guardApproved($approved) + { + if (!in_array($approved, [Quote::PENDING, Quote::REFUSED, Quote::WAITING, Quote::PUBLISHED])) { + throw new InvalidArgumentException('Wrong approved type. Got '.$approved); + } + } + + private function computeSkip($page, $pagesize) + { + return $pagesize * ($page - 1); + } +} diff --git a/app/TeenQuotes/Quotes/Repositories/FavoriteQuoteRepository.php b/app/TeenQuotes/Quotes/Repositories/FavoriteQuoteRepository.php index 89721478..54011614 100644 --- a/app/TeenQuotes/Quotes/Repositories/FavoriteQuoteRepository.php +++ b/app/TeenQuotes/Quotes/Repositories/FavoriteQuoteRepository.php @@ -1,59 +1,75 @@ - 'required|exists:quotes,id', - 'user_id' => 'required|exists:users,id', - ]; - - /** - * @var array - */ - protected $rulesPostForQuote = [ - 'quote_id' => 'required|exists:quotes,id', - ]; - - /** - * The validation rules when deleting a favorite quote - * @var array - */ - protected $rulesRemove = [ - 'quote_id' => 'required|exists:quotes,id|exists:favorite_quotes,quote_id', - 'user_id' => 'required|exists:users,id|exists:favorite_quotes,user_id', - ]; - - protected $rulesRemoveForQuote = [ - 'quote_id' => 'exists:favorite_quotes,quote_id,user_id,' - ]; - - protected function setUserForRemove(User $u) - { - $this->rulesRemoveForQuote['quote_id'] = $this->rulesRemoveForQuote['quote_id'].$u->id; - - return $this; - } -} \ No newline at end of file +class FavoriteQuoteValidator extends BaseValidator +{ + /** + * The validation rules when adding a favorite quote. + * + * @var array + */ + protected $rulesPost = [ + 'quote_id' => 'required|exists:quotes,id', + 'user_id' => 'required|exists:users,id', + ]; + + /** + * @var array + */ + protected $rulesPostForQuote = [ + 'quote_id' => 'required|exists:quotes,id', + ]; + + /** + * The validation rules when deleting a favorite quote. + * + * @var array + */ + protected $rulesRemove = [ + 'quote_id' => 'required|exists:quotes,id|exists:favorite_quotes,quote_id', + 'user_id' => 'required|exists:users,id|exists:favorite_quotes,user_id', + ]; + + protected $rulesRemoveForQuote = [ + 'quote_id' => 'exists:favorite_quotes,quote_id,user_id,', + ]; + + protected function setUserForRemove(User $u) + { + $this->rulesRemoveForQuote['quote_id'] = $this->rulesRemoveForQuote['quote_id'].$u->id; + + return $this; + } +} diff --git a/app/TeenQuotes/Quotes/Validation/QuoteValidator.php b/app/TeenQuotes/Quotes/Validation/QuoteValidator.php index db6a48e5..a5c81bd8 100644 --- a/app/TeenQuotes/Quotes/Validation/QuoteValidator.php +++ b/app/TeenQuotes/Quotes/Validation/QuoteValidator.php @@ -1,19 +1,36 @@ - 'required|min:50|max:300|unique:quotes,content', - 'quotesSubmittedToday' => 'required|integer|between:0,4', - ]; +class QuoteValidator extends BaseValidator +{ + /** + * The validation rules when posting a quote. + * + * @var array + */ + protected $rulesPosting = [ + 'content' => 'required|min:50|max:300|unique:quotes,content', + 'quotesSubmittedToday' => 'required|integer|between:0,4', + ]; + + /** + * Validation rules for the number of quotes submitted today. + * + * @var array + */ + protected $rulesNbSubmittedToday = [ + 'quotesSubmittedToday' => 'required|integer|between:0,4', + ]; - protected $rulesNbSubmittedToday = [ - 'quotesSubmittedToday' => 'required|integer|between:0,4', - ]; -} \ No newline at end of file + /** + * Validation rules when moderating a quote. + * + * @var array + */ + protected $rulesModerating = [ + 'content' => 'required|min:50|max:300', + ]; +} diff --git a/app/TeenQuotes/Robots/Controllers/RobotsController.php b/app/TeenQuotes/Robots/Controllers/RobotsController.php index fb2c543f..66fd6617 100644 --- a/app/TeenQuotes/Robots/Controllers/RobotsController.php +++ b/app/TeenQuotes/Robots/Controllers/RobotsController.php @@ -1,47 +1,63 @@ -robots = $robots; - $this->app = $app; - } - - public function getRobots() - { - $respnse = $this->constructResponse($this->app->environment()); - - return Response::make($this->robots->generate(), 200, ['Content-Type' => 'text/plain']); - } - - private function constructResponse($env) - { - switch ($env) - { - // If on the live server, serve a nice, welcoming robots.txt - case 'production': - $response = $this->robots->addUserAgent('*'); - $response .= $this->robots->addAllow('/'); - break; - - // If you're on any other server, tell everyone to go away - default: - $response = $this->robots->addUserAgent('*'); - $response .= $this->robots->addDisallow('/'); - } - - return $this->robots->generate(); - } -} \ No newline at end of file +use BaseController; +use Healey\Robots\Robots; +use Illuminate\Foundation\Application as App; +use Response; + +class RobotsController extends BaseController +{ + /** + * @var Robots + */ + private $robots; + + /** + * @var App + */ + private $app; + + /** + * @param Robots $robots + * @param App $app + */ + public function __construct(Robots $robots, App $app) + { + $this->robots = $robots; + $this->app = $app; + } + + public function getRobots() + { + $response = $this->constructResponse($this->app->environment()); + + return Response::make($response, 200, ['Content-Type' => 'text/plain']); + } + + /** + * Generate the robots.txt file. + * + * @param string $env The app environment + * + * @return Response + */ + private function constructResponse($env) + { + switch ($env) { + // If on the live server, serve a nice, welcoming robots.txt + case 'production': + $response = $this->robots->addUserAgent('*'); + $response .= $this->robots->addAllow('/'); + break; + + // If you're on any other server, tell everyone to go away + default: + $response = $this->robots->addUserAgent('*'); + $response .= $this->robots->addDisallow('/'); + } + + return $this->robots->generate(); + } +} diff --git a/app/TeenQuotes/Robots/RobotsServiceProvider.php b/app/TeenQuotes/Robots/RobotsServiceProvider.php index a20a9409..593663df 100644 --- a/app/TeenQuotes/Robots/RobotsServiceProvider.php +++ b/app/TeenQuotes/Robots/RobotsServiceProvider.php @@ -1,41 +1,41 @@ -registerRoutes(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerRoutes(); + } - private function registerRoutes() - { - $controller = 'RobotsController'; + private function registerRoutes() + { + $controller = 'RobotsController'; - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) - { - $this->app['router']->get('robots.txt', ['uses' => $controller.'@getRobots']); - }); - } + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->get('robots.txt', ['uses' => $controller.'@getRobots']); + }); + } - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - 'namespace' => $this->getBaseNamespace().'Controllers', - ]; - } -} \ No newline at end of file + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + 'namespace' => $this->getBaseNamespace().'Controllers', + ]; + } +} diff --git a/app/TeenQuotes/Settings/Models/Relations/SettingTrait.php b/app/TeenQuotes/Settings/Models/Relations/SettingTrait.php index 4a4e6500..4de1b7cc 100644 --- a/app/TeenQuotes/Settings/Models/Relations/SettingTrait.php +++ b/app/TeenQuotes/Settings/Models/Relations/SettingTrait.php @@ -1,11 +1,13 @@ -belongsTo(User::class, 'user_id', 'id'); - } -} \ No newline at end of file +trait SettingTrait +{ + public function user() + { + return $this->belongsTo(User::class, 'user_id', 'id'); + } +} diff --git a/app/TeenQuotes/Settings/Models/Setting.php b/app/TeenQuotes/Settings/Models/Setting.php index 869d9c04..030619c9 100644 --- a/app/TeenQuotes/Settings/Models/Setting.php +++ b/app/TeenQuotes/Settings/Models/Setting.php @@ -1,12 +1,14 @@ -settings = $settings; - $this->cache = $cache; - } + public function __construct(SettingRepository $settings, Cache $cache) + { + $this->settings = $settings; + $this->cache = $cache; + } - /** - * Update or create a setting for a given user and key - * - * @param \TeenQuotes\Users\Models\User $u - * @param string $key - * @param mixed $value - * @return \TeenQuotes\Settings\Models\Setting - */ - public function updateOrCreate(User $u, $key, $value) - { - // If the value was stored in cache, delete it - $cacheKeyName = $this->constructCacheName($u, $key); - if ($this->cache->has($cacheKeyName)) - $this->cache->forget($cacheKeyName); + /** + * Update or create a setting for a given user and key. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $key + * @param mixed $value + * + * @return \TeenQuotes\Settings\Models\Setting + */ + public function updateOrCreate(User $u, $key, $value) + { + // If the value was stored in cache, delete it + $cacheKeyName = $this->constructCacheName($u, $key); + if ($this->cache->has($cacheKeyName)) { + $this->cache->forget($cacheKeyName); + } - return $this->settings->updateOrCreate($u, $key, $value); - } + return $this->settings->updateOrCreate($u, $key, $value); + } - /** - * Retrieve a row for a given user and key - * - * @param \TeenQuotes\Users\Models\User $u - * @param string $key - * @return \TeenQuotes\Settings\Models\Setting - */ - public function findForUserAndKey(User $u, $key) - { - $settingRepo = $this->settings; + /** + * Retrieve a row for a given user and key. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $key + * + * @return \TeenQuotes\Settings\Models\Setting + */ + public function findForUserAndKey(User $u, $key) + { + $settingRepo = $this->settings; - // Get the value from cache or touch the database - return $this->cache->remember($this->constructCacheName($u, $key), 10, function() use ($settingRepo, $u, $key) - { - return $settingRepo->findForUserAndKey($u, $key); - }); - } + // Get the value from cache or touch the database + return $this->cache->remember($this->constructCacheName($u, $key), 10, function () use ($settingRepo, $u, $key) { + return $settingRepo->findForUserAndKey($u, $key); + }); + } - private function constructCacheName(User $u, $key) - { - return 'settings.user-'.$u->id.'.'.$key; - } -} \ No newline at end of file + private function constructCacheName(User $u, $key) + { + return 'settings.user-'.$u->id.'.'.$key; + } +} diff --git a/app/TeenQuotes/Settings/Repositories/DbSettingRepository.php b/app/TeenQuotes/Settings/Repositories/DbSettingRepository.php index af024782..0c28ffb1 100644 --- a/app/TeenQuotes/Settings/Repositories/DbSettingRepository.php +++ b/app/TeenQuotes/Settings/Repositories/DbSettingRepository.php @@ -1,40 +1,44 @@ - $u->id, - 'key' => $key - ]); - $setting->value = $value; +class DbSettingRepository implements SettingRepository +{ + /** + * Update or create a setting for a given user and key. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $key + * @param mixed $value + * + * @return \TeenQuotes\Settings\Models\Setting + */ + public function updateOrCreate(User $u, $key, $value) + { + $setting = Setting::firstOrNew([ + 'user_id' => $u->id, + 'key' => $key, + ]); + $setting->value = $value; - return $setting->save(); - } + return $setting->save(); + } - /** - * Retrieve a row for a given user and key - * - * @param \TeenQuotes\Users\Models\User $u - * @param string $key - * @return \TeenQuotes\Settings\Models\Setting - */ - public function findForUserAndKey(User $u, $key) - { - return Setting::where('user_id', '=', $u->id) - ->where('key', '=', $key) - ->first(); - } -} \ No newline at end of file + /** + * Retrieve a row for a given user and key. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $key + * + * @return \TeenQuotes\Settings\Models\Setting + */ + public function findForUserAndKey(User $u, $key) + { + return Setting::where('user_id', '=', $u->id) + ->where('key', '=', $key) + ->first(); + } +} diff --git a/app/TeenQuotes/Settings/Repositories/SettingRepository.php b/app/TeenQuotes/Settings/Repositories/SettingRepository.php index bad8b861..20224e65 100644 --- a/app/TeenQuotes/Settings/Repositories/SettingRepository.php +++ b/app/TeenQuotes/Settings/Repositories/SettingRepository.php @@ -1,25 +1,29 @@ -registerBindings(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerBindings(); + } - private function registerBindings() - { - $this->app->bind(SettingRepository::class, function() - { - $eloquentRepo = new DbSettingRepository; + private function registerBindings() + { + $this->app->bind(SettingRepository::class, function () { + $eloquentRepo = new DbSettingRepository(); - return new CachingSettingRepository($eloquentRepo, $this->app->make('Illuminate\Cache\Repository')); - }); - } -} \ No newline at end of file + return new CachingSettingRepository($eloquentRepo, $this->app->make('Illuminate\Cache\Repository')); + }); + } +} diff --git a/app/TeenQuotes/Stories/Controllers/StoriesController.php b/app/TeenQuotes/Stories/Controllers/StoriesController.php index 87e22ef9..ef984cc2 100644 --- a/app/TeenQuotes/Stories/Controllers/StoriesController.php +++ b/app/TeenQuotes/Stories/Controllers/StoriesController.php @@ -1,92 +1,103 @@ -api = App::make('TeenQuotes\Api\V1\Controllers\StoriesController'); - $this->storyValidator = App::make('TeenQuotes\Stories\Validation\StoryValidator'); - } - - public function index() - { - // Retrieve stories from the API - $apiResponse = $this->api->index(); - if ($this->responseIsNotFound($apiResponse)) - throw new StoryNotFoundException; - - // Extract the stories collection - $response = $apiResponse->getOriginalData(); - $stories = $response['stories']; - - $totalQuotes = $stories->first()->present()->totalQuotes; - - $data = [ - 'heroHide' => false, - 'heroText' => Lang::get('stories.heroText', ['nb' => $totalQuotes]), - 'mustBeLogged' => Lang::get('stories.mustBeLogged'), - 'pageDescription' => Lang::get('stories.pageDescriptionIndex'), - 'pageTitle' => Lang::get('stories.pageTitleIndex'), - 'paginator' => Paginator::make($stories->toArray(), $response['total_stories'], $response['pagesize']), - 'stories' => $stories, - 'tellUsYourStory' => Lang::get('stories.storiesTellTitle').'.', - ]; - - return View::make('stories.index', $data); - } - - public function show($id) - { - // Call the API - $apiResponse = $this->api->show($id); - if ($this->responseIsNotFound($apiResponse)) - throw new StoryNotFoundException; - - $story = $apiResponse->getOriginalData(); - - $data = [ - 'pageTitle' => Lang::get('stories.pageTitleShow', ['nb' => $story->id]), - 'pageDescription' => $story->present()->pageDescription, - 'story' => $story, - 'goBack' => Lang::get('layout.goBack'), - 'storyTitle' => Lang::get('stories.storyTitle'), - 'heroHide' => true, - ]; - - return View::make('stories.show', $data); - } - - public function store() - { - try { - $this->storyValidator->validatePosting(Input::only(['represent_txt', 'frequence_txt'])); - } - catch (FormValidationException $e) - { - return Redirect::route('stories') - ->withErrors($e->getErrors()) - ->withInput(Input::all()); - } - - // Call the API - skip the API validator - $response = $this->api->store(false); - if ($response->getStatusCode() == 201) - return Redirect::route('stories') - ->with('success', Lang::get('stories.storyAddedSuccessfull', ['login' => Auth::user()->login])); - } -} \ No newline at end of file +use App; +use Auth; +use BaseController; +use Input; +use Lang; +use Laracasts\Validation\FormValidationException; +use Paginator; +use Redirect; +use TeenQuotes\Exceptions\StoryNotFoundException; +use View; + +class StoriesController extends BaseController +{ + /** + * The API controller. + * + * @var \TeenQuotes\Api\V1\Controllers\StoriesController + */ + private $api; + + /** + * @var \TeenQuotes\Stories\Validation\StoryValidator + */ + private $storyValidator; + + public function __construct() + { + $this->api = App::make('TeenQuotes\Api\V1\Controllers\StoriesController'); + $this->storyValidator = App::make('TeenQuotes\Stories\Validation\StoryValidator'); + } + + public function index() + { + // Retrieve stories from the API + $apiResponse = $this->api->index(); + if ($this->responseIsNotFound($apiResponse)) { + throw new StoryNotFoundException(); + } + + // Extract the stories collection + $response = $apiResponse->getOriginalData(); + $stories = $response['stories']; + + $totalQuotes = $stories->first()->present()->totalQuotes; + + $data = [ + 'heroHide' => false, + 'heroText' => Lang::get('stories.heroText', ['nb' => $totalQuotes]), + 'mustBeLogged' => Lang::get('stories.mustBeLogged'), + 'pageDescription' => Lang::get('stories.pageDescriptionIndex'), + 'pageTitle' => Lang::get('stories.pageTitleIndex'), + 'paginator' => Paginator::make($stories->toArray(), $response['total_stories'], $response['pagesize']), + 'stories' => $stories, + 'tellUsYourStory' => Lang::get('stories.storiesTellTitle').'.', + ]; + + return View::make('stories.index', $data); + } + + public function show($id) + { + // Call the API + $apiResponse = $this->api->show($id); + if ($this->responseIsNotFound($apiResponse)) { + throw new StoryNotFoundException(); + } + + $story = $apiResponse->getOriginalData(); + + $data = [ + 'pageTitle' => Lang::get('stories.pageTitleShow', ['nb' => $story->id]), + 'pageDescription' => $story->present()->pageDescription, + 'story' => $story, + 'goBack' => Lang::get('layout.goBack'), + 'storyTitle' => Lang::get('stories.storyTitle'), + 'heroHide' => true, + ]; + + return View::make('stories.show', $data); + } + + public function store() + { + try { + $this->storyValidator->validatePosting(Input::only(['represent_txt', 'frequence_txt'])); + } catch (FormValidationException $e) { + return Redirect::route('stories') + ->withErrors($e->getErrors()) + ->withInput(Input::all()); + } + + // Call the API - skip the API validator + $response = $this->api->store(false); + if ($response->getStatusCode() == 201) { + return Redirect::route('stories') + ->with('success', Lang::get('stories.storyAddedSuccessfull', ['login' => Auth::user()->login])); + } + } +} diff --git a/app/TeenQuotes/Stories/Models/Relations/StoryTrait.php b/app/TeenQuotes/Stories/Models/Relations/StoryTrait.php index 6dfbe1ca..23c0a7cc 100644 --- a/app/TeenQuotes/Stories/Models/Relations/StoryTrait.php +++ b/app/TeenQuotes/Stories/Models/Relations/StoryTrait.php @@ -1,11 +1,13 @@ -belongsTo(User::class, 'user_id', 'id'); - } -} \ No newline at end of file +trait StoryTrait +{ + public function user() + { + return $this->belongsTo(User::class, 'user_id', 'id'); + } +} diff --git a/app/TeenQuotes/Stories/Models/Scopes/StoryTrait.php b/app/TeenQuotes/Stories/Models/Scopes/StoryTrait.php index 03d19698..816b3cd3 100644 --- a/app/TeenQuotes/Stories/Models/Scopes/StoryTrait.php +++ b/app/TeenQuotes/Stories/Models/Scopes/StoryTrait.php @@ -1,9 +1,11 @@ -orderBy('created_at', 'DESC'); - } -} \ No newline at end of file +namespace TeenQuotes\Stories\Models\Scopes; + +trait StoryTrait +{ + public function scopeOrderDescending($query) + { + return $query->orderBy('created_at', 'DESC'); + } +} diff --git a/app/TeenQuotes/Stories/Models/Story.php b/app/TeenQuotes/Stories/Models/Story.php index 6045227b..8d3b4419 100644 --- a/app/TeenQuotes/Stories/Models/Story.php +++ b/app/TeenQuotes/Stories/Models/Story.php @@ -1,16 +1,18 @@ -created_at->diffForHumans(); - } +class StoryPresenter extends Presenter +{ + /** + * The diff time telling when the story was published. + * + * @return string + */ + public function storyAge() + { + return $this->created_at->diffForHumans(); + } - public function totalQuotes() - { - // Round to nearest thousand - $quoteRepo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); + /** + * Get the total number of quotes published in a human readable way. + * + * @return string + */ + public function totalQuotes() + { + $repo = App::make(QuoteRepository::class); + $nbPublished = $repo->totalPublished(); - return number_format(round($quoteRepo->totalPublished(), - 3), 0, '.', ','); - } + // Round to nearest thousand + return number_format(round($nbPublished, -3), 0, '.', ','); + } - public function pageDescription() - { - return Str::limit($this->frequence_txt, 200); - } -} \ No newline at end of file + /** + * Get the page description for a story. + * + * @return string + */ + public function pageDescription() + { + return Str::limit($this->frequence_txt, 200); + } +} diff --git a/app/TeenQuotes/Stories/Repositories/DbStoryRepository.php b/app/TeenQuotes/Stories/Repositories/DbStoryRepository.php index d178b3ed..98928297 100644 --- a/app/TeenQuotes/Stories/Repositories/DbStoryRepository.php +++ b/app/TeenQuotes/Stories/Repositories/DbStoryRepository.php @@ -1,70 +1,75 @@ -withSmallUser() - ->first(); - } +class DbStoryRepository implements StoryRepository +{ + /** + * Retrieve a story by its ID. + * + * @param int $id + * + * @return \TeenQuotes\Stories\Models\Story + */ + public function findById($id) + { + return Story::where('id', '=', $id) + ->withSmallUser() + ->first(); + } - /** - * List stories - * - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function index($page, $pagesize) - { - return Story::withSmallUser() - ->orderDescending() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } + /** + * List stories. + * + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function index($page, $pagesize) + { + return Story::withSmallUser() + ->orderDescending() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } - /** - * Get the total number of stories - * - * @return int - */ - public function total() - { - return Story::count(); - } + /** + * Get the total number of stories. + * + * @return int + */ + public function total() + { + return Story::count(); + } - /** - * Create a story - * - * @param \TeenQuotes\Users\Models\User $u - * @param string $represent_txt - * @param string $frequence_txt - * @return \TeenQuotes\Stories\Models\Story - */ - public function create(User $u, $represent_txt, $frequence_txt) - { - $story = new Story; - $story->represent_txt = $represent_txt; - $story->frequence_txt = $frequence_txt; - $story->user_id = $u->id; - $story->save(); + /** + * Create a story. + * + * @param \TeenQuotes\Users\Models\User $u + * @param string $represent_txt + * @param string $frequence_txt + * + * @return \TeenQuotes\Stories\Models\Story + */ + public function create(User $u, $represent_txt, $frequence_txt) + { + $story = new Story(); + $story->represent_txt = $represent_txt; + $story->frequence_txt = $frequence_txt; + $story->user_id = $u->id; + $story->save(); - return $story; - } + return $story; + } - private function computeSkip($page, $pagesize) - { - return $pagesize * ($page - 1); - } -} \ No newline at end of file + private function computeSkip($page, $pagesize) + { + return $pagesize * ($page - 1); + } +} diff --git a/app/TeenQuotes/Stories/Repositories/StoryRepository.php b/app/TeenQuotes/Stories/Repositories/StoryRepository.php index 1a98587a..a8047c01 100644 --- a/app/TeenQuotes/Stories/Repositories/StoryRepository.php +++ b/app/TeenQuotes/Stories/Repositories/StoryRepository.php @@ -1,40 +1,45 @@ -registerRoutes(); - $this->registerBindings(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerRoutes(); + $this->registerBindings(); + } - private function registerRoutes() - { - $this->app['router']->group($this->getRouteGroupParams(), function() { - $this->app['router']->get('/', ['as' => 'stories', 'uses' => $this->getController().'@index']); - $this->app['router']->get('story/{story_id}', ['as' => 'story.show', 'uses' => $this->getController().'@show']); - $this->app['router']->post('story/new', ['as' => 'story.store', 'before' => 'auth', 'uses' => $this->getController().'@store']); - }); - } + private function registerRoutes() + { + $this->app['router']->group($this->getRouteGroupParams(), function () { + $this->app['router']->get('/', ['as' => 'stories', 'uses' => $this->getController().'@index']); + $this->app['router']->get('story/{story_id}', ['as' => 'story.show', 'uses' => $this->getController().'@show']); + $this->app['router']->post('story/new', ['as' => 'story.store', 'before' => 'auth', 'uses' => $this->getController().'@store']); + }); + } - private function registerBindings() - { - $namespace = $this->getNamespaceRepositories(); + private function registerBindings() + { + $namespace = $this->getNamespaceRepositories(); - $this->app->bind( - $namespace.'StoryRepository', - $namespace.'DbStoryRepository' - ); - } + $this->app->bind( + $namespace.'StoryRepository', + $namespace.'DbStoryRepository' + ); + } - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domainStories'), - 'namespace' => $this->getBaseNamespace().'Controllers' - ]; - } + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domainStories'), + 'namespace' => $this->getBaseNamespace().'Controllers', + ]; + } - /** - * The controller name to handle requests - * @return string - */ - private function getController() - { - return 'StoriesController'; - } -} \ No newline at end of file + /** + * The controller name to handle requests. + * + * @return string + */ + private function getController() + { + return 'StoriesController'; + } +} diff --git a/app/TeenQuotes/Stories/Validation/StoryValidator.php b/app/TeenQuotes/Stories/Validation/StoryValidator.php index 1e52e254..5cfaeb5c 100644 --- a/app/TeenQuotes/Stories/Validation/StoryValidator.php +++ b/app/TeenQuotes/Stories/Validation/StoryValidator.php @@ -1,15 +1,18 @@ - 'required|min:100|max:1000', - 'frequence_txt' => 'required|min:100|max:1000', - ]; -} \ No newline at end of file +class StoryValidator extends BaseValidator +{ + /** + * The validation rules when posting a story. + * + * @var array + */ + protected $rulesPosting = [ + 'represent_txt' => 'required|min:100|max:1000', + 'frequence_txt' => 'required|min:100|max:1000', + ]; +} diff --git a/app/TeenQuotes/Tags/Models/Relations/TagTrait.php b/app/TeenQuotes/Tags/Models/Relations/TagTrait.php index 1583755e..23bc5838 100644 --- a/app/TeenQuotes/Tags/Models/Relations/TagTrait.php +++ b/app/TeenQuotes/Tags/Models/Relations/TagTrait.php @@ -1,11 +1,13 @@ -belongsToMany(Quote::class, 'quote_tag', 'tag_id', 'quote_id'); - } -} \ No newline at end of file +trait TagTrait +{ + public function quotes() + { + return $this->belongsToMany(Quote::class, 'quote_tag', 'tag_id', 'quote_id'); + } +} diff --git a/app/TeenQuotes/Tags/Models/Tag.php b/app/TeenQuotes/Tags/Models/Tag.php index e14fe290..ffc81392 100644 --- a/app/TeenQuotes/Tags/Models/Tag.php +++ b/app/TeenQuotes/Tags/Models/Tag.php @@ -1,24 +1,25 @@ -tags = $tags; - } - - /** - * Create a new tag - * - * @param string $name - * @return \TeenQuotes\Tags\Models\Tag - */ - public function create($name) - { - return $this->tags->create($name); - } - - /** - * Get a tag thanks to its name - * - * @param string $name - * @return \TeenQuotes\Tags\Models\Tag|null - */ - public function getByName($name) - { - $callback = function() use ($name) - { - return $this->tags->getByName($name); - }; - - return Cache::rememberForever('tags.name-'.$name, $callback); - } - - /** - * Add a tag to a quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @param \TeenQuotes\Tags\Models\Tag $t - */ - public function tagQuote(Quote $q, Tag $t) - { - Cache::forget($this->cacheNameForListTags($q)); - - $keyTotal = $this->cacheNameTotalQuotesForTag($t); - - if (Cache::has($keyTotal)) - Cache::increment($keyTotal); - - return $this->tags->tagQuote($q, $t); - } - - /** - * Remove a tag from a quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @param \TeenQuotes\Tags\Models\Tag $t - */ - public function untagQuote(Quote $q, Tag $t) - { - Cache::forget($this->cacheNameForListTags($q)); - - $keyTotal = $this->cacheNameTotalQuotesForTag($t); - - if (Cache::has($keyTotal)) - Cache::decrement($keyTotal); - - return $this->tags->untagQuote($q, $t); - } - - /** - * Get a list of tags for a given quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @return array - */ - public function tagsForQuote(Quote $q) - { - $key = $this->cacheNameForListTags($q); - - $callback = function() use($q) - { - return $this->tags->tagsForQuote($q); - }; - - return Cache::remember($key, 10, $callback); - } - - /** - * Get the total number of quotes having a tag - * - * @param \TeenQuotes\Tags\Models\Tag $t - * @return int - */ - public function totalQuotesForTag(Tag $t) - { - $key = $this->cacheNameTotalQuotesForTag($t); - - $callback = function() use ($t) - { - return $this->tags->totalQuotesForTag($t); - }; - - return Cache::remember($key, 10, $callback); - } - - /** - * Get the key name when we list tags for a quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @return string - */ - private function cacheNameForListTags(Quote $q) - { - return 'tags.quote-'.$q->id.'.list-name'; - } - - /** - * Get the key name to have the number of quotes - * having a tag - * - * @param \TeenQuotes\Tags\Models\Tag $t - * @return string - */ - private function cacheNameTotalQuotesForTag(Tag $t) - { - return 'tags.tag-'.$t->name.'.total-quotes'; - } -} \ No newline at end of file +class CachingTagRepository implements TagRepository +{ + /** + * @var \TeenQuotes\Tags\Repositories\TagRepository + */ + private $tags; + + public function __construct(TagRepository $tags) + { + $this->tags = $tags; + } + + /** + * Create a new tag. + * + * @param string $name + * + * @return \TeenQuotes\Tags\Models\Tag + */ + public function create($name) + { + return $this->tags->create($name); + } + + /** + * Get a tag thanks to its name. + * + * @param string $name + * + * @return \TeenQuotes\Tags\Models\Tag|null + */ + public function getByName($name) + { + $callback = function () use ($name) { + return $this->tags->getByName($name); + }; + + return Cache::rememberForever('tags.name-'.$name, $callback); + } + + /** + * Add a tag to a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * @param \TeenQuotes\Tags\Models\Tag $t + */ + public function tagQuote(Quote $q, Tag $t) + { + Cache::forget($this->cacheNameForListTags($q)); + + $keyTotal = $this->cacheNameTotalQuotesForTag($t); + + if (Cache::has($keyTotal)) { + Cache::increment($keyTotal); + } + + return $this->tags->tagQuote($q, $t); + } + + /** + * Remove a tag from a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * @param \TeenQuotes\Tags\Models\Tag $t + */ + public function untagQuote(Quote $q, Tag $t) + { + Cache::forget($this->cacheNameForListTags($q)); + + $keyTotal = $this->cacheNameTotalQuotesForTag($t); + + if (Cache::has($keyTotal)) { + Cache::decrement($keyTotal); + } + + return $this->tags->untagQuote($q, $t); + } + + /** + * Get a list of tags for a given quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * + * @return array + */ + public function tagsForQuote(Quote $q) + { + $key = $this->cacheNameForListTags($q); + + $callback = function () use ($q) { + return $this->tags->tagsForQuote($q); + }; + + return Cache::remember($key, 10, $callback); + } + + /** + * Get the total number of quotes having a tag. + * + * @param \TeenQuotes\Tags\Models\Tag $t + * + * @return int + */ + public function totalQuotesForTag(Tag $t) + { + $key = $this->cacheNameTotalQuotesForTag($t); + + $callback = function () use ($t) { + return $this->tags->totalQuotesForTag($t); + }; + + return Cache::remember($key, 10, $callback); + } + + /** + * Get the key name when we list tags for a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * + * @return string + */ + private function cacheNameForListTags(Quote $q) + { + return 'tags.quote-'.$q->id.'.list-name'; + } + + /** + * Get the key name to have the number of quotes + * having a tag. + * + * @param \TeenQuotes\Tags\Models\Tag $t + * + * @return string + */ + private function cacheNameTotalQuotesForTag(Tag $t) + { + return 'tags.tag-'.$t->name.'.total-quotes'; + } +} diff --git a/app/TeenQuotes/Tags/Repositories/DbTagRepository.php b/app/TeenQuotes/Tags/Repositories/DbTagRepository.php index 9ef6b6aa..0696fd50 100644 --- a/app/TeenQuotes/Tags/Repositories/DbTagRepository.php +++ b/app/TeenQuotes/Tags/Repositories/DbTagRepository.php @@ -1,73 +1,79 @@ -first(); - } + /** + * Get a tag thanks to its name. + * + * @param string $name + * + * @return \TeenQuotes\Tags\Models\Tag|null + */ + public function getByName($name) + { + return Tag::whereName($name)->first(); + } - /** - * Add a tag to a quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @param \TeenQuotes\Tags\Models\Tag $t - */ - public function tagQuote(Quote $q, Tag $t) - { - $q->tags()->attach($t); - } + /** + * Add a tag to a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * @param \TeenQuotes\Tags\Models\Tag $t + */ + public function tagQuote(Quote $q, Tag $t) + { + $q->tags()->attach($t); + } - /** - * Remove a tag from a quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @param \TeenQuotes\Tags\Models\Tag $t - */ - public function untagQuote(Quote $q, Tag $t) - { - $q->tags()->detach($t); - } + /** + * Remove a tag from a quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * @param \TeenQuotes\Tags\Models\Tag $t + */ + public function untagQuote(Quote $q, Tag $t) + { + $q->tags()->detach($t); + } - /** - * Get a list of tags for a given quote - * - * @param \TeenQuotes\Quotes\Models\Quote $q - * @return array - */ - public function tagsForQuote(Quote $q) - { - return $q->tags()->lists('name'); - } + /** + * Get a list of tags for a given quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + * + * @return array + */ + public function tagsForQuote(Quote $q) + { + return $q->tags()->lists('name'); + } - /** - * Get the total number of quotes having a tag - * - * @param \TeenQuotes\Tags\Models\Tag $t - * @return int - */ - public function totalQuotesForTag(Tag $t) - { - return $t->quotes()->count(); - } -} \ No newline at end of file + /** + * Get the total number of quotes having a tag. + * + * @param \TeenQuotes\Tags\Models\Tag $t + * + * @return int + */ + public function totalQuotesForTag(Tag $t) + { + return $t->quotes()->count(); + } +} diff --git a/app/TeenQuotes/Tags/Repositories/TagRepository.php b/app/TeenQuotes/Tags/Repositories/TagRepository.php index 012bedc4..f5e49c61 100644 --- a/app/TeenQuotes/Tags/Repositories/TagRepository.php +++ b/app/TeenQuotes/Tags/Repositories/TagRepository.php @@ -1,55 +1,61 @@ -registerBindings(); - } + /** + * Register the service provider. + */ + public function register() + { + $this->registerBindings(); + } - private function registerBindings() - { - $this->app->bind(TagRepository::class, function() - { - return new CachingTagRepository(new DbTagRepository); - }); - } -} \ No newline at end of file + private function registerBindings() + { + $this->app->bind(TagRepository::class, function () { + return new CachingTagRepository(new DbTagRepository()); + }); + } +} diff --git a/app/TeenQuotes/Tools/BaseController.php b/app/TeenQuotes/Tools/BaseController.php index 583273a1..41e8b0df 100644 --- a/app/TeenQuotes/Tools/BaseController.php +++ b/app/TeenQuotes/Tools/BaseController.php @@ -1,35 +1,37 @@ -layout)) - { - $this->layout = View::make($this->layout); - } - } +class BaseController extends Controller +{ + /** + * Setup the layout used by the controller. + */ + protected function setupLayout() + { + if (!is_null($this->layout)) { + $this->layout = View::make($this->layout); + } + } - protected function responseIsNotFound(JsonResponse $r) - { - return $r->getStatusCode() == Response::HTTP_NOT_FOUND; - } + protected function responseIsNotFound(JsonResponse $r) + { + return $r->getStatusCode() == Response::HTTP_NOT_FOUND; + } - /** - * Test if we are in a testing environment - * @return boolean - */ - protected function isTestingEnvironment() - { - return in_array(App::environment(), ['testing', 'codeception']); - } + /** + * Test if we are in a testing environment. + * + * @return bool + */ + protected function isTestingEnvironment() + { + return in_array(App::environment(), ['testing', 'codeception']); + } } diff --git a/app/TeenQuotes/Tools/Colors/ColorGenerator.php b/app/TeenQuotes/Tools/Colors/ColorGenerator.php new file mode 100644 index 00000000..bd452b1b --- /dev/null +++ b/app/TeenQuotes/Tools/Colors/ColorGenerator.php @@ -0,0 +1,162 @@ +colors[self::$currentKey]; + } + + /** + * Get the current color and increment the counter. + * + * @return string The hexadecimal color, with a leading # + */ + public function nextColor() + { + $color = $this->currentColor(); + + $this->incrementColorCounter(); + + return $color; + } + + /** + * Lighten the current color for a given percentage, between 0 and 100. + * + * @param int $percentage + * + * @throws InvalidArgumentException The given percentage is not between 0 and 100 + * + * @return string The hexadecimal color, with a leading # + */ + public function lighten($percentage) + { + $this->guardPercentage($percentage); + + $color = $this->currentColor(); + $steps = $this->convertBounds($percentage); + + return $this->adjustBrightness($color, $steps); + } + + /** + * Darken the current color for a given percentage, between 0 and 100. + * + * @param int $percentage + * + * @throws InvalidArgumentException The given percentage is not between 0 and 100 + * + * @return string The hexadecimal color, with a leading # + */ + public function darken($percentage) + { + $this->guardPercentage($percentage); + + $color = $this->currentColor(); + $steps = -1 * $this->convertBounds($percentage); + + return $this->adjustBrightness($color, $steps); + } + + /** + * Go from [0; 100] to [0; 255]. + * + * @param int $percentage + * + * @return int + */ + private function convertBounds($percentage) + { + return round($percentage / 100 * 255); + } + + /** + * Increment the color counter. + */ + private function incrementColorCounter() + { + // It was the last color, go back to the beginning + if (self::$currentKey == count($this->colors) - 1) { + self::$currentKey = 0; + } else { + self::$currentKey += 1; + } + } + + /** + * Check that a given percentage value is valid. + * + * @param int $percentage + * + * @throws InvalidArgumentException The given percentage is not between 0 and 100 + */ + private function guardPercentage($percentage) + { + if (!is_numeric($percentage) or $percentage < 0 or $percentage > 100) { + throw new InvalidArgumentException("Expected a percentage between 0 and 100. Got {$percentage}"); + } + } + + /** + * Lighten or darken a color from an hexadecimal code. + * + * @author http://stackoverflow.com/questions/3512311/how-to-generate-lighter-darker-color-with-php + * + * @param string $hex The color in hexadecimal + * @param int $steps Steps should be between -255 and 255. Negative = darker, positive = lighter + * + * @return string The hexadecimal color, with a leading # + */ + private function adjustBrightness($hex, $steps) + { + $steps = max(-255, min(255, $steps)); + + // Format the hex color string + $hex = str_replace('#', '', $hex); + if (strlen($hex) == 3) { + $hex = str_repeat(substr($hex, 0, 1), 2).str_repeat(substr($hex, 1, 1), 2).str_repeat(substr($hex, 2, 1), 2); + } + + // Get decimal values + $r = hexdec(substr($hex, 0, 2)); + $g = hexdec(substr($hex, 2, 2)); + $b = hexdec(substr($hex, 4, 2)); + + // Adjust number of steps and keep it inside 0 to 255 + $r = max(0, min(255, $r + $steps)); + $g = max(0, min(255, $g + $steps)); + $b = max(0, min(255, $b + $steps)); + + $r_hex = str_pad(dechex($r), 2, '0', STR_PAD_LEFT); + $g_hex = str_pad(dechex($g), 2, '0', STR_PAD_LEFT); + $b_hex = str_pad(dechex($b), 2, '0', STR_PAD_LEFT); + + return '#'.$r_hex.$g_hex.$b_hex; + } +} diff --git a/app/TeenQuotes/Tools/Colors/ColorGeneratorInterface.php b/app/TeenQuotes/Tools/Colors/ColorGeneratorInterface.php new file mode 100644 index 00000000..01bd95bb --- /dev/null +++ b/app/TeenQuotes/Tools/Colors/ColorGeneratorInterface.php @@ -0,0 +1,44 @@ +createForIos($array, $path); + if (Config::get('mobile.iOSApp')) { + $array = $this->createForIos($array, $path); + } - if (Config::get('mobile.androidApp')) - $array = $this->createForAndroid($array, $path); + if (Config::get('mobile.androidApp')) { + $array = $this->createForAndroid($array, $path); + } - return $array; - } + return $array; + } - /** - * Create deep links data for iOS - * - * @param array $data The original data - * @param string $path The current path - * @return array - */ - private function createForIos(array $data, $path) - { - $data['al:ios:url'] = $this->buildUrl($path); - $data['al:ios:app_store_id'] = Config::get('mobile.iOSAppID'); - $data['al:ios:app_name'] = Lang::get('layout.nameWebsite'); + /** + * Create deep links data for iOS. + * + * @param array $data The original data + * @param string $path The current path + * + * @return array + */ + private function createForIos(array $data, $path) + { + $data['al:ios:url'] = $this->buildUrl($path); + $data['al:ios:app_store_id'] = Config::get('mobile.iOSAppID'); + $data['al:ios:app_name'] = Lang::get('layout.nameWebsite'); - return $data; - } + return $data; + } - /** - * Create deep links data for Android - * - * @param array $data The original data - * @param string $path The current path - * @return array - */ - private function createForAndroid(array $data, $path) - { - $data['al:android:url'] = $this->buildUrl($path); - $data['al:android:app_name'] = Lang::get('layout.nameWebsite'); - $data['al:android:package'] = Config::get('mobile.androidPackage'); + /** + * Create deep links data for Android. + * + * @param array $data The original data + * @param string $path The current path + * + * @return array + */ + private function createForAndroid(array $data, $path) + { + $data['al:android:url'] = $this->buildUrl($path); + $data['al:android:app_name'] = Lang::get('layout.nameWebsite'); + $data['al:android:package'] = Config::get('mobile.androidPackage'); - return $data; - } + return $data; + } - /** - * Build a full URL - * - * @param string $path The current path - * @return string - */ - private function buildUrl($path) - { - // If the content is paginated, update the path - if (Input::has('page')) - $path = $path.'?page='.Input::get('page'); + /** + * Build a full URL. + * + * @param string $path The current path + * + * @return string + */ + private function buildUrl($path) + { + // If the content is paginated, update the path + if (Input::has('page')) { + $path = $path.'?page='.Input::get('page'); + } - return Config::get('mobile.deepLinksProtocol').$path; - } -} \ No newline at end of file + return Config::get('mobile.deepLinksProtocol').$path; + } +} diff --git a/app/TeenQuotes/Tools/Composers/DeepLinksComposer.php b/app/TeenQuotes/Tools/Composers/DeepLinksComposer.php index b58d3f39..dc87f841 100644 --- a/app/TeenQuotes/Tools/Composers/DeepLinksComposer.php +++ b/app/TeenQuotes/Tools/Composers/DeepLinksComposer.php @@ -1,13 +1,19 @@ -with('deepLinksArray', $this->createDeepLinks(Route::currentRouteName())); - } -} \ No newline at end of file +class DeepLinksComposer extends AbstractDeepLinksComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + // For deep links + $view->with('deepLinksArray', $this->createDeepLinks(Route::currentRouteName())); + } +} diff --git a/app/TeenQuotes/Tools/Composers/Interfaces/QuotesColorsExtractor.php b/app/TeenQuotes/Tools/Composers/Interfaces/QuotesColorsExtractor.php index 37de790c..e29100a5 100644 --- a/app/TeenQuotes/Tools/Composers/Interfaces/QuotesColorsExtractor.php +++ b/app/TeenQuotes/Tools/Composers/Interfaces/QuotesColorsExtractor.php @@ -1,12 +1,16 @@ -id => "color" for a collection of quotes - * Should also save this array in session - * @param \Illuminate\Database\Eloquent\Collection $quotes The quotes collection - * @return array The associative array - */ - public function extractAndStoreColors($quotes); -} \ No newline at end of file +interface QuotesColorsExtractor +{ + /** + * Extract associative array of #quote->id => "color" for a collection of quotes + * Should also save this array in session. + * + * @param \Illuminate\Database\Eloquent\Collection $quotes The quotes collection + * + * @return array The associative array + */ + public function extractAndStoreColors($quotes); +} diff --git a/app/TeenQuotes/Tools/Namespaces/NamespaceTrait.php b/app/TeenQuotes/Tools/Namespaces/NamespaceTrait.php index c4a21b55..4421152f 100644 --- a/app/TeenQuotes/Tools/Namespaces/NamespaceTrait.php +++ b/app/TeenQuotes/Tools/Namespaces/NamespaceTrait.php @@ -1,29 +1,32 @@ -getNamespaceName().'\\'; - } +trait NamespaceTrait +{ + public function getBaseNamespace() + { + $reflection = new ReflectionClass(__CLASS__); - public function __call($name, $arguments) - { - // Handle getNamespace with a directory name - if (Str::startsWith($name, 'getNamespace')) - { - $directory = str_replace('getNamespace', '', $name); + return $reflection->getNamespaceName().'\\'; + } - return $this->getBaseNamespace().$directory.'\\'; - } + public function __call($name, $arguments) + { + // Handle getNamespace with a directory name + if (Str::startsWith($name, 'getNamespace')) { + $directory = str_replace('getNamespace', '', $name); - // Return other calls - return call_user_func_array( - array($this, $name), - $arguments - ); - } -} \ No newline at end of file + return $this->getBaseNamespace().$directory.'\\'; + } + + // Return other calls + return call_user_func_array( + [$this, $name], + $arguments + ); + } +} diff --git a/app/TeenQuotes/Tools/TextTools.php b/app/TeenQuotes/Tools/TextTools.php index 49433ba3..9cf7b209 100644 --- a/app/TeenQuotes/Tools/TextTools.php +++ b/app/TeenQuotes/Tools/TextTools.php @@ -1,52 +1,58 @@ - '.$text.' '; - } + } - public static function formatNumber($number, $decimals=0) - { - $locale = localeconv(); + public static function formatNumber($number, $decimals = 0) + { + $locale = localeconv(); - return number_format($number, $decimals, - $locale['decimal_point'], - $locale['thousands_sep'] - ); - } + return number_format($number, $decimals, + $locale['decimal_point'], + $locale['thousands_sep'] + ); + } - /** - * Used to build a campagin link - * @param string $url The URL - * @param string $name Name of the campagin. e.g. spring promo - * @param string $medium Medium of the campagin. e.g. email / cpc - * @param string $source Source of the campagin. e.g. newsletter name - * @param string $content Used to differentiate ads or links that point to the same URL. e.g textlink / logolink - */ - public static function linkCampaign($url, $name, $medium, $source, $content) - { - return $url.'?utm_name='.$name.'&utm_medium='.$medium.'&utm_source='.$source.'&utm_content='.$content; - } + /** + * Used to build a campagin link. + * + * @param string $url The URL + * @param string $name Name of the campagin. e.g. spring promo + * @param string $medium Medium of the campagin. e.g. email / cpc + * @param string $source Source of the campagin. e.g. newsletter name + * @param string $content Used to differentiate ads or links that point to the same URL. e.g textlink / logolink + */ + public static function linkCampaign($url, $name, $medium, $source, $content) + { + return $url.'?utm_name='.$name.'&utm_medium='.$medium.'&utm_source='.$source.'&utm_content='.$content; + } - /** - * Go-To action that will be displayed in some email clients - * @param string $url URL to navigate to when user executes the action. - * @param string $name A user visible name that is shown in the user interface associated with the action. - * @param string $description Snippet of text describing the contents of the email. - */ - public static function textViewAction($url, $name, $description) - { - $html = ' + /** + * Go-To action that will be displayed in some email clients. + * + * @param string $url URL to navigate to when user executes the action. + * @param string $name A user visible name that is shown in the user interface associated with the action. + * @param string $description Snippet of text describing the contents of the email. + */ + public static function textViewAction($url, $name, $description) + { + $html = '
@@ -55,6 +61,6 @@ public static function textViewAction($url, $name, $description)
'; - return preg_replace("/\s+/", " ", $html); - } -} \ No newline at end of file + return preg_replace("/\s+/", ' ', $html); + } +} diff --git a/app/TeenQuotes/Tools/ToolsServiceProvider.php b/app/TeenQuotes/Tools/ToolsServiceProvider.php new file mode 100644 index 00000000..49748f40 --- /dev/null +++ b/app/TeenQuotes/Tools/ToolsServiceProvider.php @@ -0,0 +1,40 @@ +registerBindings(); + } + + private function registerBindings() + { + $this->app->bind(ColorGeneratorInterface::class, function () { + return new ColorGenerator(); + }); + } +} diff --git a/app/TeenQuotes/Tools/Validation/Validator.php b/app/TeenQuotes/Tools/Validation/Validator.php index 62ba5fd8..755fc06a 100644 --- a/app/TeenQuotes/Tools/Validation/Validator.php +++ b/app/TeenQuotes/Tools/Validation/Validator.php @@ -1,129 +1,127 @@ -validation = $this->make($data, $this->$rule, $messages); - - return $this->handleValidation(); - } - - /** - * Get the failed rule of an attribute for the current validator - * @param string $key The name of the attribute - * @return string - */ - public function getFailedReasonFor($key) - { - $failed = $this->validation->failed(); - - if (! array_key_exists($key, $failed)) - throw new InvalidArgumentException("Validator didn't failed for key: ".$key); - - return Str::slug($this->getFailedReasonForKey($failed, $key)); - } - - public function getRulesFor($rule, $key = null) - { - $ruleName = 'rules'.$rule; - $property = $this->$ruleName; - - $cleanedRules = $this->cleanProperties($property); - if (is_null($key)) - return $cleanedRules; - - return $cleanedRules[$key]; - } - - /** - * Magic call method to forward validate* methods - * @param string $name - * @param array $arguments - * @return mixed - * @throws BadMethodCallException - */ - public function __call($name, $arguments) - { - if (Str::startsWith($name, 'validate')) - { - $property = 'rules'.str_replace('validate', '', $name); - - if (! property_exists($this, $property)) - throw new BadMethodCallException("Property ".$property." does not exist on class ".get_class($this)."."); - - if (count($arguments) == 1) - return $this->validateForRule($arguments[0], $property); - - return $this->validateForRule($arguments[0], $property, $arguments[1]); - } - - // Return other calls - return call_user_func_array( - array($this, $name), - $arguments - ); - } - - private function getFailedReasonForKey($failed, $key) - { - return array_keys($failed[$key])[0]; - } - - private function cleanProperties($properties) - { - $out = []; - - foreach ($properties as $key => $value) - { - $out[$key] = $this->cleanRules($value); - } - - return $out; - } - - private function cleanRules($property) - { - $rules = explode('|', $property); - - $out = []; - foreach ($rules as $rule) - { - $out[] = explode(':', $rule)[0]; - } - - return $out; - } - - private function handleValidation() - { - if ($this->validation->fails()) - { - throw new FormValidationException( - $this->validation->errors()->first($this->getFirstKeyFail()), - $this->validation->errors() - ); - } - - return true; - } - - private function getFirstKeyFail() - { - $keys = array_keys($this->validation->errors()->getMessages()); - - return $keys[0]; - } -} \ No newline at end of file +use Str; + +abstract class Validator extends LaravelValidator +{ + /** + * Validate data against a set of rules. + * + * @param array $data The key-value data + * @param string $rule The name of the property for the rules + * @param array $messages + * + * @return bool + * + * @throws \Laracasts\Validation\FormValidationException + */ + protected function validateForRule($data, $rule, $messages = []) + { + $this->validation = $this->make($data, $this->$rule, $messages); + + return $this->handleValidation(); + } + + /** + * Get the failed rule of an attribute for the current validator. + * + * @param string $key The name of the attribute + * + * @return string + */ + public function getFailedReasonFor($key) + { + $failed = $this->validation->failed(); + + if (!array_key_exists($key, $failed)) { + throw new InvalidArgumentException("Validator didn't failed for key: ".$key); + } + + return Str::slug($this->getFailedReasonForKey($failed, $key)); + } + + /** + * Magic call method to forward validate* methods. + * + * @param string $name + * @param array $arguments + * + * @return mixed + * + * @throws BadMethodCallException + */ + public function __call($name, $arguments) + { + if (Str::startsWith($name, 'validate')) { + $property = 'rules'.str_replace('validate', '', $name); + + if (!property_exists($this, $property)) { + throw new BadMethodCallException('Property '.$property.' does not exist on class '.get_class($this).'.'); + } + + // No custom validation messages were given + if (count($arguments) == 1) { + return $this->validateForRule($arguments[0], $property); + } + + // Validate for a rule with custom validation messages + return $this->validateForRule($arguments[0], $property, $arguments[1]); + } + + // Forward other calls + return call_user_func_array( + [$this, $name], + $arguments + ); + } + + /** + * Get the failed raison for a given key. + * + * @param array $failed + * @param string $key + * + * @return string The failed rule for this key + */ + private function getFailedReasonForKey($failed, $key) + { + return array_keys($failed[$key])[0]; + } + + /** + * Perform validation when the validator has been bound. + * + * @return bool + * + * @throws FormValidationException When the validation has failed + */ + private function handleValidation() + { + if ($this->validation->fails()) { + throw new FormValidationException( + $this->validation->errors()->first($this->getFirstKeyFail()), + $this->validation->errors() + ); + } + + return true; + } + + /** + * Get the first failed key when validation has failed. + * + * @return string + */ + private function getFirstKeyFail() + { + $keys = array_keys($this->validation->errors()->getMessages()); + + return $keys[0]; + } +} diff --git a/app/TeenQuotes/Users/Composers/ProfileEditComposer.php b/app/TeenQuotes/Users/Composers/ProfileEditComposer.php index 99484c8c..1a7e1363 100644 --- a/app/TeenQuotes/Users/Composers/ProfileEditComposer.php +++ b/app/TeenQuotes/Users/Composers/ProfileEditComposer.php @@ -1,39 +1,48 @@ -getData(); - $user = $data['user']; - $login = $user->login; +class ProfileEditComposer extends AbstractDeepLinksComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + $user = $data['user']; + $login = $user->login; - // For deep links - $view->with('deepLinksArray', $this->createDeepLinks('users/'.$login.'/edit')); - $view->with('weeklyNewsletter', $user->isSubscribedToNewsletter('weekly')); - $view->with('dailyNewsletter', $user->isSubscribedToNewsletter('daily')); - $view->with('colorsAvailable', $this->createSelectColorsData()); - $view->with('possibleNewslettersTypes', Newsletter::getPossibleTypes()); - } + // For deep links + $view->with('deepLinksArray', $this->createDeepLinks('users/'.$login.'/edit')); + $view->with('weeklyNewsletter', $user->isSubscribedToNewsletter('weekly')); + $view->with('dailyNewsletter', $user->isSubscribedToNewsletter('daily')); + $view->with('colorsAvailable', $this->createSelectColorsData()); + $view->with('possibleNewslettersTypes', Newsletter::getPossibleTypes()); + } - /** - * Create an array like ['blue' => 'Blue', 'red' => 'Red'] - * @return array - */ - private function createSelectColorsData() - { - // Create an array like - // ['blue' => 'Blue', 'red' => 'Red'] - $colorsInConf = Config::get('app.users.colorsAvailableQuotesPublished'); - $func = function ($colorName) { - return Lang::get('colors.'.$colorName); - }; - $colorsAvailable = array_combine($colorsInConf, array_map($func, $colorsInConf)); + /** + * Create an array like ['blue' => 'Blue', 'red' => 'Red']. + * + * @return array + */ + private function createSelectColorsData() + { + // Create an array like + // ['blue' => 'Blue', 'red' => 'Red'] + $colorsInConf = Config::get('app.users.colorsAvailableQuotesPublished'); + $func = function ($colorName) { + return Lang::get('colors.'.$colorName); + }; + $colorsAvailable = array_combine($colorsInConf, array_map($func, $colorsInConf)); - return $colorsAvailable; - } -} \ No newline at end of file + return $colorsAvailable; + } +} diff --git a/app/TeenQuotes/Users/Composers/SearchUsersCountryComposer.php b/app/TeenQuotes/Users/Composers/SearchUsersCountryComposer.php index 91f0b3b8..1df6ba73 100644 --- a/app/TeenQuotes/Users/Composers/SearchUsersCountryComposer.php +++ b/app/TeenQuotes/Users/Composers/SearchUsersCountryComposer.php @@ -1,20 +1,28 @@ -getData(); - $country = $data['country']; - $countryName = $country->name; +class SearchUsersCountryComposer +{ + /** + * Add data to a view. + * + * @param \Illuminate\View\View $view + */ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + $country = $data['country']; + $countryName = $country->name; - $view->with('pageTitle', Lang::get('search.usersCountryPageTitle', compact('countryName'))); - $view->with('pageDescription', Lang::get('search.usersCountryPageDescription', compact('countryName'))); - } -} \ No newline at end of file + $view->with('pageTitle', Lang::get('search.usersCountryPageTitle', compact('countryName'))); + $view->with('pageDescription', Lang::get('search.usersCountryPageDescription', compact('countryName'))); + } +} diff --git a/app/TeenQuotes/Users/Composers/ShowComposer.php b/app/TeenQuotes/Users/Composers/ShowComposer.php index 0a4bcf0f..e52ab62b 100644 --- a/app/TeenQuotes/Users/Composers/ShowComposer.php +++ b/app/TeenQuotes/Users/Composers/ShowComposer.php @@ -1,74 +1,85 @@ -getData(); - $this->type = $data['type']; - $this->user = $data['user']; + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $data = $view->getData(); + $this->type = $data['type']; + $this->user = $data['user']; - $view->with('hideAuthorQuote', $this->type == 'published'); - $view->with('commentsCount', TextTools::formatNumber($this->user->getTotalComments())); - $view->with('addedFavCount', TextTools::formatNumber($this->user->getAddedFavCount())); - $view->with('quotesPublishedCount', TextTools::formatNumber($this->user->getPublishedQuotesCount())); - $view->with('favCount', TextTools::formatNumber($this->user->getFavoriteCount())); + $view->with('hideAuthorQuote', $this->type == 'published'); + $view->with('commentsCount', TextTools::formatNumber($this->user->getTotalComments())); + $view->with('addedFavCount', TextTools::formatNumber($this->user->getAddedFavCount())); + $view->with('quotesPublishedCount', TextTools::formatNumber($this->user->getPublishedQuotesCount())); + $view->with('favCount', TextTools::formatNumber($this->user->getFavoriteCount())); - // Extract colors for quotes - $view->with('colors', $this->extractAndStoreColors($data['quotes'])); + // Extract colors for quotes + $view->with('colors', $this->extractAndStoreColors($data['quotes'])); - // Register the visit of the profile - $this->registerVisit(); - } + // Register the visit of the profile + $this->registerVisit(); + } - private function registerVisit() - { - if (Auth::check()) - { - $user_id = $this->user->id; - $visitor_id = Auth::id(); + private function registerVisit() + { + if (Auth::check()) { + $user_id = $this->user->id; + $visitor_id = Auth::id(); - if ($user_id != $visitor_id) - Queue::push(ProfileVisitorWorker::class.'@viewProfile', compact('user_id', 'visitor_id')); - } - } + if ($user_id != $visitor_id) { + Queue::push(ProfileVisitorWorker::class.'@viewProfile', compact('user_id', 'visitor_id')); + } + } + } - public function extractAndStoreColors($quotes) - { - if (! ($quotes instanceof Collection)) - $quotes = new Collection($quotes); + public function extractAndStoreColors($quotes) + { + if (!($quotes instanceof Collection)) { + $quotes = new Collection($quotes); + } - $colors = []; + $colors = []; - switch ($this->type) - { - case 'favorites': - $colors = Quote::storeQuotesColors($quotes->lists('id')); - break; + switch ($this->type) { + case 'favorites': + $colors = Quote::storeQuotesColors($quotes->lists('id')); + break; - case 'published': - $colors = Quote::storeQuotesColors($quotes->lists('id'), $this->user->getColorsQuotesPublished()); - break; - } + case 'published': + $colors = Quote::storeQuotesColors($quotes->lists('id'), $this->user->getColorsQuotesPublished()); + break; + } - return $colors; - } -} \ No newline at end of file + return $colors; + } +} diff --git a/app/TeenQuotes/Users/Composers/WelcomeComposer.php b/app/TeenQuotes/Users/Composers/WelcomeComposer.php index 8902d468..0cb58e3c 100644 --- a/app/TeenQuotes/Users/Composers/WelcomeComposer.php +++ b/app/TeenQuotes/Users/Composers/WelcomeComposer.php @@ -1,42 +1,51 @@ -getData(); - $login = $viewData['user']->login; - $type = $viewData['type']; - - $welcomeText = Lang::get('users.newUserWelcomeProfile', ['login' => $login]); - - $updateProfileTitle = Lang::get('users.newUserTutorialProfileTitle'); - $updateProfileContent = Lang::get('users.newUserTutorialProfileContent', ['url' => URL::route('users.edit', $login)]); +namespace TeenQuotes\Users\Composers; - $addingQuoteTitle = Lang::get('users.newUserTutorialAddingQuoteTitle'); - $addingQuoteContent = Lang::get('users.newUserTutorialAddingQuoteContent', ['url' => URL::route('addquote')]); - - $addingFavoritesTitle = Lang::get('users.newUserTutorialFavoritesTitle'); - $addingFavoritesContent = Lang::get('users.newUserTutorialFavoritesContent'); - - $editSettingsTitle = Lang::get('users.newUserTutorialSettingsTitle'); - $editSettingsContent = Lang::get('users.newUserTutorialSettingsContent', ['url' => URL::route('users.edit', $login)."#edit-settings"]); - - // Content - $view->with('welcomeText', $welcomeText); - $view->with('updateProfileTitle', $updateProfileTitle); - $view->with('updateProfileContent', $updateProfileContent); - $view->with('addingQuoteTitle', $addingQuoteTitle); - $view->with('addingQuoteContent', $addingQuoteContent); - $view->with('addingFavoritesTitle', $addingFavoritesTitle); - $view->with('addingFavoritesContent', $addingFavoritesContent); - $view->with('editSettingsTitle', $editSettingsTitle); - $view->with('editSettingsContent', $editSettingsContent); - - // For deep links - $view->with('deepLinksArray', $this->createDeepLinks('users/'.$login.'/'.$type)); - } -} \ No newline at end of file +use Lang; +use Route; +use TeenQuotes\Tools\Composers\AbstractDeepLinksComposer; +use URL; + +class WelcomeComposer extends AbstractDeepLinksComposer +{ + /** + * Add data to the view. + * + * @param \Illuminate\View\View $view + */ + public function compose($view) + { + $viewData = $view->getData(); + $login = $viewData['user']->login; + $type = $viewData['type']; + + $welcomeText = Lang::get('users.newUserWelcomeProfile', ['login' => $login]); + + $updateProfileTitle = Lang::get('users.newUserTutorialProfileTitle'); + $updateProfileContent = Lang::get('users.newUserTutorialProfileContent', ['url' => URL::route('users.edit', $login)]); + + $addingQuoteTitle = Lang::get('users.newUserTutorialAddingQuoteTitle'); + $addingQuoteContent = Lang::get('users.newUserTutorialAddingQuoteContent', ['url' => URL::route('addquote')]); + + $addingFavoritesTitle = Lang::get('users.newUserTutorialFavoritesTitle'); + $addingFavoritesContent = Lang::get('users.newUserTutorialFavoritesContent'); + + $editSettingsTitle = Lang::get('users.newUserTutorialSettingsTitle'); + $editSettingsContent = Lang::get('users.newUserTutorialSettingsContent', ['url' => URL::route('users.edit', $login).'#edit-settings']); + + // Content + $view->with('welcomeText', $welcomeText); + $view->with('updateProfileTitle', $updateProfileTitle); + $view->with('updateProfileContent', $updateProfileContent); + $view->with('addingQuoteTitle', $addingQuoteTitle); + $view->with('addingQuoteContent', $addingQuoteContent); + $view->with('addingFavoritesTitle', $addingFavoritesTitle); + $view->with('addingFavoritesContent', $addingFavoritesContent); + $view->with('editSettingsTitle', $editSettingsTitle); + $view->with('editSettingsContent', $editSettingsContent); + + // For deep links + $view->with('deepLinksArray', $this->createDeepLinks('users/'.$login.'/'.$type)); + } +} diff --git a/app/TeenQuotes/Users/Console/EmailSpecialEventCommand.php b/app/TeenQuotes/Users/Console/EmailSpecialEventCommand.php index ad87a4cf..dcda1ebb 100644 --- a/app/TeenQuotes/Users/Console/EmailSpecialEventCommand.php +++ b/app/TeenQuotes/Users/Console/EmailSpecialEventCommand.php @@ -1,181 +1,183 @@ -userRepo = $userRepo; - $this->userMailer = $userMailer; - } - - /** - * When a command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return array - */ - public function schedule(Schedulable $scheduler) - { - return [ - $scheduler - ->args(['newyear']) - ->months(1) - ->daysOfTheMonth(1) - ->hours(4) - ->minutes(15), - - $scheduler - ->args(['christmas']) - ->months(12) - ->daysOfTheMonth(25) - ->hours(4) - ->minutes(15), - ]; - } - - /** - * Choose the environment(s) where the command should run - * @return array Array of environments' name - */ - public function environment() - { - return ['production']; - } - - /** - * Execute the console command. - */ - public function fire() - { - if ($this->eventTypeIsValid()) - { - $event = $this->getEvent(); - - // Retrieve users that have logged in the last year - $allUsers = $this->userRepo->getLoggedInSince(Carbon::now()->subYear(1), 1, 2000); - - $delay = Carbon::now()->addMinutes(5); - $i = 1; - // We will send 60 emails every hour - foreach ($allUsers->chunk(60) as $users) - { - $driver = $this->determineMailDriver($i); - - $users->each(function($user) use($event, $delay, $driver) - { - // Log this info - $this->log("Scheduled email for event ".$event." to ".$user->login." - ".$user->email." for ".$delay->toDateTimeString()); - - // Add the email to the queue - $this->userMailer->sendEvent($event, $user, $driver, $delay); - }); - - $i++; - $delay->addHour(); - } - } - } - - private function determineMailDriver($i) - { - if ($i > 1000) - return null; - - return 'smtp'; - } - - private function log($string) - { - $this->info($string); - Log::info($string); - } - - private function eventTypeIsValid() - { - $event = $this->getEvent(); - - if (is_null($event) or ! in_array($event, $this->possibleEvents)) - { - $this->error('Wrong type of event! Got '.$event.'. Possible values are: '.$this->presentPossibleEvents().'.'); - return false; - } - - return true; - } - - private function getEvent() - { - return $this->argument('event'); - } - - private function presentPossibleEvents() - { - return implode('|', $this->possibleEvents); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return [ - ['event', InputArgument::REQUIRED, 'The name of the event. '.$this->presentPossibleEvents()], - ]; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } +class EmailSpecialEventCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'emailevent:send'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Send an email to all users for a special event.'; + + /** + * Allowed newsletter types. + * + * @var array + */ + private $possibleEvents = ['christmas', 'newyear']; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + /** + * Create a new command instance. + */ + public function __construct(UserRepository $userRepo, UserMailer $userMailer) + { + parent::__construct(); + + $this->userRepo = $userRepo; + $this->userMailer = $userMailer; + } + + /** + * When a command should run. + * + * @param \Indatus\Dispatcher\Scheduling\Schedulable + * + * @return array + */ + public function schedule(Schedulable $scheduler) + { + return [ + $scheduler + ->args(['newyear']) + ->months(1) + ->daysOfTheMonth(1) + ->hours(4) + ->minutes(15), + + $scheduler + ->args(['christmas']) + ->months(12) + ->daysOfTheMonth(25) + ->hours(4) + ->minutes(15), + ]; + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production']; + } + + /** + * Execute the console command. + */ + public function fire() + { + if ($this->eventTypeIsValid()) { + $event = $this->getEvent(); + + // Retrieve users that have logged in the last year + $allUsers = $this->userRepo->getLoggedInSince(Carbon::now()->subYear(1), 1, 2000); + + $delay = Carbon::now()->addMinutes(5); + $i = 1; + // We will send 60 emails every hour + foreach ($allUsers->chunk(60) as $users) { + $driver = $this->determineMailDriver($i); + + $users->each(function ($user) use ($event, $delay, $driver) { + // Log this info + $this->log('Scheduled email for event '.$event.' to '.$user->login.' - '.$user->email.' for '.$delay->toDateTimeString()); + + // Add the email to the queue + $this->userMailer->sendEvent($event, $user, $driver, $delay); + }); + + $i++; + $delay->addHour(); + } + } + } + + private function determineMailDriver($i) + { + if ($i > 1000) { + return null; + } + + return 'smtp'; + } + + private function log($string) + { + $this->info($string); + Log::info($string); + } + + private function eventTypeIsValid() + { + $event = $this->getEvent(); + + if (is_null($event) or !in_array($event, $this->possibleEvents)) { + $this->error('Wrong type of event! Got '.$event.'. Possible values are: '.$this->presentPossibleEvents().'.'); + + return false; + } + + return true; + } + + private function getEvent() + { + return $this->argument('event'); + } + + private function presentPossibleEvents() + { + return implode('|', $this->possibleEvents); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['event', InputArgument::REQUIRED, 'The name of the event. '.$this->presentPossibleEvents()], + ]; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } } diff --git a/app/TeenQuotes/Users/Console/SendBirthdayCommand.php b/app/TeenQuotes/Users/Console/SendBirthdayCommand.php index 14757bb3..a919af14 100644 --- a/app/TeenQuotes/Users/Console/SendBirthdayCommand.php +++ b/app/TeenQuotes/Users/Console/SendBirthdayCommand.php @@ -1,113 +1,114 @@ -userRepo = $userRepo; - $this->userMailer = $userMailer; - } - - /** - * When a command should run - * - * @param \Indatus\Dispatcher\Scheduling\Schedulable - * @return \Indatus\Dispatcher\Scheduling\Schedulable - */ - public function schedule(Schedulable $scheduler) - { - return $scheduler - ->daily() - ->hours(12) - ->minutes(30); - } - - /** - * Choose the environment(s) where the command should run - * @return array Array of environments' name - */ - public function environment() - { - return ['production']; - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function fire() - { - $users = $this->userRepo->birthdayToday(); - - $users->each(function($user) - { - $this->log("Wishing happy birthday to ".$user->login." - ".$user->email); - - $this->userMailer->wishHappyBirthday($user); - }); - } - - private function log($string) - { - $this->info($string); - Log::info($string); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return []; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return []; - } +class SendBirthdayCommand extends ScheduledCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'birthday:send'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Whish happy birthday to the concerned users.'; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + /** + * Create a new command instance. + */ + public function __construct(UserRepository $userRepo, UserMailer $userMailer) + { + parent::__construct(); + + $this->userRepo = $userRepo; + $this->userMailer = $userMailer; + } + + /** + * When a command should run. + * + * @param \Indatus\Dispatcher\Scheduling\Schedulable + * + * @return \Indatus\Dispatcher\Scheduling\Schedulable + */ + public function schedule(Schedulable $scheduler) + { + return $scheduler + ->daily() + ->hours(12) + ->minutes(30); + } + + /** + * Choose the environment(s) where the command should run. + * + * @return array Array of environments' name + */ + public function environment() + { + return ['production']; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + $users = $this->userRepo->birthdayToday(); + + $users->each(function ($user) { + $this->log('Wishing happy birthday to '.$user->login.' - '.$user->email); + + $this->userMailer->wishHappyBirthday($user); + }); + } + + private function log($string) + { + $this->info($string); + Log::info($string); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } } diff --git a/app/TeenQuotes/Users/Controllers/UsersController.php b/app/TeenQuotes/Users/Controllers/UsersController.php index b9904ee8..1ca55b5d 100644 --- a/app/TeenQuotes/Users/Controllers/UsersController.php +++ b/app/TeenQuotes/Users/Controllers/UsersController.php @@ -1,9 +1,19 @@ -beforeFilter('guest', ['only' => 'store']); - $this->beforeFilter('auth', ['only' => ['edit', 'update', 'putPassword', 'putSettings']]); - - $this->api = App::make(UsersAPIController::class); - $this->commentRepo = $commentRepo; - $this->countryRepo = $countryRepo; - $this->localisationDetector = $localisationDetector; - $this->favQuoteRepo = $favQuoteRepo; - $this->quoteRepo = $quoteRepo; - $this->settingRepo = $settingRepo; - $this->userRepo = $userRepo; - $this->userValidator = $userValidator; - } - - public function redirectOldUrl($userId) - { - $user = $this->userRepo->getById($userId); - - if (is_null($user)) - return $this->notFound(); - - return Redirect::route('users.show', $user->login, 301); - } - - /** - * Throw a "not found" exception - * - * @throws \TeenQuotes\Exceptions\UserNotFoundException - */ - public function notFound() - { - throw new UserNotFoundException; - } - - /** - * Displays the signup form - * - * @return \Response - */ - public function getSignup() - { - $data = [ - 'pageTitle' => Lang::get('auth.signupPageTitle'), - 'pageDescription' => Lang::get('auth.signupPageDescription'), - ]; - - return View::make('auth.signup', $data); - } - - public function postLoginValidator() - { - $data = Input::only(['login']); - - try { - $this->userValidator->validateLogin($data); - } - catch (FormValidationException $e) - { - return Response::json([ - 'success' => false, - 'message' => $e->getErrors()->first('login'), - 'failed' => $this->userValidator->getFailedReasonFor('login'), - ]); - } - - return Response::json([ - 'success' => true, - 'message' => $data['login'].'? '.Lang::get('auth.loginAwesome'), - ]); - } - - /** - * Store a newly created resource in storage. - * - * @return \Response - */ - public function store() - { - $data = Input::only(['login', 'password', 'email']); - - // Check if the form validates with success. - $this->userValidator->validateSignup($data); - - // Call the API - skip the API validator - $response = $this->api->store(false); - if ($response->getStatusCode() == 201) - { - // Log the user in - Auth::login($response->getOriginalData()); - - if (Session::has('url.intended')) - return Redirect::intended(route('home'))->with('success', Lang::get('auth.signupSuccessfull', ['login' => $data['login']])); - - return Redirect::route('users.show', $data['login'])->with('success', Lang::get('auth.signupSuccessfull', ['login' => $data['login']])); - } - } - - /** - * Redirect the user to a place where we have content to show if possible - * @param \TeenQuotes\Users\Models\User $user The user - * @param string $type The requested type to show - * @return \Response|null If null is returned, we can't find a better place to show content - */ - private function redirectUserIfContentNotAvailable($user, $type) - { - // Check where we can redirect the user - $publishPossible = $user->hasPublishedQuotes(); - $favoritesPossible = $user->hasFavoriteQuotes(); - $commentsPossible = $user->hasPostedComments(); - - // Check if we have content to display - // If we have nothing to show, try to redirect somewhere else - switch ($type) { - case 'favorites': - if ( ! $favoritesPossible) - { - if ($publishPossible) - return Redirect::route('users.show', $user->login); - if ($commentsPossible) - return Redirect::route('users.show', [$user->login, 'comments']); - } - break; - - case 'comments': - if ( ! $commentsPossible) - { - if ($publishPossible) - return Redirect::route('users.show', $user->login); - if ($favoritesPossible) - return Redirect::route('users.show', [$user->login, 'favorites']); - } - break; - - // Asked for published quotes - case 'published': - if ( ! $publishPossible) - { - if ($favoritesPossible) - return Redirect::route('users.show', [$user->login, 'favorites']); - if ($commentsPossible) - return Redirect::route('users.show', [$user->login, 'comments']); - } - } - - return null; - } - - private function userViewingSelfProfile($user) - { - return (Auth::check() AND Auth::user()->login == $user->login); - } - - /** - * Display the specified resource. - * - * @param string $user_id The login of the user - * @param string $type Can be 'favorites'|'comments'|'published' - * @return \Response - */ - public function show($user_id, $type = 'published') - { - // Get the user - $user = $this->userRepo->getByLogin($user_id); - - if (is_null($user)) throw new UserNotFoundException; - - // Register the view in the recommendation system - $user->registerViewUserProfile(); - - // Try to redirect to a better place if content is available - $redirect = $this->redirectUserIfContentNotAvailable($user, $type); - if ( ! is_null($redirect)) - return $redirect; - - // Throw an exception if the user has an hidden profile - // We do not throw this exception if the user is currently - // viewing its own hidden profile - if ($user->isHiddenProfile() AND ! $this->userViewingSelfProfile($user)) - throw new HiddenProfileException; - - // Build the data array. Keys: quotes, paginator - $methodName = 'dataShow'.ucfirst($type); - $data = $this->$methodName($user); - - $data['user'] = $user; - // Used for deep linking in ProfileComposer - $data['type'] = $type; - $data['viewingSelfProfile'] = $this->userViewingSelfProfile($user); - $data['pageTitle'] = Lang::get('users.profilePageTitle', ['login' => $user->login]); - $data['pageDescription'] = Lang::get('users.profilePageDescription', ['login' => $user->login]); - - // If the user is new and is viewing its own profile, a small welcome tutorial - if ($this->shouldDisplayWelcomeTutorial($data['quotes'], $user)) - return View::make('users.welcome', $data); - - return View::make('users.show', $data); - } - - private function shouldDisplayWelcomeTutorial($quotes, $user) - { - return ( - (empty($quotes) OR (($quotes instanceof Collection) AND $quotes->isEmpty())) - AND $this->userViewingSelfProfile($user) - ); - } - - private function dataShowFavorites(User $user) - { - $pageNumber = Input::get('page', 1); - - // Get the list of favorite quotes - $quotesFavorited = $this->favQuoteRepo->quotesFavoritesForUser($user); - - // Fetch the quotes - $quotes = $this->quoteRepo->getForIds($quotesFavorited, $pageNumber, Config::get('app.users.nbQuotesPerPage')); - - // Build the associated paginator - $paginator = Paginator::make($quotes->toArray(), count($quotesFavorited), Config::get('app.users.nbQuotesPerPage')); - $paginator->setBaseUrl(URL::route('users.show', [$user->login, 'favorites'], false)); - - return compact('quotes', 'paginator'); - } - - private function dataShowComments(User $user) - { - $page = Input::get('page', 1); - - $comments = $this->commentRepo->findForUser($user, $page, Config::get('app.users.nbQuotesPerPage')); - - // Build the associated paginator - $paginator = Paginator::make($comments->toArray(), $user->getTotalComments(), Config::get('app.users.nbQuotesPerPage')); - $paginator->setBaseUrl(URL::route('users.show', [$user->login, 'comments'], false)); - - return [ - 'quotes' => $comments, - 'paginator' => $paginator, - ]; - } - - private function dataShowPublished(User $user) - { - $pageNumber = Input::get('page', 1); - - $quotes = $this->quoteRepo->getQuotesByApprovedForUser($user, 'published', $pageNumber, Config::get('app.users.nbQuotesPerPage')); - - $numberQuotesPublishedForUser = $user->getPublishedQuotesCount(); - - // Build the associated paginator - $paginator = Paginator::make($quotes->toArray(), $numberQuotesPublishedForUser, Config::get('app.users.nbQuotesPerPage')); - - return compact('quotes', 'paginator'); - } - - /** - * Show the form for editing the specified resource. - * - * @param string $id The login of the user - * @throws TeenQuotes\Exceptions\UserNotFoundException - * @return \Response - */ - public function edit($id) - { - $user = $this->userRepo->getByLogin($id); - - if (is_null($user) OR ! $this->userIsAllowedToEdit($user)) - throw new UserNotFoundException; - - // The color for published quotes - $confColor = $this->settingRepo->findForUserAndKey($user, 'colorsQuotesPublished'); - - // Set the default color - if (is_null($confColor)) - $selectedColor = Config::get('app.users.defaultColorQuotesPublished'); - else - $selectedColor = $confColor->value; - - list($selectedCountry, $selectedCity) = $this->getCountryAndCity($user); - - $data = [ - 'gender' => $user->gender, - 'listCountries' => $this->countryRepo->listNameAndId(), - 'selectedCountry' => $selectedCountry, - 'selectedCity' => $selectedCity, - 'user' => $user, - 'selectedColor' => $selectedColor, - 'pageTitle' => Lang::get('users.editPageTitle'), - 'pageDescription' => Lang::get('users.editPageDescription'), - ]; - - return View::make('users.edit', $data); - } - - /** - * Get country and city for a given user. If we have no information, try to guess it! - * @param \TeenQuotes\Users\Models\User $user The user model - * @return array The country and the city - */ - private function getCountryAndCity(User $user) - { - $request = Input::instance(); - - // If the user hasn't filled its country yet we will try to auto-detect it - // If it's not possible, we will fall back to the most common country: the USA - $selectedCountry = is_null($user->country) ? $this->localisationDetector->detectCountry($request) : $user->country; - - // If the user hasn't filled its city yet we will try to auto-detect it - if (empty(Input::old('city')) AND is_null($user->city)) - $selectedCity = $this->localisationDetector->detectCity($request); - else - $selectedCity = Input::old('city'); - - return [$selectedCountry, $selectedCity]; - } - - private function userIsAllowedToEdit($user) - { - return ($user->login == Auth::user()->login); - } - - /** - * Update the specified resource in storage. - * - * @param string $id The login of the user - * @return \Response - */ - public function update($id) - { - $data = [ - 'gender' => Input::get('gender'), - 'birthdate' => Input::get('birthdate'), - 'country' => Input::get('country'), - 'city' => Input::get('city'), - 'about_me' => Input::get('about_me'), - 'avatar' => Input::file('avatar'), - ]; - - $this->userValidator->validateUpdateProfile($data); - - // Call the API - $response = $this->api->putProfile(false); - if ($response->getStatusCode() == 200) - return Redirect::back()->with('success', Lang::get('users.updateProfileSuccessfull', ['login' => Auth::user()->login])); - - App::abort(500, "Can't update profile"); - } - - /** - * Update the password in storage - * - * @param string $id The login of the user - * @return \Response - */ - public function putPassword($id) - { - $data = Input::only(['password', 'password_confirmation']); - - try { - $this->userValidator->validateUpdatePassword($data); - } - catch (FormValidationException $e) { - return Redirect::to(URL::route('users.edit', Auth::user()->login)."#edit-password") - ->withErrors($e->getErrors()) - ->withInput(Input::all()); - } - - $user = $this->userRepo->getByLogin($id); - if (! $this->userIsAllowedToEdit($user)) - App::abort(401, 'Refused'); - - $this->userRepo->updatePassword($user, $data['password']); - - return Redirect::back()->with('success', Lang::get('users.updatePasswordSuccessfull', ['login' => $user->login])); - } - - /** - * Update settings for the user - * - * @param string $id The login of the user - * @return \Response - */ - public function putSettings($id) - { - $user = $this->userRepo->getByLogin($id); - if ( ! $this->userIsAllowedToEdit($user)) - App::abort(401, 'Refused'); - - $response = $this->api->putSettings($user); - - // Handle error - if ($response->getStatusCode() == 400) { - $json = json_decode($response->getContent()); - - // If the color was wrong - if ($json->status == 'wrong_color') - return Redirect::back()->with('warning', Lang::get('users.colorNotAllowed')); - } - - if ($response->getStatusCode() == 200) - return Redirect::back()->with('success', Lang::get('users.updateSettingsSuccessfull', ['login' => $user->login])); - } - - /** - * Remove the specified resource from storage. - * - * @return \Response - */ - public function destroy() - { - $data = [ - 'password' => Input::get('password'), - 'delete-confirmation' => Input::get('delete-confirmation'), - 'login' => Auth::user()->login - ]; - - // We will use a custom message for the delete confirmation input - $messages = [ - 'delete-confirmation.in' => Lang::get('users.writeDeleteHere'), - ]; - - try { - $this->userValidator->validateDestroy($data, $messages); - } - catch (FormValidationException $e) - { - return $this->redirectToDeleteAccount(Auth::user()->login) - ->withErrors($e->getErrors()) - ->withInput(Input::except('password')); - } - - unset($data['delete-confirmation']); - if ( ! Auth::validate($data)) - return $this->redirectToDeleteAccount(Auth::user()->login) - ->withErrors(['password' => Lang::get('auth.passwordInvalid')]) - ->withInput(Input::except('password')); - - // Delete the user - $this->api->destroy(); - - return Redirect::home()->with('success', Lang::get('users.deleteAccountSuccessfull')); - } - - private function redirectToDeleteAccount($login) - { - return Redirect::to(URL::route('users.edit', $login)."#delete-account"); - } +use URL; +use View; + +class UsersController extends BaseController +{ + /** + * @var \TeenQuotes\Api\V1\Controllers\UsersController + */ + private $api; + + /** + * @var \TeenQuotes\Comments\Repositories\CommentRepository + */ + private $commentRepo; + + /** + * @var \TeenQuotes\Countries\Repositories\CountryRepository + */ + private $countryRepo; + + /** + * @var \TeenQuotes\Countries\Localisation\Detector + */ + private $localisationDetector; + + /** + * @var \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + private $favQuoteRepo; + + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + /** + * @var \TeenQuotes\Settings\Repositories\SettingRepository + */ + private $settingRepo; + + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + /** + * @var \TeenQuotes\Users\Validation\UserValidator + */ + private $userValidator; + + public function __construct(CommentRepository $commentRepo, CountryRepository $countryRepo, + Detector $localisationDetector, FavoriteQuoteRepository $favQuoteRepo, + QuoteRepository $quoteRepo, SettingRepository $settingRepo, UserRepository $userRepo, + UserValidator $userValidator) + { + $this->beforeFilter('guest', ['only' => 'store']); + $this->beforeFilter('auth', ['only' => ['edit', 'update', 'putPassword', 'putSettings']]); + + $this->api = App::make(UsersAPIController::class); + $this->commentRepo = $commentRepo; + $this->countryRepo = $countryRepo; + $this->localisationDetector = $localisationDetector; + $this->favQuoteRepo = $favQuoteRepo; + $this->quoteRepo = $quoteRepo; + $this->settingRepo = $settingRepo; + $this->userRepo = $userRepo; + $this->userValidator = $userValidator; + } + + public function redirectOldUrl($userId) + { + $user = $this->userRepo->getById($userId); + + if (is_null($user)) { + return $this->notFound(); + } + + return Redirect::route('users.show', $user->login, 301); + } + + /** + * Throw a "not found" exception. + * + * @throws \TeenQuotes\Exceptions\UserNotFoundException + */ + public function notFound() + { + throw new UserNotFoundException(); + } + + /** + * Displays the signup form. + * + * @return \Response + */ + public function getSignup() + { + $data = [ + 'pageTitle' => Lang::get('auth.signupPageTitle'), + 'pageDescription' => Lang::get('auth.signupPageDescription'), + ]; + + return View::make('auth.signup', $data); + } + + public function postLoginValidator() + { + $data = Input::only(['login']); + + try { + $this->userValidator->validateLogin($data); + } catch (FormValidationException $e) { + return Response::json([ + 'success' => false, + 'message' => $e->getErrors()->first('login'), + 'failed' => $this->userValidator->getFailedReasonFor('login'), + ]); + } + + return Response::json([ + 'success' => true, + 'message' => $data['login'].'? '.Lang::get('auth.loginAwesome'), + ]); + } + + /** + * Store a newly created resource in storage. + * + * @return \Response + */ + public function store() + { + $data = Input::only(['login', 'password', 'email']); + + // Check if the form validates with success. + $this->userValidator->validateSignup($data); + + // Call the API - skip the API validator + $response = $this->api->store(false); + if ($response->getStatusCode() == 201) { + // Log the user in + Auth::login($response->getOriginalData()); + + if (Session::has('url.intended')) { + return Redirect::intended(route('home'))->with('success', Lang::get('auth.signupSuccessfull', ['login' => $data['login']])); + } + + return Redirect::route('users.show', $data['login'])->with('success', Lang::get('auth.signupSuccessfull', ['login' => $data['login']])); + } + } + + /** + * Redirect the user to a place where we have content to show if possible. + * + * @param \TeenQuotes\Users\Models\User $user The user + * @param string $type The requested type to show + * + * @return \Response|null If null is returned, we can't find a better place to show content + */ + private function redirectUserIfContentNotAvailable($user, $type) + { + // Check where we can redirect the user + $publishPossible = $user->hasPublishedQuotes(); + $favoritesPossible = $user->hasFavoriteQuotes(); + $commentsPossible = $user->hasPostedComments(); + + // Check if we have content to display + // If we have nothing to show, try to redirect somewhere else + switch ($type) { + case 'favorites': + if (!$favoritesPossible) { + if ($publishPossible) { + return Redirect::route('users.show', $user->login); + } + if ($commentsPossible) { + return Redirect::route('users.show', [$user->login, 'comments']); + } + } + break; + + case 'comments': + if (!$commentsPossible) { + if ($publishPossible) { + return Redirect::route('users.show', $user->login); + } + if ($favoritesPossible) { + return Redirect::route('users.show', [$user->login, 'favorites']); + } + } + break; + + // Asked for published quotes + case 'published': + if (!$publishPossible) { + if ($favoritesPossible) { + return Redirect::route('users.show', [$user->login, 'favorites']); + } + if ($commentsPossible) { + return Redirect::route('users.show', [$user->login, 'comments']); + } + } + } + + return null; + } + + private function userViewingSelfProfile($user) + { + return (Auth::check() and Auth::user()->login == $user->login); + } + + /** + * Display the specified resource. + * + * @param string $user_id The login of the user + * @param string $type Can be 'favorites'|'comments'|'published' + * + * @return \Response + */ + public function show($user_id, $type = 'published') + { + // Get the user + $user = $this->userRepo->getByLogin($user_id); + + if (is_null($user)) { + throw new UserNotFoundException(); + } + + // Register the view in the recommendation system + $user->registerViewUserProfile(); + + // Try to redirect to a better place if content is available + $redirect = $this->redirectUserIfContentNotAvailable($user, $type); + if (!is_null($redirect)) { + return $redirect; + } + + // Throw an exception if the user has an hidden profile + // We do not throw this exception if the user is currently + // viewing its own hidden profile + if ($user->isHiddenProfile() and !$this->userViewingSelfProfile($user)) { + throw new HiddenProfileException(); + } + + // Build the data array. Keys: quotes, paginator + $methodName = 'dataShow'.ucfirst($type); + $data = $this->$methodName($user); + + $data['user'] = $user; + // Used for deep linking in ProfileComposer + $data['type'] = $type; + $data['viewingSelfProfile'] = $this->userViewingSelfProfile($user); + $data['pageTitle'] = Lang::get('users.profilePageTitle', ['login' => $user->login]); + $data['pageDescription'] = Lang::get('users.profilePageDescription', ['login' => $user->login]); + + // If the user is new and is viewing its own profile, a small welcome tutorial + if ($this->shouldDisplayWelcomeTutorial($data['quotes'], $user)) { + return View::make('users.welcome', $data); + } + + return View::make('users.show', $data); + } + + private function shouldDisplayWelcomeTutorial($quotes, $user) + { + return ( + (empty($quotes) or (($quotes instanceof Collection) and $quotes->isEmpty())) + and $this->userViewingSelfProfile($user) + ); + } + + private function dataShowFavorites(User $user) + { + $pageNumber = Input::get('page', 1); + + // Get the list of favorite quotes + $quotesFavorited = $this->favQuoteRepo->quotesFavoritesForUser($user); + + // Fetch the quotes + $quotes = $this->quoteRepo->getForIds($quotesFavorited, $pageNumber, Config::get('app.users.nbQuotesPerPage')); + + // Build the associated paginator + $paginator = Paginator::make($quotes->toArray(), count($quotesFavorited), Config::get('app.users.nbQuotesPerPage')); + $paginator->setBaseUrl(URL::route('users.show', [$user->login, 'favorites'], false)); + + return compact('quotes', 'paginator'); + } + + private function dataShowComments(User $user) + { + $page = Input::get('page', 1); + + $comments = $this->commentRepo->findForUser($user, $page, Config::get('app.users.nbQuotesPerPage')); + + // Build the associated paginator + $paginator = Paginator::make($comments->toArray(), $user->getTotalComments(), Config::get('app.users.nbQuotesPerPage')); + $paginator->setBaseUrl(URL::route('users.show', [$user->login, 'comments'], false)); + + return [ + 'quotes' => $comments, + 'paginator' => $paginator, + ]; + } + + private function dataShowPublished(User $user) + { + $pageNumber = Input::get('page', 1); + + $quotes = $this->quoteRepo->getQuotesByApprovedForUser($user, 'published', $pageNumber, Config::get('app.users.nbQuotesPerPage')); + + $numberQuotesPublishedForUser = $user->getPublishedQuotesCount(); + + // Build the associated paginator + $paginator = Paginator::make($quotes->toArray(), $numberQuotesPublishedForUser, Config::get('app.users.nbQuotesPerPage')); + + return compact('quotes', 'paginator'); + } + + /** + * Show the form for editing the specified resource. + * + * @param string $id The login of the user + * + * @throws TeenQuotes\Exceptions\UserNotFoundException + * + * @return \Response + */ + public function edit($id) + { + $user = $this->userRepo->getByLogin($id); + + if (is_null($user) or !$this->userIsAllowedToEdit($user)) { + throw new UserNotFoundException(); + } + + // The color for published quotes + $confColor = $this->settingRepo->findForUserAndKey($user, 'colorsQuotesPublished'); + + // Set the default color + if (is_null($confColor)) { + $selectedColor = Config::get('app.users.defaultColorQuotesPublished'); + } else { + $selectedColor = $confColor->value; + } + + list($selectedCountry, $selectedCity) = $this->getCountryAndCity($user); + + $data = [ + 'gender' => $user->gender, + 'listCountries' => $this->countryRepo->listNameAndId(), + 'selectedCountry' => $selectedCountry, + 'selectedCity' => $selectedCity, + 'user' => $user, + 'selectedColor' => $selectedColor, + 'pageTitle' => Lang::get('users.editPageTitle'), + 'pageDescription' => Lang::get('users.editPageDescription'), + ]; + + return View::make('users.edit', $data); + } + + /** + * Get country and city for a given user. If we have no information, try to guess it! + * + * @param \TeenQuotes\Users\Models\User $user The user model + * + * @return array The country and the city + */ + private function getCountryAndCity(User $user) + { + $request = Input::instance(); + + // If the user hasn't filled its country yet we will try to auto-detect it + // If it's not possible, we will fall back to the most common country: the USA + $selectedCountry = is_null($user->country) ? $this->localisationDetector->detectCountry($request) : $user->country; + + // If the user hasn't filled its city yet we will try to auto-detect it + if (empty(Input::old('city')) and is_null($user->city)) { + $selectedCity = $this->localisationDetector->detectCity($request); + } else { + $selectedCity = Input::old('city'); + } + + return [$selectedCountry, $selectedCity]; + } + + private function userIsAllowedToEdit($user) + { + return ($user->login == Auth::user()->login); + } + + /** + * Update the specified resource in storage. + * + * @param string $id The login of the user + * + * @return \Response + */ + public function update($id) + { + $data = [ + 'gender' => Input::get('gender'), + 'birthdate' => Input::get('birthdate'), + 'country' => Input::get('country'), + 'city' => Input::get('city'), + 'about_me' => Input::get('about_me'), + 'avatar' => Input::file('avatar'), + ]; + + $this->userValidator->validateUpdateProfile($data); + + // Call the API + $response = $this->api->putProfile(false); + if ($response->getStatusCode() == 200) { + return Redirect::back()->with('success', Lang::get('users.updateProfileSuccessfull', ['login' => Auth::user()->login])); + } + + App::abort(500, "Can't update profile"); + } + + /** + * Update the password in storage. + * + * @param string $id The login of the user + * + * @return \Response + */ + public function putPassword($id) + { + $data = Input::only(['password', 'password_confirmation']); + + try { + $this->userValidator->validateUpdatePassword($data); + } catch (FormValidationException $e) { + return Redirect::to(URL::route('users.edit', Auth::user()->login).'#edit-password') + ->withErrors($e->getErrors()) + ->withInput(Input::all()); + } + + $user = $this->userRepo->getByLogin($id); + if (!$this->userIsAllowedToEdit($user)) { + App::abort(401, 'Refused'); + } + + $this->userRepo->updatePassword($user, $data['password']); + + return Redirect::back()->with('success', Lang::get('users.updatePasswordSuccessfull', ['login' => $user->login])); + } + + /** + * Update settings for the user. + * + * @param string $id The login of the user + * + * @return \Response + */ + public function putSettings($id) + { + $user = $this->userRepo->getByLogin($id); + if (!$this->userIsAllowedToEdit($user)) { + App::abort(401, 'Refused'); + } + + $response = $this->api->putSettings($user); + + // Handle error + if ($response->getStatusCode() == 400) { + $json = json_decode($response->getContent()); + + // If the color was wrong + if ($json->status == 'wrong_color') { + return Redirect::back()->with('warning', Lang::get('users.colorNotAllowed')); + } + } + + if ($response->getStatusCode() == 200) { + return Redirect::back()->with('success', Lang::get('users.updateSettingsSuccessfull', ['login' => $user->login])); + } + } + + /** + * Remove the specified resource from storage. + * + * @return \Response + */ + public function destroy() + { + $data = [ + 'password' => Input::get('password'), + 'delete-confirmation' => Input::get('delete-confirmation'), + 'login' => Auth::user()->login, + ]; + + // We will use a custom message for the delete confirmation input + $messages = [ + 'delete-confirmation.in' => Lang::get('users.writeDeleteHere'), + ]; + + try { + $this->userValidator->validateDestroy($data, $messages); + } catch (FormValidationException $e) { + return $this->redirectToDeleteAccount(Auth::user()->login) + ->withErrors($e->getErrors()) + ->withInput(Input::except('password')); + } + + unset($data['delete-confirmation']); + if (!Auth::validate($data)) { + return $this->redirectToDeleteAccount(Auth::user()->login) + ->withErrors(['password' => Lang::get('auth.passwordInvalid')]) + ->withInput(Input::except('password')); + } + + // Delete the user + $this->api->destroy(); + + return Redirect::home()->with('success', Lang::get('users.deleteAccountSuccessfull')); + } + + private function redirectToDeleteAccount($login) + { + return Redirect::to(URL::route('users.edit', $login).'#delete-account'); + } } diff --git a/app/TeenQuotes/Users/Models/ProfileVisitor.php b/app/TeenQuotes/Users/Models/ProfileVisitor.php index 2a94aa8c..9e1b796d 100644 --- a/app/TeenQuotes/Users/Models/ProfileVisitor.php +++ b/app/TeenQuotes/Users/Models/ProfileVisitor.php @@ -1,12 +1,14 @@ -belongsTo(User::class, 'user_id', 'id'); - } +trait ProfileVisitorTrait +{ + public function user() + { + return $this->belongsTo(User::class, 'user_id', 'id'); + } - public function visitor() - { - return $this->belongsTo(User::class, 'visitor_id', 'id'); - } -} \ No newline at end of file + public function visitor() + { + return $this->belongsTo(User::class, 'visitor_id', 'id'); + } +} diff --git a/app/TeenQuotes/Users/Models/Relations/UserTrait.php b/app/TeenQuotes/Users/Models/Relations/UserTrait.php index 34c0c771..553a55e5 100644 --- a/app/TeenQuotes/Users/Models/Relations/UserTrait.php +++ b/app/TeenQuotes/Users/Models/Relations/UserTrait.php @@ -1,4 +1,6 @@ -hasMany(Comment::class); - } - - public function countryObject() - { - return $this->belongsTo(Country::class, 'country', 'id'); - } - - public function newsletters() - { - return $this->hasMany(Newsletter::class); - } - - public function quotes() - { - return $this->hasMany(Quote::class); - } - - public function settings() - { - return $this->hasMany(Setting::class); - } - - public function stories() - { - return $this->hasMany(Story::class); - } - - public function visitors() - { - return $this->belongsToMany(User::class, 'profile_visitors', 'visitor_id', 'user_id')->withTimestamps(); - } - - public function visited() - { - return $this->belongsToMany(User::class, 'profile_visitors', 'user_id', 'visitor_id')->withTimestamps(); - } - - public function favoriteQuotes() - { - return $this->belongsToMany(Quote::class, 'favorite_quotes') - ->with('user') - ->orderBy('favorite_quotes.id', 'DESC'); - } -} \ No newline at end of file +trait UserTrait +{ + public function comments() + { + return $this->hasMany(Comment::class); + } + + public function countryObject() + { + return $this->belongsTo(Country::class, 'country', 'id'); + } + + public function newsletters() + { + return $this->hasMany(Newsletter::class); + } + + public function quotes() + { + return $this->hasMany(Quote::class); + } + + public function settings() + { + return $this->hasMany(Setting::class); + } + + public function stories() + { + return $this->hasMany(Story::class); + } + + public function visitors() + { + return $this->belongsToMany(User::class, 'profile_visitors', 'visitor_id', 'user_id')->withTimestamps(); + } + + public function visited() + { + return $this->belongsToMany(User::class, 'profile_visitors', 'user_id', 'visitor_id')->withTimestamps(); + } + + public function favoriteQuotes() + { + return $this->belongsToMany(Quote::class, 'favorite_quotes') + ->with('user') + ->orderBy('favorite_quotes.id', 'DESC'); + } +} diff --git a/app/TeenQuotes/Users/Models/Scopes/UserTrait.php b/app/TeenQuotes/Users/Models/Scopes/UserTrait.php index f555c6f9..4e45bbf3 100644 --- a/app/TeenQuotes/Users/Models/Scopes/UserTrait.php +++ b/app/TeenQuotes/Users/Models/Scopes/UserTrait.php @@ -1,32 +1,34 @@ -where(DB::raw("DATE_FORMAT(birthdate,'%m-%d')"), '=', DB::raw("DATE_FORMAT(NOW(),'%m-%d')")); - } +trait UserTrait +{ + public function scopeBirthdayToday($query) + { + return $query->where(DB::raw("DATE_FORMAT(birthdate,'%m-%d')"), '=', DB::raw("DATE_FORMAT(NOW(),'%m-%d')")); + } - public function scopeNotHidden($query) - { - return $query->where('hide_profile', '=', 0); - } + public function scopeNotHidden($query) + { + return $query->where('hide_profile', '=', 0); + } - public function scopeHidden($query) - { - return $query->where('hide_profile', '=', 1); - } + public function scopeHidden($query) + { + return $query->where('hide_profile', '=', 1); + } - public function scopePartialLogin($query, $login) - { - return $query->whereRaw('login LIKE ?', ["%$login%"])->orderBy('login', 'ASC'); - } + public function scopePartialLogin($query, $login) + { + return $query->whereRaw('login LIKE ?', ["%$login%"])->orderBy('login', 'ASC'); + } - public function scopeFromCountry($query, Country $c) - { - return $query->where('country', $c->id); - } -} \ No newline at end of file + public function scopeFromCountry($query, Country $c) + { + return $query->where('country', $c->id); + } +} diff --git a/app/TeenQuotes/Users/Models/User.php b/app/TeenQuotes/Users/Models/User.php index 42af57d8..d51023d1 100644 --- a/app/TeenQuotes/Users/Models/User.php +++ b/app/TeenQuotes/Users/Models/User.php @@ -1,259 +1,283 @@ -favQuoteRepo = App::make('TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository'); - $this->settingRepo = App::make('TeenQuotes\Settings\Repositories\SettingRepository'); - $this->newsletterRepo = App::make('TeenQuotes\Newsletters\Repositories\NewsletterRepository'); - $this->quoteRepo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); - } - - public function getProfileHiddenAttribute() - { - return $this->isHiddenProfile(); - } - - public function setPasswordAttribute($value) - { - $this->attributes['password'] = Hash::make($value); - } - - /** - * Tells if the user wants to hide his profile - * @return boolean true if we should hide his profile, false otherwise - */ - public function isHiddenProfile() - { - return $this->hide_profile == 1; - } - - /** - * Tells if a user is a male - * @return boolean - */ - public function isMale() - { - return $this->gender == 'M'; - } - - /** - * Tells if a user is a female - * @return boolean - */ - public function isFemale() - { - return ! $this->isMale(); - } - - public function getWantsNotificationCommentQuoteAttribute() - { - return $this->wantsEmailComment(); - } - - public function getIsAdminAttribute() - { - return $this->security_level == 1; - } - - public function getTotalComments() - { - return $this->comments()->count(); - } - - public function getFavoriteCount() - { - return $this->favoriteQuotes()->count(); - } - - /** - * Tells if the user is subscribed to the daily or the weekly newsletter - * @var string $type The type of the newsletter : weekly|daily - * @return boolean true if subscribed, false otherwise - */ - public function isSubscribedToNewsletter($type) - { - return $this->newsletterRepo->userIsSubscribedToNewsletterType($this, $type); - } - - public function getIsSubscribedToDaily() - { - return $this->isSubscribedToNewsletter(Newsletter::DAILY); - } - - public function getIsSubscribedToWeekly() - { - return $this->isSubscribedToNewsletter(Newsletter::WEEKLY); - } - - public function getAddedFavCount() - { - $idsQuotesPublished = $this->quoteRepo->listPublishedIdsForUser($this); - - if (empty($idsQuotesPublished)) - return 0; - - return $this->favQuoteRepo->nbFavoritesForQuotes($idsQuotesPublished); - } - - public function getPublishedQuotesCount() - { - return $this->quoteRepo->nbPublishedForUser($this); - } - - /** - * Tells if the user wants to receive an email when a comment is - * added on one of its quotes - * @return boolean true if we should send an email, false otherwise - */ - public function wantsEmailComment() - { - return $this->notification_comment_quote == 1; - } - - /** - * Returns the old hash of a password. It was used in Teen Quotes v2 - * @var array $data The data. We need a login and a password - * @return string The corresponding hash that was used in Teen Quotes v2 - */ - public static function oldHashMethod($data) - { - // This is legacy code. This hash method was used in 2005 by Mangos... - // I feel a bit old and stupid right now. - return sha1(strtoupper($data['login']).':'.strtoupper($data['password'])); - } - - /** - * Get the array of colors to use for the published quotes of the user - * @return string The name of the color to use for the user's instance. Example: blue|red|orange - */ - public function getColorsQuotesPublished() - { - $color = $this->settingRepo->findForUserAndKey($this, 'colorsQuotesPublished'); - - // We couldn't find a value, get back to the default - if (is_null($color)) - return Config::get('app.users.defaultColorQuotesPublished'); - - return $color->value; - } - - /** - * Get the IDs of the quotes favorited by the user - * @return array - */ - public function quotesFavorited() - { - return $this->favQuoteRepo->quotesFavoritesForUser($this); - } - - public function registerViewUserProfile() - { - if ($this->isTestingEnvironment()) - return; - - // Try to retrieve the ID of the user - if (Auth::guest()) - { - $idUserApi = ResourceServer::getOwnerId(); - $viewingUserId = ! empty($idUserApi) ? $idUserApi : null; - } - else - $viewingUserId = Auth::id(); - - // Register in the recommendation system - $data = [ - 'viewer_user_id' => $viewingUserId, - 'user_id' => $this->id, - 'user_login' => $this->login, - ]; - - Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@viewUserProfile', $data); - } - - public function getURLAvatarAttribute() - { - return $this->present()->avatarLink; - } - - public function hasPublishedQuotes() - { - return $this->getPublishedQuotesCount() > 0; - } - - public function hasFavoriteQuotes() - { - return $this->getFavoriteCount() > 0; - } - - public function hasPostedComments() - { - return $this->getTotalComments() > 0; - } - - private function isTestingEnvironment() - { - return in_array(App::environment(), ['testing', 'codeception']); - } -} \ No newline at end of file +class User extends Eloquent implements UserInterface, RemindableInterface +{ + use PresentableTrait, RemindableTrait, UserTrait, UserRelationsTrait, UserScopesTrait; + + protected $presenter = 'TeenQuotes\Users\Presenters\UserPresenter'; + + /** + * The database table used by the model. + * + * @var string + */ + protected $table = 'users'; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + protected $hidden = ['password', 'ip', 'hide_profile', 'remember_token', 'updated_at', 'avatar', 'security_level', 'notification_comment_quote']; + + /** + * Adding customs attributes to the object. + * + * @var array + */ + protected $appends = ['profile_hidden', 'url_avatar', 'wants_notification_comment_quote', 'is_admin']; + + /** + * Adding attributes to the object. These attributes need extra DB queries. + * + * @var array + */ + public static $appendsFull = ['total_comments', 'favorite_count', 'added_fav_count', 'published_quotes_count', 'is_subscribed_to_daily', 'is_subscribed_to_weekly']; + + /** + * @var \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + private $favQuoteRepo; + + /** + * @var \TeenQuotes\Settings\Repositories\SettingRepository + */ + private $settingRepo; + + /** + * @var \TeenQuotes\Newsletters\Repositories\NewsletterRepository + */ + private $newsletterRepo; + + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $quoteRepo; + + public function __construct($attributes = []) + { + parent::__construct($attributes); + + $this->favQuoteRepo = App::make('TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository'); + $this->settingRepo = App::make('TeenQuotes\Settings\Repositories\SettingRepository'); + $this->newsletterRepo = App::make('TeenQuotes\Newsletters\Repositories\NewsletterRepository'); + $this->quoteRepo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); + } + + public function getProfileHiddenAttribute() + { + return $this->isHiddenProfile(); + } + + public function setPasswordAttribute($value) + { + $this->attributes['password'] = Hash::make($value); + } + + /** + * Tells if the user wants to hide his profile. + * + * @return bool true if we should hide his profile, false otherwise + */ + public function isHiddenProfile() + { + return $this->hide_profile == 1; + } + + /** + * Tells if a user is a male. + * + * @return bool + */ + public function isMale() + { + return $this->gender == 'M'; + } + + /** + * Tells if a user is a female. + * + * @return bool + */ + public function isFemale() + { + return !$this->isMale(); + } + + public function getWantsNotificationCommentQuoteAttribute() + { + return $this->wantsEmailComment(); + } + + public function getIsAdminAttribute() + { + return $this->security_level == 1; + } + + public function getTotalComments() + { + return $this->comments()->count(); + } + + public function getFavoriteCount() + { + return $this->favoriteQuotes()->count(); + } + + /** + * Tells if the user is subscribed to the daily or the weekly newsletter. + * + * @var string The type of the newsletter : weekly|daily + * + * @return bool true if subscribed, false otherwise + */ + public function isSubscribedToNewsletter($type) + { + return $this->newsletterRepo->userIsSubscribedToNewsletterType($this, $type); + } + + public function getIsSubscribedToDaily() + { + return $this->isSubscribedToNewsletter(Newsletter::DAILY); + } + + public function getIsSubscribedToWeekly() + { + return $this->isSubscribedToNewsletter(Newsletter::WEEKLY); + } + + public function getAddedFavCount() + { + $idsQuotesPublished = $this->quoteRepo->listPublishedIdsForUser($this); + + if (empty($idsQuotesPublished)) { + return 0; + } + + return $this->favQuoteRepo->nbFavoritesForQuotes($idsQuotesPublished); + } + + public function getPublishedQuotesCount() + { + return $this->quoteRepo->nbPublishedForUser($this); + } + + /** + * Tells if the user wants to receive an email when a comment is + * added on one of its quotes. + * + * @return bool true if we should send an email, false otherwise + */ + public function wantsEmailComment() + { + return $this->notification_comment_quote == 1; + } + + /** + * Returns the old hash of a password. It was used in Teen Quotes v2. + * + * @var array The data. We need a login and a password + * + * @return string The corresponding hash that was used in Teen Quotes v2 + */ + public static function oldHashMethod($data) + { + // This is legacy code. This hash method was used in 2005 by Mangos... + // I feel a bit old and stupid right now. + return sha1(strtoupper($data['login']).':'.strtoupper($data['password'])); + } + + /** + * Get the array of colors to use for the published quotes of the user. + * + * @return string The name of the color to use for the user's instance. Example: blue|red|orange + */ + public function getColorsQuotesPublished() + { + $color = $this->settingRepo->findForUserAndKey($this, 'colorsQuotesPublished'); + + // We couldn't find a value, get back to the default + if (is_null($color)) { + return Config::get('app.users.defaultColorQuotesPublished'); + } + + return $color->value; + } + + /** + * Get the IDs of the quotes favorited by the user. + * + * @return array + */ + public function quotesFavorited() + { + return $this->favQuoteRepo->quotesFavoritesForUser($this); + } + + public function registerViewUserProfile() + { + if ($this->isTestingEnvironment()) { + return null; + } + + // Try to retrieve the ID of the user + if (Auth::guest()) { + $idUserApi = ResourceServer::getOwnerId(); + $viewingUserId = !empty($idUserApi) ? $idUserApi : null; + } else { + $viewingUserId = Auth::id(); + } + + // Register in the recommendation system + $data = [ + 'viewer_user_id' => $viewingUserId, + 'user_id' => $this->id, + 'user_login' => $this->login, + ]; + + Queue::push('TeenQuotes\Queues\Workers\EasyrecWorker@viewUserProfile', $data); + } + + public function getURLAvatarAttribute() + { + return $this->present()->avatarLink; + } + + public function hasPublishedQuotes() + { + return $this->getPublishedQuotesCount() > 0; + } + + public function hasFavoriteQuotes() + { + return $this->getFavoriteCount() > 0; + } + + public function hasPostedComments() + { + return $this->getTotalComments() > 0; + } + + private function isTestingEnvironment() + { + return in_array(App::environment(), ['testing', 'codeception']); + } +} diff --git a/app/TeenQuotes/Users/Observers/UserObserver.php b/app/TeenQuotes/Users/Observers/UserObserver.php index 6377c8f3..0f3e9d4e 100644 --- a/app/TeenQuotes/Users/Observers/UserObserver.php +++ b/app/TeenQuotes/Users/Observers/UserObserver.php @@ -1,38 +1,40 @@ -newsletterManager = App::make('TeenQuotes\Newsletters\NewslettersManager'); - $this->userMailer = App::make('TeenQuotes\Mail\UserMailer'); - } - - /** - * Will be triggered when a model is created - * - * @param \TeenQuotes\Users\Models\User $user - */ - public function created($user) - { - // Subscribe the user to the weekly newsletter - $this->newsletterManager->createForUserAndType($user, Newsletter::WEEKLY); - - $this->userMailer->scheduleSigningUpFeedBack($user); - - $this->userMailer->sendWelcome($user); - } -} \ No newline at end of file +class UserObserver +{ + /** + * @var \TeenQuotes\Newsletters\NewslettersManager + */ + private $newsletterManager; + + /** + * @var \TeenQuotes\Mail\UserMailer + */ + private $userMailer; + + public function __construct() + { + $this->newsletterManager = App::make('TeenQuotes\Newsletters\NewslettersManager'); + $this->userMailer = App::make('TeenQuotes\Mail\UserMailer'); + } + + /** + * Will be triggered when a model is created. + * + * @param \TeenQuotes\Users\Models\User $user + */ + public function created($user) + { + // Subscribe the user to the weekly newsletter + $this->newsletterManager->createForUserAndType($user, Newsletter::WEEKLY); + + $this->userMailer->scheduleSigningUpFeedBack($user); + + $this->userMailer->sendWelcome($user); + } +} diff --git a/app/TeenQuotes/Users/Presenters/UserPresenter.php b/app/TeenQuotes/Users/Presenters/UserPresenter.php index 3fb776f4..05a325c3 100644 --- a/app/TeenQuotes/Users/Presenters/UserPresenter.php +++ b/app/TeenQuotes/Users/Presenters/UserPresenter.php @@ -1,43 +1,53 @@ -avatar, 'http')) - return $this->avatar; - elseif (is_null($this->avatar)) - return Config::get('app.users.avatar.default'); - // Local URL - else - return str_replace('public/', '', Request::root().'/'.Config::get('app.users.avatarPath').'/'.$this->avatar); - } +class UserPresenter extends Presenter +{ + /** + * Get the URL of the user's avatar. + * + * @return string The URL to the avatar + */ + public function avatarLink() + { + // Full URL + if (Str::startsWith($this->avatar, 'http')) { + return $this->avatar; + } elseif (is_null($this->avatar)) { + return Config::get('app.users.avatar.default'); + } + // Local URL + else { + return str_replace('public/', '', Request::root().'/'.Config::get('app.users.avatarPath').'/'.$this->avatar); + } + } - /** - * Get the name of the icon to display based on the gender of the user - * @return string The name of the icon to display : fa-male|fa-female - */ - public function iconGender() - { - return $this->entity->isMale() ? 'fa-male' : 'fa-female'; - } + /** + * Get the name of the icon to display based on the gender of the user. + * + * @return string The name of the icon to display : fa-male|fa-female + */ + public function iconGender() + { + return $this->entity->isMale() ? 'fa-male' : 'fa-female'; + } - /** - * The age of the user - * @return int - */ - public function age() - { - $carbon = Carbon::createFromFormat('Y-m-d', $this->birthdate); + /** + * The age of the user. + * + * @return int + */ + public function age() + { + $carbon = Carbon::createFromFormat('Y-m-d', $this->birthdate); - return $carbon->age; - } -} \ No newline at end of file + return $carbon->age; + } +} diff --git a/app/TeenQuotes/Users/Repositories/DbProfileVisitorRepository.php b/app/TeenQuotes/Users/Repositories/DbProfileVisitorRepository.php index 59dd581b..af363398 100644 --- a/app/TeenQuotes/Users/Repositories/DbProfileVisitorRepository.php +++ b/app/TeenQuotes/Users/Repositories/DbProfileVisitorRepository.php @@ -1,109 +1,113 @@ -userRepo = $userRepo; - } - - /** - * Tell that a user visited another user's profile - * - * @param int|\TeenQuotes\Users\Models\User $visited - * @param int|\TeenQuotes\Users\Models\User $visitor - */ - public function addVisitor($visited, $visitor) - { - $visited = $this->retrieveUser($visited); - $visitor = $this->retrieveUser($visitor); - - $visited->visitors()->save($visitor); - } - - /** - * Get visitors for a given user - * - * @param int|\TeenQuotes\Users\Models\User $u - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getVisitors($u, $page, $pagesize) - { - $u = $this->retrieveUser($u); - - return $u->visitors() - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->where(function($q) - { - $q->where('users.hide_profile', 0); - }) - ->latest('profile_visitors.id') - ->distinct() - ->get(); - } - - /** - * Get visitors' information for a given user - * - * @param int|\TeenQuotes\Users\Models\User $u - * @param int $page - * @param int $pagesize - * @return array ['login' => 'avatarURL'] array - */ - public function getVisitorsInfos($u, $page, $pagesize) - { - $collection = $this->getVisitors($u, $page, $pagesize); - - return $collection->reduce(function($result, $u) - { - $result[$u->login] = $u->getURLAvatarAttribute(); - - return $result; - }); - } - - /** - * Tells if a user has visited the profile of another user - * - * @param int|\TeenQuotes\Users\Models\User $visitor - * @param int|\TeenQuotes\Users\Models\User $visited - * @return boolean - */ - public function hasVisited($visitor, $visited) - { - $visitor = $this->retrieveUser($visitor); - $visited = $this->retrieveUser($visited); - - return in_array($visitor->id, $visited->visitors()->select('users.*')->lists('id')); - } - - /** - * Retrieves a user - * - * @param int|\TeenQuotes\Users\Models\User $u - * @return \TeenQuotes\Users\Models\User - */ - private function retrieveUser($u) - { - if ($u instanceof User) return $u; - - return $this->userRepo->getById($u); - } - - private function computeSkip($page, $pagesize) - { - return $pagesize * ($page - 1); - } -} \ No newline at end of file + +class DbProfileVisitorRepository implements ProfileVisitorRepository +{ + /** + * @var \TeenQuotes\Users\Repositories\UserRepository + */ + private $userRepo; + + public function __construct(UserRepository $userRepo) + { + $this->userRepo = $userRepo; + } + + /** + * Tell that a user visited another user's profile. + * + * @param int|\TeenQuotes\Users\Models\User $visited + * @param int|\TeenQuotes\Users\Models\User $visitor + */ + public function addVisitor($visited, $visitor) + { + $visited = $this->retrieveUser($visited); + $visitor = $this->retrieveUser($visitor); + + $visited->visitors()->save($visitor); + } + + /** + * Get visitors for a given user. + * + * @param int|\TeenQuotes\Users\Models\User $u + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getVisitors($u, $page, $pagesize) + { + $u = $this->retrieveUser($u); + + return $u->visitors() + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->where(function ($q) { + $q->where('users.hide_profile', 0); + }) + ->latest('profile_visitors.id') + ->distinct() + ->get(); + } + + /** + * Get visitors' information for a given user. + * + * @param int|\TeenQuotes\Users\Models\User $u + * @param int $page + * @param int $pagesize + * + * @return array ['login' => 'avatarURL'] array + */ + public function getVisitorsInfos($u, $page, $pagesize) + { + $collection = $this->getVisitors($u, $page, $pagesize); + + return $collection->reduce(function ($result, $u) { + $result[$u->login] = $u->getURLAvatarAttribute(); + + return $result; + }); + } + + /** + * Tells if a user has visited the profile of another user. + * + * @param int|\TeenQuotes\Users\Models\User $visitor + * @param int|\TeenQuotes\Users\Models\User $visited + * + * @return bool + */ + public function hasVisited($visitor, $visited) + { + $visitor = $this->retrieveUser($visitor); + $visited = $this->retrieveUser($visited); + + return in_array($visitor->id, $visited->visitors()->select('users.*')->lists('id')); + } + + /** + * Retrieves a user. + * + * @param int|\TeenQuotes\Users\Models\User $u + * + * @return \TeenQuotes\Users\Models\User + */ + private function retrieveUser($u) + { + if ($u instanceof User) { + return $u; + } + + return $this->userRepo->getById($u); + } + + private function computeSkip($page, $pagesize) + { + return $pagesize * ($page - 1); + } +} diff --git a/app/TeenQuotes/Users/Repositories/DbUserRepository.php b/app/TeenQuotes/Users/Repositories/DbUserRepository.php index 1aa24efa..5e466e2c 100644 --- a/app/TeenQuotes/Users/Repositories/DbUserRepository.php +++ b/app/TeenQuotes/Users/Repositories/DbUserRepository.php @@ -1,319 +1,365 @@ -first(); - } - - /** - * Get users from an array of emails - * @param array $emails Email addresses - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getByEmails(array $emails) - { - return User::whereIn('email', $emails)->get(); - } - - /** - * Retrieve a user by its login - * @param string $login - * @return \TeenQuotes\Users\Models\User - */ - public function getByLogin($login) - { - return User::whereLogin($login)->first(); - } - - /** - * Count the number of users that match the given login. Do not count users with an hidden profile. - * @param string $login - * @return int - */ - public function countByPartialLogin($login) - { - return User::partialLogin($login) - ->notHidden() - ->count(); - } - - /** - * Update the password for a user - * @param \TeenQuotes\Users\Models\User|int $u - * @param string $password - */ - public function updatePassword($u, $password) - { - $user = $this->retrieveUser($u); - $user->password = $password; - $user->save(); - } - - /** - * Update the email for a user - * @param \TeenQuotes\Users\Models\User|int $u - * @param string $email - */ - public function updateEmail($u, $email) - { - $user = $this->retrieveUser($u); - $user->email = $email; - $user->save(); - } - - /** - * Update a user's profile - * @param \TeenQuotes\Users\Models\User|int $u - * @param string $gender - * @param int $country - * @param string $city - * @param string $about_me - * @param string $birthdate - * @param Symfony\Component\HttpFoundation\File\UploadedFile $avatar - */ - public function updateProfile($u, $gender, $country, $city, $about_me, $birthdate, $avatar) - { - $user = $this->retrieveUser($u); - - if ( ! empty($gender)) - $user->gender = $gender; - if ( ! empty($country)) - $user->country = $country; - if ( ! empty($city)) - $user->city = $city; - if ( ! empty($about_me)) - $user->about_me = $about_me; - $user->birthdate = empty($birthdate) ? null : $birthdate; - - if ( ! is_null($avatar)) { - $filename = $user->id.'.'.$avatar->getClientOriginalExtension(); - $user->avatar = $filename; - } - - $user->save(); - } - - /** - * Update a user's settings - * @param \TeenQuotes\Users\Models\User|int $u - * @param boolean $notification_comment_quote - * @param boolean $hide_profile - */ - public function updateSettings($u, $notification_comment_quote, $hide_profile) - { - $user = $this->retrieveUser($u); - $user->notification_comment_quote = $notification_comment_quote; - $user->hide_profile = $hide_profile; - $user->save(); - } - - /** - * Get all users - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getAll() - { - return User::all(); - } - - /** - * Retrieve users who have their birthday today - * @return \Illuminate\Database\Eloquent\Collection - */ - public function birthdayToday() - { - return User::birthdayToday() - ->get(); - } - - /** - * Retrieve a user by its login or its ID - * @param string|int $user_id - * @return \TeenQuotes\Users\Models\User - */ - public function showByLoginOrId($user_id) - { - return User::where('login', '=', $user_id) - ->orWhere('id', '=', $user_id) - ->with(array('countryObject' => function($q) { - $q->addSelect(array('id', 'name')); - })) - ->with(array('newsletters' => function($q) { - $q->addSelect('user_id', 'type', 'created_at'); - })) - ->first(); - } - - /** - * Get users that have logged in since a given date - * @param DateTime $since - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getLoggedInSince($since, $page, $pagesize) - { - return User::where('last_visit', '>=', $since) - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Search user matching a login - * @param string $query - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function searchByPartialLogin($query, $page, $pagesize) - { - return User::partialLogin($query) - ->notHidden() - ->with('countryObject') - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Create a user - * @param string $login - * @param string $email - * @param string $password - * @param string $ip - * @param string $lastVisit - * @param int $country - * @param string $city - * @param string $avatar - * @return \TeenQuotes\Users\Models\User - */ - public function create($login, $email, $password, $ip, $lastVisit, $country, $city, $avatar = null) - { - $user = new User; - $user->login = $login; - $user->email = $email; - $user->password = $password; - $user->ip = $ip; - $user->last_visit = $lastVisit; - $user->country = $country; - $user->city = $city; - - if (! is_null($avatar)) - $user->avatar = $avatar; - - $user->save(); - - return $user; - } - - /** - * Delete a user - * @param int|\TeenQuotes\Users\Models\User $id - * @return \TeenQuotes\Users\Models\User - */ - public function destroy($u) - { - $u = $this->retrieveUser($u); - $u->delete(); - - return $u; - } - - /** - * Get the most common country ID - * @return int - */ - public function mostCommonCountryId() - { - $u = User::select('country', DB::raw('count(*) as total')) - ->whereNotNull('country') - ->groupBy('country') - ->orderBy('total', 'DESC') - ->first(); - - return $u->country; - } - - /** - * Retrieve users who have not logged in in the last year and who are subscribed to at least a newsletter - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getNonActiveHavingNewsletter() - { - return User::where('last_visit', '<=', Carbon::now()->subYear()) - ->has('newsletters') - ->get(); - } - - /** - * Get users from a country without an hidden profile - * @param \TeenQuotes\Countries\Models\Country $c - * @param int $page - * @param int $pagesize - * @return \Illuminate\Database\Eloquent\Collection - */ - public function fromCountry(Country $c, $page, $pagesize) - { - return User::notHidden() - ->fromCountry($c) - ->take($pagesize) - ->skip($this->computeSkip($page, $pagesize)) - ->get(); - } - - /** - * Count the number of users who are from a country - * @param \TeenQuotes\Countries\Models\Country $c - * @return int - */ - public function countFromCountry(Country $c) - { - return User::notHidden() - ->fromCountry($c) - ->count(); - } - - private function computeSkip($page, $pagesize) - { - return $pagesize * ($page - 1); - } - - /** - * Retrieve a user by its ID or just the user instance - * @param \TeenQuotes\Users\Models\User|int $u - * @return \TeenQuotes\Users\Models\User - * @throws \InvalidArgumentException If the type can't be recognised - */ - private function retrieveUser($u) - { - if (is_numeric($u)) - return $this->getById($u); - - if ($u instanceof User) - return $u; - - throw new InvalidArgumentException("Expecting a user instance or a user ID."); - } -} \ No newline at end of file +class DbUserRepository implements UserRepository +{ + /** + * Retrieve a user by its ID. + * + * @param int $id + * + * @return \TeenQuotes\Users\Models\User + */ + public function getById($id) + { + return User::find($id); + } + + /** + * Retrieve a user by its email address. + * + * @param string $email + * + * @return \TeenQuotes\Users\Models\User + */ + public function getByEmail($email) + { + return User::whereEmail($email)->first(); + } + + /** + * Get users from an array of emails. + * + * @param array $emails Email addresses + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getByEmails(array $emails) + { + return User::whereIn('email', $emails)->get(); + } + + /** + * Retrieve a user by its login. + * + * @param string $login + * + * @return \TeenQuotes\Users\Models\User + */ + public function getByLogin($login) + { + return User::whereLogin($login)->first(); + } + + /** + * Count the number of users that match the given login. Do not count users with an hidden profile. + * + * @param string $login + * + * @return int + */ + public function countByPartialLogin($login) + { + return User::partialLogin($login) + ->notHidden() + ->count(); + } + + /** + * Update the password for a user. + * + * @param \TeenQuotes\Users\Models\User|int $u + * @param string $password + */ + public function updatePassword($u, $password) + { + $user = $this->retrieveUser($u); + $user->password = $password; + $user->save(); + } + + /** + * Update the email for a user. + * + * @param \TeenQuotes\Users\Models\User|int $u + * @param string $email + */ + public function updateEmail($u, $email) + { + $user = $this->retrieveUser($u); + $user->email = $email; + $user->save(); + } + + /** + * Update a user's profile. + * + * @param \TeenQuotes\Users\Models\User|int $u + * @param string $gender + * @param int $country + * @param string $city + * @param string $about_me + * @param string $birthdate + * @param Symfony\Component\HttpFoundation\File\UploadedFile $avatar + */ + public function updateProfile($u, $gender, $country, $city, $about_me, $birthdate, $avatar) + { + $user = $this->retrieveUser($u); + + if (!empty($gender)) { + $user->gender = $gender; + } + if (!empty($country)) { + $user->country = $country; + } + if (!empty($city)) { + $user->city = $city; + } + if (!empty($about_me)) { + $user->about_me = $about_me; + } + $user->birthdate = empty($birthdate) ? null : $birthdate; + + if (!is_null($avatar)) { + $filename = $user->id.'.'.$avatar->getClientOriginalExtension(); + $user->avatar = $filename; + } + + $user->save(); + } + + /** + * Update a user's settings. + * + * @param \TeenQuotes\Users\Models\User|int $u + * @param bool $notification_comment_quote + * @param bool $hide_profile + */ + public function updateSettings($u, $notification_comment_quote, $hide_profile) + { + $user = $this->retrieveUser($u); + $user->notification_comment_quote = $notification_comment_quote; + $user->hide_profile = $hide_profile; + $user->save(); + } + + /** + * Get all users. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getAll() + { + return User::all(); + } + + /** + * Retrieve users who have their birthday today. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function birthdayToday() + { + return User::birthdayToday() + ->get(); + } + + /** + * Retrieve a user by its login or its ID. + * + * @param string|int $user_id + * + * @return \TeenQuotes\Users\Models\User + */ + public function showByLoginOrId($user_id) + { + return User::where('login', '=', $user_id) + ->orWhere('id', '=', $user_id) + ->with(['countryObject' => function ($q) { + $q->addSelect(['id', 'name']); + }]) + ->with(['newsletters' => function ($q) { + $q->addSelect('user_id', 'type', 'created_at'); + }]) + ->first(); + } + + /** + * Get users that have logged in since a given date. + * + * @param DateTime $since + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getLoggedInSince($since, $page, $pagesize) + { + return User::where('last_visit', '>=', $since) + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Search user matching a login. + * + * @param string $query + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function searchByPartialLogin($query, $page, $pagesize) + { + return User::partialLogin($query) + ->notHidden() + ->with('countryObject') + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Create a user. + * + * @param string $login + * @param string $email + * @param string $password + * @param string $ip + * @param string $lastVisit + * @param int $country + * @param string $city + * @param string $avatar + * + * @return \TeenQuotes\Users\Models\User + */ + public function create($login, $email, $password, $ip, $lastVisit, $country, $city, $avatar = null) + { + $user = new User(); + $user->login = $login; + $user->email = $email; + $user->password = $password; + $user->ip = $ip; + $user->last_visit = $lastVisit; + $user->country = $country; + $user->city = $city; + + if (!is_null($avatar)) { + $user->avatar = $avatar; + } + + $user->save(); + + return $user; + } + + /** + * Delete a user. + * + * @param int|\TeenQuotes\Users\Models\User $id + * + * @return \TeenQuotes\Users\Models\User + */ + public function destroy($u) + { + $u = $this->retrieveUser($u); + $u->delete(); + + return $u; + } + + /** + * Get the most common country ID. + * + * @return int + */ + public function mostCommonCountryId() + { + $u = User::select('country', DB::raw('count(*) as total')) + ->whereNotNull('country') + ->groupBy('country') + ->orderBy('total', 'DESC') + ->first(); + + return $u->country; + } + + /** + * Retrieve users who have not logged in in the last year and who are subscribed to at least a newsletter. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function getNonActiveHavingNewsletter() + { + return User::where('last_visit', '<=', Carbon::now()->subYear()) + ->has('newsletters') + ->get(); + } + + /** + * Get users from a country without an hidden profile. + * + * @param \TeenQuotes\Countries\Models\Country $c + * @param int $page + * @param int $pagesize + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function fromCountry(Country $c, $page, $pagesize) + { + return User::notHidden() + ->fromCountry($c) + ->take($pagesize) + ->skip($this->computeSkip($page, $pagesize)) + ->get(); + } + + /** + * Count the number of users who are from a country. + * + * @param \TeenQuotes\Countries\Models\Country $c + * + * @return int + */ + public function countFromCountry(Country $c) + { + return User::notHidden() + ->fromCountry($c) + ->count(); + } + + private function computeSkip($page, $pagesize) + { + return $pagesize * ($page - 1); + } + + /** + * Retrieve a user by its ID or just the user instance. + * + * @param \TeenQuotes\Users\Models\User|int $u + * + * @return \TeenQuotes\Users\Models\User + * + * @throws \InvalidArgumentException If the type can't be recognised + */ + private function retrieveUser($u) + { + if (is_numeric($u)) { + return $this->getById($u); + } + + if ($u instanceof User) { + return $u; + } + + throw new InvalidArgumentException('Expecting a user instance or a user ID.'); + } +} diff --git a/app/TeenQuotes/Users/Repositories/ProfileVisitorRepository.php b/app/TeenQuotes/Users/Repositories/ProfileVisitorRepository.php index 229c68c9..f1418baf 100644 --- a/app/TeenQuotes/Users/Repositories/ProfileVisitorRepository.php +++ b/app/TeenQuotes/Users/Repositories/ProfileVisitorRepository.php @@ -1,41 +1,46 @@ - 'avatarURL'] array - */ - public function getVisitorsInfos($u, $page, $pagesize); + /** + * Get visitors' information for a given user. + * + * @param int|\TeenQuotes\Users\Models\User $u + * @param int $page + * @param int $pagesize + * + * @return array ['login' => 'avatarURL'] array + */ + public function getVisitorsInfos($u, $page, $pagesize); - /** - * Tells if a user has visited the profile of another user - * - * @param int|\TeenQuotes\Users\Models\User $visitor - * @param int|\TeenQuotes\Users\Models\User $visited - * @return boolean - */ - public function hasVisited($visitor, $visited); -} \ No newline at end of file + /** + * Tells if a user has visited the profile of another user. + * + * @param int|\TeenQuotes\Users\Models\User $visitor + * @param int|\TeenQuotes\Users\Models\User $visited + * + * @return bool + */ + public function hasVisited($visitor, $visited); +} diff --git a/app/TeenQuotes/Users/Repositories/UserRepository.php b/app/TeenQuotes/Users/Repositories/UserRepository.php index f21c554a..9900a0a1 100644 --- a/app/TeenQuotes/Users/Repositories/UserRepository.php +++ b/app/TeenQuotes/Users/Repositories/UserRepository.php @@ -1,161 +1,195 @@ -registerObserver(); - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $this->registerRoutes(); - $this->registerSearchRoutes(); - $this->registerBindings(); - $this->registerViewComposers(); - $this->registerCommands(); - } - - private function registerBindings() - { - $repos = ['User', 'ProfileVisitor']; - - foreach ($repos as $repo) - { - $this->app->bind( - $this->getNamespaceRepositories().$repo.'Repository', - $this->getNamespaceRepositories().'Db'.$repo.'Repository' - ); - } - } - - private function registerObserver() - { - User::observe(new UserObserver); - } - - private function registerRoutes() - { - $this->app['router']->pattern('display_type', 'favorites|comments'); - - $controller = $this->getController(); - - $this->app['router']->group($this->getRouteGroupParams(), function() use ($controller) - { - $this->app['router']->get('user-{user_id}', ['uses' => $controller.'@redirectOldUrl'])->where('user_id', '[0-9]+'); - $this->app['router']->get('users/{user_id}/{display_type?}', ['as' => 'users.show', 'uses' => $controller.'@show']); - $this->app['router']->any('users/{wildcard}', $this->getController().'@notFound'); - }); - - $this->app['router']->group($this->getRouteGroupParamsAccount(), function() use ($controller) - { - $this->app['router']->get('signup', ['as' => 'signup', 'before' => 'guest', 'uses' => $controller.'@getSignup']); - $this->app['router']->delete('users', ['as' => 'users.delete', 'before' => 'auth', 'uses' => $controller.'@destroy']); - $this->app['router']->post('users/loginvalidator', ['as' => 'users.loginValidator', 'uses' => $controller.'@postLoginValidator']); - $this->app['router']->put('users/{user_id}/password', ['as' => 'users.password', 'uses' => $controller.'@putPassword']); - $this->app['router']->put('users/{user_id}/avatar', ['as' => 'users.avatar', 'uses' => $controller.'@putAvatar']); - $this->app['router']->put('users/{user_id}/settings', ['as' => 'users.settings', 'uses' => $controller.'@putSettings']); - $this->app['router']->resource('users', $controller, ['only' => ['store', 'edit', 'update']]); - }); - } - - private function registerSearchRoutes() - { - $controller = 'SearchController'; - $routeGroup = $this->getRouteGroupParams(); - $routeGroup['namespace'] = 'TeenQuotes\Quotes\Controllers'; - - $this->app['router']->group($routeGroup, function() use ($controller) { - $this->app['router']->get('search/users/country/{country_id}', ['as' => 'search.users.country', 'uses' => $controller.'@usersFromCountry']); - }); - } - - private function registerViewComposers() - { - $namespace = $this->getBaseNamespace().'Composers'; - - // When showing a user's profile - $this->app['view']->composer([ - 'users.show' - ], $namespace.'\ShowComposer'); - - // Welcome page - $this->app['view']->composer([ - 'users.welcome' - ], $namespace.'\WelcomeComposer'); - - // Self edit user's profile - $this->app['view']->composer([ - 'users.edit' - ], $namespace.'\ProfileEditComposer'); - - // Search users coming from a given country - $this->app['view']->composer([ - 'search.users' - ], $namespace.'\SearchUsersCountryComposer'); - } - - /** - * Parameters for the group of routes - * @return array - */ - private function getRouteGroupParams() - { - return [ - 'domain' => $this->app['config']->get('app.domain'), - 'namespace' => $this->getBaseNamespace().'Controllers', - ]; - } - - /** - * Get parameters for the account section - * @return array - */ - private function getRouteGroupParamsAccount() - { - $data = $this->getRouteGroupParams(); - // Switch to the secure domain - $data['domain'] = $this->app['config']->get('app.domainAccount'); - - return $data; - } - - private function registerCommands() - { - // Send birthday - $commandName = $this->getBaseNamespace().'Console\SendBirthdayCommand'; - $this->app->bindShared('users.console.sendBirthday', function($app) use($commandName) - { - return $app->make($commandName); - }); - - $this->commands('users.console.sendBirthday'); - - // Send special event - $commandName = $this->getBaseNamespace().'Console\EmailSpecialEventCommand'; - $this->app->bindShared('users.console.emailSpecialEvent', function($app) use($commandName) - { - return $app->make($commandName); - }); - - $this->commands('users.console.emailSpecialEvent'); - } - - /** - * The controller name to handle requests - * @return string - */ - private function getController() - { - return 'UsersController'; - } +class UsersServiceProvider extends ServiceProvider +{ + use NamespaceTrait; + /** + * Indicates if loading of the provider is deferred. + * + * @var bool + */ + protected $defer = false; + + /** + * Bootstrap the application events. + */ + public function boot() + { + $this->registerObserver(); + } + + /** + * Register the service provider. + */ + public function register() + { + $this->registerRoutes(); + $this->registerSearchRoutes(); + $this->registerBindings(); + $this->registerViewComposers(); + $this->registerCommands(); + } + + private function registerBindings() + { + $repos = ['User', 'ProfileVisitor']; + + foreach ($repos as $repo) { + $this->app->bind( + $this->getNamespaceRepositories().$repo.'Repository', + $this->getNamespaceRepositories().'Db'.$repo.'Repository' + ); + } + } + + private function registerObserver() + { + User::observe(new UserObserver()); + } + + private function registerRoutes() + { + $this->app['router']->pattern('display_type', 'favorites|comments'); + + $controller = $this->getController(); + + $this->app['router']->group($this->getRouteGroupParams(), function () use ($controller) { + $this->app['router']->get('user-{user_id}', ['uses' => $controller.'@redirectOldUrl'])->where('user_id', '[0-9]+'); + $this->app['router']->get('users/{user_id}/{display_type?}', ['as' => 'users.show', 'uses' => $controller.'@show']); + $this->app['router']->any('users/{wildcard}', $this->getController().'@notFound'); + }); + + $this->app['router']->group($this->getRouteGroupParamsAccount(), function () use ($controller) { + $this->app['router']->get('signup', ['as' => 'signup', 'before' => 'guest', 'uses' => $controller.'@getSignup']); + $this->app['router']->delete('users', ['as' => 'users.delete', 'before' => 'auth', 'uses' => $controller.'@destroy']); + $this->app['router']->post('users/loginvalidator', ['as' => 'users.loginValidator', 'uses' => $controller.'@postLoginValidator']); + $this->app['router']->put('users/{user_id}/password', ['as' => 'users.password', 'uses' => $controller.'@putPassword']); + $this->app['router']->put('users/{user_id}/avatar', ['as' => 'users.avatar', 'uses' => $controller.'@putAvatar']); + $this->app['router']->put('users/{user_id}/settings', ['as' => 'users.settings', 'uses' => $controller.'@putSettings']); + $this->app['router']->resource('users', $controller, ['only' => ['store', 'edit', 'update']]); + }); + } + + private function registerSearchRoutes() + { + $controller = 'SearchController'; + $routeGroup = $this->getRouteGroupParams(); + $routeGroup['namespace'] = 'TeenQuotes\Quotes\Controllers'; + + $this->app['router']->group($routeGroup, function () use ($controller) { + $this->app['router']->get('search/users/country/{country_id}', ['as' => 'search.users.country', 'uses' => $controller.'@usersFromCountry']); + }); + } + + private function registerViewComposers() + { + $namespace = $this->getBaseNamespace().'Composers'; + + // When showing a user's profile + $this->app['view']->composer([ + 'users.show', + ], $namespace.'\ShowComposer'); + + // Welcome page + $this->app['view']->composer([ + 'users.welcome', + ], $namespace.'\WelcomeComposer'); + + // Self edit user's profile + $this->app['view']->composer([ + 'users.edit', + ], $namespace.'\ProfileEditComposer'); + + // Search users coming from a given country + $this->app['view']->composer([ + 'search.users', + ], $namespace.'\SearchUsersCountryComposer'); + } + + /** + * Parameters for the group of routes. + * + * @return array + */ + private function getRouteGroupParams() + { + return [ + 'domain' => $this->app['config']->get('app.domain'), + 'namespace' => $this->getBaseNamespace().'Controllers', + ]; + } + + /** + * Get parameters for the account section. + * + * @return array + */ + private function getRouteGroupParamsAccount() + { + $data = $this->getRouteGroupParams(); + // Switch to the secure domain + $data['domain'] = $this->app['config']->get('app.domainAccount'); + + return $data; + } + + private function registerCommands() + { + // Send birthday + $commandName = $this->getBaseNamespace().'Console\SendBirthdayCommand'; + $this->app->bindShared('users.console.sendBirthday', function ($app) use ($commandName) { + return $app->make($commandName); + }); + + $this->commands('users.console.sendBirthday'); + + // Send special event + $commandName = $this->getBaseNamespace().'Console\EmailSpecialEventCommand'; + $this->app->bindShared('users.console.emailSpecialEvent', function ($app) use ($commandName) { + return $app->make($commandName); + }); + + $this->commands('users.console.emailSpecialEvent'); + } + + /** + * The controller name to handle requests. + * + * @return string + */ + private function getController() + { + return 'UsersController'; + } } diff --git a/app/TeenQuotes/Users/Validation/UserValidator.php b/app/TeenQuotes/Users/Validation/UserValidator.php index 14d1196e..adaab5db 100644 --- a/app/TeenQuotes/Users/Validation/UserValidator.php +++ b/app/TeenQuotes/Users/Validation/UserValidator.php @@ -1,59 +1,66 @@ - 'required|min:6', - 'login' => 'required|alpha_dash|exists:users,login|min:3|max:20', - ]; - - protected $rulesLogin = [ - 'login' => 'required|alpha_dash|unique:users,login|min:3|max:20', - ]; - - /** - * The validation rules when signing up - * @var array - */ - protected $rulesSignup = [ - 'password' => 'required|min:6', - 'login' => 'required|alpha_dash|unique:users,login|min:3|max:20', - 'email' => 'required|email|unique:users,email', - ]; - - /** - * The validation rules when updating a profile - * @var array - */ - protected $rulesUpdateProfile = [ - 'gender' => 'in:M,F', - 'birthdate' => 'date_format:"Y-m-d"', - 'country' => 'exists:countries,id', - 'city' => '', - 'avatar' => 'image|max:1500', - 'about_me' => 'max:500', - ]; - - /** - * The validation rules when deleting an account - * @var array - */ - protected $rulesDestroy = [ - 'password' => 'required|min:6', - 'delete-confirmation' => 'in:DELETE' - ]; - - /** - * The validation rules when updating a password - * @var array - */ - protected $rulesUpdatePassword = [ - 'password' => 'required|min:6|confirmed', - ]; -} \ No newline at end of file +class UserValidator extends BaseValidator +{ + /** + * The validation rules when signing in. + * + * @var array + */ + protected $rulesSignin = [ + 'password' => 'required|min:6', + 'login' => 'required|alpha_dash|exists:users,login|min:3|max:20', + ]; + + protected $rulesLogin = [ + 'login' => 'required|alpha_dash|unique:users,login|min:3|max:20', + ]; + + /** + * The validation rules when signing up. + * + * @var array + */ + protected $rulesSignup = [ + 'password' => 'required|min:6', + 'login' => 'required|alpha_dash|unique:users,login|min:3|max:20', + 'email' => 'required|email|unique:users,email', + ]; + + /** + * The validation rules when updating a profile. + * + * @var array + */ + protected $rulesUpdateProfile = [ + 'gender' => 'in:M,F', + 'birthdate' => 'date_format:"Y-m-d"', + 'country' => 'exists:countries,id', + 'city' => '', + 'avatar' => 'image|max:1500', + 'about_me' => 'max:500', + ]; + + /** + * The validation rules when deleting an account. + * + * @var array + */ + protected $rulesDestroy = [ + 'password' => 'required|min:6', + 'delete-confirmation' => 'in:DELETE', + ]; + + /** + * The validation rules when updating a password. + * + * @var array + */ + protected $rulesUpdatePassword = [ + 'password' => 'required|min:6|confirmed', + ]; +} diff --git a/app/commands/QuoteRefuseTooSadCommand.php b/app/commands/QuoteRefuseTooSadCommand.php index fb21cf9e..868499ee 100644 --- a/app/commands/QuoteRefuseTooSadCommand.php +++ b/app/commands/QuoteRefuseTooSadCommand.php @@ -2,174 +2,182 @@ use Illuminate\Console\Command; use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputOption; - -class QuoteRefuseTooSadCommand extends Command { - - /** - * The console command name. - * - * @var string - */ - protected $name = 'quotes:learningTooSad'; - - /** - * The console command description. - * - * @var string - */ - protected $description = 'Try to determine the appropriate treshold that describes when we will refuse too sad quotes.'; - - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function fire() - { - // Set lower bound - $lowerBound = is_null($this->argument('lowerBound')) ? 0.5 : $this->argument('lowerBound'); - if ($lowerBound > 1 OR $lowerBound < 0) - throw new InvalidArgumentException("Lower bound must be between 0 and 1.", 1); - - // Set upper bound - $upperBound = is_null($this->argument('upperBound')) ? 0.99 : $this->argument('upperBound'); - if ($upperBound > 1 OR $upperBound < 0) - throw new InvalidArgumentException("Upper bound must be between 0 and 1.", 1); - - // Set step value for the sequence - $step = is_null($this->argument('step')) ? 0.02 : $this->argument('step'); - - // Build initial arrays with thresholds, initialized at 0 - $thresholds = range($lowerBound, $upperBound, $step); - $wrongClassifications = array_fill_keys($thresholds, 0); - $foundSadQuotes = $wrongClassifications; - - $confidenceScoresNotPublished = array_fill_keys($thresholds, array()); - $confidenceScoresPublished = array_fill_keys($thresholds, array()); - - $quotes = Quote::all(); - $numberOfQuotes = count($quotes); - - $this->info('Analyzing '.$numberOfQuotes.' quotes...'); - - // Process each quote - foreach ($quotes as $quote) { - - // Display some info to know everything is working fine - if ($quote->id % 2000 == 0) - $this->info('Processing quote #'.$quote->id); - - // If the quote is too negative with enough confidence - if (SentimentAnalysis::isNegative($quote->content)) { - $scores = SentimentAnalysis::scores($quote->content); - rsort($scores); - $score = $scores[0]; - $confidenceGap = $this->computeConfidenceGap($scores); - - // Update number of sad quotes found for the appropriate thresholds - foreach ($foundSadQuotes as $threshold => $value) { - if ($score >= $threshold) - $foundSadQuotes[$threshold] = $value + 1; - } - - // Update the number of wrong classification for the appropriate thresholds - foreach ($wrongClassifications as $threshold => $value) { - if ($score >= $threshold) { - // We found that the quote was too negative but yet it was published - // Count the wrong classification - if ($quote->isPublished()) { - $wrongClassifications[$threshold] = $value + 1; - array_push($confidenceScoresPublished[$threshold], $confidenceGap); - } - else - array_push($confidenceScoresNotPublished[$threshold], $confidenceGap); - } - } - } - } - - // Display the results - foreach ($wrongClassifications as $threshold => $value) { - // Both arrays have got the same keys - $nbQuotes = $foundSadQuotes[$threshold]; - $wrongNbClassifications = $value; - $gapNotPublished = $this->arrayAverage($confidenceScoresNotPublished[$threshold]); - $gapPublished = $this->arrayAverage($confidenceScoresPublished[$threshold]); - - // Compute percentage and display some info - $percentage = $this->getPercentage($wrongNbClassifications, $nbQuotes); - $this->info('Threshold '.$threshold.': '.$nbQuotes.' quotes with '.$wrongNbClassifications.' wrong classifications ('.$percentage.' %)'); - $this->info('Average gap for published: '.$gapPublished); - $this->info('Average gap for not published: '.$gapNotPublished); - } - } - - /** - * Returns a percentage with 2 digits - * @param int $value The value - * @param int $total The total number of items - * @return float The percentage - */ - private function getPercentage($value, $total) - { - return round($value / $total * 100, 2); - } - - /** - * Compute the confidence score for a given classification, that is to say the difference between the max score and the following score - * @param array $scores The scores array, must be reversed ordered! - * @return float The difference for the two max scores, with 2 digits - */ - private function computeConfidenceGap($scores) - { - return round($scores[0] - $scores[1], 2); - } - - /** - * Compute the average of an array of values - * @param array $array The array - * @return float The average value with 2 digits - */ - private function arrayAverage($array) - { - if (count($array) === 0) - return 0; - - return round(array_sum($array) / count($array), 2); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return [ - ['lowerBound', InputArgument::OPTIONAL, 'The lower bound for the treshold.'], - ['upperBound', InputArgument::OPTIONAL, 'The upper bound for the treshold.'], - ['step', InputArgument::OPTIONAL, 'Increment value between elements in the sequence.'], - ]; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return array(); - } + +class QuoteRefuseTooSadCommand extends Command +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'quotes:learningTooSad'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Try to determine the appropriate treshold that describes when we will refuse too sad quotes.'; + + /** + * Create a new command instance. + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Set lower bound + $lowerBound = is_null($this->argument('lowerBound')) ? 0.5 : $this->argument('lowerBound'); + if ($lowerBound > 1 or $lowerBound < 0) { + throw new InvalidArgumentException('Lower bound must be between 0 and 1.', 1); + } + + // Set upper bound + $upperBound = is_null($this->argument('upperBound')) ? 0.99 : $this->argument('upperBound'); + if ($upperBound > 1 or $upperBound < 0) { + throw new InvalidArgumentException('Upper bound must be between 0 and 1.', 1); + } + + // Set step value for the sequence + $step = is_null($this->argument('step')) ? 0.02 : $this->argument('step'); + + // Build initial arrays with thresholds, initialized at 0 + $thresholds = range($lowerBound, $upperBound, $step); + $wrongClassifications = array_fill_keys($thresholds, 0); + $foundSadQuotes = $wrongClassifications; + + $confidenceScoresNotPublished = array_fill_keys($thresholds, []); + $confidenceScoresPublished = array_fill_keys($thresholds, []); + + $quotes = Quote::all(); + $numberOfQuotes = count($quotes); + + $this->info('Analyzing '.$numberOfQuotes.' quotes...'); + + // Process each quote + foreach ($quotes as $quote) { + + // Display some info to know everything is working fine + if ($quote->id % 2000 == 0) { + $this->info('Processing quote #'.$quote->id); + } + + // If the quote is too negative with enough confidence + if (SentimentAnalysis::isNegative($quote->content)) { + $scores = SentimentAnalysis::scores($quote->content); + rsort($scores); + $score = $scores[0]; + $confidenceGap = $this->computeConfidenceGap($scores); + + // Update number of sad quotes found for the appropriate thresholds + foreach ($foundSadQuotes as $threshold => $value) { + if ($score >= $threshold) { + $foundSadQuotes[$threshold] = $value + 1; + } + } + + // Update the number of wrong classification for the appropriate thresholds + foreach ($wrongClassifications as $threshold => $value) { + if ($score >= $threshold) { + // We found that the quote was too negative but yet it was published + // Count the wrong classification + if ($quote->isPublished()) { + $wrongClassifications[$threshold] = $value + 1; + array_push($confidenceScoresPublished[$threshold], $confidenceGap); + } else { + array_push($confidenceScoresNotPublished[$threshold], $confidenceGap); + } + } + } + } + } + + // Display the results + foreach ($wrongClassifications as $threshold => $value) { + // Both arrays have got the same keys + $nbQuotes = $foundSadQuotes[$threshold]; + $wrongNbClassifications = $value; + $gapNotPublished = $this->arrayAverage($confidenceScoresNotPublished[$threshold]); + $gapPublished = $this->arrayAverage($confidenceScoresPublished[$threshold]); + + // Compute percentage and display some info + $percentage = $this->getPercentage($wrongNbClassifications, $nbQuotes); + $this->info('Threshold '.$threshold.': '.$nbQuotes.' quotes with '.$wrongNbClassifications.' wrong classifications ('.$percentage.' %)'); + $this->info('Average gap for published: '.$gapPublished); + $this->info('Average gap for not published: '.$gapNotPublished); + } + } + + /** + * Returns a percentage with 2 digits. + * + * @param int $value The value + * @param int $total The total number of items + * + * @return float The percentage + */ + private function getPercentage($value, $total) + { + return round($value / $total * 100, 2); + } + + /** + * Compute the confidence score for a given classification, that is to say the difference between the max score and the following score. + * + * @param array $scores The scores array, must be reversed ordered! + * + * @return float The difference for the two max scores, with 2 digits + */ + private function computeConfidenceGap($scores) + { + return round($scores[0] - $scores[1], 2); + } + + /** + * Compute the average of an array of values. + * + * @param array $array The array + * + * @return float The average value with 2 digits + */ + private function arrayAverage($array) + { + if (count($array) === 0) { + return 0; + } + + return round(array_sum($array) / count($array), 2); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['lowerBound', InputArgument::OPTIONAL, 'The lower bound for the treshold.'], + ['upperBound', InputArgument::OPTIONAL, 'The upper bound for the treshold.'], + ['step', InputArgument::OPTIONAL, 'Increment value between elements in the sequence.'], + ]; + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return []; + } } diff --git a/app/config/app.php b/app/config/app.php index 6350e9a4..7f89a597 100644 --- a/app/config/app.php +++ b/app/config/app.php @@ -1,288 +1,289 @@ false, - - /* - |-------------------------------------------------------------------------- - | Application URL - |-------------------------------------------------------------------------- - | - | This URL is used by the console to properly generate URLs when using - | the Artisan command line tool. You should set this to the root of - | your application so that it is used when running Artisan tasks. - | - */ - - 'url' => 'http://teen-quotes.com', - - 'domain' => 'teen-quotes.com', - - 'domainAPI' => 'api.teen-quotes.com', - 'domainStories' => 'stories.teen-quotes.com', - 'domainAdmin' => 'admin.teen-quotes.com', - 'domainAccount' => 'account.teen-quotes.com', - - /* - |-------------------------------------------------------------------------- - | Application Timezone - |-------------------------------------------------------------------------- - | - | Here you may specify the default timezone for your application, which - | will be used by the PHP date and date-time functions. We have gone - | ahead and set this to a sensible default for you out of the box. - | - */ - - 'timezone' => 'UTC', - - /* - |-------------------------------------------------------------------------- - | Application Locale Configuration - |-------------------------------------------------------------------------- - | - | The application locale determines the default locale that will be used - | by the translation service provider. You are free to set this value - | to any of the locales which will be supported by the application. - | - */ - - 'locale' => 'en', - - /* - |-------------------------------------------------------------------------- - | Application Fallback Locale - |-------------------------------------------------------------------------- - | - | The fallback locale determines the locale to use when the current one - | is not available. You may change the value to correspond to any of - | the language folders that are provided through your application. - | - */ - - 'fallback_locale' => 'en', - - /* - |-------------------------------------------------------------------------- - | Encryption Key - |-------------------------------------------------------------------------- - | - | This key is used by the Illuminate encrypter service and should be set - | to a random, 32 character string, otherwise these encrypted strings - | will not be safe. Please do this before deploying an application! - | - */ - - 'key' => 'zXPYTseYZiFjua90HVGJMro7CYb8USRg', - 'cipher' => MCRYPT_RIJNDAEL_256, - - /* - |-------------------------------------------------------------------------- - | Autoloaded Service Providers - |-------------------------------------------------------------------------- - | - | The service providers listed here will be automatically loaded on the - | request to your application. Feel free to add your own services to - | this array to grant expanded functionality to your applications. - | - */ - - 'providers' => array( - - 'Antoineaugusti\LaravelEasyrec\LaravelEasyrecServiceProvider', - 'Antoineaugusti\LaravelSentimentAnalysis\LaravelSentimentAnalysisServiceProvider', - 'Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider', - 'Buonzz\GeoIP\Laravel4\ServiceProviders\GeoIPServiceProvider', - 'GrahamCampbell\HTMLMin\HTMLMinServiceProvider', - 'Healey\Robots\RobotsServiceProvider', - 'Illuminate\Auth\AuthServiceProvider', - 'Illuminate\Auth\Reminders\ReminderServiceProvider', - 'Illuminate\Cache\CacheServiceProvider', - 'Illuminate\Cookie\CookieServiceProvider', - 'Illuminate\Database\DatabaseServiceProvider', - 'Illuminate\Database\MigrationServiceProvider', - 'Illuminate\Database\SeedServiceProvider', - 'Illuminate\Encryption\EncryptionServiceProvider', - 'Illuminate\Filesystem\FilesystemServiceProvider', - 'Illuminate\Foundation\Providers\ArtisanServiceProvider', - 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', - 'Illuminate\Hashing\HashServiceProvider', - 'Illuminate\Html\HtmlServiceProvider', - 'Illuminate\Log\LogServiceProvider', - 'Illuminate\Pagination\PaginationServiceProvider', - 'Illuminate\Queue\QueueServiceProvider', - 'Illuminate\Redis\RedisServiceProvider', - 'Illuminate\Remote\RemoteServiceProvider', - 'Illuminate\Routing\ControllerServiceProvider', - 'Illuminate\Session\CommandsServiceProvider', - 'Illuminate\Session\SessionServiceProvider', - 'Illuminate\Translation\TranslationServiceProvider', - 'Illuminate\Validation\ValidationServiceProvider', - 'Illuminate\View\ViewServiceProvider', - 'Illuminate\Workbench\WorkbenchServiceProvider', - 'Indatus\Dispatcher\ServiceProvider', - 'Jenssegers\Agent\AgentServiceProvider', - 'Laracasts\Utilities\UtilitiesServiceProvider', - 'Laracasts\Validation\ValidationServiceProvider', - 'LucaDegasperi\OAuth2Server\OAuth2ServerServiceProvider', - 'Philf\Setting\SettingServiceProvider', - 'Philo\Translate\TranslateServiceProvider', - 'TeenQuotes\AdminPanel\AdminPanelServiceProvider', - 'TeenQuotes\Api\V1\ApiServiceProvider', - 'TeenQuotes\Auth\AuthServiceProvider', - 'TeenQuotes\Comments\CommentsServiceProvider', - 'TeenQuotes\Countries\CountriesServiceProvider', - 'TeenQuotes\Mail\MailServiceProvider', - 'TeenQuotes\Mail\MandrillServiceProvider', - 'TeenQuotes\Newsletters\NewsletterListServiceProvider', - 'TeenQuotes\Newsletters\NewslettersServiceProvider', - 'TeenQuotes\Notifiers\AdminNotifierServiceProvider', - 'TeenQuotes\Pages\PagesServiceProvider', - 'TeenQuotes\Queues\QueuesServiceProvider', - 'TeenQuotes\Quotes\QuotesServiceProvider', - 'TeenQuotes\Robots\RobotsServiceProvider', - 'TeenQuotes\Settings\SettingsServiceProvider', - 'TeenQuotes\Stories\StoriesServiceProvider', - 'TeenQuotes\Tags\TagsServiceProvider', - 'TeenQuotes\Users\UsersServiceProvider', - 'Thomaswelton\LaravelGravatar\LaravelGravatarServiceProvider', - 'Way\Generators\GeneratorsServiceProvider', - ), - - /* - |-------------------------------------------------------------------------- - | Service Provider Manifest - |-------------------------------------------------------------------------- - | - | The service provider manifest is used by Laravel to lazy load service - | providers which are not needed for each request, as well to keep a - | list of all of the services. Here, you may set its storage spot. - | - */ - - 'manifest' => storage_path().'/meta', - - /* - |-------------------------------------------------------------------------- - | Class Aliases - |-------------------------------------------------------------------------- - | - | This array of class aliases will be registered when this application - | is started. However, feel free to register as many as you wish as - | the aliases are "lazy" loaded so they don't hinder performance. - | - */ - - 'aliases' => array( - - 'Agent' => 'Jenssegers\Agent\Facades\Agent', - 'App' => 'Illuminate\Support\Facades\App', - 'Artisan' => 'Illuminate\Support\Facades\Artisan', - 'Auth' => 'Illuminate\Support\Facades\Auth', - 'AuthorizationServer' => 'LucaDegasperi\OAuth2Server\Facades\AuthorizationServerFacade', - 'BaseController' => 'TeenQuotes\Tools\BaseController', - 'Blade' => 'Illuminate\Support\Facades\Blade', - 'Bugsnag' => 'Bugsnag\BugsnagLaravel\BugsnagFacade', - 'Cache' => 'Illuminate\Support\Facades\Cache', - 'Carbon' => 'Carbon\Carbon', - 'ClassLoader' => 'Illuminate\Support\ClassLoader', - 'Config' => 'Illuminate\Support\Facades\Config', - 'Controller' => 'Illuminate\Routing\Controller', - 'Cookie' => 'Illuminate\Support\Facades\Cookie', - 'Crypt' => 'Illuminate\Support\Facades\Crypt', - 'DB' => 'Illuminate\Support\Facades\DB', - 'Easyrec' => 'Antoineaugusti\LaravelEasyrec\Facades\LaravelEasyrec', - 'Eloquent' => 'Illuminate\Database\Eloquent\Model', - 'Event' => 'Illuminate\Support\Facades\Event', - 'File' => 'Illuminate\Support\Facades\File', - 'Form' => 'Illuminate\Support\Facades\Form', - 'GeoIP' => 'Buonzz\GeoIP\Laravel4\Facades\GeoIP', - 'Gravatar' => 'Thomaswelton\LaravelGravatar\Facades\Gravatar', - 'Hash' => 'Illuminate\Support\Facades\Hash', - 'HTML' => 'Illuminate\Support\Facades\HTML', - 'Input' => 'Illuminate\Support\Facades\Input', - 'Lang' => 'Illuminate\Support\Facades\Lang', - 'LaraSetting' => 'Philf\Setting\Facades\Setting', - 'Log' => 'Illuminate\Support\Facades\Log', - 'Mail' => 'Illuminate\Support\Facades\Mail', - 'MailSwitcher' => 'TeenQuotes\Mail\MailSwitcher', - 'MandrillClient' => 'TeenQuotes\Mail\Facades\MandrillClient', - 'Paginator' => 'Illuminate\Support\Facades\Paginator', - 'Password' => 'Illuminate\Support\Facades\Password', - 'Queue' => 'Illuminate\Support\Facades\Queue', - 'Redirect' => 'Illuminate\Support\Facades\Redirect', - 'Redis' => 'Illuminate\Support\Facades\Redis', - 'Request' => 'Illuminate\Support\Facades\Request', - 'ResourceServer' => 'LucaDegasperi\OAuth2Server\Facades\ResourceServerFacade', - 'Response' => 'Illuminate\Support\Facades\Response', - 'Route' => 'Illuminate\Support\Facades\Route', - 'ScheduledCommand' => 'Indatus\Dispatcher\Scheduling\ScheduledCommand', - 'Schema' => 'Illuminate\Support\Facades\Schema', - 'Seeder' => 'Illuminate\Database\Seeder', - 'SentimentAnalysis' => 'Antoineaugusti\LaravelSentimentAnalysis\Facades\SentimentAnalysis', - 'Session' => 'Illuminate\Support\Facades\Session', - 'SSH' => 'Illuminate\Support\Facades\SSH', - 'Str' => 'Illuminate\Support\Str', - 'TextTools' => 'TeenQuotes\Tools\TextTools', - 'Toloquent' => 'TeenQuotes\Database\Toloquent', - 'URL' => 'Illuminate\Support\Facades\URL', - 'Validator' => 'Illuminate\Support\Facades\Validator', - 'View' => 'Illuminate\Support\Facades\View', - ), - - /* - |-------------------------------------------------------------------------- - | App variables - |-------------------------------------------------------------------------- - | - | - */ - - 'comments.nbCommentsPerPage' => 10, - - 'quotes.nbQuotesToPublishPerDay' => 5, - - 'quotes.nbQuotesPerPage' => 10, - - 'quotes.maxSubmitPerDay' => 5, - - // International Association for Suicide Prevention - 'quotes.moderationURLHelp' => 'http://www.iasp.info/resources/Crisis_Centres/', - - 'newsletters.nbQuotesToSendWeekly' => 10, - - 'newsletters.nbQuotesToSendDaily' => 2, - - 'users.avatar.default' => 'http://teen-quotes.com/assets/images/chat.png', - 'users.avatarPath' => 'uploads/avatar', - 'users.avatarWidth' => 200, - 'users.avatarHeight' => 200, - - 'users.colorsAvailableQuotesPublished' => [ - 'blue', - 'green', - 'purple', - 'red', - 'orange', - ], - - 'users.defaultColorQuotesPublished' => 'blue', - - 'users.nbQuotesPerPage' => 5, - - 'search.maxResultsPerCategory' => 10, - - 'stories.nbStoriesPerPage' => 5, -); +return [ + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => false, + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => 'http://teen-quotes.com', + + 'domain' => 'teen-quotes.com', + + 'domainAPI' => 'api.teen-quotes.com', + 'domainStories' => 'stories.teen-quotes.com', + 'domainAdmin' => 'admin.teen-quotes.com', + 'domainAccount' => 'account.teen-quotes.com', + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + */ + + 'locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Application Fallback Locale + |-------------------------------------------------------------------------- + | + | The fallback locale determines the locale to use when the current one + | is not available. You may change the value to correspond to any of + | the language folders that are provided through your application. + | + */ + + 'fallback_locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is used by the Illuminate encrypter service and should be set + | to a random, 32 character string, otherwise these encrypted strings + | will not be safe. Please do this before deploying an application! + | + */ + + 'key' => 'zXPYTseYZiFjua90HVGJMro7CYb8USRg', + 'cipher' => MCRYPT_RIJNDAEL_256, + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => [ + + 'Antoineaugusti\LaravelEasyrec\LaravelEasyrecServiceProvider', + 'Antoineaugusti\LaravelSentimentAnalysis\LaravelSentimentAnalysisServiceProvider', + 'Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider', + 'Buonzz\GeoIP\Laravel4\ServiceProviders\GeoIPServiceProvider', + 'GrahamCampbell\HTMLMin\HTMLMinServiceProvider', + 'Healey\Robots\RobotsServiceProvider', + 'Illuminate\Auth\AuthServiceProvider', + 'Illuminate\Auth\Reminders\ReminderServiceProvider', + 'Illuminate\Cache\CacheServiceProvider', + 'Illuminate\Cookie\CookieServiceProvider', + 'Illuminate\Database\DatabaseServiceProvider', + 'Illuminate\Database\MigrationServiceProvider', + 'Illuminate\Database\SeedServiceProvider', + 'Illuminate\Encryption\EncryptionServiceProvider', + 'Illuminate\Filesystem\FilesystemServiceProvider', + 'Illuminate\Foundation\Providers\ArtisanServiceProvider', + 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', + 'Illuminate\Hashing\HashServiceProvider', + 'Illuminate\Html\HtmlServiceProvider', + 'Illuminate\Log\LogServiceProvider', + 'Illuminate\Pagination\PaginationServiceProvider', + 'Illuminate\Queue\QueueServiceProvider', + 'Illuminate\Redis\RedisServiceProvider', + 'Illuminate\Remote\RemoteServiceProvider', + 'Illuminate\Routing\ControllerServiceProvider', + 'Illuminate\Session\CommandsServiceProvider', + 'Illuminate\Session\SessionServiceProvider', + 'Illuminate\Translation\TranslationServiceProvider', + 'Illuminate\Validation\ValidationServiceProvider', + 'Illuminate\View\ViewServiceProvider', + 'Illuminate\Workbench\WorkbenchServiceProvider', + 'Indatus\Dispatcher\ServiceProvider', + 'Jenssegers\Agent\AgentServiceProvider', + 'Laracasts\Utilities\UtilitiesServiceProvider', + 'Laracasts\Validation\ValidationServiceProvider', + 'LucaDegasperi\OAuth2Server\OAuth2ServerServiceProvider', + 'Philf\Setting\SettingServiceProvider', + 'Philo\Translate\TranslateServiceProvider', + 'TeenQuotes\AdminPanel\AdminPanelServiceProvider', + 'TeenQuotes\Api\V1\ApiServiceProvider', + 'TeenQuotes\Auth\AuthServiceProvider', + 'TeenQuotes\Comments\CommentsServiceProvider', + 'TeenQuotes\Countries\CountriesServiceProvider', + 'TeenQuotes\Mail\MailServiceProvider', + 'TeenQuotes\Mail\MandrillServiceProvider', + 'TeenQuotes\Newsletters\NewsletterListServiceProvider', + 'TeenQuotes\Newsletters\NewslettersServiceProvider', + 'TeenQuotes\Notifiers\AdminNotifierServiceProvider', + 'TeenQuotes\Pages\PagesServiceProvider', + 'TeenQuotes\Queues\QueuesServiceProvider', + 'TeenQuotes\Quotes\QuotesServiceProvider', + 'TeenQuotes\Robots\RobotsServiceProvider', + 'TeenQuotes\Settings\SettingsServiceProvider', + 'TeenQuotes\Stories\StoriesServiceProvider', + 'TeenQuotes\Tags\TagsServiceProvider', + 'TeenQuotes\Tools\ToolsServiceProvider', + 'TeenQuotes\Users\UsersServiceProvider', + 'Thomaswelton\LaravelGravatar\LaravelGravatarServiceProvider', + 'Way\Generators\GeneratorsServiceProvider', + ], + + /* + |-------------------------------------------------------------------------- + | Service Provider Manifest + |-------------------------------------------------------------------------- + | + | The service provider manifest is used by Laravel to lazy load service + | providers which are not needed for each request, as well to keep a + | list of all of the services. Here, you may set its storage spot. + | + */ + + 'manifest' => storage_path().'/meta', + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + 'aliases' => [ + + 'Agent' => 'Jenssegers\Agent\Facades\Agent', + 'App' => 'Illuminate\Support\Facades\App', + 'Artisan' => 'Illuminate\Support\Facades\Artisan', + 'Auth' => 'Illuminate\Support\Facades\Auth', + 'AuthorizationServer' => 'LucaDegasperi\OAuth2Server\Facades\AuthorizationServerFacade', + 'BaseController' => 'TeenQuotes\Tools\BaseController', + 'Blade' => 'Illuminate\Support\Facades\Blade', + 'Bugsnag' => 'Bugsnag\BugsnagLaravel\BugsnagFacade', + 'Cache' => 'Illuminate\Support\Facades\Cache', + 'Carbon' => 'Carbon\Carbon', + 'ClassLoader' => 'Illuminate\Support\ClassLoader', + 'Config' => 'Illuminate\Support\Facades\Config', + 'Controller' => 'Illuminate\Routing\Controller', + 'Cookie' => 'Illuminate\Support\Facades\Cookie', + 'Crypt' => 'Illuminate\Support\Facades\Crypt', + 'DB' => 'Illuminate\Support\Facades\DB', + 'Easyrec' => 'Antoineaugusti\LaravelEasyrec\Facades\LaravelEasyrec', + 'Eloquent' => 'Illuminate\Database\Eloquent\Model', + 'Event' => 'Illuminate\Support\Facades\Event', + 'File' => 'Illuminate\Support\Facades\File', + 'Form' => 'Illuminate\Support\Facades\Form', + 'GeoIP' => 'Buonzz\GeoIP\Laravel4\Facades\GeoIP', + 'Gravatar' => 'Thomaswelton\LaravelGravatar\Facades\Gravatar', + 'Hash' => 'Illuminate\Support\Facades\Hash', + 'HTML' => 'Illuminate\Support\Facades\HTML', + 'Input' => 'Illuminate\Support\Facades\Input', + 'Lang' => 'Illuminate\Support\Facades\Lang', + 'LaraSetting' => 'Philf\Setting\Facades\Setting', + 'Log' => 'Illuminate\Support\Facades\Log', + 'Mail' => 'Illuminate\Support\Facades\Mail', + 'MailSwitcher' => 'TeenQuotes\Mail\MailSwitcher', + 'MandrillClient' => 'TeenQuotes\Mail\Facades\MandrillClient', + 'Paginator' => 'Illuminate\Support\Facades\Paginator', + 'Password' => 'Illuminate\Support\Facades\Password', + 'Queue' => 'Illuminate\Support\Facades\Queue', + 'Redirect' => 'Illuminate\Support\Facades\Redirect', + 'Redis' => 'Illuminate\Support\Facades\Redis', + 'Request' => 'Illuminate\Support\Facades\Request', + 'ResourceServer' => 'LucaDegasperi\OAuth2Server\Facades\ResourceServerFacade', + 'Response' => 'Illuminate\Support\Facades\Response', + 'Route' => 'Illuminate\Support\Facades\Route', + 'ScheduledCommand' => 'Indatus\Dispatcher\Scheduling\ScheduledCommand', + 'Schema' => 'Illuminate\Support\Facades\Schema', + 'Seeder' => 'Illuminate\Database\Seeder', + 'SentimentAnalysis' => 'Antoineaugusti\LaravelSentimentAnalysis\Facades\SentimentAnalysis', + 'Session' => 'Illuminate\Support\Facades\Session', + 'SSH' => 'Illuminate\Support\Facades\SSH', + 'Str' => 'Illuminate\Support\Str', + 'TextTools' => 'TeenQuotes\Tools\TextTools', + 'Toloquent' => 'TeenQuotes\Database\Toloquent', + 'URL' => 'Illuminate\Support\Facades\URL', + 'Validator' => 'Illuminate\Support\Facades\Validator', + 'View' => 'Illuminate\Support\Facades\View', + ], + + /* + |-------------------------------------------------------------------------- + | App variables + |-------------------------------------------------------------------------- + | + | + */ + + 'comments.nbCommentsPerPage' => 10, + + 'quotes.nbQuotesToPublishPerDay' => 5, + + 'quotes.nbQuotesPerPage' => 10, + + 'quotes.maxSubmitPerDay' => 5, + + // International Association for Suicide Prevention + 'quotes.moderationURLHelp' => 'http://www.iasp.info/resources/Crisis_Centres/', + + 'newsletters.nbQuotesToSendWeekly' => 10, + + 'newsletters.nbQuotesToSendDaily' => 2, + + 'users.avatar.default' => 'http://teen-quotes.com/assets/images/chat.png', + 'users.avatarPath' => 'uploads/avatar', + 'users.avatarWidth' => 200, + 'users.avatarHeight' => 200, + + 'users.colorsAvailableQuotesPublished' => [ + 'blue', + 'green', + 'purple', + 'red', + 'orange', + ], + + 'users.defaultColorQuotesPublished' => 'blue', + + 'users.nbQuotesPerPage' => 5, + + 'search.maxResultsPerCategory' => 10, + + 'stories.nbStoriesPerPage' => 5, +]; diff --git a/app/config/auth.php b/app/config/auth.php index 08fb9372..3c020bbb 100644 --- a/app/config/auth.php +++ b/app/config/auth.php @@ -1,71 +1,71 @@ 'eloquent', + 'driver' => 'eloquent', - /* - |-------------------------------------------------------------------------- - | Authentication Model - |-------------------------------------------------------------------------- - | - | When using the "Eloquent" authentication driver, we need to know which - | Eloquent model should be used to retrieve your users. Of course, it - | is often just the "User" model but you may use whatever you like. - | - */ + /* + |-------------------------------------------------------------------------- + | Authentication Model + |-------------------------------------------------------------------------- + | + | When using the "Eloquent" authentication driver, we need to know which + | Eloquent model should be used to retrieve your users. Of course, it + | is often just the "User" model but you may use whatever you like. + | + */ - 'model' => 'TeenQuotes\Users\Models\User', + 'model' => 'TeenQuotes\Users\Models\User', - /* - |-------------------------------------------------------------------------- - | Authentication Table - |-------------------------------------------------------------------------- - | - | When using the "Database" authentication driver, we need to know which - | table should be used to retrieve your users. We have chosen a basic - | default value but you may easily change it to any table you like. - | - */ + /* + |-------------------------------------------------------------------------- + | Authentication Table + |-------------------------------------------------------------------------- + | + | When using the "Database" authentication driver, we need to know which + | table should be used to retrieve your users. We have chosen a basic + | default value but you may easily change it to any table you like. + | + */ - 'table' => 'users', + 'table' => 'users', - /* - |-------------------------------------------------------------------------- - | Password Reminder Settings - |-------------------------------------------------------------------------- - | - | Here you may set the settings for password reminders, including a view - | that should be used as your password reminder e-mail. You will also - | be able to set the name of the table that holds the reset tokens. - | - | The "expire" time is the number of minutes that the reminder should be - | considered valid. This security feature keeps tokens short-lived so - | they have less time to be guessed. You may change this as needed. - | - */ + /* + |-------------------------------------------------------------------------- + | Password Reminder Settings + |-------------------------------------------------------------------------- + | + | Here you may set the settings for password reminders, including a view + | that should be used as your password reminder e-mail. You will also + | be able to set the name of the table that holds the reset tokens. + | + | The "expire" time is the number of minutes that the reminder should be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + */ - 'reminder' => array( + 'reminder' => [ - 'email' => 'emails.auth.reminder', + 'email' => 'emails.auth.reminder', - 'table' => 'password_reminders', + 'table' => 'password_reminders', - 'expire' => 60, + 'expire' => 60, - ), + ], -); +]; diff --git a/app/config/cache.php b/app/config/cache.php index 3c8412c6..c5878209 100644 --- a/app/config/cache.php +++ b/app/config/cache.php @@ -1,89 +1,89 @@ getenv('CACHE_DRIVER'), - - /* - |-------------------------------------------------------------------------- - | File Cache Location - |-------------------------------------------------------------------------- - | - | When using the "file" cache driver, we need a location where the cache - | files may be stored. A sensible default has been specified, but you - | are free to change it to any other place on disk that you desire. - | - */ - - 'path' => storage_path().'/cache', - - /* - |-------------------------------------------------------------------------- - | Database Cache Connection - |-------------------------------------------------------------------------- - | - | When using the "database" cache driver you may specify the connection - | that should be used to store the cached items. When this option is - | null the default database connection will be utilized for cache. - | - */ - - 'connection' => null, - - /* - |-------------------------------------------------------------------------- - | Database Cache Table - |-------------------------------------------------------------------------- - | - | When using the "database" cache driver we need to know the table that - | should be used to store the cached items. A default table name has - | been provided but you're free to change it however you deem fit. - | - */ - - 'table' => 'cache', - - /* - |-------------------------------------------------------------------------- - | Memcached Servers - |-------------------------------------------------------------------------- - | - | Now you may specify an array of your Memcached servers that should be - | used when utilizing the Memcached cache driver. All of the servers - | should contain a value for "host", "port", and "weight" options. - | - */ - - 'memcached' => array( - - array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100), - - ), - - /* - |-------------------------------------------------------------------------- - | Cache Key Prefix - |-------------------------------------------------------------------------- - | - | When utilizing a RAM based store such as APC or Memcached, there might - | be other applications utilizing the same cache. So, we'll specify a - | value to get prefixed to all our keys so we can avoid collisions. - | - */ - - 'prefix' => 'laravel', - -); +return [ + + /* + |-------------------------------------------------------------------------- + | Default Cache Driver + |-------------------------------------------------------------------------- + | + | This option controls the default cache "driver" that will be used when + | using the Caching library. Of course, you may use other drivers any + | time you wish. This is the default when another is not specified. + | + | Supported: "file", "database", "apc", "memcached", "redis", "array" + | + */ + + 'driver' => getenv('CACHE_DRIVER'), + + /* + |-------------------------------------------------------------------------- + | File Cache Location + |-------------------------------------------------------------------------- + | + | When using the "file" cache driver, we need a location where the cache + | files may be stored. A sensible default has been specified, but you + | are free to change it to any other place on disk that you desire. + | + */ + + 'path' => storage_path().'/cache', + + /* + |-------------------------------------------------------------------------- + | Database Cache Connection + |-------------------------------------------------------------------------- + | + | When using the "database" cache driver you may specify the connection + | that should be used to store the cached items. When this option is + | null the default database connection will be utilized for cache. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Database Cache Table + |-------------------------------------------------------------------------- + | + | When using the "database" cache driver we need to know the table that + | should be used to store the cached items. A default table name has + | been provided but you're free to change it however you deem fit. + | + */ + + 'table' => 'cache', + + /* + |-------------------------------------------------------------------------- + | Memcached Servers + |-------------------------------------------------------------------------- + | + | Now you may specify an array of your Memcached servers that should be + | used when utilizing the Memcached cache driver. All of the servers + | should contain a value for "host", "port", and "weight" options. + | + */ + + 'memcached' => [ + + ['host' => '127.0.0.1', 'port' => 11211, 'weight' => 100], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => 'laravel', + +]; diff --git a/app/config/codeception/app.php b/app/config/codeception/app.php index 4768f4f9..5edb1cc8 100644 --- a/app/config/codeception/app.php +++ b/app/config/codeception/app.php @@ -1,6 +1,6 @@ 'localhost', - 'users.avatarPath' => 'public/uploads/avatar', -]; \ No newline at end of file + 'domain' => 'localhost', + 'users.avatarPath' => 'public/uploads/avatar', +]; diff --git a/app/config/codeception/cache.php b/app/config/codeception/cache.php index ad21466d..f9cd95f7 100644 --- a/app/config/codeception/cache.php +++ b/app/config/codeception/cache.php @@ -1,2 +1,3 @@ 'codeception', +return [ - 'connections' => array( - 'codeception' => array( - 'driver' => 'sqlite', - 'database' => dirname(dirname(dirname(__DIR__))).'/tests/_data/db.sqlite', - 'prefix' => '', - ), - ), -); + 'default' => 'codeception', + + 'connections' => [ + 'codeception' => [ + 'driver' => 'sqlite', + 'database' => dirname(dirname(dirname(__DIR__))).'/tests/_data/db.sqlite', + 'prefix' => '', + ], + ], +]; diff --git a/app/config/codeception/mail.php b/app/config/codeception/mail.php index 6654abe9..96709e10 100644 --- a/app/config/codeception/mail.php +++ b/app/config/codeception/mail.php @@ -1,9 +1,9 @@ 'smtp', - 'host' => 'localhost', - 'port' => 1025, - 'encryption' => '', - 'from' => array('address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'), -]; \ No newline at end of file + 'driver' => 'smtp', + 'host' => 'localhost', + 'port' => 1025, + 'encryption' => '', + 'from' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], +]; diff --git a/app/config/codeception/queue.php b/app/config/codeception/queue.php index 02d29c07..870164f7 100644 --- a/app/config/codeception/queue.php +++ b/app/config/codeception/queue.php @@ -1,5 +1,5 @@ 'sync', -]; \ No newline at end of file + 'default' => 'sync', +]; diff --git a/app/config/codeception/session.php b/app/config/codeception/session.php index c5b31208..81d814d0 100644 --- a/app/config/codeception/session.php +++ b/app/config/codeception/session.php @@ -1,2 +1,3 @@ 'mysql', +return [ - 'connections' => array( - 'mysql' => array( - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'codeception', - 'username' => 'travis', - 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ), - ), -); + 'default' => 'mysql', + + 'connections' => [ + 'mysql' => [ + 'driver' => 'mysql', + 'host' => 'localhost', + 'database' => 'codeception', + 'username' => 'travis', + 'password' => '', + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ], + ], +]; diff --git a/app/config/codeceptionMysql/mail.php b/app/config/codeceptionMysql/mail.php index d6d35ab0..0d318597 100644 --- a/app/config/codeceptionMysql/mail.php +++ b/app/config/codeceptionMysql/mail.php @@ -1,2 +1,3 @@ 'sync', -]; \ No newline at end of file + 'default' => 'sync', +]; diff --git a/app/config/codeceptionMysql/session.php b/app/config/codeceptionMysql/session.php index eeda063a..477b8d9c 100644 --- a/app/config/codeceptionMysql/session.php +++ b/app/config/codeceptionMysql/session.php @@ -1,2 +1,3 @@ PDO::FETCH_CLASS, - - /* - |-------------------------------------------------------------------------- - | Default Database Connection Name - |-------------------------------------------------------------------------- - | - | Here you may specify which of the database connections below you wish - | to use as your default connection for all database work. Of course - | you may use many connections at once using the Database library. - | - */ - - 'default' => 'mysql', - - /* - |-------------------------------------------------------------------------- - | Database Connections - |-------------------------------------------------------------------------- - | - | Here are each of the database connections setup for your application. - | Of course, examples of configuring each database platform that is - | supported by Laravel is shown below to make development simple. - | - | - | All database work in Laravel is done through the PHP PDO facilities - | so make sure you have the driver for your particular database of - | choice installed on your machine before you begin development. - | - */ - - 'connections' => array( - - 'sqlite' => array( - 'driver' => 'sqlite', - 'database' => __DIR__.'/../database/production.sqlite', - 'prefix' => '', - ), - - 'mysql' => array( - 'driver' => 'mysql', - 'host' => getenv('MYSQL_HOST'), - 'database' => getenv('MYSQL_DATABASE'), - 'username' => getenv('MYSQL_USERNAME'), - 'password' => getenv('MYSQL_PASSWORD'), - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ), - - 'pgsql' => array( - 'driver' => 'pgsql', - 'host' => 'localhost', - 'database' => '', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - 'prefix' => '', - 'schema' => 'public', - ), - - 'sqlsrv' => array( - 'driver' => 'sqlsrv', - 'host' => 'localhost', - 'database' => 'database', - 'username' => 'root', - 'password' => '', - 'prefix' => '', - ), - - ), - - /* - |-------------------------------------------------------------------------- - | Migration Repository Table - |-------------------------------------------------------------------------- - | - | This table keeps track of all the migrations that have already run for - | your application. Using this information, we can determine which of - | the migrations on disk haven't actually been run in the database. - | - */ - - 'migrations' => 'migrations', - - /* - |-------------------------------------------------------------------------- - | Redis Databases - |-------------------------------------------------------------------------- - | - | Redis is an open source, fast, and advanced key-value store that also - | provides a richer set of commands than a typical key-value systems - | such as APC or Memcached. Laravel makes it easy to dig right in. - | - */ - - 'redis' => array( - - 'cluster' => false, - - 'default' => array( - 'host' => '127.0.0.1', - 'port' => 6379, - 'database' => 0, - ), - - ), - - 'log' => false, -); \ No newline at end of file +return [ + + /* + |-------------------------------------------------------------------------- + | PDO Fetch Style + |-------------------------------------------------------------------------- + | + | By default, database results will be returned as instances of the PHP + | stdClass object; however, you may desire to retrieve records in an + | array format for simplicity. Here you can tweak the fetch style. + | + */ + + 'fetch' => PDO::FETCH_CLASS, + + /* + |-------------------------------------------------------------------------- + | Default Database Connection Name + |-------------------------------------------------------------------------- + | + | Here you may specify which of the database connections below you wish + | to use as your default connection for all database work. Of course + | you may use many connections at once using the Database library. + | + */ + + 'default' => 'mysql', + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Here are each of the database connections setup for your application. + | Of course, examples of configuring each database platform that is + | supported by Laravel is shown below to make development simple. + | + | + | All database work in Laravel is done through the PHP PDO facilities + | so make sure you have the driver for your particular database of + | choice installed on your machine before you begin development. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => __DIR__.'/../database/production.sqlite', + 'prefix' => '', + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'host' => getenv('MYSQL_HOST'), + 'database' => getenv('MYSQL_DATABASE'), + 'username' => getenv('MYSQL_USERNAME'), + 'password' => getenv('MYSQL_PASSWORD'), + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'host' => 'localhost', + 'database' => '', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + 'prefix' => '', + 'schema' => 'public', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'host' => 'localhost', + 'database' => 'database', + 'username' => 'root', + 'password' => '', + 'prefix' => '', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run in the database. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer set of commands than a typical key-value systems + | such as APC or Memcached. Laravel makes it easy to dig right in. + | + */ + + 'redis' => [ + + 'cluster' => false, + + 'default' => [ + 'host' => '127.0.0.1', + 'port' => 6379, + 'database' => 0, + ], + + ], + + 'log' => false, +]; diff --git a/app/config/exceptions.php b/app/config/exceptions.php index e4fbe87e..65b0b56a 100644 --- a/app/config/exceptions.php +++ b/app/config/exceptions.php @@ -1,6 +1,6 @@ view name - 500 => 'errors.500' -); \ No newline at end of file +return [ + // HTTP code => view name + 500 => 'errors.500', +]; diff --git a/app/config/local/app.php b/app/config/local/app.php index 4175f2ba..dc9a0ccb 100644 --- a/app/config/local/app.php +++ b/app/config/local/app.php @@ -1,41 +1,41 @@ true, + 'debug' => true, - 'users.avatarPath' => 'public/uploads/avatar', + 'users.avatarPath' => 'public/uploads/avatar', - 'url' => 'http://dev.tq:8000', - 'domain' => 'dev.tq', + 'url' => 'http://dev.tq:8000', + 'domain' => 'dev.tq', - 'domainAPI' => 'api.dev.tq', - 'domainStories' => 'stories.dev.tq', - 'domainAdmin' => 'admin.dev.tq', - 'domainAccount' => 'account.dev.tq', + 'domainAPI' => 'api.dev.tq', + 'domainStories' => 'stories.dev.tq', + 'domainAdmin' => 'admin.dev.tq', + 'domainAccount' => 'account.dev.tq', - 'connections' => array( - 'mysql' => array( - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'teenquotes', - 'username' => 'root', - 'password' => 'helloworld', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - 'unix_socket' => '/tmp/mysql.sock', - ), - ), -); + 'connections' => [ + 'mysql' => [ + 'driver' => 'mysql', + 'host' => 'localhost', + 'database' => 'teenquotes', + 'username' => 'root', + 'password' => 'helloworld', + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + 'unix_socket' => '/tmp/mysql.sock', + ], + ], +]; diff --git a/app/config/local/queue.php b/app/config/local/queue.php index 02d29c07..870164f7 100644 --- a/app/config/local/queue.php +++ b/app/config/local/queue.php @@ -1,5 +1,5 @@ 'sync', -]; \ No newline at end of file + 'default' => 'sync', +]; diff --git a/app/config/mail.php b/app/config/mail.php index cd1f4c52..194520f9 100644 --- a/app/config/mail.php +++ b/app/config/mail.php @@ -2,124 +2,124 @@ return [ - /* - |-------------------------------------------------------------------------- - | Mail Driver - |-------------------------------------------------------------------------- - | - | Laravel supports both SMTP and PHP's "mail" function as drivers for the - | sending of e-mail. You may specify which one you're using throughout - | your application here. By default, Laravel is setup for SMTP mail. - | - | Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", "log" - | - */ - - 'driver' => 'mandrill', - - /* - |-------------------------------------------------------------------------- - | SMTP Host Address - |-------------------------------------------------------------------------- - | - | Here you may provide the host address of the SMTP server used by your - | applications. A default option is provided that is compatible with - | the Mailgun mail service which will provide reliable deliveries. - | - */ - - 'host' => 'mail.teen-quotes.com', - - /* - |-------------------------------------------------------------------------- - | SMTP Host Port - |-------------------------------------------------------------------------- - | - | This is the SMTP port used by your application to delivery e-mails to - | users of your application. Like the host we have set this value to - | stay compatible with the Mailgun e-mail applications by default. - | - */ - - 'port' => 465, - - /* - |-------------------------------------------------------------------------- - | Global "From" Address - |-------------------------------------------------------------------------- - | - | You may wish for all e-mails sent by your application to be sent from - | the same address. Here, you may specify a name and address that is - | used globally for all e-mails that are sent by your application. - | - */ - - 'from' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], - 'from.smtp' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], - 'from.sendmail' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], - - /* - |-------------------------------------------------------------------------- - | E-Mail Encryption Protocol - |-------------------------------------------------------------------------- - | - | Here you may specify the encryption protocol that should be used when - | the application send e-mail messages. A sensible default using the - | transport layer security protocol should provide great security. - | - */ - - 'encryption' => 'tls', - - /* - |-------------------------------------------------------------------------- - | SMTP Server Username - |-------------------------------------------------------------------------- - | - | If your SMTP server requires a username for authentication, you should - | set it here. This will get used to authenticate with your server on - | connection. You may also set the "password" value below this one. - | - */ - - 'username' => getenv('SMTP_USERNAME'), - - /* - |-------------------------------------------------------------------------- - | SMTP Server Password - |-------------------------------------------------------------------------- - | - | Here you may set the password required by your SMTP server to send out - | messages from your application. This will be given to the server on - | connection so that the application will be able to send messages. - | - */ - - 'password' => getenv('SMTP_PASSWORD'), - - /* - |-------------------------------------------------------------------------- - | Sendmail System Path - |-------------------------------------------------------------------------- - | - | When using the "sendmail" driver to send e-mails, we will need to know - | the path to where Sendmail lives on this server. A default path has - | been provided here, which will work well on most of your systems. - | - */ - - 'sendmail' => '/usr/sbin/sendmail -bs', - - /* - |-------------------------------------------------------------------------- - | Mail "Pretend" - |-------------------------------------------------------------------------- - | - | When this option is enabled, e-mail will not actually be sent over the - | web and will instead be written to your application's logs files so - | you may inspect the message. This is great for local development. - | - */ - - 'pretend' => false, -]; \ No newline at end of file + /* + |-------------------------------------------------------------------------- + | Mail Driver + |-------------------------------------------------------------------------- + | + | Laravel supports both SMTP and PHP's "mail" function as drivers for the + | sending of e-mail. You may specify which one you're using throughout + | your application here. By default, Laravel is setup for SMTP mail. + | + | Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", "log" + | + */ + + 'driver' => 'mandrill', + + /* + |-------------------------------------------------------------------------- + | SMTP Host Address + |-------------------------------------------------------------------------- + | + | Here you may provide the host address of the SMTP server used by your + | applications. A default option is provided that is compatible with + | the Mailgun mail service which will provide reliable deliveries. + | + */ + + 'host' => 'mail.teen-quotes.com', + + /* + |-------------------------------------------------------------------------- + | SMTP Host Port + |-------------------------------------------------------------------------- + | + | This is the SMTP port used by your application to delivery e-mails to + | users of your application. Like the host we have set this value to + | stay compatible with the Mailgun e-mail applications by default. + | + */ + + 'port' => 465, + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all e-mails sent by your application to be sent from + | the same address. Here, you may specify a name and address that is + | used globally for all e-mails that are sent by your application. + | + */ + + 'from' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], + 'from.smtp' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], + 'from.sendmail' => ['address' => 'support@teen-quotes.com', 'name' => 'Teen Quotes'], + + /* + |-------------------------------------------------------------------------- + | E-Mail Encryption Protocol + |-------------------------------------------------------------------------- + | + | Here you may specify the encryption protocol that should be used when + | the application send e-mail messages. A sensible default using the + | transport layer security protocol should provide great security. + | + */ + + 'encryption' => 'tls', + + /* + |-------------------------------------------------------------------------- + | SMTP Server Username + |-------------------------------------------------------------------------- + | + | If your SMTP server requires a username for authentication, you should + | set it here. This will get used to authenticate with your server on + | connection. You may also set the "password" value below this one. + | + */ + + 'username' => getenv('SMTP_USERNAME'), + + /* + |-------------------------------------------------------------------------- + | SMTP Server Password + |-------------------------------------------------------------------------- + | + | Here you may set the password required by your SMTP server to send out + | messages from your application. This will be given to the server on + | connection so that the application will be able to send messages. + | + */ + + 'password' => getenv('SMTP_PASSWORD'), + + /* + |-------------------------------------------------------------------------- + | Sendmail System Path + |-------------------------------------------------------------------------- + | + | When using the "sendmail" driver to send e-mails, we will need to know + | the path to where Sendmail lives on this server. A default path has + | been provided here, which will work well on most of your systems. + | + */ + + 'sendmail' => '/usr/sbin/sendmail -bs', + + /* + |-------------------------------------------------------------------------- + | Mail "Pretend" + |-------------------------------------------------------------------------- + | + | When this option is enabled, e-mail will not actually be sent over the + | web and will instead be written to your application's logs files so + | you may inspect the message. This is great for local development. + | + */ + + 'pretend' => false, +]; diff --git a/app/config/mobile.php b/app/config/mobile.php index 98d09869..3f8e7938 100644 --- a/app/config/mobile.php +++ b/app/config/mobile.php @@ -1,20 +1,21 @@ false, + // Do we have an iOS app? + 'iOSApp' => false, - // Do we have an Android app? - 'androidApp' => false, + // Do we have an Android app? + 'androidApp' => false, - // The ID of the iOS application - 'iOSAppID' => 'id577239995', + // The ID of the iOS application + 'iOSAppID' => 'id577239995', - // The name of package for the Android app - 'androidPackage' => '', + // The name of package for the Android app + 'androidPackage' => '', - // The URL to download the iOS application - 'downloadLinkiOS' => 'https://itunes.apple.com/us/app/teen-quotes/id577239995', + // The URL to download the iOS application + 'downloadLinkiOS' => 'https://itunes.apple.com/us/app/teen-quotes/id577239995', - // Scheme for deep links - 'deepLinksProtocol' => 'TeenQuotes://', -]; \ No newline at end of file + // Scheme for deep links + 'deepLinksProtocol' => 'TeenQuotes://', +]; diff --git a/app/config/packages/antoineaugusti/laravel-easyrec/config.php b/app/config/packages/antoineaugusti/laravel-easyrec/config.php index ce84137f..43321cbd 100644 --- a/app/config/packages/antoineaugusti/laravel-easyrec/config.php +++ b/app/config/packages/antoineaugusti/laravel-easyrec/config.php @@ -1,7 +1,8 @@ 'https://demo.easyrec.org', - 'apiVersion' => '1.0', - 'apiKey' => Config::get('services.easyrec.apiKey'), - 'tenantID' => Config::get('services.easyrec.tenantID'), -); \ No newline at end of file + +return [ + 'baseURL' => 'https://demo.easyrec.org', + 'apiVersion' => '1.0', + 'apiKey' => Config::get('services.easyrec.apiKey'), + 'tenantID' => Config::get('services.easyrec.tenantID'), +]; diff --git a/app/config/packages/bugsnag/bugsnag-laravel/config.php b/app/config/packages/bugsnag/bugsnag-laravel/config.php index 40fef86d..4761d29a 100644 --- a/app/config/packages/bugsnag/bugsnag-laravel/config.php +++ b/app/config/packages/bugsnag/bugsnag-laravel/config.php @@ -1,76 +1,76 @@ getenv('BUGSNAG_API_KEY'), + /* + |-------------------------------------------------------------------------- + | API Key + |-------------------------------------------------------------------------- + | + | You can find your API key on your Bugsnag dashboard. + | + | This api key points the Bugsnag notifier to the project in your account + | which should receive your application's uncaught exceptions. + | + */ + 'api_key' => getenv('BUGSNAG_API_KEY'), - /* - |-------------------------------------------------------------------------- - | Notify Release Stages - |-------------------------------------------------------------------------- - | - | Set which release stages should send notifications to Bugsnag. - | - | Example: array('development', 'production') - | - */ - 'notify_release_stages' => ['staging', 'production'], + /* + |-------------------------------------------------------------------------- + | Notify Release Stages + |-------------------------------------------------------------------------- + | + | Set which release stages should send notifications to Bugsnag. + | + | Example: array('development', 'production') + | + */ + 'notify_release_stages' => ['staging', 'production'], - /* - |-------------------------------------------------------------------------- - | Endpoint - |-------------------------------------------------------------------------- - | - | Set what server the Bugsnag notifier should send errors to. By default - | this is set to 'https://notify.bugsnag.com', but for Bugsnag Enterprise - | this should be the URL to your Bugsnag instance. - | - */ - 'endpoint' => null, + /* + |-------------------------------------------------------------------------- + | Endpoint + |-------------------------------------------------------------------------- + | + | Set what server the Bugsnag notifier should send errors to. By default + | this is set to 'https://notify.bugsnag.com', but for Bugsnag Enterprise + | this should be the URL to your Bugsnag instance. + | + */ + 'endpoint' => null, - /* - |-------------------------------------------------------------------------- - | Filters - |-------------------------------------------------------------------------- - | - | Use this if you want to ensure you don't send sensitive data such as - | passwords, and credit card numbers to our servers. Any keys which - | contain these strings will be filtered. - | - */ - 'filters' => ['password'], + /* + |-------------------------------------------------------------------------- + | Filters + |-------------------------------------------------------------------------- + | + | Use this if you want to ensure you don't send sensitive data such as + | passwords, and credit card numbers to our servers. Any keys which + | contain these strings will be filtered. + | + */ + 'filters' => ['password'], - /* - |-------------------------------------------------------------------------- - | Proxy - |-------------------------------------------------------------------------- - | - | If your server is behind a proxy server, you can configure this as well. - | Other than the host, none of these settings are mandatory. - | - | Note: Proxy configuration is only possible if the PHP cURL extension - | is installed. - | - | Example: - | - | 'proxy' => array( - | 'host' => 'bugsnag.com', - | 'port' => 42, - | 'user' => 'username', - | 'password' => 'password123' - | ) - | - */ - 'proxy' => null -); + /* + |-------------------------------------------------------------------------- + | Proxy + |-------------------------------------------------------------------------- + | + | If your server is behind a proxy server, you can configure this as well. + | Other than the host, none of these settings are mandatory. + | + | Note: Proxy configuration is only possible if the PHP cURL extension + | is installed. + | + | Example: + | + | 'proxy' => array( + | 'host' => 'bugsnag.com', + | 'port' => 42, + | 'user' => 'username', + | 'password' => 'password123' + | ) + | + */ + 'proxy' => null, +]; diff --git a/app/config/packages/buonzz/laravel-4-freegeoip/config.php b/app/config/packages/buonzz/laravel-4-freegeoip/config.php index 20c8c53e..681d0d2d 100644 --- a/app/config/packages/buonzz/laravel-4-freegeoip/config.php +++ b/app/config/packages/buonzz/laravel-4-freegeoip/config.php @@ -1,9 +1,9 @@ 'http://www.freegeoip.net/json/', - - // Timeout when calling the API (in seconds) - 'timeout' => 3, -); \ No newline at end of file +return [ + // The URL of the FreeGeoIP API + 'freegeopipURL' => 'http://www.freegeoip.net/json/', + + // Timeout when calling the API (in seconds) + 'timeout' => 3, +]; diff --git a/app/config/packages/dinesh/bugonemail/config.php b/app/config/packages/dinesh/bugonemail/config.php index 252c9e40..8b048e55 100644 --- a/app/config/packages/dinesh/bugonemail/config.php +++ b/app/config/packages/dinesh/bugonemail/config.php @@ -1,9 +1,9 @@ Lang::get('layout.nameWebsite'), - 'notify_emails' => ['antoine.augusti@teen-quotes.com'], - 'email_template' => "bugonemail::email.notifyException", - 'notify_environment' => ['staging', 'production'], - 'prevent_exception' => ['Symfony\Component\HttpKernel\Exception\NotFoundHttpException', 'Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException'], -); +return [ + 'project_name' => Lang::get('layout.nameWebsite'), + 'notify_emails' => ['antoine.augusti@teen-quotes.com'], + 'email_template' => 'bugonemail::email.notifyException', + 'notify_environment' => ['staging', 'production'], + 'prevent_exception' => ['Symfony\Component\HttpKernel\Exception\NotFoundHttpException', 'Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException'], +]; diff --git a/app/config/packages/graham-campbell/htmlmin/config.php b/app/config/packages/graham-campbell/htmlmin/config.php index 46bbb450..c34e2428 100644 --- a/app/config/packages/graham-campbell/htmlmin/config.php +++ b/app/config/packages/graham-campbell/htmlmin/config.php @@ -14,7 +14,7 @@ * limitations under the License. */ -return array( +return [ /* |-------------------------------------------------------------------------- @@ -48,6 +48,6 @@ | */ - 'live' => false + 'live' => false, -); +]; diff --git a/app/config/packages/laracasts/utilities/config.php b/app/config/packages/laracasts/utilities/config.php index b41975cf..9e866db6 100644 --- a/app/config/packages/laracasts/utilities/config.php +++ b/app/config/packages/laracasts/utilities/config.php @@ -23,6 +23,6 @@ | That way, from your JS, you may do something like `Laracasts.myVar`. | */ - 'js_namespace' => 'laravel' + 'js_namespace' => 'laravel', -]; \ No newline at end of file +]; diff --git a/app/config/packages/lucadegasperi/oauth2-server-laravel/oauth2.php b/app/config/packages/lucadegasperi/oauth2-server-laravel/oauth2.php index 84fff595..061d5799 100644 --- a/app/config/packages/lucadegasperi/oauth2-server-laravel/oauth2.php +++ b/app/config/packages/lucadegasperi/oauth2-server-laravel/oauth2.php @@ -1,6 +1,6 @@ array( + 'grant_types' => [ - 'authorization_code' => array( + 'authorization_code' => [ 'class' => 'League\OAuth2\Server\Grant\AuthCode', 'access_token_ttl' => 3600, 'auth_token_ttl' => 3600, - ), + ], - 'password' => array( + 'password' => [ 'class' => 'League\OAuth2\Server\Grant\Password', 'access_token_ttl' => 604800, 'callback' => function ($login, $password) { - $credentials = array( + $credentials = [ 'login' => $login, 'password' => $password, - ); + ]; $valid = Auth::validate($credentials); @@ -82,9 +82,9 @@ // Credentials were not valid if (!$valid) { - + // Maybe the user uses the old hash method - if (!is_null($user) AND ($user->password == User::oldHashMethod($credentials))) { + if (!is_null($user) and ($user->password == User::oldHashMethod($credentials))) { // Update the password in database $user->password = $credentials['password']; $user->last_visit = Carbon::now()->toDateTimeString(); @@ -101,22 +101,22 @@ $user->save(); return Auth::getProvider()->retrieveByCredentials($credentials)->id; - } - ), + }, + ], - 'refresh_token' => array( + 'refresh_token' => [ 'class' => 'League\OAuth2\Server\Grant\RefreshToken', 'access_token_ttl' => 604800, 'refresh_token_ttl' => 604800, 'rotate_refresh_tokens' => false, - ), + ], - 'client_credentials' => array( + 'client_credentials' => [ 'class' => 'League\OAuth2\Server\Grant\ClientCredentials', 'access_token_ttl' => 3600, - ), + ], - ), + ], /* |-------------------------------------------------------------------------- @@ -212,4 +212,4 @@ | */ 'http_headers_only' => false, -); +]; diff --git a/app/config/packages/philf/setting/setting.php b/app/config/packages/philf/setting/setting.php index 9346c5f3..0bfd950a 100644 --- a/app/config/packages/philf/setting/setting.php +++ b/app/config/packages/philf/setting/setting.php @@ -1,8 +1,8 @@ app_path().'/storage/meta', 'filename' => 'settings.json', 'fallback' => true, - 'autoAlias'=> false, -); + 'autoAlias' => false, +]; diff --git a/app/config/packages/philo/translate/config.php b/app/config/packages/philo/translate/config.php index 5a42b2f4..b76bdfa3 100644 --- a/app/config/packages/philo/translate/config.php +++ b/app/config/packages/philo/translate/config.php @@ -1,7 +1,7 @@ array('config', 'database', 'lang', 'start', 'storage', 'tests'), - 'search_exclude_files' => array('pagination', 'reminders', 'validation'), - 'digg_folders' => array('app/views', 'app/commands'), -); \ No newline at end of file +return [ + 'search_ignore_folders' => ['config', 'database', 'lang', 'start', 'storage', 'tests'], + 'search_exclude_files' => ['pagination', 'reminders', 'validation'], + 'digg_folders' => ['app/views', 'app/commands'], +]; diff --git a/app/config/packages/thomaswelton/laravel-gravatar/config.php b/app/config/packages/thomaswelton/laravel-gravatar/config.php index de2b83eb..12e7cf4a 100644 --- a/app/config/packages/thomaswelton/laravel-gravatar/config.php +++ b/app/config/packages/thomaswelton/laravel-gravatar/config.php @@ -1,7 +1,7 @@ 150, - 'default' => '404', - 'maxRating' => 'g' -); +return [ + 'size' => 150, + 'default' => '404', + 'maxRating' => 'g', +]; diff --git a/app/config/queue.php b/app/config/queue.php index d4723cd1..8892fc32 100644 --- a/app/config/queue.php +++ b/app/config/queue.php @@ -1,85 +1,85 @@ 'iron', - - /* - |-------------------------------------------------------------------------- - | Queue Connections - |-------------------------------------------------------------------------- - | - | Here you may configure the connection information for each server that - | is used by your application. A default configuration has been added - | for each back-end shipped with Laravel. You are free to add more. - | - */ - - 'connections' => array( - - 'sync' => array( - 'driver' => 'sync', - ), - - 'beanstalkd' => array( - 'driver' => 'beanstalkd', - 'host' => 'localhost', - 'queue' => 'default', - 'ttr' => 60, - ), - - 'sqs' => array( - 'driver' => 'sqs', - 'key' => 'your-public-key', - 'secret' => 'your-secret-key', - 'queue' => 'your-queue-url', - 'region' => 'us-east-1', - ), - - 'iron' => array( - 'driver' => 'iron', - 'host' => 'mq-aws-us-east-1.iron.io', - 'token' => getenv('IRON_TOKEN'), - 'project' => getenv('IRON_PROJECT'), - 'queue' => 'teenquotes-production', - 'encrypt' => true, - ), - - 'redis' => array( - 'driver' => 'redis', - 'queue' => 'default', - ), - - ), - - /* - |-------------------------------------------------------------------------- - | Failed Queue Jobs - |-------------------------------------------------------------------------- - | - | These options configure the behavior of failed queue job logging so you - | can control which database and table are used to store the jobs that - | have failed. You may change them to any database / table you wish. - | - */ - - 'failed' => array( - - 'database' => 'mysql', 'table' => 'failed_jobs', - - ), - -); +return [ + + /* + |-------------------------------------------------------------------------- + | Default Queue Driver + |-------------------------------------------------------------------------- + | + | The Laravel queue API supports a variety of back-ends via an unified + | API, giving you convenient access to each back-end using the same + | syntax for each one. Here you may set the default queue driver. + | + | Supported: "sync", "beanstalkd", "sqs", "iron" + | + */ + + 'default' => 'iron', + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection information for each server that + | is used by your application. A default configuration has been added + | for each back-end shipped with Laravel. You are free to add more. + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => 'localhost', + 'queue' => 'default', + 'ttr' => 60, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => 'your-public-key', + 'secret' => 'your-secret-key', + 'queue' => 'your-queue-url', + 'region' => 'us-east-1', + ], + + 'iron' => [ + 'driver' => 'iron', + 'host' => 'mq-aws-us-east-1.iron.io', + 'token' => getenv('IRON_TOKEN'), + 'project' => getenv('IRON_PROJECT'), + 'queue' => 'teenquotes-production', + 'encrypt' => true, + ], + + 'redis' => [ + 'driver' => 'redis', + 'queue' => 'default', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control which database and table are used to store the jobs that + | have failed. You may change them to any database / table you wish. + | + */ + + 'failed' => [ + + 'database' => 'mysql', 'table' => 'failed_jobs', + + ], + +]; diff --git a/app/config/remote.php b/app/config/remote.php index ff73bfec..6ceb7016 100644 --- a/app/config/remote.php +++ b/app/config/remote.php @@ -2,56 +2,56 @@ return [ - /* - |-------------------------------------------------------------------------- - | Default Remote Connection Name - |-------------------------------------------------------------------------- - | - | Here you may specify the default connection that will be used for SSH - | operations. This name should correspond to a connection name below - | in the server list. Each connection will be manually accessible. - | - */ - - 'default' => 'production', - - /* - |-------------------------------------------------------------------------- - | Remote Server Connections - |-------------------------------------------------------------------------- - | - | These are the servers that will be accessible via the SSH task runner - | facilities of Laravel. This feature radically simplifies executing - | tasks on your servers, such as deploying out these applications. - | - */ - - 'connections' => [ - - 'production' => [ - 'host' => getenv('SERVER_PRODUCTION_HOST'), - 'username' => getenv('SERVER_PRODUCTION_USERNAME'), - 'password' => getenv('SERVER_PRODUCTION_PASSWORD'), - 'key' => getenv('SERVER_PRODUCTION_KEY'), - 'keyphrase' => getenv('SERVER_PRODUCTION_KEYPHRASE'), - 'root' => getenv('SERVER_PRODUCTION_ROOT'), - ], - - ], - - /* - |-------------------------------------------------------------------------- - | Remote Server Groups - |-------------------------------------------------------------------------- - | - | Here you may list connections under a single group name, which allows - | you to easily access all of the servers at once using a short name - | that is extremely easy to remember, such as "web" or "database". - | - */ - - 'groups' => [ - 'web' => ['production'] - ], - -]; \ No newline at end of file + /* + |-------------------------------------------------------------------------- + | Default Remote Connection Name + |-------------------------------------------------------------------------- + | + | Here you may specify the default connection that will be used for SSH + | operations. This name should correspond to a connection name below + | in the server list. Each connection will be manually accessible. + | + */ + + 'default' => 'production', + + /* + |-------------------------------------------------------------------------- + | Remote Server Connections + |-------------------------------------------------------------------------- + | + | These are the servers that will be accessible via the SSH task runner + | facilities of Laravel. This feature radically simplifies executing + | tasks on your servers, such as deploying out these applications. + | + */ + + 'connections' => [ + + 'production' => [ + 'host' => getenv('SERVER_PRODUCTION_HOST'), + 'username' => getenv('SERVER_PRODUCTION_USERNAME'), + 'password' => getenv('SERVER_PRODUCTION_PASSWORD'), + 'key' => getenv('SERVER_PRODUCTION_KEY'), + 'keyphrase' => getenv('SERVER_PRODUCTION_KEYPHRASE'), + 'root' => getenv('SERVER_PRODUCTION_ROOT'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Remote Server Groups + |-------------------------------------------------------------------------- + | + | Here you may list connections under a single group name, which allows + | you to easily access all of the servers at once using a short name + | that is extremely easy to remember, such as "web" or "database". + | + */ + + 'groups' => [ + 'web' => ['production'], + ], + +]; diff --git a/app/config/services.php b/app/config/services.php index fff4875e..80bde434 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -2,44 +2,44 @@ return [ - /* - |-------------------------------------------------------------------------- - | Third Party Services - |-------------------------------------------------------------------------- - | - | This file is for storing the credentials for third party services such - | as Stripe, Mailgun, Mandrill, and others. This file provides a sane - | default location for this type of information, allowing packages - | to have a conventional place to find your various credentials. - | - */ - - 'mailgun' => [ - 'domain' => getenv('MAILGUN_DOMAIN'), - 'secret' => getenv('MAILGUN_SECRET'), - 'pubkey' => getenv('MAILGUN_PUBKEY'), - ], - - 'mandrill' => [ - 'secret' => getenv('MANDRILL_SECRET'), - ], - - 'stripe' => [ - 'model' => 'TeenQuotes\Users\Models\User', - 'secret' => '', - ], - - 'mailchimp' => [ - 'secret' => getenv('MAILCHIMP_SECRET') - ], - - 'easyrec' => [ - 'apiKey' => getenv('EASYREC_APIKEY'), - 'tenantID' => 'teenquotes_'.App::environment() - ], - - 'pushbullet' => [ - 'apiKey' => getenv('PUSHBULLET_APIKEY'), - 'deviceIden' => getenv('PUSHBULLET_DEVICE_IDEN'), - ] -]; \ No newline at end of file + /* + |-------------------------------------------------------------------------- + | Third Party Services + |-------------------------------------------------------------------------- + | + | This file is for storing the credentials for third party services such + | as Stripe, Mailgun, Mandrill, and others. This file provides a sane + | default location for this type of information, allowing packages + | to have a conventional place to find your various credentials. + | + */ + + 'mailgun' => [ + 'domain' => getenv('MAILGUN_DOMAIN'), + 'secret' => getenv('MAILGUN_SECRET'), + 'pubkey' => getenv('MAILGUN_PUBKEY'), + ], + + 'mandrill' => [ + 'secret' => getenv('MANDRILL_SECRET'), + ], + + 'stripe' => [ + 'model' => 'TeenQuotes\Users\Models\User', + 'secret' => '', + ], + + 'mailchimp' => [ + 'secret' => getenv('MAILCHIMP_SECRET'), + ], + + 'easyrec' => [ + 'apiKey' => getenv('EASYREC_APIKEY'), + 'tenantID' => 'teenquotes_'.App::environment(), + ], + + 'pushbullet' => [ + 'apiKey' => getenv('PUSHBULLET_APIKEY'), + 'deviceIden' => getenv('PUSHBULLET_DEVICE_IDEN'), + ], +]; diff --git a/app/config/session.php b/app/config/session.php index b22f01db..7d8437dd 100644 --- a/app/config/session.php +++ b/app/config/session.php @@ -1,140 +1,140 @@ 'file', - - /* - |-------------------------------------------------------------------------- - | Session Lifetime - |-------------------------------------------------------------------------- - | - | Here you may specify the number of minutes that you wish the session - | to be allowed to remain idle before it expires. If you want them - | to immediately expire on the browser closing, set that option. - | - */ - - 'lifetime' => 120, - - 'expire_on_close' => false, - - /* - |-------------------------------------------------------------------------- - | Session File Location - |-------------------------------------------------------------------------- - | - | When using the native session driver, we need a location where session - | files may be stored. A default has been set for you but a different - | location may be specified. This is only needed for file sessions. - | - */ - - 'files' => storage_path().'/sessions', - - /* - |-------------------------------------------------------------------------- - | Session Database Connection - |-------------------------------------------------------------------------- - | - | When using the "database" or "redis" session drivers, you may specify a - | connection that should be used to manage these sessions. This should - | correspond to a connection in your database configuration options. - | - */ - - 'connection' => null, - - /* - |-------------------------------------------------------------------------- - | Session Database Table - |-------------------------------------------------------------------------- - | - | When using the "database" session driver, you may specify the table we - | should use to manage the sessions. Of course, a sensible default is - | provided for you; however, you are free to change this as needed. - | - */ - - 'table' => 'sessions', - - /* - |-------------------------------------------------------------------------- - | Session Sweeping Lottery - |-------------------------------------------------------------------------- - | - | Some session drivers must manually sweep their storage location to get - | rid of old sessions from storage. Here are the chances that it will - | happen on a given request. By default, the odds are 2 out of 100. - | - */ - - 'lottery' => array(2, 100), - - /* - |-------------------------------------------------------------------------- - | Session Cookie Name - |-------------------------------------------------------------------------- - | - | Here you may change the name of the cookie used to identify a session - | instance by ID. The name specified here will get used every time a - | new session cookie is created by the framework for every driver. - | - */ - - 'cookie' => 'laravel_session', - - /* - |-------------------------------------------------------------------------- - | Session Cookie Path - |-------------------------------------------------------------------------- - | - | The session cookie path determines the path for which the cookie will - | be regarded as available. Typically, this will be the root path of - | your application but you are free to change this when necessary. - | - */ - - 'path' => '/', - - /* - |-------------------------------------------------------------------------- - | Session Cookie Domain - |-------------------------------------------------------------------------- - | - | Here you may change the domain of the cookie used to identify a session - | in your application. This will determine which domains the cookie is - | available to in your application. A sensible default has been set. - | - */ - - 'domain' => '.'.Config::get('app.domain'), - - /* - |-------------------------------------------------------------------------- - | HTTPS Only Cookies - |-------------------------------------------------------------------------- - | - | By setting this option to true, session cookies will only be sent back - | to the server if the browser has a HTTPS connection. This will keep - | the cookie from being sent to you if it can not be done securely. - | - */ - - 'secure' => false, - -); +return [ + + /* + |-------------------------------------------------------------------------- + | Default Session Driver + |-------------------------------------------------------------------------- + | + | This option controls the default session "driver" that will be used on + | requests. By default, we will use the lightweight native driver but + | you may specify any of the other wonderful drivers provided here. + | + | Supported: "file", "cookie", "database", "apc", + | "memcached", "redis", "array" + | + */ + + 'driver' => 'file', + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to immediately expire on the browser closing, set that option. + | + */ + + 'lifetime' => 120, + + 'expire_on_close' => false, + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When using the native session driver, we need a location where session + | files may be stored. A default has been set for you but a different + | location may be specified. This is only needed for file sessions. + | + */ + + 'files' => storage_path().'/sessions', + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table we + | should use to manage the sessions. Of course, a sensible default is + | provided for you; however, you are free to change this as needed. + | + */ + + 'table' => 'sessions', + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the cookie used to identify a session + | instance by ID. The name specified here will get used every time a + | new session cookie is created by the framework for every driver. + | + */ + + 'cookie' => 'laravel_session', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application but you are free to change this when necessary. + | + */ + + 'path' => '/', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | Here you may change the domain of the cookie used to identify a session + | in your application. This will determine which domains the cookie is + | available to in your application. A sensible default has been set. + | + */ + + 'domain' => '.'.Config::get('app.domain'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you if it can not be done securely. + | + */ + + 'secure' => false, + +]; diff --git a/app/config/staging/app.php b/app/config/staging/app.php index 186afb7d..4dc602a0 100644 --- a/app/config/staging/app.php +++ b/app/config/staging/app.php @@ -1,9 +1,10 @@ 'http://dev.teen-quotes.com', - 'domain' => 'dev.teen-quotes.com', - 'domainAPI' => 'api.teen-quotes.com', - 'domainStories' => 'stories.dev.teen-quotes.com', - 'domainAdmin' => 'admin.dev.teen-quotes.com', - 'domainAccount' => 'account.dev.teen-quotes.com', + 'url' => 'http://dev.teen-quotes.com', + 'domain' => 'dev.teen-quotes.com', + 'domainAPI' => 'api.teen-quotes.com', + 'domainStories' => 'stories.dev.teen-quotes.com', + 'domainAdmin' => 'admin.dev.teen-quotes.com', + 'domainAccount' => 'account.dev.teen-quotes.com', ]; diff --git a/app/config/staging/queue.php b/app/config/staging/queue.php index 02d29c07..870164f7 100644 --- a/app/config/staging/queue.php +++ b/app/config/staging/queue.php @@ -1,5 +1,5 @@ 'sync', -]; \ No newline at end of file + 'default' => 'sync', +]; diff --git a/app/config/testing/cache.php b/app/config/testing/cache.php index 66a8a39a..9f436e27 100644 --- a/app/config/testing/cache.php +++ b/app/config/testing/cache.php @@ -1,20 +1,20 @@ 'array', + 'driver' => 'array', -); +]; diff --git a/app/config/testing/database.php b/app/config/testing/database.php index 1643e57e..290210a8 100644 --- a/app/config/testing/database.php +++ b/app/config/testing/database.php @@ -1,19 +1,20 @@ 'sqlite', +return [ - 'connections' => array( - 'sqlite' => array( - 'driver' => 'sqlite', - 'database' => ':memory:', - 'prefix' => '', - ), - - 'codeception' => array( - 'driver' => 'sqlite', - 'database' => dirname(dirname(__DIR__)).'/tests/_data/db.sqlite', - 'prefix' => '', - ), - ), -); + 'default' => 'sqlite', + + 'connections' => [ + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ], + + 'codeception' => [ + 'driver' => 'sqlite', + 'database' => dirname(dirname(__DIR__)).'/tests/_data/db.sqlite', + 'prefix' => '', + ], + ], +]; diff --git a/app/config/testing/mail.php b/app/config/testing/mail.php index 9ad7fa9f..d244a885 100644 --- a/app/config/testing/mail.php +++ b/app/config/testing/mail.php @@ -1,5 +1,5 @@ 'log' -]; \ No newline at end of file + 'driver' => 'log', +]; diff --git a/app/config/testing/queue.php b/app/config/testing/queue.php index 02d29c07..870164f7 100644 --- a/app/config/testing/queue.php +++ b/app/config/testing/queue.php @@ -1,5 +1,5 @@ 'sync', -]; \ No newline at end of file + 'default' => 'sync', +]; diff --git a/app/config/testing/session.php b/app/config/testing/session.php index 0364b63d..17de8095 100644 --- a/app/config/testing/session.php +++ b/app/config/testing/session.php @@ -1,21 +1,21 @@ 'array', + 'driver' => 'array', -); +]; diff --git a/app/config/view.php b/app/config/view.php index 19488064..2724364e 100644 --- a/app/config/view.php +++ b/app/config/view.php @@ -1,31 +1,31 @@ array(__DIR__.'/../../ressources/views'), + 'paths' => [__DIR__.'/../../ressources/views'], - /* - |-------------------------------------------------------------------------- - | Pagination View - |-------------------------------------------------------------------------- - | - | This view will be used to render the pagination link output, and can - | be easily customized here to show any view you like. A clean view - | compatible with Twitter's Bootstrap is given to you by default. - | - */ + /* + |-------------------------------------------------------------------------- + | Pagination View + |-------------------------------------------------------------------------- + | + | This view will be used to render the pagination link output, and can + | be easily customized here to show any view you like. A clean view + | compatible with Twitter's Bootstrap is given to you by default. + | + */ - 'pagination' => 'pagination::slider-3', + 'pagination' => 'pagination::slider-3', -); +]; diff --git a/app/config/workbench.php b/app/config/workbench.php index f90fb704..c2e6a7c3 100644 --- a/app/config/workbench.php +++ b/app/config/workbench.php @@ -1,31 +1,31 @@ 'Antoine Augusti', + 'name' => 'Antoine Augusti', - /* - |-------------------------------------------------------------------------- - | Workbench Author E-Mail Address - |-------------------------------------------------------------------------- - | - | Like the option above, your e-mail address is used when generating new - | workbench packages. The e-mail is placed in your composer.json file - | automatically after the package is created by the workbench tool. - | - */ + /* + |-------------------------------------------------------------------------- + | Workbench Author E-Mail Address + |-------------------------------------------------------------------------- + | + | Like the option above, your e-mail address is used when generating new + | workbench packages. The e-mail is placed in your composer.json file + | automatically after the package is created by the workbench tool. + | + */ - 'email' => 'antoine.augusti@gmail.com', + 'email' => 'antoine.augusti@gmail.com', -); +]; diff --git a/app/database/migrations/2014_04_19_165416_create_countries_table.php b/app/database/migrations/2014_04_19_165416_create_countries_table.php index fc329efa..8aaaa63d 100644 --- a/app/database/migrations/2014_04_19_165416_create_countries_table.php +++ b/app/database/migrations/2014_04_19_165416_create_countries_table.php @@ -3,32 +3,26 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateCountriesTable extends Migration { - - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::create('countries', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->string('name')->unique(); - $table->string('country_code', 5)->unique(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('countries'); - } +class CreateCountriesTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::create('countries', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->unique(); + $table->string('country_code', 5)->unique(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('countries'); + } } diff --git a/app/database/migrations/2014_04_20_081041_create_users_table.php b/app/database/migrations/2014_04_20_081041_create_users_table.php index 40ee9379..012e142d 100644 --- a/app/database/migrations/2014_04_20_081041_create_users_table.php +++ b/app/database/migrations/2014_04_20_081041_create_users_table.php @@ -3,48 +3,42 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateUsersTable extends Migration { +class CreateUsersTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('users'); - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('users'); - - Schema::create('users', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->string('login'); - $table->string('password'); - $table->string('email'); - $table->tinyInteger('security_level')->unsigned()->default(0); - $table->string('ip'); - $table->date('birthdate')->nullable()->default(null); - $table->enum('gender', array('M', 'F'))->nullable(); - $table->string('country')->references('id')->on('countries')->onDelete('cascade')->nullable()->default(null); - $table->string('city')->nullable(); - $table->string('avatar')->nullable()->default(null); - $table->string('about_me', 500)->nullable(); - $table->tinyInteger('hide_profile')->unsigned()->default(0); - $table->tinyInteger('notification_comment_quote')->unsigned()->default(1); - $table->dateTime('last_visit')->nullable(); - $table->rememberToken(); - $table->timestamps(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('users'); - } + Schema::create('users', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('login'); + $table->string('password'); + $table->string('email'); + $table->tinyInteger('security_level')->unsigned()->default(0); + $table->string('ip'); + $table->date('birthdate')->nullable()->default(null); + $table->enum('gender', ['M', 'F'])->nullable(); + $table->string('country')->references('id')->on('countries')->onDelete('cascade')->nullable()->default(null); + $table->string('city')->nullable(); + $table->string('avatar')->nullable()->default(null); + $table->string('about_me', 500)->nullable(); + $table->tinyInteger('hide_profile')->unsigned()->default(0); + $table->tinyInteger('notification_comment_quote')->unsigned()->default(1); + $table->dateTime('last_visit')->nullable(); + $table->rememberToken(); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('users'); + } } diff --git a/app/database/migrations/2014_04_20_082050_create_quotes_table.php b/app/database/migrations/2014_04_20_082050_create_quotes_table.php index 8bdab42e..9af80f01 100644 --- a/app/database/migrations/2014_04_20_082050_create_quotes_table.php +++ b/app/database/migrations/2014_04_20_082050_create_quotes_table.php @@ -3,43 +3,38 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateQuotesTable extends Migration { - - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('quotes'); - - Schema::create('quotes', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->string('content', 500); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->tinyInteger('approved')->default(0); - $table->timestamps(); - }); - - if (App::environment() != 'testing') - DB::statement('ALTER TABLE quotes ADD FULLTEXT search(content)'); - } - +class CreateQuotesTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('quotes'); + + Schema::create('quotes', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('content', 500); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->tinyInteger('approved')->default(0); + $table->timestamps(); + }); - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::table('quotes', function($table) { + if (App::environment() != 'testing') { + DB::statement('ALTER TABLE quotes ADD FULLTEXT search(content)'); + } + } + + /** + * Reverse the migrations. + */ + public function down() + { + Schema::table('quotes', function ($table) { $table->dropIndex('search'); }); - Schema::drop('quotes'); - } - + Schema::drop('quotes'); + } } diff --git a/app/database/migrations/2014_04_20_085037_create_comments_table.php b/app/database/migrations/2014_04_20_085037_create_comments_table.php index 2921dcad..41eab22f 100644 --- a/app/database/migrations/2014_04_20_085037_create_comments_table.php +++ b/app/database/migrations/2014_04_20_085037_create_comments_table.php @@ -3,38 +3,32 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateCommentsTable extends Migration { +class CreateCommentsTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('comments'); - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('comments'); - - Schema::create('comments', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->string('content', 500); - $table->integer('quote_id')->unsigned()->index(); - $table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade'); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->timestamps(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('comments'); - } + Schema::create('comments', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('content', 500); + $table->integer('quote_id')->unsigned()->index(); + $table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade'); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('comments'); + } } diff --git a/app/database/migrations/2014_04_20_085307_create_user_user_table.php b/app/database/migrations/2014_04_20_085307_create_user_user_table.php index bf868ae4..1d8832d3 100644 --- a/app/database/migrations/2014_04_20_085307_create_user_user_table.php +++ b/app/database/migrations/2014_04_20_085307_create_user_user_table.php @@ -3,37 +3,31 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateUserUserTable extends Migration { +class CreateUserUserTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('profile_visitors'); - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('profile_visitors'); - - Schema::create('profile_visitors', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->integer('visitor_id')->unsigned()->index(); - $table->foreign('visitor_id')->references('id')->on('users')->onDelete('cascade'); - $table->timestamps(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('profile_visitors'); - } + Schema::create('profile_visitors', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->integer('visitor_id')->unsigned()->index(); + $table->foreign('visitor_id')->references('id')->on('users')->onDelete('cascade'); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('profile_visitors'); + } } diff --git a/app/database/migrations/2014_04_20_085428_create_quote_user_table.php b/app/database/migrations/2014_04_20_085428_create_quote_user_table.php index 6e3a5e7c..72c5652c 100644 --- a/app/database/migrations/2014_04_20_085428_create_quote_user_table.php +++ b/app/database/migrations/2014_04_20_085428_create_quote_user_table.php @@ -3,37 +3,31 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateQuoteUserTable extends Migration { +class CreateQuoteUserTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('favorite_quotes'); - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('favorite_quotes'); - - Schema::create('favorite_quotes', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->integer('quote_id')->unsigned()->index(); - $table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade'); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->timestamps(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('favorite_quotes'); - } + Schema::create('favorite_quotes', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->integer('quote_id')->unsigned()->index(); + $table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade'); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('favorite_quotes'); + } } diff --git a/app/database/migrations/2014_04_20_085555_create_newsletters_table.php b/app/database/migrations/2014_04_20_085555_create_newsletters_table.php index 5d31e595..6a1740db 100644 --- a/app/database/migrations/2014_04_20_085555_create_newsletters_table.php +++ b/app/database/migrations/2014_04_20_085555_create_newsletters_table.php @@ -4,36 +4,30 @@ use Illuminate\Database\Schema\Blueprint; use TeenQuotes\Newsletters\Models\Newsletter; -class CreateNewslettersTable extends Migration { +class CreateNewslettersTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('newsletters'); - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('newsletters'); + Schema::create('newsletters', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->enum('type', Newsletter::getPossibleTypes())->default('weekly'); + $table->timestamps(); + }); + } - Schema::create('newsletters', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->enum('type', Newsletter::getPossibleTypes())->default('weekly'); - $table->timestamps(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('newsletters'); - } - -} \ No newline at end of file + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('newsletters'); + } +} diff --git a/app/database/migrations/2014_04_20_085822_create_stories_table.php b/app/database/migrations/2014_04_20_085822_create_stories_table.php index b9e9db6e..778415e3 100644 --- a/app/database/migrations/2014_04_20_085822_create_stories_table.php +++ b/app/database/migrations/2014_04_20_085822_create_stories_table.php @@ -3,37 +3,31 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -class CreateStoriesTable extends Migration { +class CreateStoriesTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('stories'); - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::dropIfExists('stories'); - - Schema::create('stories', function(Blueprint $table) { - $table->engine = "InnoDB"; - $table->increments('id'); - $table->text('represent_txt'); - $table->text('frequence_txt'); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->timestamps(); - }); - } - - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('stories'); - } + Schema::create('stories', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->text('represent_txt'); + $table->text('frequence_txt'); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('stories'); + } } diff --git a/app/database/migrations/2014_04_25_155003_create_password_reminders_table.php b/app/database/migrations/2014_04_25_155003_create_password_reminders_table.php index dfbcf83f..de888d61 100644 --- a/app/database/migrations/2014_04_25_155003_create_password_reminders_table.php +++ b/app/database/migrations/2014_04_25_155003_create_password_reminders_table.php @@ -1,33 +1,27 @@ string('email')->index(); - $table->string('token')->index(); - $table->timestamp('created_at'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('password_reminders'); - } +class CreatePasswordRemindersTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::create('password_reminders', function (Blueprint $table) { + $table->string('email')->index(); + $table->string('token')->index(); + $table->timestamp('created_at'); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('password_reminders'); + } } diff --git a/app/database/migrations/2014_05_11_072156_create_settings_table.php b/app/database/migrations/2014_05_11_072156_create_settings_table.php index b0bfe376..cd38cd1b 100644 --- a/app/database/migrations/2014_05_11_072156_create_settings_table.php +++ b/app/database/migrations/2014_05_11_072156_create_settings_table.php @@ -1,37 +1,32 @@ engine = "InnoDB"; - $table->increments('id'); - $table->integer('user_id')->unsigned()->index(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - $table->string('key', 50); - $table->string('value', 500); - }); - } +class CreateSettingsTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('settings'); - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('settings'); - } + Schema::create('settings', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->integer('user_id')->unsigned()->index(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->string('key', 50); + $table->string('value', 500); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('settings'); + } } diff --git a/app/database/migrations/2015_02_08_170159_create_tags_table.php b/app/database/migrations/2015_02_08_170159_create_tags_table.php index fe57b019..9b754e54 100644 --- a/app/database/migrations/2015_02_08_170159_create_tags_table.php +++ b/app/database/migrations/2015_02_08_170159_create_tags_table.php @@ -1,35 +1,29 @@ engine = "InnoDB"; - $table->increments('id'); - $table->string('name')->unique(); - }); - } - +class CreateTagsTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('tags'); - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('tags'); - } + Schema::create('tags', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->unique(); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('tags'); + } } diff --git a/app/database/migrations/2015_02_08_170224_create_quote_tag_table.php b/app/database/migrations/2015_02_08_170224_create_quote_tag_table.php index 41202203..b8886a34 100644 --- a/app/database/migrations/2015_02_08_170224_create_quote_tag_table.php +++ b/app/database/migrations/2015_02_08_170224_create_quote_tag_table.php @@ -1,36 +1,31 @@ engine = "InnoDB"; - $table->integer('quote_id')->unsigned()->index(); - $table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade'); - $table->integer('tag_id')->unsigned()->index(); - $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); - }); - } +class CreateQuoteTagTable extends Migration +{ + /** + * Run the migrations. + */ + public function up() + { + Schema::dropIfExists('quote_tag'); - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('quote_tag'); - } + Schema::create('quote_tag', function (Blueprint $table) { + $table->engine = 'InnoDB'; + $table->integer('quote_id')->unsigned()->index(); + $table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade'); + $table->integer('tag_id')->unsigned()->index(); + $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); + }); + } + /** + * Reverse the migrations. + */ + public function down() + { + Schema::drop('quote_tag'); + } } diff --git a/app/database/seeds/CommentsTableSeeder.php b/app/database/seeds/CommentsTableSeeder.php index 667ea4c6..6c5c08b8 100644 --- a/app/database/seeds/CommentsTableSeeder.php +++ b/app/database/seeds/CommentsTableSeeder.php @@ -3,25 +3,23 @@ use Faker\Factory as Faker; use TeenQuotes\Comments\Models\Comment; -class CommentsTableSeeder extends Seeder { +class CommentsTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Comments table ...'); + Comment::truncate(); - public function run() - { - $this->command->info('Deleting existing Comments table ...'); - Comment::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); - - $this->command->info('Seeding Comments table using Faker...'); - foreach(range(1, 1500) as $index) - { - Comment::create([ - 'content' => $faker->paragraph(3), - 'quote_id' => $faker->numberBetween(150, 750), - 'user_id' => $faker->numberBetween(1, 100), - 'created_at' => $faker->dateTimeBetween('-2 years', 'now'), - ]); - } - } - -} \ No newline at end of file + $this->command->info('Seeding Comments table using Faker...'); + foreach (range(1, 1500) as $index) { + Comment::create([ + 'content' => $faker->paragraph(3), + 'quote_id' => $faker->numberBetween(150, 750), + 'user_id' => $faker->numberBetween(1, 100), + 'created_at' => $faker->dateTimeBetween('-2 years', 'now'), + ]); + } + } +} diff --git a/app/database/seeds/CountriesTableSeeder.php b/app/database/seeds/CountriesTableSeeder.php index 55594165..ea4f9406 100644 --- a/app/database/seeds/CountriesTableSeeder.php +++ b/app/database/seeds/CountriesTableSeeder.php @@ -1,253 +1,252 @@ command->info('Deleting existing Countries table ...'); + Country::truncate(); - public function run() - { - $this->command->info('Deleting existing Countries table ...'); - Country::truncate(); + $this->command->info('Seeding Countries table'); - $this->command->info('Seeding Countries table'); - - Country::create(['name' => 'Afghanistan', 'country_code' => 'AF']); - Country::create(['name' => 'Albania', 'country_code' => 'AL']); - Country::create(['name' => 'Algeria', 'country_code' => 'DZ']); - Country::create(['name' => 'American Samoa', 'country_code' => 'AS']); - Country::create(['name' => 'Andorra', 'country_code' => 'AD']); - Country::create(['name' => 'Angola', 'country_code' => 'AO']); - Country::create(['name' => 'Anguilla', 'country_code' => 'AI']); - Country::create(['name' => 'Antarctica', 'country_code' => 'AQ']); - Country::create(['name' => 'Antigua and Barbuda', 'country_code' => 'AG']); - Country::create(['name' => 'Argentina', 'country_code' => 'AR']); - Country::create(['name' => 'Armenia', 'country_code' => 'AM']); - Country::create(['name' => 'Aruba', 'country_code' => 'AW']); - Country::create(['name' => 'Australia', 'country_code' => 'AU']); - Country::create(['name' => 'Austria', 'country_code' => 'AT']); - Country::create(['name' => 'Azerbaijan', 'country_code' => 'AZ']); - Country::create(['name' => 'Bahamas', 'country_code' => 'BS']); - Country::create(['name' => 'Bahrain', 'country_code' => 'BH']); - Country::create(['name' => 'Bangladesh', 'country_code' => 'BD']); - Country::create(['name' => 'Barbados', 'country_code' => 'BB']); - Country::create(['name' => 'Belarus', 'country_code' => 'BY']); - Country::create(['name' => 'Belgium', 'country_code' => 'BE']); - Country::create(['name' => 'Belize', 'country_code' => 'BZ']); - Country::create(['name' => 'Benin', 'country_code' => 'BJ']); - Country::create(['name' => 'Bermuda', 'country_code' => 'BM']); - Country::create(['name' => 'Bhutan', 'country_code' => 'BT']); - Country::create(['name' => 'Bolivia', 'country_code' => 'BO']); - Country::create(['name' => 'Bosnia and Herzegovina', 'country_code' => 'BA']); - Country::create(['name' => 'Botswana', 'country_code' => 'BW']); - Country::create(['name' => 'Bouvet Island', 'country_code' => 'BV']); - Country::create(['name' => 'Brazil', 'country_code' => 'BR']); - Country::create(['name' => 'British Indian Ocean Territory', 'country_code' => 'IO']); - Country::create(['name' => 'Brunei Darussalam', 'country_code' => 'BN']); - Country::create(['name' => 'Bulgaria', 'country_code' => 'BG']); - Country::create(['name' => 'Burkina Faso', 'country_code' => 'BF']); - Country::create(['name' => 'Burundi', 'country_code' => 'BI']); - Country::create(['name' => 'Cambodia', 'country_code' => 'KH']); - Country::create(['name' => 'Cameroon', 'country_code' => 'CM']); - Country::create(['name' => 'Canada', 'country_code' => 'CA']); - Country::create(['name' => 'Cape Verde', 'country_code' => 'CV']); - Country::create(['name' => 'Cayman Islands', 'country_code' => 'KY']); - Country::create(['name' => 'Central African Republic', 'country_code' => 'CF']); - Country::create(['name' => 'Chad', 'country_code' => 'TD']); - Country::create(['name' => 'Chile', 'country_code' => 'CL']); - Country::create(['name' => 'China', 'country_code' => 'CN']); - Country::create(['name' => 'Christmas Island', 'country_code' => 'CX']); - Country::create(['name' => 'Cocos (Keeling) Islands', 'country_code' => 'CC']); - Country::create(['name' => 'Colombia', 'country_code' => 'CO']); - Country::create(['name' => 'Comoros', 'country_code' => 'KM']); - Country::create(['name' => 'Congo', 'country_code' => 'CG']); - Country::create(['name' => 'Congo The Democratic Republic of The Congo', 'country_code' => 'CD']); - Country::create(['name' => 'Cook Islands', 'country_code' => 'CK']); - Country::create(['name' => 'Costa Rica', 'country_code' => 'CR']); - Country::create(['name' => 'Cote D\'ivoire', 'country_code' => 'CI']); - Country::create(['name' => 'Croatia', 'country_code' => 'HR']); - Country::create(['name' => 'Cuba', 'country_code' => 'CU']); - Country::create(['name' => 'Cyprus', 'country_code' => 'CY']); - Country::create(['name' => 'Czech Republic', 'country_code' => 'CZ']); - Country::create(['name' => 'Denmark', 'country_code' => 'DK']); - Country::create(['name' => 'Djibouti', 'country_code' => 'DJ']); - Country::create(['name' => 'Dominica', 'country_code' => 'DM']); - Country::create(['name' => 'Dominican Republic', 'country_code' => 'DO']); - Country::create(['name' => 'Ecuador', 'country_code' => 'EC']); - Country::create(['name' => 'Egypt', 'country_code' => 'EG']); - Country::create(['name' => 'El Salvador', 'country_code' => 'SV']); - Country::create(['name' => 'Equatorial', 'country_code' => 'GQ']); - Country::create(['name' => 'Eritrea', 'country_code' => 'ER']); - Country::create(['name' => 'Estonia', 'country_code' => 'EE']); - Country::create(['name' => 'Ethiopia', 'country_code' => 'ET']); - Country::create(['name' => 'Falkland Islands (Malvinas)', 'country_code' => 'FK']); - Country::create(['name' => 'Faroe', 'country_code' => 'FO']); - Country::create(['name' => 'Fiji', 'country_code' => 'FJ']); - Country::create(['name' => 'Finland', 'country_code' => 'FI']); - Country::create(['name' => 'France', 'country_code' => 'FR']); - Country::create(['name' => 'French Guiana', 'country_code' => 'GF']); - Country::create(['name' => 'French Polynesia', 'country_code' => 'PF']); - Country::create(['name' => 'French Southern Territories', 'country_code' => 'TF']); - Country::create(['name' => 'Gabon', 'country_code' => 'GA']); - Country::create(['name' => 'Gambia', 'country_code' => 'GM']); - Country::create(['name' => 'Georgia', 'country_code' => 'GE']); - Country::create(['name' => 'Germany', 'country_code' => 'DE']); - Country::create(['name' => 'Ghana', 'country_code' => 'GH']); - Country::create(['name' => 'Gibraltar', 'country_code' => 'GI']); - Country::create(['name' => 'Greece', 'country_code' => 'GR']); - Country::create(['name' => 'Greenland', 'country_code' => 'GL']); - Country::create(['name' => 'Grenada', 'country_code' => 'GD']); - Country::create(['name' => 'Guadeloupe', 'country_code' => 'GP']); - Country::create(['name' => 'Guam', 'country_code' => 'GU']); - Country::create(['name' => 'Guatemala', 'country_code' => 'GT']); - Country::create(['name' => 'Guinea', 'country_code' => 'GN']); - Country::create(['name' => 'Guinea-Bissau', 'country_code' => 'GW']); - Country::create(['name' => 'Guyana', 'country_code' => 'GY']); - Country::create(['name' => 'Haiti', 'country_code' => 'HT']); - Country::create(['name' => 'Heard Island and McDonald Islands', 'country_code' => 'HM']); - Country::create(['name' => 'Honduras', 'country_code' => 'HN']); - Country::create(['name' => 'Hong Kong', 'country_code' => 'HK']); - Country::create(['name' => 'Hungary', 'country_code' => 'HU']); - Country::create(['name' => 'Iceland', 'country_code' => 'IS']); - Country::create(['name' => 'India', 'country_code' => 'IN']); - Country::create(['name' => 'Indonesia', 'country_code' => 'ID']); - Country::create(['name' => 'Iran', 'country_code' => 'IR']); - Country::create(['name' => 'Iraq', 'country_code' => 'IQ']); - Country::create(['name' => 'Ireland', 'country_code' => 'IE']); - Country::create(['name' => 'Israel', 'country_code' => 'IL']); - Country::create(['name' => 'Italy', 'country_code' => 'IT']); - Country::create(['name' => 'Jamaica', 'country_code' => 'JM']); - Country::create(['name' => 'Japan', 'country_code' => 'JP']); - Country::create(['name' => 'Jordan', 'country_code' => 'JO']); - Country::create(['name' => 'Kazakhstan', 'country_code' => 'KZ']); - Country::create(['name' => 'Kenya', 'country_code' => 'KE']); - Country::create(['name' => 'Kiribati', 'country_code' => 'KI']); - Country::create(['name' => 'Korea', 'country_code' => 'KR']); - Country::create(['name' => 'Kuwait', 'country_code' => 'KW']); - Country::create(['name' => 'Kyrgyzstan', 'country_code' => 'KG']); - Country::create(['name' => 'Lao People\'s Democratic Republic', 'country_code' => 'LA']); - Country::create(['name' => 'Latvia', 'country_code' => 'LV']); - Country::create(['name' => 'Lebanon', 'country_code' => 'LB']); - Country::create(['name' => 'Lesotho', 'country_code' => 'LS']); - Country::create(['name' => 'Liberia', 'country_code' => 'LR']); - Country::create(['name' => 'Libyan Arab Jamahiriya', 'country_code' => 'LY']); - Country::create(['name' => 'Liechtenstein', 'country_code' => 'LI']); - Country::create(['name' => 'Lithuania', 'country_code' => 'LT']); - Country::create(['name' => 'Luxembourg', 'country_code' => 'LU']); - Country::create(['name' => 'Macao', 'country_code' => 'MO']); - Country::create(['name' => 'Macedonia', 'country_code' => 'MK']); - Country::create(['name' => 'Madagascar', 'country_code' => 'MG']); - Country::create(['name' => 'Malawi', 'country_code' => 'MW']); - Country::create(['name' => 'Malaysia', 'country_code' => 'MY']); - Country::create(['name' => 'Maldives', 'country_code' => 'MV']); - Country::create(['name' => 'Mali', 'country_code' => 'ML']); - Country::create(['name' => 'Malta', 'country_code' => 'MT']); - Country::create(['name' => 'Marshall Islands', 'country_code' => 'MH']); - Country::create(['name' => 'Martinique', 'country_code' => 'MQ']); - Country::create(['name' => 'Mauritania', 'country_code' => 'MR']); - Country::create(['name' => 'Mauritius', 'country_code' => 'MU']); - Country::create(['name' => 'Mayotte', 'country_code' => 'YT']); - Country::create(['name' => 'Mexico', 'country_code' => 'MX']); - Country::create(['name' => 'Micronesia', 'country_code' => 'FM']); - Country::create(['name' => 'Moldova', 'country_code' => 'MD']); - Country::create(['name' => 'Monaco', 'country_code' => 'MC']); - Country::create(['name' => 'Mongolia', 'country_code' => 'MN']); - Country::create(['name' => 'Montserrat', 'country_code' => 'MS']); - Country::create(['name' => 'Morocco', 'country_code' => 'MA']); - Country::create(['name' => 'Mozambique', 'country_code' => 'MZ']); - Country::create(['name' => 'Myanmar', 'country_code' => 'MM']); - Country::create(['name' => 'Namibia', 'country_code' => 'NA']); - Country::create(['name' => 'Nauru', 'country_code' => 'NR']); - Country::create(['name' => 'Nepal', 'country_code' => 'NP']); - Country::create(['name' => 'Netherlands', 'country_code' => 'NL']); - Country::create(['name' => 'Netherlands Antilles', 'country_code' => 'BQ']); - Country::create(['name' => 'New Caledonia', 'country_code' => 'NC']); - Country::create(['name' => 'New Zealand', 'country_code' => 'NZ']); - Country::create(['name' => 'Nicaragua', 'country_code' => 'NI']); - Country::create(['name' => 'Niger', 'country_code' => 'NE']); - Country::create(['name' => 'Nigeria', 'country_code' => 'NG']); - Country::create(['name' => 'Niue', 'country_code' => 'NU']); - Country::create(['name' => 'Norfolk Island', 'country_code' => 'NF']); - Country::create(['name' => 'Northern Mariana Islands', 'country_code' => 'MP']); - Country::create(['name' => 'Norway', 'country_code' => 'NO']); - Country::create(['name' => 'Oman', 'country_code' => 'OM']); - Country::create(['name' => 'Pakistan', 'country_code' => 'PK']); - Country::create(['name' => 'Palau', 'country_code' => 'PW']); - Country::create(['name' => 'Palestinian Territory', 'country_code' => 'PS']); - Country::create(['name' => 'Panama', 'country_code' => 'PA']); - Country::create(['name' => 'Papua New Guinea', 'country_code' => 'PG']); - Country::create(['name' => 'Paraguay', 'country_code' => 'PY']); - Country::create(['name' => 'Peru', 'country_code' => 'PE']); - Country::create(['name' => 'Philippines', 'country_code' => 'PH']); - Country::create(['name' => 'Pitcairn', 'country_code' => 'PN']); - Country::create(['name' => 'Poland', 'country_code' => 'PL']); - Country::create(['name' => 'Portugal', 'country_code' => 'PT']); - Country::create(['name' => 'Puerto Rico', 'country_code' => 'PR']); - Country::create(['name' => 'Qatar', 'country_code' => 'QA']); - Country::create(['name' => 'Reunion', 'country_code' => 'RE']); - Country::create(['name' => 'Romania', 'country_code' => 'RO']); - Country::create(['name' => 'Russian Federation', 'country_code' => 'RU']); - Country::create(['name' => 'Rwanda', 'country_code' => 'RW']); - Country::create(['name' => 'Saint Helena', 'country_code' => 'SH']); - Country::create(['name' => 'Saint Kitts and Nevis', 'country_code' => 'KN']); - Country::create(['name' => 'Saint Lucia', 'country_code' => 'LC']); - Country::create(['name' => 'Saint Pierre and Miquelon', 'country_code' => 'PM']); - Country::create(['name' => 'Saint Vincent and the Grenadines', 'country_code' => 'VC']); - Country::create(['name' => 'Samoa', 'country_code' => 'WS']); - Country::create(['name' => 'San Marino', 'country_code' => 'SM']); - Country::create(['name' => 'Sao Tome and Principe', 'country_code' => 'ST']); - Country::create(['name' => 'Saudi Arabia', 'country_code' => 'SA']); - Country::create(['name' => 'Senegal', 'country_code' => 'SN']); - Country::create(['name' => 'Serbia', 'country_code' => 'RS']); - Country::create(['name' => 'Seychelles', 'country_code' => 'SC']); - Country::create(['name' => 'Sierra Leone', 'country_code' => 'SL']); - Country::create(['name' => 'Singapore', 'country_code' => 'SG']); - Country::create(['name' => 'Slovakia', 'country_code' => 'Sk']); - Country::create(['name' => 'Slovenia', 'country_code' => 'SI']); - Country::create(['name' => 'Solomon Islands', 'country_code' => 'SB']); - Country::create(['name' => 'Somalia', 'country_code' => 'SO']); - Country::create(['name' => 'South Africa', 'country_code' => 'ZA']); - Country::create(['name' => 'South Georgia and The South Sandwich Islands', 'country_code' => 'GS']); - Country::create(['name' => 'Spain', 'country_code' => 'ES']); - Country::create(['name' => 'Sri Lanka', 'country_code' => 'LK']); - Country::create(['name' => 'Sudan', 'country_code' => 'SD']); - Country::create(['name' => 'Suriname', 'country_code' => 'SR']); - Country::create(['name' => 'Svalbard and Jan Mayen', 'country_code' => 'SJ']); - Country::create(['name' => 'Swaziland', 'country_code' => 'SZ']); - Country::create(['name' => 'Sweden', 'country_code' => 'SE']); - Country::create(['name' => 'Switzerland', 'country_code' => 'CH']); - Country::create(['name' => 'Syrian Arab Republic', 'country_code' => 'SY']); - Country::create(['name' => 'Taiwan', 'country_code' => 'TW']); - Country::create(['name' => 'Tajikistan', 'country_code' => 'TJ']); - Country::create(['name' => 'Tanzania', 'country_code' => 'TZ']); - Country::create(['name' => 'Thailand', 'country_code' => 'TH']); - Country::create(['name' => 'Timor-leste', 'country_code' => 'TL']); - Country::create(['name' => 'Togo', 'country_code' => 'TG']); - Country::create(['name' => 'Tokelau', 'country_code' => 'TK']); - Country::create(['name' => 'Tonga', 'country_code' => 'TO']); - Country::create(['name' => 'Trinidad and Tobago', 'country_code' => 'TT']); - Country::create(['name' => 'Tunisia', 'country_code' => 'TN']); - Country::create(['name' => 'Turkey', 'country_code' => 'TR']); - Country::create(['name' => 'Turkmenistan', 'country_code' => 'TM']); - Country::create(['name' => 'Turks and Caicos Islands', 'country_code' => 'TC']); - Country::create(['name' => 'Tuvalu', 'country_code' => 'TV']); - Country::create(['name' => 'Uganda', 'country_code' => 'UG']); - Country::create(['name' => 'Ukraine', 'country_code' => 'UA']); - Country::create(['name' => 'United Arab Emirates', 'country_code' => 'AE']); - Country::create(['name' => 'United Kingdom', 'country_code' => 'GB']); - Country::create(['name' => 'United States', 'country_code' => 'US']); - Country::create(['name' => 'United States Minor Outlying Islands', 'country_code' => 'UM']); - Country::create(['name' => 'Uruguay', 'country_code' => 'UY']); - Country::create(['name' => 'Uzbekistan', 'country_code' => 'UZ']); - Country::create(['name' => 'Vanuatu', 'country_code' => 'VU']); - Country::create(['name' => 'Venezuela', 'country_code' => 'VE']); - Country::create(['name' => 'Vietnam', 'country_code' => 'VN']); - Country::create(['name' => 'Virgin Islands, British Virgin Islands', 'country_code' => 'VG']); - Country::create(['name' => 'Virgin Islands, U.S. Virgin Islands', 'country_code' => 'VI']); - Country::create(['name' => 'Wallis and Futuna', 'country_code' => 'WF']); - Country::create(['name' => 'Western Sahara', 'country_code' => 'EH']); - Country::create(['name' => 'Yemen', 'country_code' => 'YE']); - Country::create(['name' => 'Zambia', 'country_code' => 'ZM']); - Country::create(['name' => 'Zimbabwe', 'country_code' => 'ZW']); - } -} \ No newline at end of file + Country::create(['name' => 'Afghanistan', 'country_code' => 'AF']); + Country::create(['name' => 'Albania', 'country_code' => 'AL']); + Country::create(['name' => 'Algeria', 'country_code' => 'DZ']); + Country::create(['name' => 'American Samoa', 'country_code' => 'AS']); + Country::create(['name' => 'Andorra', 'country_code' => 'AD']); + Country::create(['name' => 'Angola', 'country_code' => 'AO']); + Country::create(['name' => 'Anguilla', 'country_code' => 'AI']); + Country::create(['name' => 'Antarctica', 'country_code' => 'AQ']); + Country::create(['name' => 'Antigua and Barbuda', 'country_code' => 'AG']); + Country::create(['name' => 'Argentina', 'country_code' => 'AR']); + Country::create(['name' => 'Armenia', 'country_code' => 'AM']); + Country::create(['name' => 'Aruba', 'country_code' => 'AW']); + Country::create(['name' => 'Australia', 'country_code' => 'AU']); + Country::create(['name' => 'Austria', 'country_code' => 'AT']); + Country::create(['name' => 'Azerbaijan', 'country_code' => 'AZ']); + Country::create(['name' => 'Bahamas', 'country_code' => 'BS']); + Country::create(['name' => 'Bahrain', 'country_code' => 'BH']); + Country::create(['name' => 'Bangladesh', 'country_code' => 'BD']); + Country::create(['name' => 'Barbados', 'country_code' => 'BB']); + Country::create(['name' => 'Belarus', 'country_code' => 'BY']); + Country::create(['name' => 'Belgium', 'country_code' => 'BE']); + Country::create(['name' => 'Belize', 'country_code' => 'BZ']); + Country::create(['name' => 'Benin', 'country_code' => 'BJ']); + Country::create(['name' => 'Bermuda', 'country_code' => 'BM']); + Country::create(['name' => 'Bhutan', 'country_code' => 'BT']); + Country::create(['name' => 'Bolivia', 'country_code' => 'BO']); + Country::create(['name' => 'Bosnia and Herzegovina', 'country_code' => 'BA']); + Country::create(['name' => 'Botswana', 'country_code' => 'BW']); + Country::create(['name' => 'Bouvet Island', 'country_code' => 'BV']); + Country::create(['name' => 'Brazil', 'country_code' => 'BR']); + Country::create(['name' => 'British Indian Ocean Territory', 'country_code' => 'IO']); + Country::create(['name' => 'Brunei Darussalam', 'country_code' => 'BN']); + Country::create(['name' => 'Bulgaria', 'country_code' => 'BG']); + Country::create(['name' => 'Burkina Faso', 'country_code' => 'BF']); + Country::create(['name' => 'Burundi', 'country_code' => 'BI']); + Country::create(['name' => 'Cambodia', 'country_code' => 'KH']); + Country::create(['name' => 'Cameroon', 'country_code' => 'CM']); + Country::create(['name' => 'Canada', 'country_code' => 'CA']); + Country::create(['name' => 'Cape Verde', 'country_code' => 'CV']); + Country::create(['name' => 'Cayman Islands', 'country_code' => 'KY']); + Country::create(['name' => 'Central African Republic', 'country_code' => 'CF']); + Country::create(['name' => 'Chad', 'country_code' => 'TD']); + Country::create(['name' => 'Chile', 'country_code' => 'CL']); + Country::create(['name' => 'China', 'country_code' => 'CN']); + Country::create(['name' => 'Christmas Island', 'country_code' => 'CX']); + Country::create(['name' => 'Cocos (Keeling) Islands', 'country_code' => 'CC']); + Country::create(['name' => 'Colombia', 'country_code' => 'CO']); + Country::create(['name' => 'Comoros', 'country_code' => 'KM']); + Country::create(['name' => 'Congo', 'country_code' => 'CG']); + Country::create(['name' => 'Congo The Democratic Republic of The Congo', 'country_code' => 'CD']); + Country::create(['name' => 'Cook Islands', 'country_code' => 'CK']); + Country::create(['name' => 'Costa Rica', 'country_code' => 'CR']); + Country::create(['name' => 'Cote D\'ivoire', 'country_code' => 'CI']); + Country::create(['name' => 'Croatia', 'country_code' => 'HR']); + Country::create(['name' => 'Cuba', 'country_code' => 'CU']); + Country::create(['name' => 'Cyprus', 'country_code' => 'CY']); + Country::create(['name' => 'Czech Republic', 'country_code' => 'CZ']); + Country::create(['name' => 'Denmark', 'country_code' => 'DK']); + Country::create(['name' => 'Djibouti', 'country_code' => 'DJ']); + Country::create(['name' => 'Dominica', 'country_code' => 'DM']); + Country::create(['name' => 'Dominican Republic', 'country_code' => 'DO']); + Country::create(['name' => 'Ecuador', 'country_code' => 'EC']); + Country::create(['name' => 'Egypt', 'country_code' => 'EG']); + Country::create(['name' => 'El Salvador', 'country_code' => 'SV']); + Country::create(['name' => 'Equatorial', 'country_code' => 'GQ']); + Country::create(['name' => 'Eritrea', 'country_code' => 'ER']); + Country::create(['name' => 'Estonia', 'country_code' => 'EE']); + Country::create(['name' => 'Ethiopia', 'country_code' => 'ET']); + Country::create(['name' => 'Falkland Islands (Malvinas)', 'country_code' => 'FK']); + Country::create(['name' => 'Faroe', 'country_code' => 'FO']); + Country::create(['name' => 'Fiji', 'country_code' => 'FJ']); + Country::create(['name' => 'Finland', 'country_code' => 'FI']); + Country::create(['name' => 'France', 'country_code' => 'FR']); + Country::create(['name' => 'French Guiana', 'country_code' => 'GF']); + Country::create(['name' => 'French Polynesia', 'country_code' => 'PF']); + Country::create(['name' => 'French Southern Territories', 'country_code' => 'TF']); + Country::create(['name' => 'Gabon', 'country_code' => 'GA']); + Country::create(['name' => 'Gambia', 'country_code' => 'GM']); + Country::create(['name' => 'Georgia', 'country_code' => 'GE']); + Country::create(['name' => 'Germany', 'country_code' => 'DE']); + Country::create(['name' => 'Ghana', 'country_code' => 'GH']); + Country::create(['name' => 'Gibraltar', 'country_code' => 'GI']); + Country::create(['name' => 'Greece', 'country_code' => 'GR']); + Country::create(['name' => 'Greenland', 'country_code' => 'GL']); + Country::create(['name' => 'Grenada', 'country_code' => 'GD']); + Country::create(['name' => 'Guadeloupe', 'country_code' => 'GP']); + Country::create(['name' => 'Guam', 'country_code' => 'GU']); + Country::create(['name' => 'Guatemala', 'country_code' => 'GT']); + Country::create(['name' => 'Guinea', 'country_code' => 'GN']); + Country::create(['name' => 'Guinea-Bissau', 'country_code' => 'GW']); + Country::create(['name' => 'Guyana', 'country_code' => 'GY']); + Country::create(['name' => 'Haiti', 'country_code' => 'HT']); + Country::create(['name' => 'Heard Island and McDonald Islands', 'country_code' => 'HM']); + Country::create(['name' => 'Honduras', 'country_code' => 'HN']); + Country::create(['name' => 'Hong Kong', 'country_code' => 'HK']); + Country::create(['name' => 'Hungary', 'country_code' => 'HU']); + Country::create(['name' => 'Iceland', 'country_code' => 'IS']); + Country::create(['name' => 'India', 'country_code' => 'IN']); + Country::create(['name' => 'Indonesia', 'country_code' => 'ID']); + Country::create(['name' => 'Iran', 'country_code' => 'IR']); + Country::create(['name' => 'Iraq', 'country_code' => 'IQ']); + Country::create(['name' => 'Ireland', 'country_code' => 'IE']); + Country::create(['name' => 'Israel', 'country_code' => 'IL']); + Country::create(['name' => 'Italy', 'country_code' => 'IT']); + Country::create(['name' => 'Jamaica', 'country_code' => 'JM']); + Country::create(['name' => 'Japan', 'country_code' => 'JP']); + Country::create(['name' => 'Jordan', 'country_code' => 'JO']); + Country::create(['name' => 'Kazakhstan', 'country_code' => 'KZ']); + Country::create(['name' => 'Kenya', 'country_code' => 'KE']); + Country::create(['name' => 'Kiribati', 'country_code' => 'KI']); + Country::create(['name' => 'Korea', 'country_code' => 'KR']); + Country::create(['name' => 'Kuwait', 'country_code' => 'KW']); + Country::create(['name' => 'Kyrgyzstan', 'country_code' => 'KG']); + Country::create(['name' => 'Lao People\'s Democratic Republic', 'country_code' => 'LA']); + Country::create(['name' => 'Latvia', 'country_code' => 'LV']); + Country::create(['name' => 'Lebanon', 'country_code' => 'LB']); + Country::create(['name' => 'Lesotho', 'country_code' => 'LS']); + Country::create(['name' => 'Liberia', 'country_code' => 'LR']); + Country::create(['name' => 'Libyan Arab Jamahiriya', 'country_code' => 'LY']); + Country::create(['name' => 'Liechtenstein', 'country_code' => 'LI']); + Country::create(['name' => 'Lithuania', 'country_code' => 'LT']); + Country::create(['name' => 'Luxembourg', 'country_code' => 'LU']); + Country::create(['name' => 'Macao', 'country_code' => 'MO']); + Country::create(['name' => 'Macedonia', 'country_code' => 'MK']); + Country::create(['name' => 'Madagascar', 'country_code' => 'MG']); + Country::create(['name' => 'Malawi', 'country_code' => 'MW']); + Country::create(['name' => 'Malaysia', 'country_code' => 'MY']); + Country::create(['name' => 'Maldives', 'country_code' => 'MV']); + Country::create(['name' => 'Mali', 'country_code' => 'ML']); + Country::create(['name' => 'Malta', 'country_code' => 'MT']); + Country::create(['name' => 'Marshall Islands', 'country_code' => 'MH']); + Country::create(['name' => 'Martinique', 'country_code' => 'MQ']); + Country::create(['name' => 'Mauritania', 'country_code' => 'MR']); + Country::create(['name' => 'Mauritius', 'country_code' => 'MU']); + Country::create(['name' => 'Mayotte', 'country_code' => 'YT']); + Country::create(['name' => 'Mexico', 'country_code' => 'MX']); + Country::create(['name' => 'Micronesia', 'country_code' => 'FM']); + Country::create(['name' => 'Moldova', 'country_code' => 'MD']); + Country::create(['name' => 'Monaco', 'country_code' => 'MC']); + Country::create(['name' => 'Mongolia', 'country_code' => 'MN']); + Country::create(['name' => 'Montserrat', 'country_code' => 'MS']); + Country::create(['name' => 'Morocco', 'country_code' => 'MA']); + Country::create(['name' => 'Mozambique', 'country_code' => 'MZ']); + Country::create(['name' => 'Myanmar', 'country_code' => 'MM']); + Country::create(['name' => 'Namibia', 'country_code' => 'NA']); + Country::create(['name' => 'Nauru', 'country_code' => 'NR']); + Country::create(['name' => 'Nepal', 'country_code' => 'NP']); + Country::create(['name' => 'Netherlands', 'country_code' => 'NL']); + Country::create(['name' => 'Netherlands Antilles', 'country_code' => 'BQ']); + Country::create(['name' => 'New Caledonia', 'country_code' => 'NC']); + Country::create(['name' => 'New Zealand', 'country_code' => 'NZ']); + Country::create(['name' => 'Nicaragua', 'country_code' => 'NI']); + Country::create(['name' => 'Niger', 'country_code' => 'NE']); + Country::create(['name' => 'Nigeria', 'country_code' => 'NG']); + Country::create(['name' => 'Niue', 'country_code' => 'NU']); + Country::create(['name' => 'Norfolk Island', 'country_code' => 'NF']); + Country::create(['name' => 'Northern Mariana Islands', 'country_code' => 'MP']); + Country::create(['name' => 'Norway', 'country_code' => 'NO']); + Country::create(['name' => 'Oman', 'country_code' => 'OM']); + Country::create(['name' => 'Pakistan', 'country_code' => 'PK']); + Country::create(['name' => 'Palau', 'country_code' => 'PW']); + Country::create(['name' => 'Palestinian Territory', 'country_code' => 'PS']); + Country::create(['name' => 'Panama', 'country_code' => 'PA']); + Country::create(['name' => 'Papua New Guinea', 'country_code' => 'PG']); + Country::create(['name' => 'Paraguay', 'country_code' => 'PY']); + Country::create(['name' => 'Peru', 'country_code' => 'PE']); + Country::create(['name' => 'Philippines', 'country_code' => 'PH']); + Country::create(['name' => 'Pitcairn', 'country_code' => 'PN']); + Country::create(['name' => 'Poland', 'country_code' => 'PL']); + Country::create(['name' => 'Portugal', 'country_code' => 'PT']); + Country::create(['name' => 'Puerto Rico', 'country_code' => 'PR']); + Country::create(['name' => 'Qatar', 'country_code' => 'QA']); + Country::create(['name' => 'Reunion', 'country_code' => 'RE']); + Country::create(['name' => 'Romania', 'country_code' => 'RO']); + Country::create(['name' => 'Russian Federation', 'country_code' => 'RU']); + Country::create(['name' => 'Rwanda', 'country_code' => 'RW']); + Country::create(['name' => 'Saint Helena', 'country_code' => 'SH']); + Country::create(['name' => 'Saint Kitts and Nevis', 'country_code' => 'KN']); + Country::create(['name' => 'Saint Lucia', 'country_code' => 'LC']); + Country::create(['name' => 'Saint Pierre and Miquelon', 'country_code' => 'PM']); + Country::create(['name' => 'Saint Vincent and the Grenadines', 'country_code' => 'VC']); + Country::create(['name' => 'Samoa', 'country_code' => 'WS']); + Country::create(['name' => 'San Marino', 'country_code' => 'SM']); + Country::create(['name' => 'Sao Tome and Principe', 'country_code' => 'ST']); + Country::create(['name' => 'Saudi Arabia', 'country_code' => 'SA']); + Country::create(['name' => 'Senegal', 'country_code' => 'SN']); + Country::create(['name' => 'Serbia', 'country_code' => 'RS']); + Country::create(['name' => 'Seychelles', 'country_code' => 'SC']); + Country::create(['name' => 'Sierra Leone', 'country_code' => 'SL']); + Country::create(['name' => 'Singapore', 'country_code' => 'SG']); + Country::create(['name' => 'Slovakia', 'country_code' => 'Sk']); + Country::create(['name' => 'Slovenia', 'country_code' => 'SI']); + Country::create(['name' => 'Solomon Islands', 'country_code' => 'SB']); + Country::create(['name' => 'Somalia', 'country_code' => 'SO']); + Country::create(['name' => 'South Africa', 'country_code' => 'ZA']); + Country::create(['name' => 'South Georgia and The South Sandwich Islands', 'country_code' => 'GS']); + Country::create(['name' => 'Spain', 'country_code' => 'ES']); + Country::create(['name' => 'Sri Lanka', 'country_code' => 'LK']); + Country::create(['name' => 'Sudan', 'country_code' => 'SD']); + Country::create(['name' => 'Suriname', 'country_code' => 'SR']); + Country::create(['name' => 'Svalbard and Jan Mayen', 'country_code' => 'SJ']); + Country::create(['name' => 'Swaziland', 'country_code' => 'SZ']); + Country::create(['name' => 'Sweden', 'country_code' => 'SE']); + Country::create(['name' => 'Switzerland', 'country_code' => 'CH']); + Country::create(['name' => 'Syrian Arab Republic', 'country_code' => 'SY']); + Country::create(['name' => 'Taiwan', 'country_code' => 'TW']); + Country::create(['name' => 'Tajikistan', 'country_code' => 'TJ']); + Country::create(['name' => 'Tanzania', 'country_code' => 'TZ']); + Country::create(['name' => 'Thailand', 'country_code' => 'TH']); + Country::create(['name' => 'Timor-leste', 'country_code' => 'TL']); + Country::create(['name' => 'Togo', 'country_code' => 'TG']); + Country::create(['name' => 'Tokelau', 'country_code' => 'TK']); + Country::create(['name' => 'Tonga', 'country_code' => 'TO']); + Country::create(['name' => 'Trinidad and Tobago', 'country_code' => 'TT']); + Country::create(['name' => 'Tunisia', 'country_code' => 'TN']); + Country::create(['name' => 'Turkey', 'country_code' => 'TR']); + Country::create(['name' => 'Turkmenistan', 'country_code' => 'TM']); + Country::create(['name' => 'Turks and Caicos Islands', 'country_code' => 'TC']); + Country::create(['name' => 'Tuvalu', 'country_code' => 'TV']); + Country::create(['name' => 'Uganda', 'country_code' => 'UG']); + Country::create(['name' => 'Ukraine', 'country_code' => 'UA']); + Country::create(['name' => 'United Arab Emirates', 'country_code' => 'AE']); + Country::create(['name' => 'United Kingdom', 'country_code' => 'GB']); + Country::create(['name' => 'United States', 'country_code' => 'US']); + Country::create(['name' => 'United States Minor Outlying Islands', 'country_code' => 'UM']); + Country::create(['name' => 'Uruguay', 'country_code' => 'UY']); + Country::create(['name' => 'Uzbekistan', 'country_code' => 'UZ']); + Country::create(['name' => 'Vanuatu', 'country_code' => 'VU']); + Country::create(['name' => 'Venezuela', 'country_code' => 'VE']); + Country::create(['name' => 'Vietnam', 'country_code' => 'VN']); + Country::create(['name' => 'Virgin Islands, British Virgin Islands', 'country_code' => 'VG']); + Country::create(['name' => 'Virgin Islands, U.S. Virgin Islands', 'country_code' => 'VI']); + Country::create(['name' => 'Wallis and Futuna', 'country_code' => 'WF']); + Country::create(['name' => 'Western Sahara', 'country_code' => 'EH']); + Country::create(['name' => 'Yemen', 'country_code' => 'YE']); + Country::create(['name' => 'Zambia', 'country_code' => 'ZM']); + Country::create(['name' => 'Zimbabwe', 'country_code' => 'ZW']); + } +} diff --git a/app/database/seeds/DatabaseSeeder.php b/app/database/seeds/DatabaseSeeder.php index bd530739..dad27b29 100644 --- a/app/database/seeds/DatabaseSeeder.php +++ b/app/database/seeds/DatabaseSeeder.php @@ -1,48 +1,46 @@ disableForeignKeyChecks(); - - // Reset and rerun all migrations - Artisan::call('migrate:refresh'); - - // Do not send any e-mails when creating ressources - Config::set('mail.pretend', true); - - $this->call('UsersTableSeeder'); - $this->call('QuotesTableSeeder'); - $this->call('CommentsTableSeeder'); - $this->call('FavoriteQuotesTableSeeder'); - $this->call('ProfileVisitorsTableSeeder'); - $this->call('NewslettersTableSeeder'); - $this->call('StoriesTableSeeder'); - $this->call('CountriesTableSeeder'); - $this->call('SettingsTableSeeder'); - $this->call('TagsTableSeeder'); - - $this->enableForeignKeyChecks(); - - // Flush the cache - Artisan::call('cache:clear'); - } - - private function disableForeignKeyChecks() - { - DB::statement('SET FOREIGN_KEY_CHECKS = 0'); - } - - private function enableForeignKeyChecks() - { - DB::statement('SET FOREIGN_KEY_CHECKS = 1'); - } +class DatabaseSeeder extends Seeder +{ + /** + * Run the database seeds. + */ + public function run() + { + Eloquent::unguard(); + + $this->disableForeignKeyChecks(); + + // Reset and rerun all migrations + Artisan::call('migrate:refresh'); + + // Do not send any e-mails when creating ressources + Config::set('mail.pretend', true); + + $this->call('UsersTableSeeder'); + $this->call('QuotesTableSeeder'); + $this->call('CommentsTableSeeder'); + $this->call('FavoriteQuotesTableSeeder'); + $this->call('ProfileVisitorsTableSeeder'); + $this->call('NewslettersTableSeeder'); + $this->call('StoriesTableSeeder'); + $this->call('CountriesTableSeeder'); + $this->call('SettingsTableSeeder'); + $this->call('TagsTableSeeder'); + + $this->enableForeignKeyChecks(); + + // Flush the cache + Artisan::call('cache:clear'); + } + + private function disableForeignKeyChecks() + { + DB::statement('SET FOREIGN_KEY_CHECKS = 0'); + } + + private function enableForeignKeyChecks() + { + DB::statement('SET FOREIGN_KEY_CHECKS = 1'); + } } diff --git a/app/database/seeds/FavoriteQuotesTableSeeder.php b/app/database/seeds/FavoriteQuotesTableSeeder.php index a397381c..1a44874c 100644 --- a/app/database/seeds/FavoriteQuotesTableSeeder.php +++ b/app/database/seeds/FavoriteQuotesTableSeeder.php @@ -3,26 +3,24 @@ use Faker\Factory as Faker; use TeenQuotes\Quotes\Models\FavoriteQuote; -class FavoriteQuotesTableSeeder extends Seeder { +class FavoriteQuotesTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing FavoriteQuote table ...'); + FavoriteQuote::truncate(); - public function run() - { - $this->command->info('Deleting existing FavoriteQuote table ...'); - FavoriteQuote::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); + $this->command->info('Seeding FavoriteQuote table using Faker...'); + $i = 1; + foreach (range(1, 2000) as $index) { + FavoriteQuote::create([ + 'quote_id' => $faker->numberBetween(50, 700), + 'user_id' => $faker->numberBetween(1, 100), + ]); - $this->command->info('Seeding FavoriteQuote table using Faker...'); - $i = 1; - foreach(range(1, 2000) as $index) - { - FavoriteQuote::create([ - 'quote_id' => $faker->numberBetween(50, 700), - 'user_id' => $faker->numberBetween(1, 100), - ]); - - $i++; - } - } - -} \ No newline at end of file + $i++; + } + } +} diff --git a/app/database/seeds/NewslettersTableSeeder.php b/app/database/seeds/NewslettersTableSeeder.php index d037e524..252dac71 100644 --- a/app/database/seeds/NewslettersTableSeeder.php +++ b/app/database/seeds/NewslettersTableSeeder.php @@ -3,23 +3,21 @@ use Faker\Factory as Faker; use TeenQuotes\Newsletters\Models\Newsletter; -class NewslettersTableSeeder extends Seeder { +class NewslettersTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Newsletter table ...'); + Newsletter::truncate(); - public function run() - { - $this->command->info('Deleting existing Newsletter table ...'); - Newsletter::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); - - $this->command->info('Seeding Newsletter table using Faker...'); - foreach(range(1, 80) as $index) - { - Newsletter::create([ - 'user_id' => $faker->numberBetween(1, 100), - 'type' => $faker->randomElement(Newsletter::getPossibleTypes()), - ]); - } - } - -} \ No newline at end of file + $this->command->info('Seeding Newsletter table using Faker...'); + foreach (range(1, 80) as $index) { + Newsletter::create([ + 'user_id' => $faker->numberBetween(1, 100), + 'type' => $faker->randomElement(Newsletter::getPossibleTypes()), + ]); + } + } +} diff --git a/app/database/seeds/ProfileVisitorsTableSeeder.php b/app/database/seeds/ProfileVisitorsTableSeeder.php index 39affacd..830bbc1a 100644 --- a/app/database/seeds/ProfileVisitorsTableSeeder.php +++ b/app/database/seeds/ProfileVisitorsTableSeeder.php @@ -3,22 +3,21 @@ use Faker\Factory as Faker; use TeenQuotes\Users\Models\ProfileVisitor; -class ProfileVisitorsTableSeeder extends Seeder { +class ProfileVisitorsTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing ProfileVisitor table ...'); + ProfileVisitor::truncate(); - public function run() - { - $this->command->info('Deleting existing ProfileVisitor table ...'); - ProfileVisitor::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); - - $this->command->info('Seeding ProfileVisitor table using Faker...'); - foreach(range(1, 400) as $index) - { - ProfileVisitor::create([ - 'user_id' => $faker->numberBetween(1, 100), - 'visitor_id' => $faker->numberBetween(1, 100), - ]); - } - } -} \ No newline at end of file + $this->command->info('Seeding ProfileVisitor table using Faker...'); + foreach (range(1, 400) as $index) { + ProfileVisitor::create([ + 'user_id' => $faker->numberBetween(1, 100), + 'visitor_id' => $faker->numberBetween(1, 100), + ]); + } + } +} diff --git a/app/database/seeds/QuotesTableSeeder.php b/app/database/seeds/QuotesTableSeeder.php index 029979e0..6d4f8441 100644 --- a/app/database/seeds/QuotesTableSeeder.php +++ b/app/database/seeds/QuotesTableSeeder.php @@ -3,48 +3,50 @@ use Faker\Factory as Faker; use TeenQuotes\Quotes\Models\Quote; -class QuotesTableSeeder extends Seeder { - - public function run() - { - $this->command->info('Deleting existing Quotes table ...'); - Quote::truncate(); - - $faker = Faker::create(); - - $this->command->info('Seeding Quotes table using Faker...'); - $i = 1; - $date = Carbon::createFromDate(2011, 12, 1); - foreach(range(1, 750) as $index) - { - // Generate 50 quotes for each approved value - // between -1 and 2 - - - Quote::create([ - 'content' => $faker->paragraph(3), - 'user_id' => $faker->numberBetween(1, 100), - 'approved' => $this->getApproveForNumber($i), - 'created_at' => $date, - ]); - - $date = $date->addDay(); - $i++; - } - } - - private function getApproveForNumber($i) - { - if ($i < 50) - $approved = Quote::REFUSED; - if ($i >= 50 AND $i <= 700) - $approved = Quote::PUBLISHED; - if ($i > 700 AND $i <= 725) - $approved = Quote::PENDING; - if ($i > 725) - $approved = Quote::WAITING; - - return $approved; - } - -} \ No newline at end of file +class QuotesTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Quotes table ...'); + Quote::truncate(); + + $faker = Faker::create(); + + $this->command->info('Seeding Quotes table using Faker...'); + $i = 1; + $date = Carbon::createFromDate(2011, 12, 1); + foreach (range(1, 750) as $index) { + // Generate 50 quotes for each approved value + // between -1 and 2 + + + Quote::create([ + 'content' => $faker->paragraph(3), + 'user_id' => $faker->numberBetween(1, 100), + 'approved' => $this->getApproveForNumber($i), + 'created_at' => $date, + ]); + + $date = $date->addDay(); + $i++; + } + } + + private function getApproveForNumber($i) + { + if ($i < 50) { + $approved = Quote::REFUSED; + } + if ($i >= 50 and $i <= 700) { + $approved = Quote::PUBLISHED; + } + if ($i > 700 and $i <= 725) { + $approved = Quote::PENDING; + } + if ($i > 725) { + $approved = Quote::WAITING; + } + + return $approved; + } +} diff --git a/app/database/seeds/SettingsTableSeeder.php b/app/database/seeds/SettingsTableSeeder.php index 9239476d..bde24ef4 100644 --- a/app/database/seeds/SettingsTableSeeder.php +++ b/app/database/seeds/SettingsTableSeeder.php @@ -3,24 +3,23 @@ use Faker\Factory as Faker; use TeenQuotes\Settings\Models\Setting; -class SettingsTableSeeder extends Seeder { +class SettingsTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Settings table ...'); + Setting::truncate(); - public function run() - { - $this->command->info('Deleting existing Settings table ...'); - Setting::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); - - $this->command->info('Seeding Settings table using Faker...'); - foreach(range(1, 100) as $userID) - { - // Colors for published quotes for each user - Setting::create([ - 'user_id' => $userID, - 'key' => 'colorsQuotesPublished', - 'value' => $faker->randomElement(['blue', 'green', 'purple', 'red', 'orange']) - ]); - } - } -} \ No newline at end of file + $this->command->info('Seeding Settings table using Faker...'); + foreach (range(1, 100) as $userID) { + // Colors for published quotes for each user + Setting::create([ + 'user_id' => $userID, + 'key' => 'colorsQuotesPublished', + 'value' => $faker->randomElement(['blue', 'green', 'purple', 'red', 'orange']), + ]); + } + } +} diff --git a/app/database/seeds/StoriesTableSeeder.php b/app/database/seeds/StoriesTableSeeder.php index 12bff467..7f597509 100644 --- a/app/database/seeds/StoriesTableSeeder.php +++ b/app/database/seeds/StoriesTableSeeder.php @@ -3,25 +3,23 @@ use Faker\Factory as Faker; use TeenQuotes\Stories\Models\Story; -class StoriesTableSeeder extends Seeder { +class StoriesTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Stories table ...'); + Story::truncate(); - public function run() - { - $this->command->info('Deleting existing Stories table ...'); - Story::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); - - $this->command->info('Seeding Stories table using Faker...'); - foreach(range(1, 10) as $index) - { - Story::create([ - 'represent_txt' => $faker->paragraph(5), - 'frequence_txt' => $faker->paragraph(5), - 'user_id' => $faker->numberBetween(1, 100), - 'created_at' => $faker->dateTimeBetween('-2 years', 'now'), - ]); - } - } - -} \ No newline at end of file + $this->command->info('Seeding Stories table using Faker...'); + foreach (range(1, 10) as $index) { + Story::create([ + 'represent_txt' => $faker->paragraph(5), + 'frequence_txt' => $faker->paragraph(5), + 'user_id' => $faker->numberBetween(1, 100), + 'created_at' => $faker->dateTimeBetween('-2 years', 'now'), + ]); + } + } +} diff --git a/app/database/seeds/TagsTableSeeder.php b/app/database/seeds/TagsTableSeeder.php index 4d386d7f..7431dda6 100644 --- a/app/database/seeds/TagsTableSeeder.php +++ b/app/database/seeds/TagsTableSeeder.php @@ -1,37 +1,34 @@ command->info('Deleting existing Tags table ...'); - Tag::truncate(); - - $faker = Faker::create(); - - $this->command->info('Seeding Tags table using Faker...'); - foreach(range(1, 15) as $index) - { - Tag::create([ - 'name' => $faker->word - ]); - } - - $this->command->info('Associating tags for quotes...'); - DB::table('quote_tag')->truncate(); - - foreach (range(500, 700) as $quote_id) - { - $q = Quote::find($quote_id); - - for ($i = 1; $i <= $faker->numberBetween(0, 3); $i++) - { - $q->tags()->attach($faker->numberBetween(1, 15)); - } - } - } -} \ No newline at end of file +class TagsTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Tags table ...'); + Tag::truncate(); + + $faker = Faker::create(); + + $this->command->info('Seeding Tags table using Faker...'); + foreach (range(1, 15) as $index) { + Tag::create([ + 'name' => $faker->word, + ]); + } + + $this->command->info('Associating tags for quotes...'); + DB::table('quote_tag')->truncate(); + + foreach (range(500, 700) as $quote_id) { + $q = Quote::find($quote_id); + + for ($i = 1; $i <= $faker->numberBetween(0, 3); $i++) { + $q->tags()->attach($faker->numberBetween(1, 15)); + } + } + } +} diff --git a/app/database/seeds/UsersTableSeeder.php b/app/database/seeds/UsersTableSeeder.php index 48dd92d7..d81dbddd 100644 --- a/app/database/seeds/UsersTableSeeder.php +++ b/app/database/seeds/UsersTableSeeder.php @@ -3,57 +3,56 @@ use Faker\Factory as Faker; use TeenQuotes\Users\Models\User; -class UsersTableSeeder extends Seeder { +class UsersTableSeeder extends Seeder +{ + public function run() + { + $this->command->info('Deleting existing Users table ...'); + User::truncate(); - public function run() - { - $this->command->info('Deleting existing Users table ...'); - User::truncate(); + $faker = Faker::create(); - $faker = Faker::create(); - - $this->command->info('Seeding Users table using Faker...'); - foreach(range(1, 100) as $index) - { - // Random user - if ($index != 42) { - User::create([ - 'login' => $faker->bothify('?????##'), - 'password' => "1234", - 'email' => $faker->email, - 'ip' => $faker->ipv4, - 'birthdate' => $faker->date('Y-m-d', 'now'), - 'gender' => $faker->randomElement(array('M', 'F')), - 'country' => $faker->numberBetween(1, 237), - 'city' => $faker->city, - 'avatar' => NULL, - 'about_me' => $faker->paragraph(3), - // Profile not hidden at 80 % - 'hide_profile' => ($faker->numberBetween(1, 100) >= 80) ? 1 : 0, - 'notification_comment_quote' => $faker->numberBetween(0, 1), - 'last_visit' => $faker->dateTimeThisYear()->format('Y-m-d H:i:s'), - ]); - } - // Admin account - else { - User::create([ - 'login' => 'antoineaugusti', - 'password' => "123456", - 'email' => 'antoine.augusti@gmail.com', - 'security_level' => 1, - 'ip' => $faker->ipv4, - 'birthdate' => $faker->date('Y-m-d', 'now'), - 'gender' => 'M', - 'country' => $faker->numberBetween(1, 237), - 'city' => $faker->city, - 'avatar' => '42.png', - 'about_me' => $faker->paragraph(3), - 'hide_profile' => 0, - 'notification_comment_quote' => 1, - 'last_visit' => $faker->dateTimeThisYear()->format('Y-m-d H:i:s'), - ]); - $this->command->info('Admin account : #42 - antoineaugusti - 123456'); - } - } - } -} \ No newline at end of file + $this->command->info('Seeding Users table using Faker...'); + foreach (range(1, 100) as $index) { + // Random user + if ($index != 42) { + User::create([ + 'login' => $faker->bothify('?????##'), + 'password' => '1234', + 'email' => $faker->email, + 'ip' => $faker->ipv4, + 'birthdate' => $faker->date('Y-m-d', 'now'), + 'gender' => $faker->randomElement(['M', 'F']), + 'country' => $faker->numberBetween(1, 237), + 'city' => $faker->city, + 'avatar' => null, + 'about_me' => $faker->paragraph(3), + // Profile not hidden at 80 % + 'hide_profile' => ($faker->numberBetween(1, 100) >= 80) ? 1 : 0, + 'notification_comment_quote' => $faker->numberBetween(0, 1), + 'last_visit' => $faker->dateTimeThisYear()->format('Y-m-d H:i:s'), + ]); + } + // Admin account + else { + User::create([ + 'login' => 'antoineaugusti', + 'password' => '123456', + 'email' => 'antoine.augusti@gmail.com', + 'security_level' => 1, + 'ip' => $faker->ipv4, + 'birthdate' => $faker->date('Y-m-d', 'now'), + 'gender' => 'M', + 'country' => $faker->numberBetween(1, 237), + 'city' => $faker->city, + 'avatar' => '42.png', + 'about_me' => $faker->paragraph(3), + 'hide_profile' => 0, + 'notification_comment_quote' => 1, + 'last_visit' => $faker->dateTimeThisYear()->format('Y-m-d H:i:s'), + ]); + $this->command->info('Admin account : #42 - antoineaugusti - 123456'); + } + } + } +} diff --git a/app/filters.php b/app/filters.php index 47e1a614..815531bf 100644 --- a/app/filters.php +++ b/app/filters.php @@ -11,36 +11,31 @@ | */ -App::before(function($request) -{ - if (Config::get('database.log', false) OR App::environment('local')) - { - Event::listen('illuminate.query', function($query, $bindings, $time, $name) - { - $data = compact('bindings', 'time', 'name'); - - // Format binding data for sql insertion - foreach ($bindings as $i => $binding) - { - if ($binding instanceof \DateTime) - $bindings[$i] = $binding->format('\'Y-m-d H:i:s\''); - else if (is_string($binding)) - $bindings[$i] = "'$binding'"; - } - - // Insert bindings into query - $query = str_replace(array('%', '?'), array('%%', '%s'), $query); - $query = vsprintf($query, $bindings); - - Log::info($query, $data); - }); - } +App::before(function ($request) { + if (Config::get('database.log', false) or App::environment('local')) { + Event::listen('illuminate.query', function ($query, $bindings, $time, $name) { + $data = compact('bindings', 'time', 'name'); + + // Format binding data for sql insertion + foreach ($bindings as $i => $binding) { + if ($binding instanceof \DateTime) { + $bindings[$i] = $binding->format('\'Y-m-d H:i:s\''); + } elseif (is_string($binding)) { + $bindings[$i] = "'$binding'"; + } + } + + // Insert bindings into query + $query = str_replace(['%', '?'], ['%%', '%s'], $query); + $query = vsprintf($query, $bindings); + + Log::info($query, $data); + }); + } }); - -App::after(function($request, $response) -{ - // +App::after(function ($request, $response) { + // }); /* @@ -54,53 +49,48 @@ | */ -Route::filter('auth', function() -{ - if (Auth::guest()) - { - if (Route::currentRouteName() == 'addquote') - { - // Flash an attribute in session to display a custom message - // on the signin / signup page - Session::flash('requireLoggedInAddQuote', true); - return Redirect::guest('signin'); - } - - return Redirect::guest('signin')->with('warning', Lang::get('auth.requireLoggedIn')); - } -}); +Route::filter('auth', function () { + if (Auth::guest()) { + if (Route::currentRouteName() == 'addquote') { + // Flash an attribute in session to display a custom message + // on the signin / signup page + Session::flash('requireLoggedInAddQuote', true); + + return Redirect::guest('signin'); + } -Route::filter('admin', function() -{ - if ( ! (Auth::check() AND Auth::user()->is_admin)) - App::abort('401', 'Nothing to do here'); + return Redirect::guest('signin')->with('warning', Lang::get('auth.requireLoggedIn')); + } }); +Route::filter('admin', function () { + if (!(Auth::check() and Auth::user()->is_admin)) { + App::abort('401', 'Nothing to do here'); + } +}); -Route::filter('auth.basic', function() -{ - return Auth::basic(); +Route::filter('auth.basic', function () { + return Auth::basic(); }); -Route::filter('session.remove', function() -{ - return Config::set('session.driver', 'array'); +Route::filter('session.remove', function () { + return Config::set('session.driver', 'array'); }); -Route::filter('search.isValid', function($route) -{ - // search.getResults has the query as a parameter - // search.dispatcher uses a POST - $query = (count($route->parameters()) > 0) ? $route->getParameter('query') : Input::get('search'); +Route::filter('search.isValid', function ($route) { + // search.getResults has the query as a parameter + // search.dispatcher uses a POST + $query = (count($route->parameters()) > 0) ? $route->getParameter('query') : Input::get('search'); - $data = [ - 'search' => $query, - ]; + $data = [ + 'search' => $query, + ]; - $validator = Validator::make($data, ['search' => 'min:3']); + $validator = Validator::make($data, ['search' => 'min:3']); - if ($validator->fails()) - return Redirect::route('search.form')->withErrors($validator)->withInput(['search' => $query]); + if ($validator->fails()) { + return Redirect::route('search.form')->withErrors($validator)->withInput(['search' => $query]); + } }); /* @@ -114,10 +104,10 @@ | */ -Route::filter('guest', function() -{ - if (Auth::check()) - return Redirect::route('home')->with('warning', Lang::get('auth.alreadyLoggedIn')); +Route::filter('guest', function () { + if (Auth::check()) { + return Redirect::route('home')->with('warning', Lang::get('auth.alreadyLoggedIn')); + } }); /* @@ -131,10 +121,8 @@ | */ -Route::filter('csrf', function() -{ - if (Session::token() != Input::get('_token')) - { - throw new Illuminate\Session\TokenMismatchException; - } -}); \ No newline at end of file +Route::filter('csrf', function () { + if (Session::token() != Input::get('_token')) { + throw new Illuminate\Session\TokenMismatchException(); + } +}); diff --git a/app/helpers.php b/app/helpers.php index 840131e8..9128e62a 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -1,24 +1,22 @@ 'Android application', - 'iosTitle' => 'iOS application', - 'desktopTitle' => 'Desktop application', - 'tabletTitle' => 'Tablet application', - 'mobileTitle' => 'Mobile application', - 'pageDescription' => 'Download the '.Lang::get('layout.nameWebsite').' application that fits your device. Wherever you go, we will be with you.', - 'noAppYet' => "We don't have an application yet, but this website is fully functional with your device! You have access to all the features of ".Lang::get('layout.nameWebsite')." inside your web browser across all your devices.

If you think that this website is not optimized for your device, please contact us!", -); \ No newline at end of file + +return [ + 'androidTitle' => 'Android application', + 'iosTitle' => 'iOS application', + 'desktopTitle' => 'Desktop application', + 'tabletTitle' => 'Tablet application', + 'mobileTitle' => 'Mobile application', + 'pageDescription' => 'Download the '.Lang::get('layout.nameWebsite').' application that fits your device. Wherever you go, we will be with you.', + 'noAppYet' => "We don't have an application yet, but this website is fully functional with your device! You have access to all the features of ".Lang::get('layout.nameWebsite')." inside your web browser across all your devices.

If you think that this website is not optimized for your device, please contact us!", +]; diff --git a/app/lang/en/auth.php b/app/lang/en/auth.php index fa39a961..7818211f 100644 --- a/app/lang/en/auth.php +++ b/app/lang/en/auth.php @@ -1,55 +1,56 @@ 'You are already logged in.', - 'loginSuccessfull' => 'Hi :login! Nice to see you :)', - 'passwordInvalid' => 'Your password is invalid.', - 'login' => 'Login', - 'password' => 'Password', - 'emailAddress' => 'Email address', - 'loginButton' => 'Log me in!', - 'logoutSuccessfull' => 'You have been logged out. See you soon :login :)', - 'logoutNotLoggedIn' => 'Try to log in first!', - 'requireLoggedIn' => 'Oops, you need to be logged in!', - 'requireLoggedInAddQuoteTitle' => 'Hi! Who are you?', - 'requireLoggedInAddQuoteContent' => 'Before adding a quote, you need to be logged in. Having an account is just a matter of seconds and it will make you cooler, for sure. ', - 'signupButton' => "I'm a cool kid!", - 'signupText' => 'To create an account on '.Lang::get('layout.nameWebsite').' and be able to access all the advantages that come with it, fill in the form below, your account will be created in an instant!', - 'signupSuccessfull' => 'Hi :login! Your account has been created :)', - 'signupAdvantages' => '
  • Share your thoughts and write a quote!
  • Store your favorite quotes
  • Comment on quotes
  • ', - 'loginAwesome' => "It sounds awesome!", - 'welcomeBack' => "Welcome back!", - 'wantToBeCool' => "I want to be cool too!", - 'dontOwnAccountYet' => "So you don't have an account yet? Not cool...

    This is your lucky day, in 1 minute you'll have one! You just have to click the fancy button below.

    ", - 'wantsAnAccount' => "I want an account!", - 'pleasureSeeYouAgain' => "What a pleasure to see you again!", - 'signinPageTitle' => 'Log in | '.Lang::get('layout.nameWebsite'), - 'signinPageDescription' => 'Log in to your account and enter in your space on '.Lang::get('layout.nameWebsite').'.', - 'signupPageTitle' => 'Create an account | '.Lang::get('layout.nameWebsite'), - 'signupPageDescription' => 'Create an account and access to all the advantages that come with it in a minute.', - 'resetMyPassword' => 'Reset my password!', - 'iveLostMyPassword' => "I've lost my password!", - 'lostCheerUp' => "Don't worry, we are here to help! We deal with issues like this everyday. Our robots will take care of you, just enter your email address bellow and check your inbox!", - 'heyEmail' => 'Hey!', - 'askedResetPasswordEmail' => "You've just asked to reset your password on ".Lang::get('layout.nameWebsite')." and we are here to help!

    Click the link, complete the form and you will be out of trouble in a minute:", - 'passwordReminderEmailSubject' => 'Password reminder', - 'welcomeBackPasswordChanged' => 'Welcome back :login! Your password has been changed.', - 'resetCheerUp' => "Okay, in a minute this incident will be closed and your account will be back to you. Confirm your email address, enter a new password and you'll be ready to go!", - 'changeMyPasswordButton' => 'Change my password', - 'iHaveAnAccount' => 'I have an account!', - 'mustBeLoggedToAddcooment' => "Oops, you can't post a comment if you don't have an account!

    Fortunately, this is not very difficult. Psst, if I were you, I would click on one of these buttons below.", - 'dontRememberPassword' => "I don't remember my password!", - 'createYourAccount' => 'Create your account', - 'subjectWelcomeEmail' => 'Welcome on '.Lang::get('layout.nameWebsite').' :login!', - 'welcomeEmailWithUsername' => 'Welcome :login!', - 'bodyWelcomeEmail' => "We are excited to welcome you on board! With your account you are now able to submit quotes, add quotes to your favorite and comment on quotes. And a lot more!

    You can now go to your profile, you will find a nice starter kit: :urlProfile.

    See you soon on ".Lang::get('layout.nameWebsite')." :login!", - 'teamFooterEmail' => 'The '.Lang::get('layout.nameWebsite').' Team.', - 'carefulPrivacy' => 'We are super careful with your privacy. We promise.', - 'didYouMean' => 'Did you mean ', - 'mailAddressUpdated' => 'Your email address has been updated!', - 'mailAddressInvalid' => "This email address seems to be invalid", - 'mailAddressValid' => "Seems good! We will know how to reach you.", - 'resetPasswordPageTitle' => 'Reset my password | '.Lang::get('layout.nameWebsite'), - 'resetPasswordPageDescription' => 'Reset your password and recover your account', - 'contactHumanTitle' => 'I need some help', - 'contactHumanContent' => 'Having trouble to recover your account? Get in touch with a real human. Contact us!' -); \ No newline at end of file + +return [ + 'alreadyLoggedIn' => 'You are already logged in.', + 'loginSuccessfull' => 'Hi :login! Nice to see you :)', + 'passwordInvalid' => 'Your password is invalid.', + 'login' => 'Login', + 'password' => 'Password', + 'emailAddress' => 'Email address', + 'loginButton' => 'Log me in!', + 'logoutSuccessfull' => 'You have been logged out. See you soon :login :)', + 'logoutNotLoggedIn' => 'Try to log in first!', + 'requireLoggedIn' => 'Oops, you need to be logged in!', + 'requireLoggedInAddQuoteTitle' => 'Hi! Who are you?', + 'requireLoggedInAddQuoteContent' => 'Before adding a quote, you need to be logged in. Having an account is just a matter of seconds and it will make you cooler, for sure. ', + 'signupButton' => "I'm a cool kid!", + 'signupText' => 'To create an account on '.Lang::get('layout.nameWebsite').' and be able to access all the advantages that come with it, fill in the form below, your account will be created in an instant!', + 'signupSuccessfull' => 'Hi :login! Your account has been created :)', + 'signupAdvantages' => '
  • Share your thoughts and write a quote!
  • Store your favorite quotes
  • Comment on quotes
  • ', + 'loginAwesome' => 'It sounds awesome!', + 'welcomeBack' => 'Welcome back!', + 'wantToBeCool' => 'I want to be cool too!', + 'dontOwnAccountYet' => "So you don't have an account yet? Not cool...

    This is your lucky day, in 1 minute you'll have one! You just have to click the fancy button below.

    ", + 'wantsAnAccount' => 'I want an account!', + 'pleasureSeeYouAgain' => 'What a pleasure to see you again!', + 'signinPageTitle' => 'Log in | '.Lang::get('layout.nameWebsite'), + 'signinPageDescription' => 'Log in to your account and enter in your space on '.Lang::get('layout.nameWebsite').'.', + 'signupPageTitle' => 'Create an account | '.Lang::get('layout.nameWebsite'), + 'signupPageDescription' => 'Create an account and access to all the advantages that come with it in a minute.', + 'resetMyPassword' => 'Reset my password!', + 'iveLostMyPassword' => "I've lost my password!", + 'lostCheerUp' => "Don't worry, we are here to help! We deal with issues like this everyday. Our robots will take care of you, just enter your email address bellow and check your inbox!", + 'heyEmail' => 'Hey!', + 'askedResetPasswordEmail' => "You've just asked to reset your password on ".Lang::get('layout.nameWebsite').' and we are here to help!

    Click the link, complete the form and you will be out of trouble in a minute:', + 'passwordReminderEmailSubject' => 'Password reminder', + 'welcomeBackPasswordChanged' => 'Welcome back :login! Your password has been changed.', + 'resetCheerUp' => "Okay, in a minute this incident will be closed and your account will be back to you. Confirm your email address, enter a new password and you'll be ready to go!", + 'changeMyPasswordButton' => 'Change my password', + 'iHaveAnAccount' => 'I have an account!', + 'mustBeLoggedToAddcooment' => "Oops, you can't post a comment if you don't have an account!

    Fortunately, this is not very difficult. Psst, if I were you, I would click on one of these buttons below.", + 'dontRememberPassword' => "I don't remember my password!", + 'createYourAccount' => 'Create your account', + 'subjectWelcomeEmail' => 'Welcome on '.Lang::get('layout.nameWebsite').' :login!', + 'welcomeEmailWithUsername' => 'Welcome :login!', + 'bodyWelcomeEmail' => "We are excited to welcome you on board! With your account you are now able to submit quotes, add quotes to your favorite and comment on quotes. And a lot more!

    You can now go to your profile, you will find a nice starter kit: :urlProfile.

    See you soon on ".Lang::get('layout.nameWebsite').' :login!', + 'teamFooterEmail' => 'The '.Lang::get('layout.nameWebsite').' Team.', + 'carefulPrivacy' => 'We are super careful with your privacy. We promise.', + 'didYouMean' => 'Did you mean ', + 'mailAddressUpdated' => 'Your email address has been updated!', + 'mailAddressInvalid' => 'This email address seems to be invalid', + 'mailAddressValid' => 'Seems good! We will know how to reach you.', + 'resetPasswordPageTitle' => 'Reset my password | '.Lang::get('layout.nameWebsite'), + 'resetPasswordPageDescription' => 'Reset your password and recover your account', + 'contactHumanTitle' => 'I need some help', + 'contactHumanContent' => 'Having trouble to recover your account? Get in touch with a real human. Contact us!', +]; diff --git a/app/lang/en/colors.php b/app/lang/en/colors.php index 1fd928eb..cc97abf8 100644 --- a/app/lang/en/colors.php +++ b/app/lang/en/colors.php @@ -1,8 +1,9 @@ 'Blue', - 'red' => 'Red', - 'orange' => 'Orange', - 'purple' => 'Purple', - 'green' => 'Green', -); \ No newline at end of file + +return [ + 'blue' => 'Blue', + 'red' => 'Red', + 'orange' => 'Orange', + 'purple' => 'Purple', + 'green' => 'Green', +]; diff --git a/app/lang/en/comments.php b/app/lang/en/comments.php index 5636fc73..4852d866 100644 --- a/app/lang/en/comments.php +++ b/app/lang/en/comments.php @@ -1,19 +1,20 @@ 'Comments', - 'addComment' => 'Add a comment', - 'addMyComment' => 'Add my comment!', - 'yourComment' => 'Your comment', - 'commentAddedSuccessfull' => 'Your comment has been added successfully!', - 'noCommentsYet' => 'Be the first to add a comment on this quote!', - 'commentAddedOnQuote' => 'A comment has been posted on one of your quotes. Just to remind you, here is your quote:', - 'ifWantsToSeeComment' => 'If you want to see this new comment, please follow this link: :url', - 'commentAddedSubjectEmail' => 'Comment posted on your quote #:id', - 'contentShortHint' => "It's a bit short!", - 'contentGreatHint' => "It seems nice!", - 'cantEditThisComment' => "You can't edit this comment.", - 'commentEditSuccessfull' => "Your comment was successfully updated!", - 'editMyComment' => 'Edit my comment!', - 'updateYourComment' => 'Update my comment', - 'updateCommentPageTitle' => 'Update my comment | '.Lang::get('layout.nameWebsite') -); \ No newline at end of file + +return [ + 'comments' => 'Comments', + 'addComment' => 'Add a comment', + 'addMyComment' => 'Add my comment!', + 'yourComment' => 'Your comment', + 'commentAddedSuccessfull' => 'Your comment has been added successfully!', + 'noCommentsYet' => 'Be the first to add a comment on this quote!', + 'commentAddedOnQuote' => 'A comment has been posted on one of your quotes. Just to remind you, here is your quote:', + 'ifWantsToSeeComment' => 'If you want to see this new comment, please follow this link: :url', + 'commentAddedSubjectEmail' => 'Comment posted on your quote #:id', + 'contentShortHint' => "It's a bit short!", + 'contentGreatHint' => 'It seems nice!', + 'cantEditThisComment' => "You can't edit this comment.", + 'commentEditSuccessfull' => 'Your comment was successfully updated!', + 'editMyComment' => 'Edit my comment!', + 'updateYourComment' => 'Update my comment', + 'updateCommentPageTitle' => 'Update my comment | '.Lang::get('layout.nameWebsite'), +]; diff --git a/app/lang/en/contact.php b/app/lang/en/contact.php index d560b1de..17af2e2f 100644 --- a/app/lang/en/contact.php +++ b/app/lang/en/contact.php @@ -1,16 +1,17 @@ 'Contact | '.Lang::get('layout.nameWebsite'), - 'pageDescription' => 'Contact the team. Say hi, report a bug or propose a feature!', - 'contactTitle' => 'Contact us', - 'teamTitle' => 'Our team', - 'stayInTouchTitle' => 'Stay in touch', - 'stayInTouchContent' => 'We are very concerned by you, our visitors. You are our top priority and this is the reason why we will be very happy to hear from you!

    You have an idea? A suggestion? Something seems to be broken on the website? You want to show us your love? You want to drink a beer with us?

    We will be very happy to answer to your message. Here are a few informations if you wish to contact us, by hook or by crook (but we do not accept carrier pigeons).', - 'emailAddress' => 'support@'.Config::get('app.domain'), - 'chooseYourWeapon' => 'Choose your weapon', - 'teamDescriptionClara' => 'Clara is in charge of the Twitter account. She loves life. Since 2009 she tweets everyday to inspire us! Thanks to her we have build the '.Lang::get('layout.nameWebsite').' web suite.', - 'teamDescriptionAntoine' => 'Antoine is the lead developer. He likes when servers respond fast and when everything work as expected. He is always happy to have an impact on your life. He works hard to make things easy for you.', - 'teamDescriptionMaxime' => 'Maxime is the iOS developer. Thanks to him you have '.Lang::get('layout.nameWebsite').' in your pocket, one tap away! He hates Antoine because he designs difficult-to-understand systems.', - 'teamDescriptionJonathan' => 'Jonathan is the designer. Usually, Antoine designs something ugly and Jonathan makes it pretty. If you like the design then you will love Jonathan. And everybody loves Jonathan!', - 'teamDescriptionMichel' => 'Michel is the tester. If something is not working or could be improved, he will find it for sure. A lot of software work thanks to him!', -); \ No newline at end of file + +return [ + 'pageTitle' => 'Contact | '.Lang::get('layout.nameWebsite'), + 'pageDescription' => 'Contact the team. Say hi, report a bug or propose a feature!', + 'contactTitle' => 'Contact us', + 'teamTitle' => 'Our team', + 'stayInTouchTitle' => 'Stay in touch', + 'stayInTouchContent' => 'We are very concerned by you, our visitors. You are our top priority and this is the reason why we will be very happy to hear from you!

    You have an idea? A suggestion? Something seems to be broken on the website? You want to show us your love? You want to drink a beer with us?

    We will be very happy to answer to your message. Here are a few informations if you wish to contact us, by hook or by crook (but we do not accept carrier pigeons).', + 'emailAddress' => 'support@'.Config::get('app.domain'), + 'chooseYourWeapon' => 'Choose your weapon', + 'teamDescriptionClara' => 'Clara is in charge of the Twitter account. She loves life. Since 2009 she tweets everyday to inspire us! Thanks to her we have build the '.Lang::get('layout.nameWebsite').' web suite.', + 'teamDescriptionAntoine' => 'Antoine is the lead developer. He likes when servers respond fast and when everything work as expected. He is always happy to have an impact on your life. He works hard to make things easy for you.', + 'teamDescriptionMaxime' => 'Maxime is the iOS developer. Thanks to him you have '.Lang::get('layout.nameWebsite').' in your pocket, one tap away! He hates Antoine because he designs difficult-to-understand systems.', + 'teamDescriptionJonathan' => 'Jonathan is the designer. Usually, Antoine designs something ugly and Jonathan makes it pretty. If you like the design then you will love Jonathan. And everybody loves Jonathan!', + 'teamDescriptionMichel' => 'Michel is the tester. If something is not working or could be improved, he will find it for sure. A lot of software work thanks to him!', +]; diff --git a/app/lang/en/email.php b/app/lang/en/email.php index 2c1be1b9..315e7cb9 100644 --- a/app/lang/en/email.php +++ b/app/lang/en/email.php @@ -1,27 +1,27 @@ "Today is a special day for you :login! :age years old, how amazing it is? You will have to celebrate this day with your family and your friends!

    All the team want to wish you a happy birthday! We hope that you will have a great day :)

    See you soon on ".Lang::get('layout.nameWebsite')." and have a nice day!", - 'christmasBody' => "The entire team of ".Lang::get('layout.nameWebsite')." wishes you a Merry Christmas and hope you enjoy these few days of family vacation. We hope you've been nice this year and that Santa will give you great gifts!

    We're looking forward to see you soon on ".Lang::get('layout.nameWebsite')."!", - 'eventChristmasSubjectEmail' => "Merry Christmas!", - 'eventNewyearSubjectEmail' => "Happy New Year!", - 'footerApplication' => 'iOS application:', - 'footerInstagram' => 'Instagram:', - 'footerStories' => 'Stories:', - 'footerTwitter' => 'Twitter:', - 'footerWebsite' => 'Website:', - 'happyBirthdaySubjectEmail' => 'Happy birthday!', - 'hiWithLogin' => 'Hi :login!', - 'iconApp' => 'http://'.Config::get('app.domain').'/assets/images/emails/app.png', - 'iconInstagram' => 'http://'.Config::get('app.domain').'/assets/images/emails/instagram.png', - 'iconStories' => 'http://'.Config::get('app.domain').'/assets/images/emails/stories.png', - 'iconTwitter' => 'http://'.Config::get('app.domain').'/assets/images/emails/twitter.png', - 'iconWebsite' => 'http://'.Config::get('app.domain').'/assets/images/emails/website.png', - 'imageBirthday' => 'http://'.Config::get('app.domain').'/assets/images/emails/birthday.png', - 'imageChristmas' => 'http://'.Config::get('app.domain').'/assets/images/emails/christmas.png', - 'imageNewyear' => 'http://'.Config::get('app.domain').'/assets/images/emails/newyear.png', - 'manageEmailSettings' => 'You received this email because your settings are set this way. You can manage your email settings when editing your profile. To edit your profile, please follow this link :url', - 'newyearBody' => "New is the year, new are the hopes and the aspirations. New is the resolution, new are the spirits and forever our warm wishes are for you. Have a promising and fulfilling new year!

    The entire team of ".Lang::get('layout.nameWebsite')." wish you a Happy New Year! We hope this year will awesome for you!

    We're looking forward to see you soon on ".Lang::get('layout.nameWebsite')."!", - 'unsubscribeNewsletterSubject' => 'You have been unsubscribed from newsletters', - 'URLLogo' => 'http://'.Config::get('app.domain').'/assets/images/logo.png', -]; \ No newline at end of file + 'birthdayContent' => 'Today is a special day for you :login! :age years old, how amazing it is? You will have to celebrate this day with your family and your friends!

    All the team want to wish you a happy birthday! We hope that you will have a great day :)

    See you soon on '.Lang::get('layout.nameWebsite').' and have a nice day!', + 'christmasBody' => 'The entire team of '.Lang::get('layout.nameWebsite')." wishes you a Merry Christmas and hope you enjoy these few days of family vacation. We hope you've been nice this year and that Santa will give you great gifts!

    We're looking forward to see you soon on ".Lang::get('layout.nameWebsite').'!', + 'eventChristmasSubjectEmail' => 'Merry Christmas!', + 'eventNewyearSubjectEmail' => 'Happy New Year!', + 'footerApplication' => 'iOS application:', + 'footerInstagram' => 'Instagram:', + 'footerStories' => 'Stories:', + 'footerTwitter' => 'Twitter:', + 'footerWebsite' => 'Website:', + 'happyBirthdaySubjectEmail' => 'Happy birthday!', + 'hiWithLogin' => 'Hi :login!', + 'iconApp' => 'http://'.Config::get('app.domain').'/assets/images/emails/app.png', + 'iconInstagram' => 'http://'.Config::get('app.domain').'/assets/images/emails/instagram.png', + 'iconStories' => 'http://'.Config::get('app.domain').'/assets/images/emails/stories.png', + 'iconTwitter' => 'http://'.Config::get('app.domain').'/assets/images/emails/twitter.png', + 'iconWebsite' => 'http://'.Config::get('app.domain').'/assets/images/emails/website.png', + 'imageBirthday' => 'http://'.Config::get('app.domain').'/assets/images/emails/birthday.png', + 'imageChristmas' => 'http://'.Config::get('app.domain').'/assets/images/emails/christmas.png', + 'imageNewyear' => 'http://'.Config::get('app.domain').'/assets/images/emails/newyear.png', + 'manageEmailSettings' => 'You received this email because your settings are set this way. You can manage your email settings when editing your profile. To edit your profile, please follow this link :url', + 'newyearBody' => 'New is the year, new are the hopes and the aspirations. New is the resolution, new are the spirits and forever our warm wishes are for you. Have a promising and fulfilling new year!

    The entire team of '.Lang::get('layout.nameWebsite')." wish you a Happy New Year! We hope this year will awesome for you!

    We're looking forward to see you soon on ".Lang::get('layout.nameWebsite').'!', + 'unsubscribeNewsletterSubject' => 'You have been unsubscribed from newsletters', + 'URLLogo' => 'http://'.Config::get('app.domain').'/assets/images/logo.png', +]; diff --git a/app/lang/en/errors.php b/app/lang/en/errors.php index ac06a9c3..a4eb1e4a 100644 --- a/app/lang/en/errors.php +++ b/app/lang/en/errors.php @@ -1,6 +1,7 @@ " + +return [ + 'defaultNotFound' => "

    This :resource:

      @@ -27,27 +28,27 @@
    ", - 'countryNotFoundPageTitle' => 'Country not found | '.Lang::get('layout.nameWebsite'), - 'countryNotFoundTitle' => 'Country not found!', - 'countryText' => 'country', - 'hiddenProfileBody' => "Oops, it appears that the profile of :login is hidden! It means that only :login can see this profile.

    We take your privacy very seriously and you can hide your profile if you don't want to open your information on ".Lang::get('layout.nameWebsite')." to others.", - 'hiddenProfileTitle' => 'This profile is hidden!', - 'pageNotFoundPageTitle' => 'Page not found | '.Lang::get('layout.nameWebsite'), - 'pageNotFoundTitle' => 'Page not found!', - 'pageText' => 'page', - 'quoteNotFoundPageTitle' => 'Quote not found | '.Lang::get('layout.nameWebsite'), - 'quoteNotFoundTitle' => 'Quote not found!', - 'quoteText' => 'quote', - 'storyNotFoundPageTitle' => 'Story not found | '.Lang::get('layout.nameWebsite'), - 'storyNotFoundTitle' => 'Story not found!', - 'storyText' => 'story', - 'tagNotFoundPageTitle' => 'Tag not found | '.Lang::get('layout.nameWebsite'), - 'tagNotFoundTitle' => 'Tag not found!', - 'tagText' => 'tag', - 'tokenNotFoundPageTitle' => 'Token not found | '.Lang::get('layout.nameWebsite'), - 'tokenNotFoundTitle' => 'Token not found!', - 'tokenText' => 'token', - 'userNotFoundPageTitle' => 'User not found | '.Lang::get('layout.nameWebsite'), - 'userNotFoundTitle' => 'User not found!', - 'userText' => 'user', -); \ No newline at end of file + 'countryNotFoundPageTitle' => 'Country not found | '.Lang::get('layout.nameWebsite'), + 'countryNotFoundTitle' => 'Country not found!', + 'countryText' => 'country', + 'hiddenProfileBody' => "Oops, it appears that the profile of :login is hidden! It means that only :login can see this profile.

    We take your privacy very seriously and you can hide your profile if you don't want to open your information on ".Lang::get('layout.nameWebsite').' to others.', + 'hiddenProfileTitle' => 'This profile is hidden!', + 'pageNotFoundPageTitle' => 'Page not found | '.Lang::get('layout.nameWebsite'), + 'pageNotFoundTitle' => 'Page not found!', + 'pageText' => 'page', + 'quoteNotFoundPageTitle' => 'Quote not found | '.Lang::get('layout.nameWebsite'), + 'quoteNotFoundTitle' => 'Quote not found!', + 'quoteText' => 'quote', + 'storyNotFoundPageTitle' => 'Story not found | '.Lang::get('layout.nameWebsite'), + 'storyNotFoundTitle' => 'Story not found!', + 'storyText' => 'story', + 'tagNotFoundPageTitle' => 'Tag not found | '.Lang::get('layout.nameWebsite'), + 'tagNotFoundTitle' => 'Tag not found!', + 'tagText' => 'tag', + 'tokenNotFoundPageTitle' => 'Token not found | '.Lang::get('layout.nameWebsite'), + 'tokenNotFoundTitle' => 'Token not found!', + 'tokenText' => 'token', + 'userNotFoundPageTitle' => 'User not found | '.Lang::get('layout.nameWebsite'), + 'userNotFoundTitle' => 'User not found!', + 'userText' => 'user', +]; diff --git a/app/lang/en/feedback.php b/app/lang/en/feedback.php index 96d702e6..44ca86c4 100644 --- a/app/lang/en/feedback.php +++ b/app/lang/en/feedback.php @@ -1,6 +1,6 @@ "It's been a bit less than a week since you signed up for ".Lang::get('layout.nameWebsite')." and we are really happy to have you on board!

    We are committed to offering a great experience to our beloved users. If you have any questions, feedback or need help with anything at all, reply to this email and a member of our support team will get back to you with a personal reply. Go ahead and try!

    Have an awesome day!", - 'welcomeSubject' => 'How is it going so far?', -]; \ No newline at end of file + 'welcomeContent' => "It's been a bit less than a week since you signed up for ".Lang::get('layout.nameWebsite').' and we are really happy to have you on board!

    We are committed to offering a great experience to our beloved users. If you have any questions, feedback or need help with anything at all, reply to this email and a member of our support team will get back to you with a personal reply. Go ahead and try!

    Have an awesome day!', + 'welcomeSubject' => 'How is it going so far?', +]; diff --git a/app/lang/en/layout.php b/app/lang/en/layout.php index 877548a9..e5103d6d 100644 --- a/app/lang/en/layout.php +++ b/app/lang/en/layout.php @@ -1,26 +1,27 @@ 'Add your quote', - 'apps' => 'Apps', - 'blog' => 'Blog', - 'cardFacebookHeight' => '262', - 'cardFacebookURL' => 'http://'.Config::get('app.domain').'/assets/images/card_facebook.png', - 'cardFacebookWidth' => '500', - 'cardTwitterHeight' => '500', - 'cardTwitterURL' => 'http://'.Config::get('app.domain').'/assets/images/card.png', - 'cardTwitterWidth' => '500', - 'catchphrase' => 'Because some quotes are simply true', - 'contact' => 'Contact', - 'goBack' => 'Go back', - 'instagramUsername' => '@officialohteenquotes', - 'legalTerms' => 'Legal', - 'login' => 'Log in', - 'logout' => 'Log out', - 'myProfile' => 'My profile', - 'nameWebsite' => 'Teen Quotes', - 'randomQuotes' => 'Random quotes', - 'search' => 'Search', - 'stories' => 'Stories', - 'topQuotes' => 'Tops', - 'twitterUsername' => '@ohteenquotes', -]; \ No newline at end of file + 'addQuote' => 'Add your quote', + 'apps' => 'Apps', + 'blog' => 'Blog', + 'cardFacebookHeight' => '262', + 'cardFacebookURL' => 'http://'.Config::get('app.domain').'/assets/images/card_facebook.png', + 'cardFacebookWidth' => '500', + 'cardTwitterHeight' => '500', + 'cardTwitterURL' => 'http://'.Config::get('app.domain').'/assets/images/card.png', + 'cardTwitterWidth' => '500', + 'catchphrase' => 'Because some quotes are simply true', + 'contact' => 'Contact', + 'goBack' => 'Go back', + 'instagramUsername' => '@officialohteenquotes', + 'legalTerms' => 'Legal', + 'login' => 'Log in', + 'logout' => 'Log out', + 'myProfile' => 'My profile', + 'nameWebsite' => 'Teen Quotes', + 'randomQuotes' => 'Random quotes', + 'search' => 'Search', + 'stories' => 'Stories', + 'topQuotes' => 'Tops', + 'twitterUsername' => '@ohteenquotes', +]; diff --git a/app/lang/en/legal.php b/app/lang/en/legal.php index a37974b0..6cf52945 100644 --- a/app/lang/en/legal.php +++ b/app/lang/en/legal.php @@ -1,8 +1,9 @@ 'Terms of use', - 'pageDescription' => 'Our terms of use and our privacy are available here. Ready to have a lot of fun?', - 'termsOfUseContent' => ' + +return [ + 'termsOfUseTitle' => 'Terms of use', + 'pageDescription' => 'Our terms of use and our privacy are available here. Ready to have a lot of fun?', + 'termsOfUseContent' => '

    The use of submissions found in the server '.Config::get('app.domain').' is authorized under condition of non-alteration of its contents and the restriction of its use to personal use only and for the purpose of information. Its use for commercial activities is strictly prohibited. Any other use than the above herein mentioned is strictly prohibited by law.

    Anyone who does not respect the applicable provisions is guilty of the delict of piracy and is object of the penalties stipulated by law. The information provided does not include the design or the pagination of '.Config::get('app.domain').' or of any other site managed, controlled or owned by '.Lang::get('layout.nameWebsite').'.

    @@ -15,10 +16,10 @@ Regarding the comments and other submissions by any member, the author of the before mentioned submissions acknowledges full agreement to '.Lang::get('layout.nameWebsite').' to (1) use, copy, distribute, transmit, publicly display, publicly perform, reproduce, edit, modify, translate and reformat his or her contribution within the framework of the website '.Config::get('app.domain').' and any of its partners, (2) to redistribute its rights in the full extent permitted by the applicable regulations.

    The contributions posted on '.Config::get('app.domain').' are not financially compensated. '.Config::get('app.domain').' reserves the right to remove comments and submissions at any time without prior notice. By submitting or posting to any part of the site, you automatically grant, and you represent and warrant that you have the right to grant to '.Lang::get('layout.nameWebsite').' the authorizations stipulated in the present article. '.Lang::get('layout.nameWebsite').' reserves the right to change, modify, add, or delete portions of the terms of use and caution sentences of its websites at any time without further notice. It is your responsibility to regularly check the site to determine if there have been changes to these terms of use and to review such changes. Your continued use of the service or the site '.Config::get('app.domain').' after any such changes constitutes your acceptance of the new terms of use.

    ', - 'privacyPolicyTitle' => 'Privacy Policy', - 'privacyPolicyContent' => " + 'privacyPolicyTitle' => 'Privacy Policy', + 'privacyPolicyContent' => '

    - This Privacy Policy discloses the privacy practices of the ".Config::get('app.domain')." website (the Site). Specifically, it outlines the types of information that we gather about you while you are using the Site, and the ways in which we use and share this information.

    + This Privacy Policy discloses the privacy practices of the '.Config::get('app.domain')." website (the Site). Specifically, it outlines the types of information that we gather about you while you are using the Site, and the ways in which we use and share this information.

    We will not use the information that we collect while you are using the Site, nor will we authorize third parties to use such information, to mail or email promotional offers directly to you unless you have specifically informed us that you would like to receive such promotional offers.

    Please read this Privacy Policy carefully. By visiting and using the Site, you agree that your use of our Site, and any dispute over our online privacy practices, is governed by this Privacy Policy and of Terms of use. Because the Web is an evolving medium, we may need to change our Privacy Policy at some point in the future, in which case we'll post the revised Privacy Policy on this website and update the Last Updated date to reflect the date of the changes. By continuing to use the Site after we post any such changes, you accept the Privacy Policy as modified.

    @@ -38,7 +39,7 @@ We also collect and store non-personally identifiable information that is generated automatically as you navigate through the Site. For example, we may collect information about your computer's connection to the Internet, which allows us, among other things, to improve the delivery of our web pages to you and to measure traffic on the Site. We also may use a standard feature found in browser software called a cookie to enhance your experience with the Site. Cookies are small files that your web browser places on your hard drive for record-keeping purposes. By showing how and when visitors use the Site, cookies help us deliver advertisements, identify how many unique users visit us, and track user trends and patterns. They also prevent you from having to re-enter your preferences on certain areas of the Site where you have entered preference information before. This Site also may use web beacons (single-pixel graphic files also known as transparent GIFs) to access cookies and to count users who visit the Site or open our HTML-formatted email messages.

    If you want to limit the non-personally identifiable information that is automatically collected while you use our Site, most Web browsers allow you to disable cookies. To disable cookies using Internet Explorer, select “Internet Options” under the Tools menu and click on “Privacy.” Select “High” or “Block All Cookies.” To disable cookies using Mozilla Firefox, select “Options” under the “Tools” menu. If you choose to disable cookies, you may not be able to use or participate in some or all of the features offered through the Site.

    - +

    How is this Information Used?

    We use the information we collect from you while you are using the Site in a variety of ways, including, for example, to process your registration request, provide you with services and communications that you have requested, customize features and advertising that appear on the Site, deliver our Site content to you, measure Site traffic, measure user interests and traffic patterns, and improve the Site and the services and features offered via the Site.

    @@ -51,7 +52,7 @@

    Please be aware that we may occasionally release information about visitors if required to do so by law or if, in our business judgment, such disclosure is reasonably necessary: (a) to comply with legal process; (b) to enforce our Terms of Service; or (c) to protect the rights, property, or personal safety of our Site, us, our affiliates, our officers, directors, employees, representatives, our licensors, other users, and/or the public.

    - Please also note that as our business grows, we may buy or sell various assets. In the unlikely event that we sell some or all of our assets, or our Site, is acquired by another company, information about our Site users may be among the transferred assets. + Please also note that as our business grows, we may buy or sell various assets. In the unlikely event that we sell some or all of our assets, or our Site, is acquired by another company, information about our Site users may be among the transferred assets.

    Data Collected in Connection with Ad Serving and Targeting

    @@ -65,21 +66,21 @@

    This children's privacy statement explains our practices with respect to the online collection and use of personal information from children under the age of 13.

    This Site is not directed to children under the age of thirteen and we do NOT knowingly collect personally identifiable information from children under the age of 13 as part of the Site. We screen users who wish to provide personal information in order to prevent users under the age of 13 from providing such information. If we become aware that we have inadvertently received personally identifiable information from a user under the age of 13 as part of the Site, we will delete such information from our records. Because we do not collect any personally identifiable information from children under the age of 13 via the Site, we also do NOT knowingly distribute such information to third parties. We do NOT knowingly allow children under the age of 13 to publicly post or otherwise distribute personally identifiable contact information through the Site.

    - Because we do not collect any personally identifiable information from children under the age of 13 via the Site, we do NOT condition the participation of a child under 13 in the Site's online activities on providing personally identifiable information. + Because we do not collect any personally identifiable information from children under the age of 13 via the Site, we do NOT condition the participation of a child under 13 in the Site's online activities on providing personally identifiable information.

    How To Make Changes to Your Information

    - If you are a registered member of our Site, you can make changes to your account information by logging in to the Site and using the account tools available via the Site. If you have subscribed to one or more of our email newsletters, you may also change your subscriber information, modify your subscriptions, and/or unsubscribe from these newsletters at any time by visiting your account member's editing form. + If you are a registered member of our Site, you can make changes to your account information by logging in to the Site and using the account tools available via the Site. If you have subscribed to one or more of our email newsletters, you may also change your subscriber information, modify your subscriptions, and/or unsubscribe from these newsletters at any time by visiting your account member's editing form.

    - +

    Storage of Information

    - All information we gather on our Site is stored within a database to which only we and our hosting services provider are provided access. However, as effective as the reasonable security measures implemented by us may be, no physical or electronic security system is impenetrable. We cannot guarantee the security of our Site’s servers or databases, nor can we guarantee that information you supply will not be intercepted while being transmitted to us over the Internet + All information we gather on our Site is stored within a database to which only we and our hosting services provider are provided access. However, as effective as the reasonable security measures implemented by us may be, no physical or electronic security system is impenetrable. We cannot guarantee the security of our Site’s servers or databases, nor can we guarantee that information you supply will not be intercepted while being transmitted to us over the Internet

    - +

    Questions Regarding Privacy

    - If you have questions or concerns about this Privacy Policy, our privacy practices, or your dealings with us, please contact us by writing to: ".HTML::email('support@'.Config::get("app.domain"))." -

    ", -); \ No newline at end of file + If you have questions or concerns about this Privacy Policy, our privacy practices, or your dealings with us, please contact us by writing to: ".HTML::email('support@'.Config::get('app.domain')).' +

    ', +]; diff --git a/app/lang/en/newsletters.php b/app/lang/en/newsletters.php index dcd1f862..06c03545 100644 --- a/app/lang/en/newsletters.php +++ b/app/lang/en/newsletters.php @@ -1,10 +1,11 @@ "You've been waiting for a long time, but here it is! The weekly newsletter is out and it is in your inbox!

    Here is a bunch of cool quotes published on ".Lang::get('layout.nameWebsite').":", - 'callToVisitWebsite' => "And remember: if you want to read more awesome quotes there is only a place to do that, and it's called ".Lang::get('layout.nameWebsite')."!", - 'dailySubjectEmail' => 'The daily newsletter', - 'otherQuotesToRead' => "Some other quotes have been published today but if you want to read more awesome quotes there is only a place to do that, and it's called ".Lang::get('layout.nameWebsite')."!

    Have a nice day :login! :)", - 'someQuotesPublishedToday' => "Here are some quotes that have been published today on ".Lang::get('layout.nameWebsite').":", - 'unsubscribeBecauseInactive' => 'We are missing you!

    You have been automatically unsubscribed from all the newsletters you were subscribed because it appears that you haven\'t logged in in a year on '.Lang::get('layout.nameWebsite').'. If you wish to subscribe again, you can do so when editing your settings.

    We hope to see you soon on '.Lang::get('layout.nameWebsite').'!', - 'weeklySubjectEmail' => 'The weekly newsletter', -); \ No newline at end of file + +return [ + 'beenWaitingForLong' => "You've been waiting for a long time, but here it is! The weekly newsletter is out and it is in your inbox!

    Here is a bunch of cool quotes published on ".Lang::get('layout.nameWebsite').':', + 'callToVisitWebsite' => "And remember: if you want to read more awesome quotes there is only a place to do that, and it's called ".Lang::get('layout.nameWebsite').'!', + 'dailySubjectEmail' => 'The daily newsletter', + 'otherQuotesToRead' => "Some other quotes have been published today but if you want to read more awesome quotes there is only a place to do that, and it's called ".Lang::get('layout.nameWebsite').'!

    Have a nice day :login! :)', + 'someQuotesPublishedToday' => 'Here are some quotes that have been published today on '.Lang::get('layout.nameWebsite').':', + 'unsubscribeBecauseInactive' => 'We are missing you!

    You have been automatically unsubscribed from all the newsletters you were subscribed because it appears that you haven\'t logged in in a year on '.Lang::get('layout.nameWebsite').'. If you wish to subscribe again, you can do so when editing your settings.

    We hope to see you soon on '.Lang::get('layout.nameWebsite').'!', + 'weeklySubjectEmail' => 'The weekly newsletter', +]; diff --git a/app/lang/en/pagination.php b/app/lang/en/pagination.php index 6b99ef5f..b9940a13 100644 --- a/app/lang/en/pagination.php +++ b/app/lang/en/pagination.php @@ -1,20 +1,20 @@ '« Previous', + 'previous' => '« Previous', - 'next' => 'Next »', + 'next' => 'Next »', -); +]; diff --git a/app/lang/en/quotes.php b/app/lang/en/quotes.php index bd9aaadb..f6e2db37 100644 --- a/app/lang/en/quotes.php +++ b/app/lang/en/quotes.php @@ -1,51 +1,51 @@ '

    Hi Adblock user!

    It appears that you are blocking our only ad. We don\'t use '.Lang::get('layout.nameWebsite').' to be rich, we just use ads to pay our servers. Please consider disabling your ad blocker here: we promise, we will continue to work hard for you.

    Thanks a lot
    Antoine - Lead developer at '.Lang::get('layout.nameWebsite').'
    ', - 'addquotePageDescription' => 'Speak your mind and share your thoughts with the world. Add a quote right now!', - 'addquotePageTitle' => 'Add a quote | '.Lang::get('layout.nameWebsite'), - 'addYourQuote' => 'Add your quote', - 'commentComments' => '{1} :nb comment| [2,Inf] :nb comments', - 'contentGreatHint' => "It's going to be a great quote!", - 'contentShortHint' => "It's a bit short!", - 'daysText' => 'day|days', - 'favoritesText' => '{0} Nobody favorited this quote yet.|{1} :name0 favorited this quote.|{2} :name0 and :name1 favorited this quote.|{3} :name0, :name1 and :name2 favorited this quote.| [4,Inf] :name0, :name1, :name2 and :nbRemaining others favorited this quote.', - 'fewRules' => 'A few rules', - 'homePageDescription' => 'Inspiring quotes for teenagers about love, life and friends. Share your feelings! Because some quotes are simply true.', - 'homePageTitle' => Lang::get('layout.nameWebsite').' | Love and life quotes for teenagers', - 'nbDays' => '{1} tomorrow| [2, Inf] in :nb days', - 'noticeByEmail' => 'Your quote will then be approved or rejected by our team, you will be informed by email.', - 'quoteAddedSuccessfull' => 'Your quote has been submitted :login! You\'ll get an email soon.', - 'quoteAlertSubjectEmail' => 'Your quote has been rejected', - 'quoteApproveSubjectEmail' => 'Your quote has been approved!', - 'quoteHasBeenApprovedEnd' => ", you'll receive another email. It's gonna be legendary! Just to remind you, here is your quote:", - 'quoteHasBeenApprovedFinal' => "Beautiful, isn't it? Thanks a lot for submitting an awesome quote. Keep submitting, you can publish as much quotes as you want!", - 'quoteHasBeenApprovedStart' => "Congratulations! Your quote #:id has been approved by our team!

    You know what it means? Your quote will be published ", - 'quoteHasBeenPublished' => 'We want to let you know that your quote #:id has been published and is now visible everywhere in the world!

    If you want to take a look at it, you can follow this link: :url. You can now share it with your friends. You are now a kind of superstar!

    Thanks a lot for contributing to '.Lang::get('layout.nameWebsite').'. A lot of people will enjoy reading your quote, and this is super cool.', - 'quoteHasBeenRefused' => 'Unfortunately your quote #:id has been refused by our team.Your quote will not be published.

    Just to remind you, here is your quote:', - 'quoteHasBeenRefusedAlertSad' => "We found that your quote was very sad and we can't promote such sadness on ".Lang::get('layout.nameWebsite').". If you are personally going through some difficult times, please do get in touch with someone you can trust or call someone that can help you. Life is something amazing. Don't do something you will definitely regret.", - 'quoteHasBeenRefusedEnd' => "Please take into consideration that we refuse almost 75 % of the quotes because we want to keep the very best.
    Don't worry, one of your quotes is gonna be approved soon. Remember: write an original quote, in proper English, and eventually you will be published on ".Lang::get('layout.nameWebsite')."!

    Thanks a lot for submitting a quote :login.", - 'quotePublishedSubjectEmail' => 'Your quote has been published!', - 'quotesTagsIndexPageDescription' => 'Browse quotes for a specific tag, sharing a common topic on '.Lang::get('layout.nameWebsite').'.', - 'quotesTagsIndexPageTitle' => 'Browse quotes for a tag | '.Lang::get('layout.nameWebsite'), - 'quotesText' => 'quote|quotes', - 'quotesTopCommentsPageDescription' => 'A list of the most commented quotes available on '.Lang::get('layout.nameWebsite').'.', - 'quotesTopCommentsPageTitle' => 'Most commented quotes | '.Lang::get('layout.nameWebsite'), - 'quotesTopFavoritesPageDescription' => 'A list of the most favorited quotes available on '.Lang::get('layout.nameWebsite').'.', - 'quotesTopFavoritesPageTitle' => 'Most favorited quotes | '.Lang::get('layout.nameWebsite'), - 'quoteUnapproveSubjectEmail' => 'Your quote has been rejected', - 'randomPageDescription' => 'Random quotes released on '.Lang::get('layout.nameWebsite').'. Because some quotes are simply true. Your everyday life moments.', - 'randomPageTitle' => 'Random quotes | '.Lang::get('layout.nameWebsite'), - 'rulesAddQuote' => '
  • Your quote must be written in proper English
  • Your quote should not already be on '.Lang::get('layout.nameWebsite').'
  • Your quote should not be too sad
  • ', - 'sharePromotion' => 'Enjoying '.Lang::get('layout.nameWebsite').'? Share the love with your friends and share a quote!', - 'sharePromotionTitle' => 'Share the love', - 'signupPromotion' => "Create an account right now. You can save quotes in your favorites, add your own quote and a lot more.", - 'signupPromotionTitle' => 'Enjoying '.Lang::get('layout.nameWebsite').'?', - 'singleQuotePageTitle' => 'Quote #:id | '.Lang::get('layout.nameWebsite'), - 'speakYourMind' => 'Speak your mind and share your thoughts with the world!', - 'submitMyQuote' => 'Submit my quote!', - 'topComments' => 'By comments', - 'topFavorites' => 'By favorites', - 'yourQuote' => 'Your quote', - 'quotesForTag' => 'Quotes for tag', -]; \ No newline at end of file + 'adblockDisclaimer' => '

    Hi Adblock user!

    It appears that you are blocking our only ad. We don\'t use '.Lang::get('layout.nameWebsite').' to be rich, we just use ads to pay our servers. Please consider disabling your ad blocker here: we promise, we will continue to work hard for you.

    Thanks a lot
    Antoine - Lead developer at '.Lang::get('layout.nameWebsite').'
    ', + 'addquotePageDescription' => 'Speak your mind and share your thoughts with the world. Add a quote right now!', + 'addquotePageTitle' => 'Add a quote | '.Lang::get('layout.nameWebsite'), + 'addYourQuote' => 'Add your quote', + 'commentComments' => '{1} :nb comment| [2,Inf] :nb comments', + 'contentGreatHint' => "It's going to be a great quote!", + 'contentShortHint' => "It's a bit short!", + 'daysText' => 'day|days', + 'favoritesText' => '{0} Nobody favorited this quote yet.|{1} :name0 favorited this quote.|{2} :name0 and :name1 favorited this quote.|{3} :name0, :name1 and :name2 favorited this quote.| [4,Inf] :name0, :name1, :name2 and :nbRemaining others favorited this quote.', + 'fewRules' => 'A few rules', + 'homePageDescription' => 'Inspiring quotes for teenagers about love, life and friends. Share your feelings! Because some quotes are simply true.', + 'homePageTitle' => Lang::get('layout.nameWebsite').' | Love and life quotes for teenagers', + 'nbDays' => '{1} tomorrow| [2, Inf] in :nb days', + 'noticeByEmail' => 'Your quote will then be approved or rejected by our team, you will be informed by email.', + 'quoteAddedSuccessfull' => 'Your quote has been submitted :login! You\'ll get an email soon.', + 'quoteAlertSubjectEmail' => 'Your quote has been rejected', + 'quoteApproveSubjectEmail' => 'Your quote has been approved!', + 'quoteHasBeenApprovedEnd' => ", you'll receive another email. It's gonna be legendary! Just to remind you, here is your quote:", + 'quoteHasBeenApprovedFinal' => "Beautiful, isn't it? Thanks a lot for submitting an awesome quote. Keep submitting, you can publish as much quotes as you want!", + 'quoteHasBeenApprovedStart' => 'Congratulations! Your quote #:id has been approved by our team!

    You know what it means? Your quote will be published ', + 'quoteHasBeenPublished' => 'We want to let you know that your quote #:id has been published and is now visible everywhere in the world!

    If you want to take a look at it, you can follow this link: :url. You can now share it with your friends. You are now a kind of superstar!

    Thanks a lot for contributing to '.Lang::get('layout.nameWebsite').'. A lot of people will enjoy reading your quote, and this is super cool.', + 'quoteHasBeenRefused' => 'Unfortunately your quote #:id has been refused by our team.Your quote will not be published.

    Just to remind you, here is your quote:', + 'quoteHasBeenRefusedAlertSad' => "We found that your quote was very sad and we can't promote such sadness on ".Lang::get('layout.nameWebsite').". If you are personally going through some difficult times, please do get in touch with someone you can trust or call someone that can help you. Life is something amazing. Don't do something you will definitely regret.", + 'quoteHasBeenRefusedEnd' => "Please take into consideration that we refuse almost 75 % of the quotes because we want to keep the very best.
    Don't worry, one of your quotes is gonna be approved soon. Remember: write an original quote, in proper English, and eventually you will be published on ".Lang::get('layout.nameWebsite').'!

    Thanks a lot for submitting a quote :login.', + 'quotePublishedSubjectEmail' => 'Your quote has been published!', + 'quotesTagsIndexPageDescription' => 'Browse quotes for a specific tag, sharing a common topic on '.Lang::get('layout.nameWebsite').'.', + 'quotesTagsIndexPageTitle' => 'Browse quotes for a tag | '.Lang::get('layout.nameWebsite'), + 'quotesText' => 'quote|quotes', + 'quotesTopCommentsPageDescription' => 'A list of the most commented quotes available on '.Lang::get('layout.nameWebsite').'.', + 'quotesTopCommentsPageTitle' => 'Most commented quotes | '.Lang::get('layout.nameWebsite'), + 'quotesTopFavoritesPageDescription' => 'A list of the most favorited quotes available on '.Lang::get('layout.nameWebsite').'.', + 'quotesTopFavoritesPageTitle' => 'Most favorited quotes | '.Lang::get('layout.nameWebsite'), + 'quoteUnapproveSubjectEmail' => 'Your quote has been rejected', + 'randomPageDescription' => 'Random quotes released on '.Lang::get('layout.nameWebsite').'. Because some quotes are simply true. Your everyday life moments.', + 'randomPageTitle' => 'Random quotes | '.Lang::get('layout.nameWebsite'), + 'rulesAddQuote' => '
  • Your quote must be written in proper English
  • Your quote should not already be on '.Lang::get('layout.nameWebsite').'
  • Your quote should not be too sad
  • ', + 'sharePromotion' => 'Enjoying '.Lang::get('layout.nameWebsite').'? Share the love with your friends and share a quote!', + 'sharePromotionTitle' => 'Share the love', + 'signupPromotion' => "Create an account right now. You can save quotes in your favorites, add your own quote and a lot more.", + 'signupPromotionTitle' => 'Enjoying '.Lang::get('layout.nameWebsite').'?', + 'singleQuotePageTitle' => 'Quote #:id | '.Lang::get('layout.nameWebsite'), + 'speakYourMind' => 'Speak your mind and share your thoughts with the world!', + 'submitMyQuote' => 'Submit my quote!', + 'topComments' => 'By comments', + 'topFavorites' => 'By favorites', + 'yourQuote' => 'Your quote', + 'quotesForTag' => 'Quotes for tag', +]; diff --git a/app/lang/en/reminders.php b/app/lang/en/reminders.php index 8c4a37de..d449262a 100644 --- a/app/lang/en/reminders.php +++ b/app/lang/en/reminders.php @@ -1,24 +1,24 @@ "Your password must be at least six characters.", + 'password' => 'Your password must be at least six characters.', - "user" => "We can't find a user with that e-mail address.", + 'user' => "We can't find a user with that e-mail address.", - "token" => "This password reset token is invalid.", + 'token' => 'This password reset token is invalid.', - "sent" => "Password reminder sent! Check your inbox!", + 'sent' => 'Password reminder sent! Check your inbox!', -); +]; diff --git a/app/lang/en/search.php b/app/lang/en/search.php index 1dd72cb3..432b7572 100644 --- a/app/lang/en/search.php +++ b/app/lang/en/search.php @@ -1,20 +1,21 @@ 'Do a search and find quotes, users and more on '.Lang::get('layout.nameWebsite').'.', - 'formPageTitle' => 'Search form | '.Lang::get('layout.nameWebsite'), - 'noResultsAtAll' => "Oops, we found nothing! Try something else maybe :)", - 'quotesResult' => 'Quotes', - 'redirectedToMostCommonCountry' => 'No results were found. Showing you users from the most common country instead', - 'result' => 'result|results', - 'resultForQuery' => 'Results for “:query”', - 'resultsPageDescription' => 'Results of the search for “:query”. Find users and quotes on '.Lang::get('layout.nameWebsite'), - 'resultsPageTitle' => 'Search “:query” | '.Lang::get('layout.nameWebsite'), - 'searchInput' => 'What do you want to search?', - 'searchInputPlaceholder' => 'A quote, a user...', - 'searchSubmit' => 'Look for this!', - 'searchTitle' => 'Search', - 'showingTopResults' => 'Showing the top :nb results', - 'usersCountryPageDescription' => 'Users from :countryName on '.Lang::get('layout.nameWebsite').'. Find users and quotes on '.Lang::get('layout.nameWebsite'), - 'usersCountryPageTitle' => 'Users from :countryName | '.Lang::get('layout.nameWebsite'), - 'usersResult' => 'Users', -]; \ No newline at end of file + 'formPageDescription' => 'Do a search and find quotes, users and more on '.Lang::get('layout.nameWebsite').'.', + 'formPageTitle' => 'Search form | '.Lang::get('layout.nameWebsite'), + 'noResultsAtAll' => 'Oops, we found nothing! Try something else maybe :)', + 'quotesResult' => 'Quotes', + 'redirectedToMostCommonCountry' => 'No results were found. Showing you users from the most common country instead', + 'result' => 'result|results', + 'resultForQuery' => 'Results for “:query”', + 'resultsPageDescription' => 'Results of the search for “:query”. Find users and quotes on '.Lang::get('layout.nameWebsite'), + 'resultsPageTitle' => 'Search “:query” | '.Lang::get('layout.nameWebsite'), + 'searchInput' => 'What do you want to search?', + 'searchInputPlaceholder' => 'A quote, a user...', + 'searchSubmit' => 'Look for this!', + 'searchTitle' => 'Search', + 'showingTopResults' => 'Showing the top :nb results', + 'usersCountryPageDescription' => 'Users from :countryName on '.Lang::get('layout.nameWebsite').'. Find users and quotes on '.Lang::get('layout.nameWebsite'), + 'usersCountryPageTitle' => 'Users from :countryName | '.Lang::get('layout.nameWebsite'), + 'usersResult' => 'Users', +]; diff --git a/app/lang/en/stories.php b/app/lang/en/stories.php index 4621c1bd..b3a150a5 100644 --- a/app/lang/en/stories.php +++ b/app/lang/en/stories.php @@ -1,18 +1,19 @@ 'Stories | '.Lang::get('layout.nameWebsite'), - 'pageTitleShow' => 'Story #:nb | '.Lang::get('layout.nameWebsite'), - 'pageDescriptionIndex' => 'Tell us how you use '.Lang::get('layout.nameWebsite').' in your daily life to share your feelings', - 'heroText' => 'When we built '.Lang::get('layout.nameWebsite').', we wanted to share our feelings with the Internet. Today, thousands of people read more than :nb quotes on '.Lang::get('layout.nameWebsite').', everyday.', - 'storiesTellTitle' => 'Tell us your story', - 'useTellTitle' => 'Tell us how you use '.Lang::get('layout.nameWebsite'), - 'storyTitle' => 'Story', - 'submitStory' => 'Add my story!', - 'addStory' => 'Add my story', - 'inputRepresent' => 'How do you use '.Lang::get('layout.nameWebsite').'?', - 'placeholderRepresent' => 'Why is it useful to you? What have you learned? Does it help you to feel better?', - 'inputFrequence' => 'How often do you use '.Lang::get('layout.nameWebsite').'? Where?', - 'placeholderFrequence' => 'Do you use the website / mobile / app? How often do you visit '.Lang::get('layout.nameWebsite').'? Do you share some quotes with your friends? Do you write some quotes?', - 'storyAddedSuccessfull' => 'Your story has been added :login!', - 'mustBeLogged' => 'You must be logged in if you want to add your story ', -); \ No newline at end of file + +return [ + 'pageTitleIndex' => 'Stories | '.Lang::get('layout.nameWebsite'), + 'pageTitleShow' => 'Story #:nb | '.Lang::get('layout.nameWebsite'), + 'pageDescriptionIndex' => 'Tell us how you use '.Lang::get('layout.nameWebsite').' in your daily life to share your feelings', + 'heroText' => 'When we built '.Lang::get('layout.nameWebsite').', we wanted to share our feelings with the Internet. Today, thousands of people read more than :nb quotes on '.Lang::get('layout.nameWebsite').', everyday.', + 'storiesTellTitle' => 'Tell us your story', + 'useTellTitle' => 'Tell us how you use '.Lang::get('layout.nameWebsite'), + 'storyTitle' => 'Story', + 'submitStory' => 'Add my story!', + 'addStory' => 'Add my story', + 'inputRepresent' => 'How do you use '.Lang::get('layout.nameWebsite').'?', + 'placeholderRepresent' => 'Why is it useful to you? What have you learned? Does it help you to feel better?', + 'inputFrequence' => 'How often do you use '.Lang::get('layout.nameWebsite').'? Where?', + 'placeholderFrequence' => 'Do you use the website / mobile / app? How often do you visit '.Lang::get('layout.nameWebsite').'? Do you share some quotes with your friends? Do you write some quotes?', + 'storyAddedSuccessfull' => 'Your story has been added :login!', + 'mustBeLogged' => 'You must be logged in if you want to add your story ', +]; diff --git a/app/lang/en/tags.php b/app/lang/en/tags.php index 731b28f9..4e2fd38d 100644 --- a/app/lang/en/tags.php +++ b/app/lang/en/tags.php @@ -1,12 +1,12 @@ 'School', - 'family' => 'Family', - 'love' => 'Love', - 'friends' => 'Friends', - 'holiday' => 'Holiday', - 'music' => 'Music', - 'awkward' => 'Awkward', - 'book' => 'Book', -]; \ No newline at end of file + 'school' => 'School', + 'family' => 'Family', + 'love' => 'Love', + 'friends' => 'Friends', + 'holiday' => 'Holiday', + 'music' => 'Music', + 'awkward' => 'Awkward', + 'book' => 'Book', +]; diff --git a/app/lang/en/users.php b/app/lang/en/users.php index 4cff0bd5..8033fad4 100644 --- a/app/lang/en/users.php +++ b/app/lang/en/users.php @@ -1,73 +1,74 @@ 'About me', - 'aboutMePlacehoolder' => "I'm awesome, I love life, I listen to music...", - 'addedFavCountText' => "my quote favorited|my quotes favorited", - 'birthdateInput' => 'Birthdate', - 'browserCantChangeAvatar' => "You can't change your avatar with your browser. Please use the website!", - 'changeMyPasswordSubmit' => 'Change my password!', - 'changePasswordCatchphrase' => "If you don't like something, change it. If you can't change it, find a way to change it.", - 'changePasswordTitle' => 'Change my password', - 'cityInput' => 'City', - 'cityPlaceholder' => 'e.g. New York', - 'colorNotAllowed' => "You are not allowed to use this color", - 'colorsInput' => "Your published quotes' color", - 'comments' => 'Comments', - 'commentsCountText' => 'comment|comments', - 'countryInput' => 'Country', - 'dailyNewsletterInput' => 'Receive a daily email with some published quotes', - 'dateFormatInput' => 'Y-m-d. e.g. 1995-01-31', - 'deleteAccountSubmit' => 'Delete my account', - 'deleteAccountSuccessfull' => "Your account has been deleted successfully", - 'deleteAccountTitle' => "Delete my account", - 'deleteAccountWarning' => "If you choose to delete your account, we will remove all your quotes, all your favorites and everything you have added on ".Lang::get('layout.nameWebsite').". Be very careful, you can't undone this action.", - 'editPageDescription' => 'Ready to meet the new you? Update your information and give your profile a fresh look!', - 'editPageTitle' => 'Edit your profile | '.Lang::get('layout.nameWebsite'), - 'editProfileSubmit' => 'Edit my profile!', - 'editProfileTitle' => 'Edit my profile', - 'editSettingsCatchphrase' => "There is nothing permanent except change. Just below you'll find everything you want to suit your needs.", - 'editSettingsSubmit' => 'Edit my settings!', - 'editSettingsTitle' => 'Edit my settings', - 'favCountText' => 'favorites|favorites', - 'favoriteQuotes' => 'Favorite quotes', - 'femaleLabel' => 'Female', - 'genderLabel' => 'Gender', - 'hideProfileInput' => 'Hide my profile', - 'hintAvatar' => 'Show us how beautiful you are!', - 'hintBirthdate' => 'We only use this to display your age.', - 'iAmAMan' => "I'm a man!", - 'iAmAWoman' => "I'm a woman!", - 'inputsOptionalInfo' => 'Everything is optional here. Fill in what you want!', - 'maleLabel' => 'Male', - 'newPasswordInput' => 'New password', - 'newUserTutorialAddingQuoteContent' => 'If you are inspired (and you want to inspire others!) you may want to write a quote!', - 'newUserTutorialAddingQuoteTitle' => 'Writing a quote', - 'newUserTutorialFavoritesContent' => 'If you love quotes as much as we do, you may want to add some quotes in your favorites! Once added in your favorites, you can read them from your profile.', - 'newUserTutorialFavoritesTitle' => 'Adding some favorites', - 'newUserTutorialProfileContent' => 'Your profile seems a little bit empty now. How about filling up your profile? People will be happy to know more about you!', - 'newUserTutorialProfileTitle' => 'Filling up your profile', - 'newUserTutorialSettingsContent' => "You have been subscribed to the weekly newsletter and will receive some quotes on Mondays. You can always edit your settings.", - 'newUserTutorialSettingsTitle' => 'Managing settings', - 'newUserWelcomeProfile' => 'Welcome :login! Your profile is quite empty for the moment, but it is okay: you are new here! Here are some interesting things to do.', - 'notificationCommentQuoteInput' => 'Receive an email when a comment is added on one of my quotes', - 'passwordConfirmationInput' => 'Confirm your password', - 'passwordInput' => 'Password', - 'profileCurrentlyHidden' => "Your profile is currently hidden. Only you can see this!", - 'profilePageDescription' => 'Visit the profile of :login on Teen Quotes and learn some cool facts!', - 'profilePageTitle' => ":login's profile | ".Lang::get('layout.nameWebsite'), - 'publishedQuotes' => 'Published quotes', - 'quotesPublishedCountText' => 'published quote|published quotes', - 'seeFavoritedQuotes' => 'Favorite quotes', - 'seePublishedQuotes' => 'Published quotes', - 'updatePasswordSuccessfull' => 'Your password has been changed :login!', - 'updateProfileSuccessfull' => 'You have a brand new profile :login!', - 'updateSettingsSuccessfull' => 'Your settings have been changed :login!', - 'weeklyNewsletterInput' => 'Receive a weekly email with some quotes', - 'welcomeTweetButton' => 'Tweet it!', - 'welcomeTweetText' => "I've just signed up on ".Lang::get('layout.nameWebsite')."! It's the best place to read amazing quotes. Check this out: ".Config::get('app.url'), - 'writeDelete' => 'Write "DELETE" here', - 'writeDeleteHere' => 'You need to write "DELETE" here', - 'yearsOldAbbreviation' => 'y/o', - 'yourAvatarInput' => 'Your avatar', - 'yourPassword' => 'Your password', + 'aboutMeInput' => 'About me', + 'aboutMePlacehoolder' => "I'm awesome, I love life, I listen to music...", + 'addedFavCountText' => 'my quote favorited|my quotes favorited', + 'birthdateInput' => 'Birthdate', + 'browserCantChangeAvatar' => "You can't change your avatar with your browser. Please use the website!", + 'changeMyPasswordSubmit' => 'Change my password!', + 'changePasswordCatchphrase' => "If you don't like something, change it. If you can't change it, find a way to change it.", + 'changePasswordTitle' => 'Change my password', + 'cityInput' => 'City', + 'cityPlaceholder' => 'e.g. New York', + 'colorNotAllowed' => 'You are not allowed to use this color', + 'colorsInput' => "Your published quotes' color", + 'comments' => 'Comments', + 'commentsCountText' => 'comment|comments', + 'countryInput' => 'Country', + 'dailyNewsletterInput' => 'Receive a daily email with some published quotes', + 'dateFormatInput' => 'Y-m-d. e.g. 1995-01-31', + 'deleteAccountSubmit' => 'Delete my account', + 'deleteAccountSuccessfull' => 'Your account has been deleted successfully', + 'deleteAccountTitle' => 'Delete my account', + 'deleteAccountWarning' => 'If you choose to delete your account, we will remove all your quotes, all your favorites and everything you have added on '.Lang::get('layout.nameWebsite').". Be very careful, you can't undone this action.", + 'editPageDescription' => 'Ready to meet the new you? Update your information and give your profile a fresh look!', + 'editPageTitle' => 'Edit your profile | '.Lang::get('layout.nameWebsite'), + 'editProfileSubmit' => 'Edit my profile!', + 'editProfileTitle' => 'Edit my profile', + 'editSettingsCatchphrase' => "There is nothing permanent except change. Just below you'll find everything you want to suit your needs.", + 'editSettingsSubmit' => 'Edit my settings!', + 'editSettingsTitle' => 'Edit my settings', + 'favCountText' => 'favorites|favorites', + 'favoriteQuotes' => 'Favorite quotes', + 'femaleLabel' => 'Female', + 'genderLabel' => 'Gender', + 'hideProfileInput' => 'Hide my profile', + 'hintAvatar' => 'Show us how beautiful you are!', + 'hintBirthdate' => 'We only use this to display your age.', + 'iAmAMan' => "I'm a man!", + 'iAmAWoman' => "I'm a woman!", + 'inputsOptionalInfo' => 'Everything is optional here. Fill in what you want!', + 'maleLabel' => 'Male', + 'newPasswordInput' => 'New password', + 'newUserTutorialAddingQuoteContent' => 'If you are inspired (and you want to inspire others!) you may want to write a quote!', + 'newUserTutorialAddingQuoteTitle' => 'Writing a quote', + 'newUserTutorialFavoritesContent' => 'If you love quotes as much as we do, you may want to add some quotes in your favorites! Once added in your favorites, you can read them from your profile.', + 'newUserTutorialFavoritesTitle' => 'Adding some favorites', + 'newUserTutorialProfileContent' => 'Your profile seems a little bit empty now. How about filling up your profile? People will be happy to know more about you!', + 'newUserTutorialProfileTitle' => 'Filling up your profile', + 'newUserTutorialSettingsContent' => "You have been subscribed to the weekly newsletter and will receive some quotes on Mondays. You can always edit your settings.", + 'newUserTutorialSettingsTitle' => 'Managing settings', + 'newUserWelcomeProfile' => 'Welcome :login! Your profile is quite empty for the moment, but it is okay: you are new here! Here are some interesting things to do.', + 'notificationCommentQuoteInput' => 'Receive an email when a comment is added on one of my quotes', + 'passwordConfirmationInput' => 'Confirm your password', + 'passwordInput' => 'Password', + 'profileCurrentlyHidden' => 'Your profile is currently hidden. Only you can see this!', + 'profilePageDescription' => 'Visit the profile of :login on Teen Quotes and learn some cool facts!', + 'profilePageTitle' => ":login's profile | ".Lang::get('layout.nameWebsite'), + 'publishedQuotes' => 'Published quotes', + 'quotesPublishedCountText' => 'published quote|published quotes', + 'seeFavoritedQuotes' => 'Favorite quotes', + 'seePublishedQuotes' => 'Published quotes', + 'updatePasswordSuccessfull' => 'Your password has been changed :login!', + 'updateProfileSuccessfull' => 'You have a brand new profile :login!', + 'updateSettingsSuccessfull' => 'Your settings have been changed :login!', + 'weeklyNewsletterInput' => 'Receive a weekly email with some quotes', + 'welcomeTweetButton' => 'Tweet it!', + 'welcomeTweetText' => "I've just signed up on ".Lang::get('layout.nameWebsite')."! It's the best place to read amazing quotes. Check this out: ".Config::get('app.url'), + 'writeDelete' => 'Write "DELETE" here', + 'writeDeleteHere' => 'You need to write "DELETE" here', + 'yearsOldAbbreviation' => 'y/o', + 'yourAvatarInput' => 'Your avatar', + 'yourPassword' => 'Your password', ]; diff --git a/app/lang/en/validation.php b/app/lang/en/validation.php index 05a27df9..dbb1fd40 100644 --- a/app/lang/en/validation.php +++ b/app/lang/en/validation.php @@ -1,104 +1,104 @@ "The :attribute must be accepted.", - "active_url" => "The :attribute is not a valid URL.", - "after" => "The :attribute must be a date after :date.", - "alpha" => "The :attribute may only contain letters.", - "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", - "alpha_num" => "The :attribute may only contain letters and numbers.", - "array" => "The :attribute must be an array.", - "before" => "The :attribute must be a date before :date.", - "between" => array( - "numeric" => "The :attribute must be between :min and :max.", - "file" => "The :attribute must be between :min and :max kilobytes.", - "string" => "The :attribute must be between :min and :max characters.", - "array" => "The :attribute must have between :min and :max items.", - ), - "confirmed" => "The :attribute confirmation does not match.", - "date" => "The :attribute is not a valid date.", - "date_format" => "The :attribute does not match the format :format.", - "different" => "The :attribute and :other must be different.", - "digits" => "The :attribute must be :digits digits.", - "digits_between" => "The :attribute must be between :min and :max digits.", - "email" => "The :attribute must be a valid email address.", - "exists" => "The selected :attribute was not found.", - "image" => "The :attribute must be an image.", - "in" => "The selected :attribute is invalid.", - "integer" => "The :attribute must be an integer.", - "ip" => "The :attribute must be a valid IP address.", - "max" => array( - "numeric" => "The :attribute may not be greater than :max.", - "file" => "The :attribute may not be greater than :max kilobytes.", - "string" => "The :attribute may not be greater than :max characters.", - "array" => "The :attribute may not have more than :max items.", - ), - "mimes" => "The :attribute must be a file of type: :values.", - "min" => array( - "numeric" => "The :attribute must be at least :min.", - "file" => "The :attribute must be at least :min kilobytes.", - "string" => "The :attribute must be at least :min characters.", - "array" => "The :attribute must have at least :min items.", - ), - "not_in" => "The selected :attribute is invalid.", - "numeric" => "The :attribute must be a number.", - "regex" => "The :attribute format is invalid.", - "required" => "The :attribute field is required.", - "required_if" => "The :attribute field is required when :other is :value.", - "required_with" => "The :attribute field is required when :values is present.", - "required_with_all" => "The :attribute field is required when :values is present.", - "required_without" => "The :attribute field is required when :values is not present.", - "required_without_all" => "The :attribute field is required when none of :values are present.", - "same" => "The :attribute and :other must match.", - "size" => array( - "numeric" => "The :attribute must be :size.", - "file" => "The :attribute must be :size kilobytes.", - "string" => "The :attribute must be :size characters.", - "array" => "The :attribute must contain :size items.", - ), - "unique" => "The :attribute has already been taken.", - "url" => "The :attribute format is invalid.", + 'accepted' => 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute was not found.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ - 'custom' => array( - 'quotesSubmittedToday' => array( - 'between' => "You have submitted enough quotes for today, check back tomorrow!", - ), - ), + 'custom' => [ + 'quotesSubmittedToday' => [ + 'between' => 'You have submitted enough quotes for today, check back tomorrow!', + ], + ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ - 'attributes' => array(), + 'attributes' => [], -); +]; diff --git a/app/start/artisan.php b/app/start/artisan.php index 9891513c..136bda0f 100644 --- a/app/start/artisan.php +++ b/app/start/artisan.php @@ -10,4 +10,4 @@ | the console gets access to each of the command object instances. | */ -Artisan::add(new QuoteRefuseTooSadCommand); \ No newline at end of file +Artisan::add(new QuoteRefuseTooSadCommand()); diff --git a/app/start/global.php b/app/start/global.php index 3c51ed03..7dc53b1c 100644 --- a/app/start/global.php +++ b/app/start/global.php @@ -11,11 +11,11 @@ | */ -ClassLoader::addDirectories(array( +ClassLoader::addDirectories([ - app_path().'/commands', - app_path().'/database/seeds', -)); + app_path().'/commands', + app_path().'/database/seeds', +]); /* |-------------------------------------------------------------------------- @@ -43,92 +43,86 @@ | */ -App::error(function(TeenQuotes\Exceptions\HiddenProfileException $exception, $code) -{ - $userLogin = Route::input('user_id'); +App::error(function (TeenQuotes\Exceptions\HiddenProfileException $exception, $code) { + $userLogin = Route::input('user_id'); - $data = [ - 'title' => Lang::get('errors.hiddenProfileTitle'), - 'content' => Lang::get('errors.hiddenProfileBody', ['login' => $userLogin]), - ]; + $data = [ + 'title' => Lang::get('errors.hiddenProfileTitle'), + 'content' => Lang::get('errors.hiddenProfileBody', ['login' => $userLogin]), + ]; - // Send event to Google Analytics - JavaScript::put([ - 'eventCategory' => 'profile-hidden', - 'eventAction' => $userLogin, - 'eventLabel' => URL::current() - ]); + // Send event to Google Analytics + JavaScript::put([ + 'eventCategory' => 'profile-hidden', + 'eventAction' => $userLogin, + 'eventLabel' => URL::current(), + ]); - return Response::view('errors.default', $data, 401); + return Response::view('errors.default', $data, 401); }); -App::error(function(Laracasts\Validation\FormValidationException $e, $code) -{ - // In the API - if (Request::wantsJson()) - { - $failedKey = array_keys($e->getErrors()->getMessages())[0]; - - return Response::json([ - 'status' => 'wrong_'.$failedKey, - 'error' => $e->getErrors()->first($failedKey), - ], 400); - } - - return Redirect::back() - ->withInput(Input::except(['password', 'avatar'])) - ->withErrors($e->getErrors()); +App::error(function (Laracasts\Validation\FormValidationException $e, $code) { + // In the API + if (Request::wantsJson()) { + $failedKey = array_keys($e->getErrors()->getMessages())[0]; + + return Response::json([ + 'status' => 'wrong_'.$failedKey, + 'error' => $e->getErrors()->first($failedKey), + ], 400); + } + + return Redirect::back() + ->withInput(Input::except(['password', 'avatar'])) + ->withErrors($e->getErrors()); }); -App::error(function(TeenQuotes\Exceptions\TQNotFoundException $exception, $code) -{ - $resourceName = strtolower(str_replace("NotFoundException", "", class_basename(get_class($exception)))); - - if (in_array($resourceName, ['quote', 'user', 'tag', 'token', 'story', 'country'])) - { - $data = [ - 'content' => Lang::get('errors.defaultNotFound', ['resource' => Lang::get('errors.'.$resourceName.'Text')]), - 'title' => Lang::get('errors.'.$resourceName.'NotFoundTitle'), - 'pageTitle' => Lang::get('errors.'.$resourceName.'NotFoundPageTitle'), - ]; - - // Send event to Google Analytics - JavaScript::put([ - 'eventCategory' => '404', - 'eventAction' => $resourceName, - 'eventLabel' => URL::current() - ]); - - return Response::view('errors.default', $data, 404); - } +App::error(function (TeenQuotes\Exceptions\TQNotFoundException $exception, $code) { + $resourceName = strtolower(str_replace('NotFoundException', '', class_basename(get_class($exception)))); + + if (in_array($resourceName, ['quote', 'user', 'tag', 'token', 'story', 'country'])) { + $data = [ + 'content' => Lang::get('errors.defaultNotFound', ['resource' => Lang::get('errors.'.$resourceName.'Text')]), + 'title' => Lang::get('errors.'.$resourceName.'NotFoundTitle'), + 'pageTitle' => Lang::get('errors.'.$resourceName.'NotFoundPageTitle'), + ]; + + // Send event to Google Analytics + JavaScript::put([ + 'eventCategory' => '404', + 'eventAction' => $resourceName, + 'eventLabel' => URL::current(), + ]); + + return Response::view('errors.default', $data, 404); + } }); // Handle 404 -App::missing(function($exception) -{ - $data = [ - 'content' => Lang::get('errors.defaultNotFound', ['resource' => Lang::get('errors.pageText')]), - 'title' => Lang::get('errors.pageNotFoundTitle') - ]; - - // Send event to Google Analytics - JavaScript::put([ - 'eventCategory' => '404', - 'eventAction' => 'unknow', - 'eventLabel' => URL::current() - ]); +App::missing(function ($exception) { + $data = [ + 'content' => Lang::get('errors.defaultNotFound', ['resource' => Lang::get('errors.pageText')]), + 'title' => Lang::get('errors.pageNotFoundTitle'), + ]; + + // Send event to Google Analytics + JavaScript::put([ + 'eventCategory' => '404', + 'eventAction' => 'unknow', + 'eventLabel' => URL::current(), + ]); return Response::view('errors.default', $data, 404); }); // This error handler will be at the end of the stack -App::pushError(function(Exception $exception, $code) -{ - Log::error($exception); +App::pushError(function (Exception $exception, $code) { + Log::error($exception); - // Show a custom view - if (App::environment() != 'local') - return Response::view('errors.500', ['pageTitle' => 'Oops, something is wrong!'], $code); + // Show a custom view + if (App::environment() != 'local') { + return Response::view('errors.500', ['pageTitle' => 'Oops, something is wrong!'], $code); + } }); /* @@ -142,9 +136,8 @@ | */ -App::down(function() -{ - return Response::view('errors.maintenance', ['pageTitle' => 'Be right back!'], 503); +App::down(function () { + return Response::view('errors.maintenance', ['pageTitle' => 'Be right back!'], 503); }); /* @@ -158,4 +151,4 @@ | */ -require app_path().'/filters.php'; \ No newline at end of file +require app_path().'/filters.php'; diff --git a/app/start/local.php b/app/start/local.php index 3d148509..3d9949b8 100644 --- a/app/start/local.php +++ b/app/start/local.php @@ -1,3 +1,3 @@ @foreach ($quotes as $quote) - @include('quotes.singleQuoteAdmin', compact("quote")) - - + @include('quotes.singleQuoteAdmin', compact('quote', 'colorGenerator', 'i')) + @endforeach
    -@stop \ No newline at end of file +@stop diff --git a/ressources/views/emails/layout/html/style.blade.php b/ressources/views/emails/layout/html/style.blade.php index fca98d60..78faacb4 100644 --- a/ressources/views/emails/layout/html/style.blade.php +++ b/ressources/views/emails/layout/html/style.blade.php @@ -49,6 +49,9 @@ #container #body-content .quote { background-color: #27AE60; color: #FFFFFF; + border-bottom-width: 2px; + border-bottom-style: solid; + border-bottom-color: #27AE60; padding: 10px 10px 15px 10px; margin: 25px 15px 25px 15px; } @@ -77,4 +80,4 @@ #footer-disclaimer { font-size: 90%; } - \ No newline at end of file + diff --git a/ressources/views/emails/newsletters/daily.blade.php b/ressources/views/emails/newsletters/daily.blade.php index bb3b1ab5..11308832 100644 --- a/ressources/views/emails/newsletters/daily.blade.php +++ b/ressources/views/emails/newsletters/daily.blade.php @@ -4,13 +4,11 @@ {{ Lang::get('email.hiWithLogin', ['login' => '*|LOGIN|*']) }}

    {{ Lang::get('newsletters.someQuotesPublishedToday') }} - - @foreach ($quotes as $quote) - @include('emails.quotes.single', compact('quote')) - @endforeach + + @include('emails.quotes.multiple', compact('quotes')) {{ Lang::get('newsletters.otherQuotesToRead', ['login' => '*|LOGIN|*']) }} @stop -@include('emails.newsletters.editSettings', ['login' => '*|LOGIN|*']) \ No newline at end of file +@include('emails.newsletters.editSettings', ['login' => '*|LOGIN|*']) diff --git a/ressources/views/emails/newsletters/weekly.blade.php b/ressources/views/emails/newsletters/weekly.blade.php index be7e3840..db2bac9b 100644 --- a/ressources/views/emails/newsletters/weekly.blade.php +++ b/ressources/views/emails/newsletters/weekly.blade.php @@ -4,13 +4,11 @@ {{ Lang::get('email.hiWithLogin', ['login' => '*|LOGIN|*']) }}

    {{ Lang::get('newsletters.beenWaitingForLong') }} - - @foreach ($quotes as $quote) - @include('emails.quotes.single', compact('quote')) - @endforeach + + @include('emails.quotes.multiple', compact('quotes')) {{ Lang::get('newsletters.callToVisitWebsite') }} @stop -@include('emails.newsletters.editSettings', ['login' => '*|LOGIN|*']) \ No newline at end of file +@include('emails.newsletters.editSettings', ['login' => '*|LOGIN|*']) diff --git a/ressources/views/emails/quotes/multiple.blade.php b/ressources/views/emails/quotes/multiple.blade.php new file mode 100644 index 00000000..6cc8a483 --- /dev/null +++ b/ressources/views/emails/quotes/multiple.blade.php @@ -0,0 +1,3 @@ +@foreach ($quotes as $quote) + @include('emails.quotes.single', compact('quote')) +@endforeach diff --git a/ressources/views/emails/quotes/single.blade.php b/ressources/views/emails/quotes/single.blade.php index 04239d8f..4fd99f29 100644 --- a/ressources/views/emails/quotes/single.blade.php +++ b/ressources/views/emails/quotes/single.blade.php @@ -1,4 +1,13 @@ -
    +@if (isset($colorGenerator)) + darken(20); + $colorQuote = $colorGenerator->nextColor(); + ?> +
    +@else +
    +@endif + {{{ $quote->content}}}
    @if ($quote->isPublished()) @@ -12,4 +21,4 @@ {{{ $quote->user->login }}}
    -
    \ No newline at end of file +
    diff --git a/ressources/views/quotes/singleQuoteAdmin.blade.php b/ressources/views/quotes/singleQuoteAdmin.blade.php index de11afaa..5abd3ea7 100644 --- a/ressources/views/quotes/singleQuoteAdmin.blade.php +++ b/ressources/views/quotes/singleQuoteAdmin.blade.php @@ -1,6 +1,6 @@ darken(20); +$colorQuote = $colorGenerator->nextColor(); if ($i % 2 == 1) $transition = 'fadeInRight'; else @@ -11,6 +11,6 @@
    - @include ('quotes.partials.moderationButtons') + @include('quotes.partials.moderationButtons', compact('quote'))
    - \ No newline at end of file + diff --git a/tests/TestCase.php b/tests/TestCase.php index 03d329e7..3e9f0ac6 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,18 +1,18 @@ getCssParentClass($q); - - $I = $this->getModule('Laravel4'); - - $I->see($q->content, $parentClass); - } - - /** - * I can see moderation buttons for each quote - * @param \TeenQuotes\Quotes\Models\Quote $q - */ - public function seeModerationButtonsForQuote(Quote $q) - { - $parentClass = $this->getCssParentClass($q); - - $I = $this->getModule('Laravel4'); - - // I can see moderation decisions - $moderationDecisions = Moderation::getAvailableTypes(); - foreach ($moderationDecisions as $decision) - { - $cssClass = $parentClass.' .quote-moderation[data-decision="'.$decision.'"]'; - $I->seeNumberOfElements($cssClass, 1); - } - - // I can see the edit button - $I->seeNumberOfElements($this->getCssEditLink($q), 1); - } - - /** - * Click the edit button for a quote and assert that we've been redirected - * @param \TeenQuotes\Quotes\Models\Quote $q - */ - public function clickEditButtonFor(Quote $q) - { - $I = $this->getModule('Laravel4'); - - $I->click($this->getCssEditLink($q)); - $I->seeCurrentRouteIs('admin.quotes.edit', $q->id); - } - - /** - * Check that the author of a quote got an email telling him that one of its - * quote was approved - * @param \TeenQuotes\Quotes\Models\Quote $quote - */ - public function seeAuthorOfQuoteHasBeenWarnedOfApproval(Quote $quote) - { - $I = $this->getModule('MailCatcher'); - - $I->seeInLastEmailTo($quote->user->email, 'Your quote has been approved!'); - } - - /** - * Check that a quote is pending. Grab the quote from the DB - * @param \TeenQuotes\Quotes\Models\Quote $q - */ - public function seeQuoteIsPending(Quote $q) - { - $I = $this->getModule('Laravel4'); - - $quote = $I->grabRecord('quotes', ['id' => $q->id]); - - $I->assertEquals($quote->approved, Quote::PENDING); - } - - /** - * Get the CSS class for the link to the edit form for a quote - * @param \TeenQuotes\Quotes\ModelsQuote $q - */ - private function getCssEditLink(Quote $q) - { - $parentClass = $this->getCssParentClass($q); - - return $parentClass.' .admin__quote__edit-button'; - } - - /** - * Get the CSS class for a quote - * @param \TeenQuotes\Quotes\ModelsQuote $q - */ - private function getCssParentClass(Quote $q) - { - return '.quote[data-id='.$q->id.']'; - } -} \ No newline at end of file +class AdminPanelHelper extends Module +{ + /** + * I can see that the content of a quote is displayed. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + */ + public function seeContentForQuoteWaitingForModeration(Quote $q) + { + $parentClass = $this->getCssParentClass($q); + + $I = $this->getModule('Laravel4'); + + $I->see($q->content, $parentClass); + } + + /** + * I can see moderation buttons for each quote. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + */ + public function seeModerationButtonsForQuote(Quote $q) + { + $parentClass = $this->getCssParentClass($q); + + $I = $this->getModule('Laravel4'); + + // I can see moderation decisions + $moderationDecisions = Moderation::getAvailableTypes(); + foreach ($moderationDecisions as $decision) { + $cssClass = $parentClass.' .quote-moderation[data-decision="'.$decision.'"]'; + $I->seeNumberOfElements($cssClass, 1); + } + + // I can see the edit button + $I->seeNumberOfElements($this->getCssEditLink($q), 1); + } + + /** + * Click the edit button for a quote and assert that we've been redirected. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + */ + public function clickEditButtonFor(Quote $q) + { + $I = $this->getModule('Laravel4'); + + $I->click($this->getCssEditLink($q)); + $I->seeCurrentRouteIs('admin.quotes.edit', $q->id); + } + + /** + * Check that the author of a quote got an email telling him that one of its + * quote was approved. + * + * @param \TeenQuotes\Quotes\Models\Quote $quote + */ + public function seeAuthorOfQuoteHasBeenWarnedOfApproval(Quote $quote) + { + $I = $this->getModule('MailCatcher'); + + $I->seeInLastEmailTo($quote->user->email, 'Your quote has been approved!'); + } + + /** + * Check that a quote is pending. Grab the quote from the DB. + * + * @param \TeenQuotes\Quotes\Models\Quote $q + */ + public function seeQuoteIsPending(Quote $q) + { + $I = $this->getModule('Laravel4'); + + $quote = $I->grabRecord('quotes', ['id' => $q->id]); + + $I->assertEquals($quote->approved, Quote::PENDING); + } + + /** + * Get the CSS class for the link to the edit form for a quote. + * + * @param \TeenQuotes\Quotes\ModelsQuote $q + */ + private function getCssEditLink(Quote $q) + { + $parentClass = $this->getCssParentClass($q); + + return $parentClass.' .admin__quote__edit-button'; + } + + /** + * Get the CSS class for a quote. + * + * @param \TeenQuotes\Quotes\ModelsQuote $q + */ + private function getCssParentClass(Quote $q) + { + return '.quote[data-id='.$q->id.']'; + } +} diff --git a/tests/_support/ApiHelper.php b/tests/_support/ApiHelper.php index 83eff4c0..17d00aeb 100644 --- a/tests/_support/ApiHelper.php +++ b/tests/_support/ApiHelper.php @@ -1,574 +1,604 @@ -assertStatusCodeIs(Response::HTTP_NOT_FOUND); + $this->assertObjectHasAttribute('status', $this->json); + $this->assertObjectHasAttribute('error', $this->json); + + return $this; + } + + private function assertObjectHasAttribute($attribute, $object) + { + $this->assertTrue(property_exists($object, $attribute)); + } + + private function assertObjectNotHasAttribute($attribute, $object) + { + $this->assertFalse(property_exists($object, $attribute)); + } + + public function generateString($length) + { + if ($length == 0) { + return ''; + } + + return str_random($length); + } + + public function logUserWithId($id) + { + $this->userIdLoggedIn = $id; + Auth::loginUsingId($id); + + return Auth::user(); + } + + public function assertStatusCodeIs($code) + { + $this->assertEquals($code, $this->response->getStatusCode()); + + return $this; + } + + private function assertResponseHasAttributes($array) + { + $this->assertObjectHasAttributes($this->json, $array); + } + + public function assertResponseHasRequiredAttributes() + { + $this->assertObjectHasAttributes($this->json, $this->requiredAttributes); + } + + public function assertObjectHasRequiredAttributes($object) + { + return $this->assertObjectHasAttributes($object, $this->requiredAttributes); + } + + private function assertObjectHasAttributes($object, $array) + { + foreach ($array as $value) { + $this->assertObjectHasAttribute($value, $object); + if (Str::contains($value, '_id')) { + $this->assertTrue(is_integer($object->$value)); + } + } + } + + public function tryPaginatedContentNotFound($method = 'index', $params = null) + { + $data = [ + 'page' => $this->getIdNonExistingRessource(), + 'pagesize' => $this->nbRessources, + ]; + + $this->addInputReplace($data); + + $this->doRequest($method, $params); -class ApiHelper extends Module { - - /** - * The controller class to use for the current test case - * @var mixed - */ - protected $controller; - - /** - * The response given by a controller - * @var Illuminate\Http\Response - */ - protected $response; - - /** - * The current page of an endpoint of the API - * @var int - */ - protected $page = null; - - /** - * The current pagesize of an endpoint of the API - * @var int - */ - protected $pagesize = null; - - /** - * The ID of the logged in user - * @var [type] - */ - protected $userIdLoggedIn; - - /** - * The JSON response in an object format - * @var stdClass - */ - protected $json; - - /** - * Parameters that will be added when replacing inputs - * @var array - */ - protected $addArray = []; - - /** - * Number of ressources to create - * @var integer - */ - protected $nbRessources = 3; - - /** - * Describes relations embedded - * @var array - */ - protected $embedsRelation = []; - - /** - * The content that we are dealing with - * @var string - */ - protected $contentType; - - /** - * Attributes that should be here - * @var array - */ - protected $requiredAttributes; - - public function assertResponseIsNotFound() - { - $this->assertStatusCodeIs(Response::HTTP_NOT_FOUND); - $this->assertObjectHasAttribute('status', $this->json); - $this->assertObjectHasAttribute('error', $this->json); - - return $this; - } - - private function assertObjectHasAttribute($attribute, $object) - { - $this->assertTrue(property_exists($object, $attribute)); - } - - private function assertObjectNotHasAttribute($attribute, $object) - { - $this->assertFalse(property_exists($object, $attribute)); - } - - public function generateString($length) - { - if ($length == 0) - return ''; - - return str_random($length); - } - - public function logUserWithId($id) - { - $this->userIdLoggedIn = $id; - Auth::loginUsingId($id); - - return Auth::user(); - } - - public function assertStatusCodeIs($code) - { - $this->assertEquals($code, $this->response->getStatusCode()); - - return $this; - } - - private function assertResponseHasAttributes($array) - { - $this->assertObjectHasAttributes($this->json, $array); - } - - public function assertResponseHasRequiredAttributes() - { - $this->assertObjectHasAttributes($this->json, $this->requiredAttributes); - } - - public function assertObjectHasRequiredAttributes($object) - { - return $this->assertObjectHasAttributes($object, $this->requiredAttributes); - } - - private function assertObjectHasAttributes($object, $array) - { - foreach ($array as $value) - { - $this->assertObjectHasAttribute($value, $object); - if (Str::contains($value, '_id')) - $this->assertTrue(is_integer($object->$value)); - } - } - - public function tryPaginatedContentNotFound($method = 'index', $params = null) - { - $data = [ - 'page' => $this->getIdNonExistingRessource(), - 'pagesize' => $this->nbRessources - ]; - - $this->addInputReplace($data); - - $this->doRequest($method, $params); - - $this->assertResponseIsNotFound(); - - return $this; - } - - public function withStatusMessage($status) - { - $this->assertResponseKeyIs('status', $status); - - return $this; - } - - public function withSuccessMessage($status) - { - $this->assertResponseKeyIs('success', $status); - - return $this; - } - - public function withErrorMessage($error) - { - $this->assertResponseKeyIs('error', $error); - - return $this; - } - - public function tryStore($method = 'store', $requestParams = null) - { - $this->doRequest($method, $requestParams); - - return $this; - } - - public function bindJson($content) - { - $this->json = json_decode($content); - } + $this->assertResponseIsNotFound(); + + return $this; + } + + public function withStatusMessage($status) + { + $this->assertResponseKeyIs('status', $status); - public function doRequest($method, $params = null) - { - Input::replace($this->addArray); + return $this; + } - if (is_null($params)) - $this->response = $this->controller->$method(); - else - $this->response = call_user_func_array([$this->controller, $method], (array) $params); + public function withSuccessMessage($status) + { + $this->assertResponseKeyIs('success', $status); - $this->bindJson($this->response->getContent()); + return $this; + } - // Delete overriden request parameters - // when the request has been made - $this->addArray = []; + public function withErrorMessage($error) + { + $this->assertResponseKeyIs('error', $error); - return $this; - } + return $this; + } - public function getIdNonExistingRessource() - { - return $this->nbRessources + 1; - } + public function tryStore($method = 'store', $requestParams = null) + { + $this->doRequest($method, $requestParams); + + return $this; + } + + public function bindJson($content) + { + $this->json = json_decode($content); + } + + public function doRequest($method, $params = null) + { + Input::replace($this->addArray); - public function tryShowNotFound() - { - $this->response = $this->controller->show($this->getIdNonExistingRessource()); - $this->bindJson($this->response->getContent()); + if (is_null($params)) { + $this->response = $this->controller->$method(); + } else { + $this->response = call_user_func_array([$this->controller, $method], (array) $params); + } - $this->assertResponseIsNotFound(); + $this->bindJson($this->response->getContent()); - return $this; - } + // Delete overriden request parameters + // when the request has been made + $this->addArray = []; - public function assertBelongsToLoggedInUser() - { - $this->assertEquals($this->json->user_id, $this->userIdLoggedIn); + return $this; + } - return $this; - } + public function getIdNonExistingRessource() + { + return $this->nbRessources + 1; + } - public function tryShowFound($id) - { - $this->doRequest('show', $id); - $this->bindJson($this->response->getContent()); + public function tryShowNotFound() + { + $this->response = $this->controller->show($this->getIdNonExistingRessource()); + $this->bindJson($this->response->getContent()); - $this->assertStatusCodeIs(Response::HTTP_OK); + $this->assertResponseIsNotFound(); - $this->assertObjectMatchesExpectedSchema($this->json); - } + return $this; + } - public function tryFirstPage($method = 'index', $requestParams = null) - { - $this->page = 1; - $this->pagesize = $this->nbRessources; + public function assertBelongsToLoggedInUser() + { + $this->assertEquals($this->json->user_id, $this->userIdLoggedIn); + + return $this; + } - $this->replacePagesInput(); + public function tryShowFound($id) + { + $this->doRequest('show', $id); + $this->bindJson($this->response->getContent()); - $this->doRequest($method, $requestParams); + $this->assertStatusCodeIs(Response::HTTP_OK); - $this->assertIsPaginatedResponse(); + $this->assertObjectMatchesExpectedSchema($this->json); + } - $objectName = $this->contentType; - $objects = $this->json->$objectName; - for ($i = 0; $i < $this->nbRessources; $i++) - $this->assertObjectMatchesExpectedSchema($objects[$i]); + public function tryFirstPage($method = 'index', $requestParams = null) + { + $this->page = 1; + $this->pagesize = $this->nbRessources; - $this->assertNeighborsPagesMatch(); - } + $this->replacePagesInput(); - public function assertResponseMatchesExpectedSchema() - { - $this->assertObjectMatchesExpectedSchema($this->json); - } + $this->doRequest($method, $requestParams); - private function assertObjectMatchesExpectedSchema($object) - { - $this->assertObjectHasAttributes($object, $this->requiredAttributes); + $this->assertIsPaginatedResponse(); - if ($this->embedsSmallUser()) - $this->assertObjectContainsSmallUser($object); - if ($this->embedsQuote()) - $this->assertObjectContainsQuote($object); - if ($this->embedsCountry()) - $this->assertObjectContainsCountry($object); - if ($this->embedsNewsletters()) - $this->assertObjectContainsNewsletters($object); - } - - public function tryMiddlePage($method = 'index', $requestParams = null) - { - $this->page = max(2, ($this->nbRessources / 2)); - $this->pagesize = 1; - - $this->replacePagesInput(); - - $this->doRequest($method, $requestParams); - - $this->assertIsPaginatedResponse(); - $this->assertHasNextAndPreviousPage(); - - $objectName = $this->contentType; - $objects = $this->json->$objectName; - - $this->assertObjectMatchesExpectedSchema(reset($objects)); - - $this->assertNeighborsPagesMatch(); - } - - public function addInputReplace($addArray) - { - foreach ($addArray as $key => $value) - $this->addArray[$key] = $value; - } - - private function replacePagesInput() - { - $this->addInputReplace([ - 'page' => $this->page, - 'pagesize' => $this->pagesize, - ]); - } - - private function assertObjectContainsSmallUser($object) - { - return $this->assertObjectIsSmallUser($object->user); - } - - private function assertObjectContainsQuote($object) - { - return $this->assertObjectIsQuote($object->quote); - } - - private function assertObjectContainsCountry($object) - { - return $this->assertObjectIsCountry($object->country_object); - } - - private function assertObjectContainsNewsletters($object) - { - $newsletters = $object->newsletters; - - // Check the format for each newsletter - foreach ($newsletters as $o) - { - $this->assertObjectIsNewsletter($o); - } - } - - public function assertResponseKeyIs($key, $value) - { - $this->assertEquals($this->json->$key, $value); - } - - public function setContentType($value) - { - $this->contentType = $value; - } - - public function setController($value) - { - $this->controller = $value; - } - - public function setResponse($value) - { - $this->response = $value; - } - - public function setEmbedsRelation(array $value) - { - $this->embedsRelation = $value; - } - - public function setRequiredAttributes($value) - { - $this->requiredAttributes = $value; - } - - public function getNbRessources() - { - return $this->nbRessources; - } - - public function getController() - { - return $this->controller; - } - - public function getResponse() - { - return $this->response; - } - - public function getDecodedJson() - { - return $this->json; - } - - private function assertNeighborsPagesMatch() - { - $this->checkPagesAreSet(); - - $nextPage = $this->page + 1; - $previousPage = $this->page - 1; - - if ($nextPage < $this->computeTotalPages()) - $this->assertTrue(Str::contains($this->json->next_page, 'page='.$nextPage.'&pagesize='.$this->pagesize)); - if ($previousPage >= 1 AND $this->computeTotalPages() > 1) - $this->assertTrue(Str::contains($this->json->previous_page, 'page='.$previousPage.'&pagesize='.$this->pagesize)); - } - - private function assertObjectIsSmallUser($object) - { - // Assert attributes - $this->assertObjectHasAttribute('id', $object); - $this->assertObjectHasAttribute('is_admin', $object); - $this->assertObjectHasAttribute('login', $object); - $this->assertObjectHasAttribute('profile_hidden', $object); - $this->assertObjectHasAttribute('url_avatar', $object); - $this->assertObjectHasAttribute('wants_notification_comment_quote', $object); - - // Assert types - $this->assertTrue(is_integer($object->id)); - $this->assertTrue(is_bool($object->is_admin)); - $this->assertTrue(is_bool($object->profile_hidden)); - $this->assertTrue(is_bool($object->wants_notification_comment_quote)); - $this->assertTrue(Str::startsWith($object->url_avatar, 'http')); - } - - private function assertObjectIsQuote($object) - { - // Assert attributes - $this->assertObjectHasAttribute('id', $object); - $this->assertObjectHasAttribute('content', $object); - $this->assertObjectHasAttribute('user_id', $object); - $this->assertObjectHasAttribute('approved', $object); - $this->assertObjectHasAttribute('created_at', $object); - $this->assertObjectHasAttribute('has_comments', $object); - $this->assertObjectHasAttribute('total_comments', $object); - $this->assertObjectHasAttribute('is_favorite', $object); - $this->assertObjectHasAttribute('total_favorites', $object); - $this->assertObjectHasAttribute('tags_list', $object); - - // Assert types - $this->assertTrue(is_integer($object->id)); - $this->assertTrue(is_string($object->content)); - $this->assertTrue(is_integer($object->user_id)); - $this->assertTrue(is_integer($object->approved)); - $this->assertTrue(is_string($object->created_at)); - $this->assertTrue(is_bool($object->has_comments)); - $this->assertTrue(is_integer($object->total_comments)); - $this->assertTrue(is_bool($object->is_favorite)); - $this->assertTrue(is_integer($object->total_favorites)); - $this->assertTrue(is_array($object->tags_list)); - } - - private function assertObjectIsCountry($object) - { - // Assert attributes - $this->assertObjectHasAttribute('id', $object); - $this->assertObjectHasAttribute('name', $object); - $this->assertObjectHasAttribute('country_code', $object); - - // Assert types - $this->assertTrue(is_integer($object->id)); - $this->assertTrue(is_string($object->name)); - $this->assertTrue(is_string($object->country_code)); - } - - private function assertObjectIsNewsletter($object) - { - // Assert attributes - $this->assertObjectHasAttribute('user_id', $object); - $this->assertObjectHasAttribute('type', $object); - $this->assertObjectHasAttribute('created_at', $object); - - // Assert types - $this->assertTrue(is_integer($object->user_id)); - $this->assertTrue(is_string($object->type)); - $this->assertTrue(in_array($object->type, ['weekly', 'daily'])); - $this->assertTrue(is_string($object->created_at)); - } - - private function assertIsPaginatedResponse() - { - $this->checkPagesAreSet(); - - // Assert attributes - $attributeName = 'total_'.$this->contentType; - $this->assertObjectHasAttribute($attributeName, $this->json); - $this->assertObjectHasAttribute('total_pages', $this->json); - $this->assertObjectHasAttribute('page', $this->json); - $this->assertObjectHasAttribute('pagesize', $this->json); - $this->assertObjectHasAttribute('url', $this->json); - $this->assertObjectHasAttribute('has_next_page', $this->json); - $this->assertObjectHasAttribute('has_previous_page', $this->json); - - if ($this->json->has_next_page) - $this->assertObjectHasAttribute('next_page', $this->json); - - if ($this->json->has_previous_page) - $this->assertObjectHasAttribute('previous_page', $this->json); - - // Assert types - $this->assertTrue(is_integer($this->json->$attributeName)); - $this->assertTrue(is_integer($this->json->total_pages)); - $this->assertTrue(is_integer($this->json->page)); - $this->assertTrue(is_integer($this->json->pagesize)); - $this->assertTrue(is_bool($this->json->has_next_page)); - $this->assertTrue(is_bool($this->json->has_previous_page)); - - // Assert values - $this->assertEquals($this->page, $this->json->page); - $this->assertEquals($this->pagesize, $this->json->pagesize); - $this->assertEquals($this->nbRessources, $this->json->$attributeName); - $this->assertEquals($this->computeTotalPages(), $this->json->total_pages); - - // Check URL format - if ($this->json->has_next_page) - $this->assertTrue(Str::startsWith($this->json->next_page, 'http')); - else - $this->assertObjectNotHasAttribute('next_page', $this->json); - - if ($this->json->has_previous_page) - $this->assertTrue(Str::startsWith($this->json->previous_page, 'http')); - else - $this->assertObjectNotHasAttribute('previous_page', $this->json); - } - - private function computeTotalPages() - { - return ceil($this->nbRessources / $this->pagesize); - } - - private function checkPagesAreSet() - { - if (is_null($this->page) OR is_null($this->pagesize)) - throw new InvalidArgumentException("Page and pagesize must be set before calling this method", 1); - } - - private function assertHasNextAndPreviousPage() - { - $this->assertTrue($this->json->has_next_page); - $this->assertTrue($this->json->has_previous_page); - } - - private function assertHasNextPage() - { - $this->assertTrue($this->json->has_next_page); - $this->assertFalse($this->json->has_previous_page); - } - - private function assertHasPreviousPage() - { - $this->assertFalse($this->json->has_next_page); - $this->assertTrue($this->json->has_previous_page); - } - - private function embedsSmallUser() - { - return in_array('small_user', $this->embedsRelation); - } - - private function embedsQuote() - { - return in_array('quote', $this->embedsRelation); - } - - private function embedsCountry() - { - return in_array('country', $this->embedsRelation); - } - - private function embedsNewsletters() - { - return in_array('newsletters', $this->embedsRelation); - } - - private function assertResponseHasSmallUser() - { - $this->assertObjectHasAttribute('user', $this->json); - $this->assertObjectIsSmallUser($this->json->user); - } -} \ No newline at end of file + $objectName = $this->contentType; + $objects = $this->json->$objectName; + for ($i = 0; $i < $this->nbRessources; $i++) { + $this->assertObjectMatchesExpectedSchema($objects[$i]); + } + + $this->assertNeighborsPagesMatch(); + } + + public function assertResponseMatchesExpectedSchema() + { + $this->assertObjectMatchesExpectedSchema($this->json); + } + + private function assertObjectMatchesExpectedSchema($object) + { + $this->assertObjectHasAttributes($object, $this->requiredAttributes); + + if ($this->embedsSmallUser()) { + $this->assertObjectContainsSmallUser($object); + } + if ($this->embedsQuote()) { + $this->assertObjectContainsQuote($object); + } + if ($this->embedsCountry()) { + $this->assertObjectContainsCountry($object); + } + if ($this->embedsNewsletters()) { + $this->assertObjectContainsNewsletters($object); + } + } + + public function tryMiddlePage($method = 'index', $requestParams = null) + { + $this->page = max(2, ($this->nbRessources / 2)); + $this->pagesize = 1; + + $this->replacePagesInput(); + + $this->doRequest($method, $requestParams); + + $this->assertIsPaginatedResponse(); + $this->assertHasNextAndPreviousPage(); + + $objectName = $this->contentType; + $objects = $this->json->$objectName; + + $this->assertObjectMatchesExpectedSchema(reset($objects)); + + $this->assertNeighborsPagesMatch(); + } + + public function addInputReplace($addArray) + { + foreach ($addArray as $key => $value) { + $this->addArray[$key] = $value; + } + } + + private function replacePagesInput() + { + $this->addInputReplace([ + 'page' => $this->page, + 'pagesize' => $this->pagesize, + ]); + } + + private function assertObjectContainsSmallUser($object) + { + return $this->assertObjectIsSmallUser($object->user); + } + + private function assertObjectContainsQuote($object) + { + return $this->assertObjectIsQuote($object->quote); + } + + private function assertObjectContainsCountry($object) + { + return $this->assertObjectIsCountry($object->country_object); + } + + private function assertObjectContainsNewsletters($object) + { + $newsletters = $object->newsletters; + + // Check the format for each newsletter + foreach ($newsletters as $o) { + $this->assertObjectIsNewsletter($o); + } + } + + public function assertResponseKeyIs($key, $value) + { + $this->assertEquals($this->json->$key, $value); + } + + public function setContentType($value) + { + $this->contentType = $value; + } + + public function setController($value) + { + $this->controller = $value; + } + + public function setResponse($value) + { + $this->response = $value; + } + + public function setEmbedsRelation(array $value) + { + $this->embedsRelation = $value; + } + + public function setRequiredAttributes($value) + { + $this->requiredAttributes = $value; + } + + public function getNbRessources() + { + return $this->nbRessources; + } + + public function getController() + { + return $this->controller; + } + + public function getResponse() + { + return $this->response; + } + + public function getDecodedJson() + { + return $this->json; + } + + private function assertNeighborsPagesMatch() + { + $this->checkPagesAreSet(); + + $nextPage = $this->page + 1; + $previousPage = $this->page - 1; + + if ($nextPage < $this->computeTotalPages()) { + $this->assertTrue(Str::contains($this->json->next_page, 'page='.$nextPage.'&pagesize='.$this->pagesize)); + } + if ($previousPage >= 1 and $this->computeTotalPages() > 1) { + $this->assertTrue(Str::contains($this->json->previous_page, 'page='.$previousPage.'&pagesize='.$this->pagesize)); + } + } + + private function assertObjectIsSmallUser($object) + { + // Assert attributes + $this->assertObjectHasAttribute('id', $object); + $this->assertObjectHasAttribute('is_admin', $object); + $this->assertObjectHasAttribute('login', $object); + $this->assertObjectHasAttribute('profile_hidden', $object); + $this->assertObjectHasAttribute('url_avatar', $object); + $this->assertObjectHasAttribute('wants_notification_comment_quote', $object); + + // Assert types + $this->assertTrue(is_integer($object->id)); + $this->assertTrue(is_bool($object->is_admin)); + $this->assertTrue(is_bool($object->profile_hidden)); + $this->assertTrue(is_bool($object->wants_notification_comment_quote)); + $this->assertTrue(Str::startsWith($object->url_avatar, 'http')); + } + + private function assertObjectIsQuote($object) + { + // Assert attributes + $this->assertObjectHasAttribute('id', $object); + $this->assertObjectHasAttribute('content', $object); + $this->assertObjectHasAttribute('user_id', $object); + $this->assertObjectHasAttribute('approved', $object); + $this->assertObjectHasAttribute('created_at', $object); + $this->assertObjectHasAttribute('has_comments', $object); + $this->assertObjectHasAttribute('total_comments', $object); + $this->assertObjectHasAttribute('is_favorite', $object); + $this->assertObjectHasAttribute('total_favorites', $object); + $this->assertObjectHasAttribute('tags_list', $object); + + // Assert types + $this->assertTrue(is_integer($object->id)); + $this->assertTrue(is_string($object->content)); + $this->assertTrue(is_integer($object->user_id)); + $this->assertTrue(is_integer($object->approved)); + $this->assertTrue(is_string($object->created_at)); + $this->assertTrue(is_bool($object->has_comments)); + $this->assertTrue(is_integer($object->total_comments)); + $this->assertTrue(is_bool($object->is_favorite)); + $this->assertTrue(is_integer($object->total_favorites)); + $this->assertTrue(is_array($object->tags_list)); + } + + private function assertObjectIsCountry($object) + { + // Assert attributes + $this->assertObjectHasAttribute('id', $object); + $this->assertObjectHasAttribute('name', $object); + $this->assertObjectHasAttribute('country_code', $object); + + // Assert types + $this->assertTrue(is_integer($object->id)); + $this->assertTrue(is_string($object->name)); + $this->assertTrue(is_string($object->country_code)); + } + + private function assertObjectIsNewsletter($object) + { + // Assert attributes + $this->assertObjectHasAttribute('user_id', $object); + $this->assertObjectHasAttribute('type', $object); + $this->assertObjectHasAttribute('created_at', $object); + + // Assert types + $this->assertTrue(is_integer($object->user_id)); + $this->assertTrue(is_string($object->type)); + $this->assertTrue(in_array($object->type, ['weekly', 'daily'])); + $this->assertTrue(is_string($object->created_at)); + } + + private function assertIsPaginatedResponse() + { + $this->checkPagesAreSet(); + + // Assert attributes + $attributeName = 'total_'.$this->contentType; + $this->assertObjectHasAttribute($attributeName, $this->json); + $this->assertObjectHasAttribute('total_pages', $this->json); + $this->assertObjectHasAttribute('page', $this->json); + $this->assertObjectHasAttribute('pagesize', $this->json); + $this->assertObjectHasAttribute('url', $this->json); + $this->assertObjectHasAttribute('has_next_page', $this->json); + $this->assertObjectHasAttribute('has_previous_page', $this->json); + + if ($this->json->has_next_page) { + $this->assertObjectHasAttribute('next_page', $this->json); + } + + if ($this->json->has_previous_page) { + $this->assertObjectHasAttribute('previous_page', $this->json); + } + + // Assert types + $this->assertTrue(is_integer($this->json->$attributeName)); + $this->assertTrue(is_integer($this->json->total_pages)); + $this->assertTrue(is_integer($this->json->page)); + $this->assertTrue(is_integer($this->json->pagesize)); + $this->assertTrue(is_bool($this->json->has_next_page)); + $this->assertTrue(is_bool($this->json->has_previous_page)); + + // Assert values + $this->assertEquals($this->page, $this->json->page); + $this->assertEquals($this->pagesize, $this->json->pagesize); + $this->assertEquals($this->nbRessources, $this->json->$attributeName); + $this->assertEquals($this->computeTotalPages(), $this->json->total_pages); + + // Check URL format + if ($this->json->has_next_page) { + $this->assertTrue(Str::startsWith($this->json->next_page, 'http')); + } else { + $this->assertObjectNotHasAttribute('next_page', $this->json); + } + + if ($this->json->has_previous_page) { + $this->assertTrue(Str::startsWith($this->json->previous_page, 'http')); + } else { + $this->assertObjectNotHasAttribute('previous_page', $this->json); + } + } + + private function computeTotalPages() + { + return ceil($this->nbRessources / $this->pagesize); + } + + private function checkPagesAreSet() + { + if (is_null($this->page) or is_null($this->pagesize)) { + throw new InvalidArgumentException('Page and pagesize must be set before calling this method', 1); + } + } + + private function assertHasNextAndPreviousPage() + { + $this->assertTrue($this->json->has_next_page); + $this->assertTrue($this->json->has_previous_page); + } + + private function assertHasNextPage() + { + $this->assertTrue($this->json->has_next_page); + $this->assertFalse($this->json->has_previous_page); + } + + private function assertHasPreviousPage() + { + $this->assertFalse($this->json->has_next_page); + $this->assertTrue($this->json->has_previous_page); + } + + private function embedsSmallUser() + { + return in_array('small_user', $this->embedsRelation); + } + + private function embedsQuote() + { + return in_array('quote', $this->embedsRelation); + } + + private function embedsCountry() + { + return in_array('country', $this->embedsRelation); + } + + private function embedsNewsletters() + { + return in_array('newsletters', $this->embedsRelation); + } + + private function assertResponseHasSmallUser() + { + $this->assertObjectHasAttribute('user', $this->json); + $this->assertObjectIsSmallUser($this->json->user); + } +} diff --git a/tests/_support/AuthHelper.php b/tests/_support/AuthHelper.php index ca63acff..88f8b54b 100644 --- a/tests/_support/AuthHelper.php +++ b/tests/_support/AuthHelper.php @@ -1,40 +1,44 @@ -getModule('DbSeederHelper')->haveAnAccount(compact('login', 'password')); - - $this->getModule('NavigationHelper')->navigateToTheSignInPage(); - $this->getModule('FormFillerHelper')->fillSigninForm($login, $passwordClear); - } - - public function checkThatIHaveBeenLoggedIn() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('home'); - $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('Nice to see you :)'); - $I->see('My profile', '.navbar'); - $I->assertTrue(Auth::check()); - } - - public function performLogoutFlow() - { - $I = $this->getModule('Laravel4'); - - $this->getModule('NavigationHelper')->navigateToMyProfile(); - $I->click('Log out'); - } -} \ No newline at end of file +class AuthHelper extends Module +{ + /** + * Fill the sign in form and log in. + * + * @param string $login + * @param string $passwordClear + */ + public function signIn($login, $passwordClear) + { + // Will be automatically hashed + $password = $passwordClear; + + $this->getModule('DbSeederHelper')->haveAnAccount(compact('login', 'password')); + + $this->getModule('NavigationHelper')->navigateToTheSignInPage(); + $this->getModule('FormFillerHelper')->fillSigninForm($login, $passwordClear); + } + + public function checkThatIHaveBeenLoggedIn() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('home'); + $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('Nice to see you :)'); + $I->see('My profile', '.navbar'); + $I->assertTrue(Auth::check()); + } + + public function performLogoutFlow() + { + $I = $this->getModule('Laravel4'); + + $this->getModule('NavigationHelper')->navigateToMyProfile(); + $I->click('Log out'); + } +} diff --git a/tests/_support/DbSeederHelper.php b/tests/_support/DbSeederHelper.php index 3386e426..244fbc98 100644 --- a/tests/_support/DbSeederHelper.php +++ b/tests/_support/DbSeederHelper.php @@ -1,4 +1,6 @@ -insertInDatabase(1, 'User', $overrides); - } + /** + * Create a new user and store it in database. Can pass an array (key-value) to override dummy values. + * + * @param array $overrides The key-value array used to override dummy values + * + * @return \TeenQuotes\Users\Models\User The created user instance + */ + public function haveAnAccount($overrides = []) + { + return $this->insertInDatabase(1, 'User', $overrides); + } - /** - * Log a new user. Can pass an array (key-value) to override dummy values - * @param array $overrides The key-value array used to override dummy values - * @return \TeenQuotes\Users\Models\User The logged in user - */ - public function logANewUser($overrides = []) - { - $u = $this->haveAnAccount($overrides); + /** + * Log a new user. Can pass an array (key-value) to override dummy values. + * + * @param array $overrides The key-value array used to override dummy values + * + * @return \TeenQuotes\Users\Models\User The logged in user + */ + public function logANewUser($overrides = []) + { + $u = $this->haveAnAccount($overrides); - Auth::loginUsingId($u->id); + Auth::loginUsingId($u->id); - return $u; - } + return $u; + } - /** - * Insert a record in database - * @param int $times The number of elements to insert - * @param string $class The name of the class to insert - * @param array $overrides The key-value array used to override dummy values - * @return array|object The created record(s) - */ - public function insertInDatabase($times, $class, $overrides = []) - { - return TestDummy::times($times)->create($this->classToFullNamespace($class), $overrides); - } + /** + * Insert a record in database. + * + * @param int $times The number of elements to insert + * @param string $class The name of the class to insert + * @param array $overrides The key-value array used to override dummy values + * + * @return array|object The created record(s) + */ + public function insertInDatabase($times, $class, $overrides = []) + { + return TestDummy::times($times)->create($this->classToFullNamespace($class), $overrides); + } - /** - * Resolve a class name to its full namespace - * @param string $class - * @return string - */ - private function classToFullNamespace($class) - { - // "Nice behaviour" classes - if ($this->isNiceBehaviourClass($class)) - { - $plural = ucfirst(strtolower(Str::plural($class))); + /** + * Resolve a class name to its full namespace. + * + * @param string $class + * + * @return string + */ + private function classToFullNamespace($class) + { + // "Nice behaviour" classes + if ($this->isNiceBehaviourClass($class)) { + $plural = ucfirst(strtolower(Str::plural($class))); - return 'TeenQuotes\\'.$plural.'\\Models\\'.ucfirst(strtolower($class)); - } + return 'TeenQuotes\\'.$plural.'\\Models\\'.ucfirst(strtolower($class)); + } - // Other classes - switch ($class) - { - case 'FavoriteQuote': - return 'TeenQuotes\\Quotes\\Models\\FavoriteQuote'; - } + // Other classes + switch ($class) { + case 'FavoriteQuote': + return 'TeenQuotes\\Quotes\\Models\\FavoriteQuote'; + } - // We haven't be able to resolve this class - throw new InvalidArgumentException("Can't resolve the full namespace for the given class name: ".$class); - } + // We haven't be able to resolve this class + throw new InvalidArgumentException("Can't resolve the full namespace for the given class name: ".$class); + } - /** - * Tell if a class behaves nicely - * @param string $name The name of the class, without a namespace - * @return boolean - */ - private function isNiceBehaviourClass($name) - { - $niceClasses = [ - 'comment', - 'country', - 'newsletter', - 'quote', - 'setting', - 'story', - 'tag', - 'user', - ]; + /** + * Tell if a class behaves nicely. + * + * @param string $name The name of the class, without a namespace + * + * @return bool + */ + private function isNiceBehaviourClass($name) + { + $niceClasses = [ + 'comment', + 'country', + 'newsletter', + 'quote', + 'setting', + 'story', + 'tag', + 'user', + ]; - return in_array(strtolower($name), $niceClasses); - } -} \ No newline at end of file + return in_array(strtolower($name), $niceClasses); + } +} diff --git a/tests/_support/FormFillerHelper.php b/tests/_support/FormFillerHelper.php index a2a579d1..e8e2e559 100644 --- a/tests/_support/FormFillerHelper.php +++ b/tests/_support/FormFillerHelper.php @@ -1,167 +1,176 @@ -getModule('Laravel4'); - - $I->fillField('Login', $login); - $I->fillField('Password', $password); - $I->click('Log me in!', 'form'); - } - - public function fillEditCommentForm($text) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('#content-comment', $text); - $I->click('Edit my comment!'); - } - - public function fillAddQuoteForm() - { - $I = $this->getModule('Laravel4'); - - $I->fillField('#content-quote', Str::random(150)); - $I->click('Submit my quote!'); - } - - public function fillAddCommentForm($text) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('#content-comment', $text); - $I->click('Add my comment!'); - } - - public function fillSearchForm($search) - { - $I = $this->getModule('Laravel4'); - - $I->seeCurrentRouteIs('search.form'); - $I->fillField("#search", $search); - $I->click('Look for this!'); - } - - public function fillStoryForm($represent, $frequence) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('#represent_txt', $represent); - $I->fillField('#frequence_txt', $frequence); - $I->click('Add my story!'); - } - - /** - * Fill the edit profile form with the given key-value pairs - * @param array $params The key-values pairs. Required keys: gender, birthdate (YYYY-MM-DD), country_name, city, about_me. Optional: avatar (filename) - */ - public function fillEditProfileFormWith(array $params) - { - $I = $this->getModule('Laravel4'); - - $I->selectOption('input[name=gender]', $params['gender']); - $I->fillField('Birthdate', $params['birthdate']); - $I->selectOption('select[name=country]', $params['country_name']); - $I->fillField('City', $params['city']); - $I->fillField('About me', $params['about_me']); - - // If an avatar was given, attach it to the form - if (array_key_exists('avatar', $params)) - $I->attachFile('input#avatar', $params['avatar']); - - $I->click('Edit my profile!'); - } - - /** - * Fill the password reset form for a given user - * @param User $u The given user - */ - public function fillPasswordResetFormFor(User $u) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('#email', $u->email); - $I->click('Reset my password!'); - } - - /** - * Fill the delete account form - * @param string $password The clear password - * @param string $confirmation The confirmation word - */ - public function fillDeleteAccountForm($password, $confirmation) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('#delete-account #password', $password); - $I->fillField('#delete-confirmation', $confirmation); - $I->click('Delete my account'); - } - - public function fillRegistrationFormFor($login) - { - $I = $this->getModule('Laravel4'); - - // Set a dummy IP address - $_SERVER['REMOTE_ADDR'] = '200.22.22.22'; - - $I->seeInTitle('Create an account'); - $I->see('Create your account'); - $I->fillField('#login-signup', $login); - $I->fillField('#email-signup', $login.'@yahoo.com'); - $I->fillField('#password', 'azerty22'); - $I->click("#submit-form"); - } - - /** - * Fill the "update my password" form on the user's profile - * @param string $password The new password - * @param string $passwordRepeat The new repeated password - */ - public function fillChangePasswordForm($password, $passwordRepeat) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('New password', $password); - $I->fillField('Confirm your password', $passwordRepeat); - $I->click('Change my password!'); - } - - /** - * Fill and submit the form to set the new content of a quote waiting to be moderated - * @param string $content The new content - */ - public function fillNewContentWaitingQuoteForm($content) - { - $I = $this->getModule('Laravel4'); - - $I->fillField('Content of the quote', $content); - $I->click('Edit this quote!'); - } - - public function fillUserSettingsForm(array $params) - { - $I = $this->getModule('Laravel4'); - - $I->selectOption('select[name=colors]', $params['color']); - - foreach (['notification_comment_quote', 'hide_profile', 'daily_newsletter', 'weekly_newsletter'] as $value) { - if ($params[$value] == 1) - $I->checkOption('input[name='.$value.']'); - else - $I->uncheckOption('input[name='.$value.']'); - } - - // Submit the form - $I->click('Edit my settings!'); - $I->seeCurrentRouteIs('users.edit', Auth::user()->login); - $I->see('Your settings have been changed'); - } -} \ No newline at end of file +class FormFillerHelper extends Module +{ + public function fillSigninForm($login, $password) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('Login', $login); + $I->fillField('Password', $password); + $I->click('Log me in!', 'form'); + } + + public function fillEditCommentForm($text) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('#content-comment', $text); + $I->click('Edit my comment!'); + } + + public function fillAddQuoteForm() + { + $I = $this->getModule('Laravel4'); + + $I->fillField('#content-quote', Str::random(150)); + $I->click('Submit my quote!'); + } + + public function fillAddCommentForm($text) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('#content-comment', $text); + $I->click('Add my comment!'); + } + + public function fillSearchForm($search) + { + $I = $this->getModule('Laravel4'); + + $I->seeCurrentRouteIs('search.form'); + $I->fillField('#search', $search); + $I->click('Look for this!'); + } + + public function fillStoryForm($represent, $frequence) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('#represent_txt', $represent); + $I->fillField('#frequence_txt', $frequence); + $I->click('Add my story!'); + } + + /** + * Fill the edit profile form with the given key-value pairs. + * + * @param array $params The key-values pairs. Required keys: gender, birthdate (YYYY-MM-DD), country_name, city, about_me. Optional: avatar (filename) + */ + public function fillEditProfileFormWith(array $params) + { + $I = $this->getModule('Laravel4'); + + $I->selectOption('input[name=gender]', $params['gender']); + $I->fillField('Birthdate', $params['birthdate']); + $I->selectOption('select[name=country]', $params['country_name']); + $I->fillField('City', $params['city']); + $I->fillField('About me', $params['about_me']); + + // If an avatar was given, attach it to the form + if (array_key_exists('avatar', $params)) { + $I->attachFile('input#avatar', $params['avatar']); + } + + $I->click('Edit my profile!'); + } + + /** + * Fill the password reset form for a given user. + * + * @param User $u The given user + */ + public function fillPasswordResetFormFor(User $u) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('#email', $u->email); + $I->click('Reset my password!'); + } + + /** + * Fill the delete account form. + * + * @param string $password The clear password + * @param string $confirmation The confirmation word + */ + public function fillDeleteAccountForm($password, $confirmation) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('#delete-account #password', $password); + $I->fillField('#delete-confirmation', $confirmation); + $I->click('Delete my account'); + } + + public function fillRegistrationFormFor($login) + { + $I = $this->getModule('Laravel4'); + + // Set a dummy IP address + $_SERVER['REMOTE_ADDR'] = '200.22.22.22'; + + $I->seeInTitle('Create an account'); + $I->see('Create your account'); + $I->fillField('#login-signup', $login); + $I->fillField('#email-signup', $login.'@yahoo.com'); + $I->fillField('#password', 'azerty22'); + $I->click('#submit-form'); + } + + /** + * Fill the "update my password" form on the user's profile. + * + * @param string $password The new password + * @param string $passwordRepeat The new repeated password + */ + public function fillChangePasswordForm($password, $passwordRepeat) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('New password', $password); + $I->fillField('Confirm your password', $passwordRepeat); + $I->click('Change my password!'); + } + + /** + * Fill and submit the form to set the new content of a quote waiting to be moderated. + * + * @param string $content The new content + */ + public function fillNewContentWaitingQuoteForm($content) + { + $I = $this->getModule('Laravel4'); + + $I->fillField('Content of the quote', $content); + $I->click('Edit this quote!'); + } + + public function fillUserSettingsForm(array $params) + { + $I = $this->getModule('Laravel4'); + + $I->selectOption('select[name=colors]', $params['color']); + + foreach (['notification_comment_quote', 'hide_profile', 'daily_newsletter', 'weekly_newsletter'] as $value) { + if ($params[$value] == 1) { + $I->checkOption('input[name='.$value.']'); + } else { + $I->uncheckOption('input[name='.$value.']'); + } + } + + // Submit the form + $I->click('Edit my settings!'); + $I->seeCurrentRouteIs('users.edit', Auth::user()->login); + $I->see('Your settings have been changed'); + } +} diff --git a/tests/_support/FunctionalHelper.php b/tests/_support/FunctionalHelper.php index f1a146e4..58c8479a 100644 --- a/tests/_support/FunctionalHelper.php +++ b/tests/_support/FunctionalHelper.php @@ -1,77 +1,84 @@ -getModule('Laravel4'); - - $I->see($message, '.error-form'); - } + /** + * Assert that I can see an error message on a form. + * + * @param string $message The expected message + */ + public function seeFormError($message) + { + $I = $this->getModule('Laravel4'); + + $I->see($message, '.error-form'); + } + + /** + * Assert that we can see a success alert with a given message. + * + * @param string $message The expected message + */ + public function seeSuccessFlashMessage($message) + { + $I = $this->getModule('Laravel4'); + + $I->see($message, '.alert-success'); + } - /** - * Assert that we can see a success alert with a given message - * @param string $message The expected message - */ - public function seeSuccessFlashMessage($message) - { - $I = $this->getModule('Laravel4'); - - $I->see($message, '.alert-success'); - } + /** + * Create a new user. Can pass an array (key-value) to override dummy values. + * + * @param array $overrides The key-value array used to override dummy values + * + * @return TeenQuotes\Users\Models\User The created user instance + */ + public function buildUser($overrides = []) + { + return TestDummy::build($this->classToFullNamespace('User'), $overrides); + } - /** - * Create a new user. Can pass an array (key-value) to override dummy values - * @param array $overrides The key-value array used to override dummy values - * @return TeenQuotes\Users\Models\User The created user instance - */ - public function buildUser($overrides = []) - { - return TestDummy::build($this->classToFullNamespace('User'), $overrides); - } + public function sendAjaxDeleteRequest($uri, $params = []) + { + $this->getModule('Laravel4')->sendAjaxRequest('DELETE', $uri, $params); + } - public function sendAjaxDeleteRequest($uri, $params = []) - { - $this->getModule('Laravel4')->sendAjaxRequest('DELETE', $uri, $params); - } + public function sendAjaxPutRequest($uri, $params = []) + { + $this->getModule('Laravel4')->sendAjaxRequest('PUT', $uri, $params); + } - public function sendAjaxPutRequest($uri, $params = []) - { - $this->getModule('Laravel4')->sendAjaxRequest('PUT', $uri, $params); - } + /** + * Resolve a class name to its full namespace. + * + * @param string $class + * + * @return string + */ + private function classToFullNamespace($class) + { + // "Nice behaviour" classes + if (in_array(strtolower($class), ['comment', 'country', 'newsletter', 'quote', 'user', 'story'])) { + $plural = ucfirst(strtolower(Str::plural($class))); - /** - * Resolve a class name to its full namespace - * @param string $class - * @return string - */ - private function classToFullNamespace($class) - { - // "Nice behaviour" classes - if (in_array(strtolower($class), ['comment', 'country', 'newsletter', 'quote', 'user', 'story'])) { - $plural = ucfirst(strtolower(Str::plural($class))); - - return 'TeenQuotes\\'.$plural.'\\Models\\'.ucfirst(strtolower($class)); - } + return 'TeenQuotes\\'.$plural.'\\Models\\'.ucfirst(strtolower($class)); + } - // Other classes - switch ($class) { - case 'FavoriteQuote': - return 'TeenQuotes\\Quotes\\Models\\FavoriteQuote'; - } + // Other classes + switch ($class) { + case 'FavoriteQuote': + return 'TeenQuotes\\Quotes\\Models\\FavoriteQuote'; + } - // We haven't be able to resolve this class - throw new InvalidArgumentException("Can't resolve the full namespace for the given class name: ".$class); - } -} \ No newline at end of file + // We haven't be able to resolve this class + throw new InvalidArgumentException("Can't resolve the full namespace for the given class name: ".$class); + } +} diff --git a/tests/_support/IntegrationHelper.php b/tests/_support/IntegrationHelper.php index c1cfff2f..f0d4e771 100644 --- a/tests/_support/IntegrationHelper.php +++ b/tests/_support/IntegrationHelper.php @@ -1,13 +1,15 @@ -getModule('Asserts'); +class IntegrationHelper extends Module +{ + public function assertIsCollection($object) + { + $I = $this->getModule('Asserts'); - $I->assertTrue($object instanceof \Illuminate\Database\Eloquent\Collection); - } -} \ No newline at end of file + $I->assertTrue($object instanceof \Illuminate\Database\Eloquent\Collection); + } +} diff --git a/tests/_support/NavigationHelper.php b/tests/_support/NavigationHelper.php index c3ca6d9c..25b663b6 100644 --- a/tests/_support/NavigationHelper.php +++ b/tests/_support/NavigationHelper.php @@ -1,95 +1,97 @@ -getModule('Laravel4'); - - $I->assertTrue(Auth::check()); - $I->amOnRoute('home'); - $I->click('My profile', '.nav'); - } - - public function navigateToTheAdminPanel() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('admin.quotes.index'); - } - - public function navigateToTheSearchPage() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('home'); - $I->click('Search', '.nav'); - } - - public function navigateToTheStoryPage() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('home'); - $I->click('Stories', 'footer'); - } - - public function navigateToMyEditProfilePage() - { - $I = $this->getModule('Laravel4'); - $u = Auth::user(); - - $this->navigateToMyProfile(); - - $I->click('Edit my profile'); - - // Assert that we can do several actions - $I->seeCurrentRouteIs('users.edit', $u->login); - $I->seeInTitle('Edit your profile'); - $I->see('Edit my profile'); - $I->see('Change my password'); - $I->see('Edit my settings'); - $I->see('Delete my account'); - } - - public function navigateToTheResetPasswordPage() - { - $I = $this->getModule('Laravel4'); - - $this->navigateToTheSignInPage(); - $I->click("I don't remember my password!"); - $I->seeCurrentRouteIs('password.remind'); - } - - public function navigateToTheSignInPage() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('home'); - $I->click('Log in'); - $I->seeCurrentRouteIs('signin'); - } - - public function navigateToTheSignUpPage() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('home'); - $I->click('Log in'); - $I->seeCurrentRouteIs('signin'); - $I->click('I want an account!'); - $I->seeCurrentRouteIs('signup'); - } - - public function navigateToTheAddQuotePage() - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('home'); - $I->click('Add your quote'); - $I->seeCurrentRouteIs('addquote'); - } -} \ No newline at end of file +class NavigationHelper extends Module +{ + public function navigateToMyProfile() + { + $I = $this->getModule('Laravel4'); + + $I->assertTrue(Auth::check()); + $I->amOnRoute('home'); + $I->click('My profile', '.nav'); + } + + public function navigateToTheAdminPanel() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('admin.quotes.index'); + } + + public function navigateToTheSearchPage() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('home'); + $I->click('Search', '.nav'); + } + + public function navigateToTheStoryPage() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('home'); + $I->click('Stories', 'footer'); + } + + public function navigateToMyEditProfilePage() + { + $I = $this->getModule('Laravel4'); + $u = Auth::user(); + + $this->navigateToMyProfile(); + + $I->click('Edit my profile'); + + // Assert that we can do several actions + $I->seeCurrentRouteIs('users.edit', $u->login); + $I->seeInTitle('Edit your profile'); + $I->see('Edit my profile'); + $I->see('Change my password'); + $I->see('Edit my settings'); + $I->see('Delete my account'); + } + + public function navigateToTheResetPasswordPage() + { + $I = $this->getModule('Laravel4'); + + $this->navigateToTheSignInPage(); + $I->click("I don't remember my password!"); + $I->seeCurrentRouteIs('password.remind'); + } + + public function navigateToTheSignInPage() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('home'); + $I->click('Log in'); + $I->seeCurrentRouteIs('signin'); + } + + public function navigateToTheSignUpPage() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('home'); + $I->click('Log in'); + $I->seeCurrentRouteIs('signin'); + $I->click('I want an account!'); + $I->seeCurrentRouteIs('signup'); + } + + public function navigateToTheAddQuotePage() + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('home'); + $I->click('Add your quote'); + $I->seeCurrentRouteIs('addquote'); + } +} diff --git a/tests/_support/QuotesHelper.php b/tests/_support/QuotesHelper.php index bd46c303..5ce59a28 100644 --- a/tests/_support/QuotesHelper.php +++ b/tests/_support/QuotesHelper.php @@ -1,163 +1,174 @@ -getNbPagesToCreate() * $this->getNbQuotesPerPage(); - } - - public function getNbPagesToCreate() - { - return 3; - } - - public function getNbQuotesPerPage() - { - return Config::get('app.quotes.nbQuotesPerPage'); - } - - public function submitANewQuote() - { - $I = $this->getModule('Laravel4'); - - $this->getModule('NavigationHelper')->navigateToTheAddQuotePage(); - - $oldNbWaitingQuotes = $this->numberWaitingQuotesForUser(); - - $this->getModule('FormFillerHelper')->fillAddQuoteForm(); - - $I->amOnRoute('home'); - $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('Your quote has been submitted'); - - $currentNbWaitingQuotes = $this->numberWaitingQuotesForUser(); - - // Assert that the quote was added to the DB - $I->assertEquals($oldNbWaitingQuotes + 1, $currentNbWaitingQuotes); - } - - public function cantSubmitANewQuote() - { - $I = $this->getModule('Laravel4'); - - $this->getModule('NavigationHelper')->navigateToTheAddQuotePage(); - - $oldNbWaitingQuotes = $this->numberWaitingQuotesForUser(); - - $this->getModule('FormFillerHelper')->fillAddQuoteForm(); - - $I->amOnRoute('addquote'); - $I->see('You have submitted enough quotes for today'); - - $currentNbWaitingQuotes = $this->numberWaitingQuotesForUser(); - - // Assert that the quote was not added to the DB - $I->assertEquals($oldNbWaitingQuotes, $currentNbWaitingQuotes); - } - - /** - * Add a quote to the favorites of a user - * @param int $quote_id The ID of the quote - * @param int $user_id The user ID - */ - public function addAFavoriteForUser($quote_id, $user_id) - { - return $this->getModule('DbSeederHelper')->insertInDatabase(1, 'FavoriteQuote', ['quote_id' => $quote_id, 'user_id' => $user_id]); - } - - /** - * Count the number of quotes waiting moderation for a user - * @param User $u The user. If null, use the authenticated user - * @return int The number of quotes waiting moderation for the user - */ - public function numberWaitingQuotesForUser(User $u = null) - { - if (is_null($u)) - $u = Auth::user(); - - return Quote::forUser($u) - ->waiting() - ->count(); - } - - /** - * Create some published quotes - * @param array $overrides The key-value array used to override dummy values. If the key nb_quotes is given, specifies the number of quotes to create - * @return array The created quotes - */ - public function createSomePublishedQuotes($overrides = []) - { - $overrides['approved'] = Quote::PUBLISHED; - - // Determine the number of quotes to create - $nbQuotes = 10; - if (array_key_exists('nb_quotes', $overrides)) - { - $nbQuotes = $overrides['nb_quotes']; - unset($overrides['nb_quotes']); - } - - return $this->createSomeQuotes($nbQuotes, $overrides); - } - - /** - * Create some waiting quotes - * @param array $overrides The key-value array used to override dummy values. If the key nb_quotes is given, specifies the number of quotes to create - * @return array The created quotes - */ - public function createSomeWaitingQuotes($overrides = []) - { - $overrides['approved'] = Quote::WAITING; - - // Determine the number of quotes to create - $nbQuotes = 10; - if (array_key_exists('nb_quotes', $overrides)) - { - $nbQuotes = $overrides['nb_quotes']; - unset($overrides['nb_quotes']); - } - - return $this->createSomeQuotes($nbQuotes, $overrides); - } - - /** - * Create some pending quotes - * @param array $overrides The key-value array used to override dummy values. If the key nb_quotes is given, specifies the number of quotes to create - * @return array The created quotes - */ - public function createSomePendingQuotes($overrides = []) - { - $overrides['approved'] = Quote::PENDING; - - // Determine the number of quotes to create - $nbQuotes = 10; - if (array_key_exists('nb_quotes', $overrides)) - { - $nbQuotes = $overrides['nb_quotes']; - unset($overrides['nb_quotes']); - } - - return $this->createSomeQuotes($nbQuotes, $overrides); - } - - /** - * Create some quotes - * @param int $nbQuotes The number of quotes to create - * @param array $data The key-value array to override default values - * @return array The created quotes - */ - private function createSomeQuotes($nbQuotes, array $data) - { - return $this->getModule('DbSeederHelper')->insertInDatabase($nbQuotes, 'Quote', $data); - } -} \ No newline at end of file +class QuotesHelper extends Module +{ + public function getNbComments() + { + return Config::get('app.comments.nbCommentsPerPage'); + } + + public function getTotalNumberOfQuotesToCreate() + { + return $this->getNbPagesToCreate() * $this->getNbQuotesPerPage(); + } + + public function getNbPagesToCreate() + { + return 3; + } + + public function getNbQuotesPerPage() + { + return Config::get('app.quotes.nbQuotesPerPage'); + } + + public function submitANewQuote() + { + $I = $this->getModule('Laravel4'); + + $this->getModule('NavigationHelper')->navigateToTheAddQuotePage(); + + $oldNbWaitingQuotes = $this->numberWaitingQuotesForUser(); + + $this->getModule('FormFillerHelper')->fillAddQuoteForm(); + + $I->amOnRoute('home'); + $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('Your quote has been submitted'); + + $currentNbWaitingQuotes = $this->numberWaitingQuotesForUser(); + + // Assert that the quote was added to the DB + $I->assertEquals($oldNbWaitingQuotes + 1, $currentNbWaitingQuotes); + } + + public function cantSubmitANewQuote() + { + $I = $this->getModule('Laravel4'); + + $this->getModule('NavigationHelper')->navigateToTheAddQuotePage(); + + $oldNbWaitingQuotes = $this->numberWaitingQuotesForUser(); + + $this->getModule('FormFillerHelper')->fillAddQuoteForm(); + + $I->amOnRoute('addquote'); + $I->see('You have submitted enough quotes for today'); + + $currentNbWaitingQuotes = $this->numberWaitingQuotesForUser(); + + // Assert that the quote was not added to the DB + $I->assertEquals($oldNbWaitingQuotes, $currentNbWaitingQuotes); + } + + /** + * Add a quote to the favorites of a user. + * + * @param int $quote_id The ID of the quote + * @param int $user_id The user ID + */ + public function addAFavoriteForUser($quote_id, $user_id) + { + return $this->getModule('DbSeederHelper')->insertInDatabase(1, 'FavoriteQuote', ['quote_id' => $quote_id, 'user_id' => $user_id]); + } + + /** + * Count the number of quotes waiting moderation for a user. + * + * @param User $u The user. If null, use the authenticated user + * + * @return int The number of quotes waiting moderation for the user + */ + public function numberWaitingQuotesForUser(User $u = null) + { + if (is_null($u)) { + $u = Auth::user(); + } + + return Quote::forUser($u) + ->waiting() + ->count(); + } + + /** + * Create some published quotes. + * + * @param array $overrides The key-value array used to override dummy values. If the key nb_quotes is given, specifies the number of quotes to create + * + * @return array The created quotes + */ + public function createSomePublishedQuotes($overrides = []) + { + $overrides['approved'] = Quote::PUBLISHED; + + // Determine the number of quotes to create + $nbQuotes = 10; + if (array_key_exists('nb_quotes', $overrides)) { + $nbQuotes = $overrides['nb_quotes']; + unset($overrides['nb_quotes']); + } + + return $this->createSomeQuotes($nbQuotes, $overrides); + } + + /** + * Create some waiting quotes. + * + * @param array $overrides The key-value array used to override dummy values. If the key nb_quotes is given, specifies the number of quotes to create + * + * @return array The created quotes + */ + public function createSomeWaitingQuotes($overrides = []) + { + $overrides['approved'] = Quote::WAITING; + + // Determine the number of quotes to create + $nbQuotes = 10; + if (array_key_exists('nb_quotes', $overrides)) { + $nbQuotes = $overrides['nb_quotes']; + unset($overrides['nb_quotes']); + } + + return $this->createSomeQuotes($nbQuotes, $overrides); + } + + /** + * Create some pending quotes. + * + * @param array $overrides The key-value array used to override dummy values. If the key nb_quotes is given, specifies the number of quotes to create + * + * @return array The created quotes + */ + public function createSomePendingQuotes($overrides = []) + { + $overrides['approved'] = Quote::PENDING; + + // Determine the number of quotes to create + $nbQuotes = 10; + if (array_key_exists('nb_quotes', $overrides)) { + $nbQuotes = $overrides['nb_quotes']; + unset($overrides['nb_quotes']); + } + + return $this->createSomeQuotes($nbQuotes, $overrides); + } + + /** + * Create some quotes. + * + * @param int $nbQuotes The number of quotes to create + * @param array $data The key-value array to override default values + * + * @return array The created quotes + */ + private function createSomeQuotes($nbQuotes, array $data) + { + return $this->getModule('DbSeederHelper')->insertInDatabase($nbQuotes, 'Quote', $data); + } +} diff --git a/tests/_support/StoriesHelper.php b/tests/_support/StoriesHelper.php index ce84a2d0..02aab9f8 100644 --- a/tests/_support/StoriesHelper.php +++ b/tests/_support/StoriesHelper.php @@ -1,50 +1,54 @@ -getNbPagesToCreate() * $this->getNbStoriesPerPage(); - } - - public function getNbPagesToCreate() - { - return 3; - } - - public function getNbStoriesPerPage() - { - return Config::get('app.stories.nbStoriesPerPage'); - } - - /** - * Create some stories - * @param array $overrides The key-value array used to override dummy values. If the key nb_stories is given, specifies the number of stories to create - * @return array The created stories - */ - public function createSomeStories($overrides = []) - { - // Create stories in the past - $overrides['created_at'] = Carbon::now()->subMonth(1); - - $nbStories = $this->getNbStoriesToCreate(); - - if (array_key_exists('nb_stories', $overrides)) { - $nbStories = $overrides['nb_stories']; - unset($overrides['nb_stories']); - } - - return $this->getModule('DbSeederHelper')->insertInDatabase($nbStories, 'Story', $overrides); - } - - public function createAStoryWithHiddenUser() - { - $user = $this->getModule('DbSeederHelper')->insertInDatabase(1, 'User', ['hide_profile' => 1]); - - return $this->getModule('DbSeederHelper')->insertInDatabase(1, 'Story', ['user_id' => $user->id]); - } -} \ No newline at end of file +class StoriesHelper extends Module +{ + public function getNbStoriesToCreate() + { + return $this->getNbPagesToCreate() * $this->getNbStoriesPerPage(); + } + + public function getNbPagesToCreate() + { + return 3; + } + + public function getNbStoriesPerPage() + { + return Config::get('app.stories.nbStoriesPerPage'); + } + + /** + * Create some stories. + * + * @param array $overrides The key-value array used to override dummy values. If the key nb_stories is given, specifies the number of stories to create + * + * @return array The created stories + */ + public function createSomeStories($overrides = []) + { + // Create stories in the past + $overrides['created_at'] = Carbon::now()->subMonth(1); + + $nbStories = $this->getNbStoriesToCreate(); + + if (array_key_exists('nb_stories', $overrides)) { + $nbStories = $overrides['nb_stories']; + unset($overrides['nb_stories']); + } + + return $this->getModule('DbSeederHelper')->insertInDatabase($nbStories, 'Story', $overrides); + } + + public function createAStoryWithHiddenUser() + { + $user = $this->getModule('DbSeederHelper')->insertInDatabase(1, 'User', ['hide_profile' => 1]); + + return $this->getModule('DbSeederHelper')->insertInDatabase(1, 'Story', ['user_id' => $user->id]); + } +} diff --git a/tests/_support/UserHelper.php b/tests/_support/UserHelper.php index 37e1b40b..393beb91 100644 --- a/tests/_support/UserHelper.php +++ b/tests/_support/UserHelper.php @@ -1,4 +1,6 @@ -assertMySettingsHaveTheseValues([ - 'color' => $this->getDefaultColorForPublishedQuotes(), - // Receive a notification if a comment is posted on one of my quotes - 'notification_comment_quote' => 1, - // Profile not hidden - 'hide_profile' => 0, - // Subscribed to the weekly newsletter - 'daily_newsletter' => 0, - 'weekly_newsletter' => 1 - ]); - } - - /** - * Get the default color for published quotes on a user's profile - * @return string - */ - private function getDefaultColorForPublishedQuotes() - { - return ucfirst(Config::get('app.users.defaultColorQuotesPublished')); - } - - public function assertMySettingsHaveTheseValues(array $params) - { - $I = $this->getModule('Laravel4'); - - $I->seeOptionIsSelected('select[name=colors]', $params['color']); - - foreach (['notification_comment_quote', 'hide_profile', 'daily_newsletter', 'weekly_newsletter'] as $value) { - if ($params[$value] == 1) - $I->seeCheckboxIsChecked('input[name='.$value.']'); - else - $I->dontSeeCheckboxIsChecked('input[name='.$value.']'); - } - } - - public function hideProfileForCurrentUser() - { - $this->getModule('NavigationHelper')->navigateToMyEditProfilePage(); - - $this->getModule('FormFillerHelper')->fillUserSettingsForm([ - 'notification_comment_quote' => 1, - 'hide_profile' => 1, - 'daily_newsletter' => 0, - 'weekly_newsletter' => 1, - 'color' => $this->getDefaultColorForPublishedQuotes(), - ]); - } - - public function assertEditProfileFormIsFilledWith(array $params) - { - $I = $this->getModule('Laravel4'); - - $I->seeOptionIsSelected('input[name=gender]', $params['gender']); - $I->see($params['birthdate']); - $I->seeOptionIsSelected('select[name=country]', $params['country_name']); - $I->see($params['city']); - $I->see($params['about_me']); - } - - /** - * Assert that the logged in user has got the given key-values pairs for its profile - * @param array $params The key-values pairs. - * Possible keys: gender, birthdate (YYYY-MM-DD), country_name, city, about_me, avatar (filename) - * quotes-published-count, fav-count, comments-count, added-fav-count - */ - public function assertProfileHasBeenChangedWithParams(array $params) - { - $I = $this->getModule('Laravel4'); - $user = Auth::user(); - - $I->seeCurrentRouteIs('users.edit', $user->login); - $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('You have a brand new profile'); - - $this->getModule('NavigationHelper')->navigateToMyProfile(); - $this->assertProfileContainsInformation($params); - } - - /** - * Assert that the logged in user has got the given key-values pairs for its profile - * @param array $params The key-values pairs. - * Possible keys: gender, birthdate (YYYY-MM-DD), country_name, city, about_me, avatar (filename) - * quotes-published-count, fav-count, comments-count, added-fav-count - */ - public function assertProfileContainsInformation(array $params) - { - $I = $this->getModule('Laravel4'); - $user = Auth::user(); - - if (array_key_exists('country_name', $params)) - $I->see($params['country_name']); - - if (array_key_exists('city', $params)) - $I->see($params['city']); - - if (array_key_exists('about_me', $params)) - $I->see($params['about_me']); - - if (array_key_exists('birthdate', $params)) { - $age = $this->computeAgeFromYYYMMDD($params['birthdate']); - $I->see($age.' y/o'); - } - - if (array_key_exists('gender', $params)) { - if ($params['gender'] == 'M') - $I->see("I'm a man"); - else - $I->see("I'm a woman"); - } - - // Check that the URL for the avatar has been set - // Check that the file has been moved to the expected directory - if (array_key_exists('avatar', $params)) { - $avatar = $this->getAvatarNameForUser($user, $params['avatar']); - $I->assertTrue(Str::endsWith($avatar, $user->avatar)); - $I->getModule('Filesystem')->seeFileFound($avatar, $this->getAvatarsPath()); - } - - // Test user statistics - if (array_key_exists('quotes-published-count', $params)) - $I->see($params['quotes-published-count'], '#quotes-published-count'); - - if (array_key_exists('fav-count', $params)) - $I->see($params['fav-count'], '#fav-count'); - - if (array_key_exists('comments-count', $params)) - $I->see($params['comments-count'], '#comments-count'); - - if (array_key_exists('added-fav-count', $params)) - $I->see($params['added-fav-count'], '#added-fav-count'); - } - - /** - * Construct the name of an avatar for a user and a filename - * @param User $u The user - * @param string $file The filename - * @return string - */ - private function getAvatarNameForUser(User $u, $file) - { - return $u->id.'.'.$this->getExtension($file); - } - - /** - * Extract the extension of a filename in a dumb way - * @param string $filename The filename - * @return string The extension - */ - private function getExtension($filename) - { - $chunks = explode('.', $filename); - - return $chunks[1]; - } - - /** - * Get the path where avatars are stored - * @return string - */ - private function getAvatarsPath() - { - return Config::get('app.users.avatarPath').'/'; - } - - /** - * Compute the age from a date formatted as YYYY-MM-DD - * @param string $date The date formatted as YYYY-MM-DD - * @return int The age - */ - private function computeAgeFromYYYMMDD($date) - { - // Create an array to have year, month and day - $parts = explode('-', $date); - - return Carbon::createFromDate($parts[0], $parts[1], $parts[2])->age; - } - - public function assertPasswordHasBeenChanged() - { - $I = $this->getModule('Laravel4'); - $u = Auth::user(); - - $I->seeCurrentRouteIs('users.edit', $u->login); - $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('Your password has been changed'); - } - - public function amOnMyNewProfile($login) - { - $I = $this->getModule('Laravel4'); - - $I->amOnRoute('users.show', $login); - $I->assertTrue(Auth::check()); - $I->seeRecord('users', compact('login')); - $I->seeElement('#welcome-profile'); - } -} \ No newline at end of file +class UserHelper extends Module +{ + public function assertMySettingsHaveDefaultValues() + { + $this->assertMySettingsHaveTheseValues([ + 'color' => $this->getDefaultColorForPublishedQuotes(), + // Receive a notification if a comment is posted on one of my quotes + 'notification_comment_quote' => 1, + // Profile not hidden + 'hide_profile' => 0, + // Subscribed to the weekly newsletter + 'daily_newsletter' => 0, + 'weekly_newsletter' => 1, + ]); + } + + /** + * Get the default color for published quotes on a user's profile. + * + * @return string + */ + private function getDefaultColorForPublishedQuotes() + { + return ucfirst(Config::get('app.users.defaultColorQuotesPublished')); + } + + public function assertMySettingsHaveTheseValues(array $params) + { + $I = $this->getModule('Laravel4'); + + $I->seeOptionIsSelected('select[name=colors]', $params['color']); + + foreach (['notification_comment_quote', 'hide_profile', 'daily_newsletter', 'weekly_newsletter'] as $value) { + if ($params[$value] == 1) { + $I->seeCheckboxIsChecked('input[name='.$value.']'); + } else { + $I->dontSeeCheckboxIsChecked('input[name='.$value.']'); + } + } + } + + public function hideProfileForCurrentUser() + { + $this->getModule('NavigationHelper')->navigateToMyEditProfilePage(); + + $this->getModule('FormFillerHelper')->fillUserSettingsForm([ + 'notification_comment_quote' => 1, + 'hide_profile' => 1, + 'daily_newsletter' => 0, + 'weekly_newsletter' => 1, + 'color' => $this->getDefaultColorForPublishedQuotes(), + ]); + } + + public function assertEditProfileFormIsFilledWith(array $params) + { + $I = $this->getModule('Laravel4'); + + $I->seeOptionIsSelected('input[name=gender]', $params['gender']); + $I->see($params['birthdate']); + $I->seeOptionIsSelected('select[name=country]', $params['country_name']); + $I->see($params['city']); + $I->see($params['about_me']); + } + + /** + * Assert that the logged in user has got the given key-values pairs for its profile. + * + * @param array $params The key-values pairs. + * Possible keys: gender, birthdate (YYYY-MM-DD), country_name, city, about_me, avatar (filename) + * quotes-published-count, fav-count, comments-count, added-fav-count + */ + public function assertProfileHasBeenChangedWithParams(array $params) + { + $I = $this->getModule('Laravel4'); + $user = Auth::user(); + + $I->seeCurrentRouteIs('users.edit', $user->login); + $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('You have a brand new profile'); + + $this->getModule('NavigationHelper')->navigateToMyProfile(); + $this->assertProfileContainsInformation($params); + } + + /** + * Assert that the logged in user has got the given key-values pairs for its profile. + * + * @param array $params The key-values pairs. + * Possible keys: gender, birthdate (YYYY-MM-DD), country_name, city, about_me, avatar (filename) + * quotes-published-count, fav-count, comments-count, added-fav-count + */ + public function assertProfileContainsInformation(array $params) + { + $I = $this->getModule('Laravel4'); + $user = Auth::user(); + + if (array_key_exists('country_name', $params)) { + $I->see($params['country_name']); + } + + if (array_key_exists('city', $params)) { + $I->see($params['city']); + } + + if (array_key_exists('about_me', $params)) { + $I->see($params['about_me']); + } + + if (array_key_exists('birthdate', $params)) { + $age = $this->computeAgeFromYYYMMDD($params['birthdate']); + $I->see($age.' y/o'); + } + + if (array_key_exists('gender', $params)) { + if ($params['gender'] == 'M') { + $I->see("I'm a man"); + } else { + $I->see("I'm a woman"); + } + } + + // Check that the URL for the avatar has been set + // Check that the file has been moved to the expected directory + if (array_key_exists('avatar', $params)) { + $avatar = $this->getAvatarNameForUser($user, $params['avatar']); + $I->assertTrue(Str::endsWith($avatar, $user->avatar)); + $I->getModule('Filesystem')->seeFileFound($avatar, $this->getAvatarsPath()); + } + + // Test user statistics + if (array_key_exists('quotes-published-count', $params)) { + $I->see($params['quotes-published-count'], '#quotes-published-count'); + } + + if (array_key_exists('fav-count', $params)) { + $I->see($params['fav-count'], '#fav-count'); + } + + if (array_key_exists('comments-count', $params)) { + $I->see($params['comments-count'], '#comments-count'); + } + + if (array_key_exists('added-fav-count', $params)) { + $I->see($params['added-fav-count'], '#added-fav-count'); + } + } + + /** + * Construct the name of an avatar for a user and a filename. + * + * @param User $u The user + * @param string $file The filename + * + * @return string + */ + private function getAvatarNameForUser(User $u, $file) + { + return $u->id.'.'.$this->getExtension($file); + } + + /** + * Extract the extension of a filename in a dumb way. + * + * @param string $filename The filename + * + * @return string The extension + */ + private function getExtension($filename) + { + $chunks = explode('.', $filename); + + return $chunks[1]; + } + + /** + * Get the path where avatars are stored. + * + * @return string + */ + private function getAvatarsPath() + { + return Config::get('app.users.avatarPath').'/'; + } + + /** + * Compute the age from a date formatted as YYYY-MM-DD. + * + * @param string $date The date formatted as YYYY-MM-DD + * + * @return int The age + */ + private function computeAgeFromYYYMMDD($date) + { + // Create an array to have year, month and day + $parts = explode('-', $date); + + return Carbon::createFromDate($parts[0], $parts[1], $parts[2])->age; + } + + public function assertPasswordHasBeenChanged() + { + $I = $this->getModule('Laravel4'); + $u = Auth::user(); + + $I->seeCurrentRouteIs('users.edit', $u->login); + $this->getModule('FunctionalHelper')->seeSuccessFlashMessage('Your password has been changed'); + } + + public function amOnMyNewProfile($login) + { + $I = $this->getModule('Laravel4'); + + $I->amOnRoute('users.show', $login); + $I->assertTrue(Auth::check()); + $I->seeRecord('users', compact('login')); + $I->seeElement('#welcome-profile'); + } +} diff --git a/tests/fixtures.yml b/tests/fixtures.yml index c7b802dc..7609020a 100644 --- a/tests/fixtures.yml +++ b/tests/fixtures.yml @@ -46,4 +46,4 @@ TeenQuotes\Settings\Models\Setting: value: $string TeenQuotes\Tags\Models\Tag: - name: $string \ No newline at end of file + name: $string diff --git a/tests/functional.suite.yml b/tests/functional.suite.yml index 15790751..60fff9ec 100644 --- a/tests/functional.suite.yml +++ b/tests/functional.suite.yml @@ -28,4 +28,4 @@ modules: filters: true MailCatcher: url: 'http://127.0.0.1' - port: '1080' \ No newline at end of file + port: '1080' diff --git a/tests/functional/AdminPanel/EditWaitingQuoteCest.php b/tests/functional/AdminPanel/EditWaitingQuoteCest.php index 277f3b1a..06ec4d1b 100644 --- a/tests/functional/AdminPanel/EditWaitingQuoteCest.php +++ b/tests/functional/AdminPanel/EditWaitingQuoteCest.php @@ -1,71 +1,73 @@ tester = $I; - public function _before(FunctionalTester $I) - { - $this->tester = $I; + $this->nbQuotes = [ + 'pending' => 7, + 'waiting' => 26, + ]; - $this->nbQuotes = [ - 'pending' => 7, - 'waiting' => 26, - ]; + $I->createSomePublishedQuotes(); + $this->waitingQuotes = $I->createSomeWaitingQuotes(['nb_quotes' => $this->nbQuotes['waiting']]); + $I->createSomePendingQuotes(['nb_quotes' => $this->nbQuotes['pending']]); - $I->createSomePublishedQuotes(); - $this->waitingQuotes = $I->createSomeWaitingQuotes(['nb_quotes' => $this->nbQuotes['waiting']]); - $I->createSomePendingQuotes(['nb_quotes' => $this->nbQuotes['pending']]); + $this->admin = $I->logANewUser(['security_level' => 1]); + } - $this->admin = $I->logANewUser(['security_level' => 1]); - } + public function editQuoteWaitingForModeration(FunctionalTester $I) + { + $I->am("a Teen Quotes' administrator"); + $I->wantTo('edit and publish a quote waiting to be moderated'); - public function editQuoteWaitingForModeration(FunctionalTester $I) - { - $I->am("a Teen Quotes' administrator"); - $I->wantTo('edit and publish a quote waiting to be moderated'); + // Go to the admin panel + $I->navigateToTheAdminPanel(); - // Go to the admin panel - $I->navigateToTheAdminPanel(); + $quote = $this->waitingQuotes[0]; + $I->seeModerationButtonsForQuote($quote); - $quote = $this->waitingQuotes[0]; - $I->seeModerationButtonsForQuote($quote); + // Click the edit button and fill the form + $newContent = str_repeat('abc', 20); + $this->editContentOfQuote($quote, $newContent); + } - // Click the edit button and fill the form - $newContent = str_repeat('abc', 20); - $this->editContentOfQuote($quote, $newContent); - } - - private function editContentOfQuote(Quote $quote, $newContent) - { - $this->tester->clickEditButtonFor($quote); - $this->tester->fillNewContentWaitingQuoteForm($newContent); - $this->tester->seeSuccessFlashMessage('The quote has been edited and approved!'); - $this->tester->seeQuoteIsPending($quote); - $this->tester->seeAuthorOfQuoteHasBeenWarnedOfApproval($quote); - } -} \ No newline at end of file + private function editContentOfQuote(Quote $quote, $newContent) + { + $this->tester->clickEditButtonFor($quote); + $this->tester->fillNewContentWaitingQuoteForm($newContent); + $this->tester->seeSuccessFlashMessage('The quote has been edited and approved!'); + $this->tester->seeQuoteIsPending($quote); + $this->tester->seeAuthorOfQuoteHasBeenWarnedOfApproval($quote); + } +} diff --git a/tests/functional/AdminPanel/ListWaitingQuotesCest.php b/tests/functional/AdminPanel/ListWaitingQuotesCest.php index e6f5a740..583ee9ca 100644 --- a/tests/functional/AdminPanel/ListWaitingQuotesCest.php +++ b/tests/functional/AdminPanel/ListWaitingQuotesCest.php @@ -1,113 +1,120 @@ tester = $I; - - $this->nbQuotes = [ - 'pending' => 7, - 'waiting' => 26, - ]; - - $I->createSomePublishedQuotes(); - $this->waitingQuotes = $I->createSomeWaitingQuotes(['nb_quotes' => $this->nbQuotes['waiting']]); - $I->createSomePendingQuotes(['nb_quotes' => $this->nbQuotes['pending']]); - - $this->admin = $I->logANewUser(['security_level' => 1]); - } - - public function viewQuotesWaitingForModeration(FunctionalTester $I) - { - $I->am("a Teen Quotes' administrator"); - $I->wantTo('view quotes waiting for moderation'); - - $nbDaysToPublish = $this->computeNbDaysToPublishQuotes($this->nbQuotes['pending']); - - // Go to the admin panel - $I->navigateToTheAdminPanel(); - - // Check that counters are properly set - $this->seeNumberOfWaitingQuotesIs($this->nbQuotes['waiting']); - $this->seeNumberOfPendingQuotesIs($this->nbQuotes['pending']); - $this->seeNumberOfDaysToPublishIs($nbDaysToPublish); - - $this->seeRequiredElementsForQuotes($this->waitingQuotes); - } - - /** - * I can see that quotes have things properly being displayed - * @param array $quotes - */ - private function seeRequiredElementsForQuotes(array $quotes) - { - foreach ($this->waitingQuotes as $quote) - { - $this->tester->seeModerationButtonsForQuote($quote); - $this->tester->seeContentForQuoteWaitingForModeration($quote); - } - } - - /** - * Compute the number of days to publish the given number of quotes - * @param int $nbQuotes The number of quotes to publish - * @return int - */ - private function computeNbDaysToPublishQuotes($nbQuotes) - { - return ceil($nbQuotes / Config::get('app.quotes.nbQuotesToPublishPerDay')); - } - - /** - * Assert that the number of waiting quotes is the given value - * @param int $nb - */ - private function seeNumberOfWaitingQuotesIs($nb) - { - $this->tester->see($nb, '#nb-quotes-waiting'); - } - - /** - * Assert that the number days to publish quotes is the given value - * @param int $nb - */ - private function seeNumberOfDaysToPublishIs($nb) - { - $this->tester->see($nb, '#nb-quotes-per-day'); - } - - /** - * Assert that the number of pending quotes is the given value - * @param int $nb - */ - private function seeNumberOfPendingQuotesIs($nb) - { - $this->tester->see($nb, '#nb-quotes-pending'); - } -} \ No newline at end of file + +class ListWaitingQuotesCest +{ + /** + * The admin user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $admin; + + /** + * @var \FunctionalTester + */ + private $tester; + + /** + * The number of quotes created, by approved type. + * + * @var array + */ + private $nbQuotes; + + /** + * Quotes that are waiting to be published. + * + * @var array + */ + private $waitingQuotes; + + public function _before(FunctionalTester $I) + { + $this->tester = $I; + + $this->nbQuotes = [ + 'pending' => 7, + 'waiting' => 26, + ]; + + $I->createSomePublishedQuotes(); + $this->waitingQuotes = $I->createSomeWaitingQuotes(['nb_quotes' => $this->nbQuotes['waiting']]); + $I->createSomePendingQuotes(['nb_quotes' => $this->nbQuotes['pending']]); + + $this->admin = $I->logANewUser(['security_level' => 1]); + } + + public function viewQuotesWaitingForModeration(FunctionalTester $I) + { + $I->am("a Teen Quotes' administrator"); + $I->wantTo('view quotes waiting for moderation'); + + $nbDaysToPublish = $this->computeNbDaysToPublishQuotes($this->nbQuotes['pending']); + + // Go to the admin panel + $I->navigateToTheAdminPanel(); + + // Check that counters are properly set + $this->seeNumberOfWaitingQuotesIs($this->nbQuotes['waiting']); + $this->seeNumberOfPendingQuotesIs($this->nbQuotes['pending']); + $this->seeNumberOfDaysToPublishIs($nbDaysToPublish); + + $this->seeRequiredElementsForQuotes($this->waitingQuotes); + } + + /** + * I can see that quotes have things properly being displayed. + * + * @param array $quotes + */ + private function seeRequiredElementsForQuotes(array $quotes) + { + foreach ($this->waitingQuotes as $quote) { + $this->tester->seeModerationButtonsForQuote($quote); + $this->tester->seeContentForQuoteWaitingForModeration($quote); + } + } + + /** + * Compute the number of days to publish the given number of quotes. + * + * @param int $nbQuotes The number of quotes to publish + * + * @return int + */ + private function computeNbDaysToPublishQuotes($nbQuotes) + { + return ceil($nbQuotes / Config::get('app.quotes.nbQuotesToPublishPerDay')); + } + + /** + * Assert that the number of waiting quotes is the given value. + * + * @param int $nb + */ + private function seeNumberOfWaitingQuotesIs($nb) + { + $this->tester->see($nb, '#nb-quotes-waiting'); + } + + /** + * Assert that the number days to publish quotes is the given value. + * + * @param int $nb + */ + private function seeNumberOfDaysToPublishIs($nb) + { + $this->tester->see($nb, '#nb-quotes-per-day'); + } + + /** + * Assert that the number of pending quotes is the given value. + * + * @param int $nb + */ + private function seeNumberOfPendingQuotesIs($nb) + { + $this->tester->see($nb, '#nb-quotes-pending'); + } +} diff --git a/tests/functional/Auth/LogOutCest.php b/tests/functional/Auth/LogOutCest.php index a6c7ac6e..d6c9ff76 100644 --- a/tests/functional/Auth/LogOutCest.php +++ b/tests/functional/Auth/LogOutCest.php @@ -1,22 +1,22 @@ createSomePublishedQuotes(); - } +class LogOutCest +{ + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + } - public function clickOnLogoutOnProfile(FunctionalTester $I) - { - $I->am('a Teen Quotes member'); - $I->wantTo('log out from my account'); + public function clickOnLogoutOnProfile(FunctionalTester $I) + { + $I->am('a Teen Quotes member'); + $I->wantTo('log out from my account'); - $I->logANewUser(); - - $I->performLogoutFlow(); + $I->logANewUser(); - $I->seeSuccessFlashMessage('You have been logged out.'); - $I->assertFalse(Auth::check()); - } -} \ No newline at end of file + $I->performLogoutFlow(); + + $I->seeSuccessFlashMessage('You have been logged out.'); + $I->assertFalse(Auth::check()); + } +} diff --git a/tests/functional/Auth/PasswordForgottenCest.php b/tests/functional/Auth/PasswordForgottenCest.php index a4b11213..ee7a2e14 100644 --- a/tests/functional/Auth/PasswordForgottenCest.php +++ b/tests/functional/Auth/PasswordForgottenCest.php @@ -1,37 +1,37 @@ createSomePublishedQuotes(); + } - public function _before(FunctionalTester $I) - { - $I->createSomePublishedQuotes(); - } + public function resetAForgottenPassword(FunctionalTester $I) + { + $I->am('a Teen Quotes member'); + $I->wantTo('reset my password'); - public function resetAForgottenPassword(FunctionalTester $I) - { - $I->am('a Teen Quotes member'); - $I->wantTo('reset my password'); + $I->navigateToTheResetPasswordPage(); - $I->navigateToTheResetPasswordPage(); + $u = $I->haveAnAccount(); - $u = $I->haveAnAccount(); - - $I->fillPasswordResetFormFor($u); - $I->seeSuccessFlashMessage('Password reminder sent!'); + $I->fillPasswordResetFormFor($u); + $I->seeSuccessFlashMessage('Password reminder sent!'); - // Assert that the email has been sent - $I->seeInLastEmailSubjectTo($u->email, 'Password reminder'); - $I->seeInLastEmailTo($u->email, "You've just asked to reset your password"); - } + // Assert that the email has been sent + $I->seeInLastEmailSubjectTo($u->email, 'Password reminder'); + $I->seeInLastEmailTo($u->email, "You've just asked to reset your password"); + } - public function resetAForgottenPasswordWithAnInvalidEmailAddress(FunctionalTester $I) - { - $I->am('not a Teen Quotes member'); - $I->wantTo('reset my password with an unknown email address'); + public function resetAForgottenPasswordWithAnInvalidEmailAddress(FunctionalTester $I) + { + $I->am('not a Teen Quotes member'); + $I->wantTo('reset my password with an unknown email address'); - $I->navigateToTheResetPasswordPage(); + $I->navigateToTheResetPasswordPage(); - $I->fillPasswordResetFormFor($I->buildUser()); - $I->seeFormError("We can't find a user with that e-mail address"); - } -} \ No newline at end of file + $I->fillPasswordResetFormFor($I->buildUser()); + $I->seeFormError("We can't find a user with that e-mail address"); + } +} diff --git a/tests/functional/Auth/SignInCest.php b/tests/functional/Auth/SignInCest.php index 779793a1..e6a3cc68 100644 --- a/tests/functional/Auth/SignInCest.php +++ b/tests/functional/Auth/SignInCest.php @@ -1,52 +1,52 @@ createSomePublishedQuotes(); - } - - public function performSigninFlow(FunctionalTester $I) - { - $I->am('a Teen Quotes member'); - $I->wantTo('sign in to my Teen Quotes account'); - - $I->signIn('foobar42', 'azerty22'); - $I->checkThatIHaveBeenLoggedIn(); - } - - public function wrongLogin(FunctionalTester $I) - { - $I->am('a guest'); - $I->wantTo('sign in with an unexisting login.'); - - $I->navigateToTheSignInPage(); - $I->fillSigninForm('foobar', 'azerty'); - $I->seeFormError('The selected login was not found.'); - } - - public function wrongPassword(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo('sign in with a wrong password.'); - - $I->haveAnAccount(['login' => 'foobar', 'password' => 'blahblah']); - - $I->navigateToTheSignInPage(); - $I->fillSigninForm('foobar', 'azerty'); - $I->seeFormError('Your password is invalid.'); - } - - public function tooSmallPassword(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo('sign in with a too small password.'); - - $I->haveAnAccount(['login' => 'foobar', 'password' => 'blahblah']); - - $I->navigateToTheSignInPage(); - $I->fillSigninForm('foobar', 'ab'); - $I->seeFormError('The password must be at least 6 characters.'); - } -} \ No newline at end of file +class SignInCest +{ + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + } + + public function performSigninFlow(FunctionalTester $I) + { + $I->am('a Teen Quotes member'); + $I->wantTo('sign in to my Teen Quotes account'); + + $I->signIn('foobar42', 'azerty22'); + $I->checkThatIHaveBeenLoggedIn(); + } + + public function wrongLogin(FunctionalTester $I) + { + $I->am('a guest'); + $I->wantTo('sign in with an unexisting login.'); + + $I->navigateToTheSignInPage(); + $I->fillSigninForm('foobar', 'azerty'); + $I->seeFormError('The selected login was not found.'); + } + + public function wrongPassword(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('sign in with a wrong password.'); + + $I->haveAnAccount(['login' => 'foobar', 'password' => 'blahblah']); + + $I->navigateToTheSignInPage(); + $I->fillSigninForm('foobar', 'azerty'); + $I->seeFormError('Your password is invalid.'); + } + + public function tooSmallPassword(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('sign in with a too small password.'); + + $I->haveAnAccount(['login' => 'foobar', 'password' => 'blahblah']); + + $I->navigateToTheSignInPage(); + $I->fillSigninForm('foobar', 'ab'); + $I->seeFormError('The password must be at least 6 characters.'); + } +} diff --git a/tests/functional/Auth/SignUpCest.php b/tests/functional/Auth/SignUpCest.php index a06be09c..a9ee957f 100644 --- a/tests/functional/Auth/SignUpCest.php +++ b/tests/functional/Auth/SignUpCest.php @@ -1,26 +1,26 @@ createSomePublishedQuotes(); - } +class SignUpCest +{ + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + } - public function performSignupFlow(FunctionalTester $I) - { - $I->am('a guest'); - $I->wantTo("create a Teen Quotes' account"); - - $login = 'foobar'; + public function performSignupFlow(FunctionalTester $I) + { + $I->am('a guest'); + $I->wantTo("create a Teen Quotes' account"); - $I->navigateToTheSignUpPage(); - $I->fillRegistrationFormFor($login); - $I->amOnMyNewProfile($login); + $login = 'foobar'; - // Assert that the welcome e-mail has been sent - $I->seeInLastEmailSubject('Welcome on Teen Quotes '.$login.'!'); - $I->seeInLastEmail('We are excited to welcome you on board!'); - $I->seeInLastEmail('You can now go to your profile, you will find a nice starter kit'); - } -} \ No newline at end of file + $I->navigateToTheSignUpPage(); + $I->fillRegistrationFormFor($login); + $I->amOnMyNewProfile($login); + + // Assert that the welcome e-mail has been sent + $I->seeInLastEmailSubject('Welcome on Teen Quotes '.$login.'!'); + $I->seeInLastEmail('We are excited to welcome you on board!'); + $I->seeInLastEmail('You can now go to your profile, you will find a nice starter kit'); + } +} diff --git a/tests/functional/Comment/AddCommentCest.php b/tests/functional/Comment/AddCommentCest.php index a82639a2..ca515c8e 100644 --- a/tests/functional/Comment/AddCommentCest.php +++ b/tests/functional/Comment/AddCommentCest.php @@ -2,115 +2,117 @@ use TeenQuotes\Quotes\Models\Quote; -class AddCommentCest { - - /** - * The number of comments to add to the first quote - * @var integer - */ - private $nbComments = 5; - - /** - * The created quotes - * @var array - */ - private $quotes; - - public function _before(FunctionalTester $I) - { - $I->logANewUser(); - $this->quotes = $I->createSomePublishedQuotes(); - $I->insertInDatabase($this->nbComments, 'Comment', ['quote_id' => $this->quotes[0]->id]); - } - - public function postANewCommentOnAQuote(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a comment on a quote"); - - // Go to the quote, verify that we have the right number of comments - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeNumberOfElements('.comment', $this->nbComments); - - // Post a new comment - $txtToAdd = Str::random(100); - $I->fillAddCommentForm($txtToAdd); - - // Assert that the comment has been added to this quote - $nbCommentsExpected = $this->nbComments + 1; - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeSuccessFlashMessage('Your comment has been added successfully!'); - $I->seeNumberOfElements('.comment', $nbCommentsExpected); - $I->see($txtToAdd, '.comment[data-id='.($nbCommentsExpected).']'); - - // We have got a link to the profile of the comment's author - $I->see(Auth::user()->login, '.comment[data-id='.$nbCommentsExpected.'] a.link-author-name'); - $I->assertEquals(1, Auth::user()->getTotalComments()); - $I->assertEquals($nbCommentsExpected, Quote::find($this->quotes[0]->id)->total_comments); - } - - public function postATooShortCommentOnAQuote(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a comment too short on a quote"); - - // Go to the quote, verify that we have the right number of comments - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeNumberOfElements('.comment', $this->nbComments); - - // Try to post a new comment - $txtToAdd = Str::random(9); - $I->fillAddCommentForm($txtToAdd); - - // Assert that we have got an error - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeFormError('The content must be at least 10 characters.'); - - // The comment was not posted - $I->seeNumberOfElements('.comment', $this->nbComments); - $I->assertEquals($this->nbComments, Quote::find($this->quotes[0]->id)->total_comments); - } - - public function postATooLongCommentOnAQuote(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a comment too long on a quote"); - - // Go to the quote, verify that we have the right number of comments - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeNumberOfElements('.comment', $this->nbComments); - - // Try to post a new comment - $txtToAdd = Str::random(501); - $I->fillAddCommentForm($txtToAdd); - - // Assert that we have got an error - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeFormError('The content may not be greater than 500 characters.'); - - // The comment was not posted - $I->seeNumberOfElements('.comment', $this->nbComments); - $I->assertEquals($this->nbComments, Quote::find($this->quotes[0]->id)->total_comments); - } - - public function postACommentIsRequired(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("leave an empty comment on a quote"); - - // Go to the quote, verify that we have the right number of comments - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeNumberOfElements('.comment', $this->nbComments); - - // Try to post a new comment - $I->fillAddCommentForm(''); - - // Assert that we have got an error - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeFormError('The content field is required.'); - - // The comment was not posted - $I->seeNumberOfElements('.comment', $this->nbComments); - $I->assertEquals($this->nbComments, Quote::find($this->quotes[0]->id)->total_comments); - } -} \ No newline at end of file +class AddCommentCest +{ + /** + * The number of comments to add to the first quote. + * + * @var int + */ + private $nbComments = 5; + + /** + * The created quotes. + * + * @var array + */ + private $quotes; + + public function _before(FunctionalTester $I) + { + $I->logANewUser(); + $this->quotes = $I->createSomePublishedQuotes(); + $I->insertInDatabase($this->nbComments, 'Comment', ['quote_id' => $this->quotes[0]->id]); + } + + public function postANewCommentOnAQuote(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a comment on a quote'); + + // Go to the quote, verify that we have the right number of comments + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeNumberOfElements('.comment', $this->nbComments); + + // Post a new comment + $txtToAdd = Str::random(100); + $I->fillAddCommentForm($txtToAdd); + + // Assert that the comment has been added to this quote + $nbCommentsExpected = $this->nbComments + 1; + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeSuccessFlashMessage('Your comment has been added successfully!'); + $I->seeNumberOfElements('.comment', $nbCommentsExpected); + $I->see($txtToAdd, '.comment[data-id='.($nbCommentsExpected).']'); + + // We have got a link to the profile of the comment's author + $I->see(Auth::user()->login, '.comment[data-id='.$nbCommentsExpected.'] a.link-author-name'); + $I->assertEquals(1, Auth::user()->getTotalComments()); + $I->assertEquals($nbCommentsExpected, Quote::find($this->quotes[0]->id)->total_comments); + } + + public function postATooShortCommentOnAQuote(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a comment too short on a quote'); + + // Go to the quote, verify that we have the right number of comments + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeNumberOfElements('.comment', $this->nbComments); + + // Try to post a new comment + $txtToAdd = Str::random(9); + $I->fillAddCommentForm($txtToAdd); + + // Assert that we have got an error + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeFormError('The content must be at least 10 characters.'); + + // The comment was not posted + $I->seeNumberOfElements('.comment', $this->nbComments); + $I->assertEquals($this->nbComments, Quote::find($this->quotes[0]->id)->total_comments); + } + + public function postATooLongCommentOnAQuote(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a comment too long on a quote'); + + // Go to the quote, verify that we have the right number of comments + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeNumberOfElements('.comment', $this->nbComments); + + // Try to post a new comment + $txtToAdd = Str::random(501); + $I->fillAddCommentForm($txtToAdd); + + // Assert that we have got an error + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeFormError('The content may not be greater than 500 characters.'); + + // The comment was not posted + $I->seeNumberOfElements('.comment', $this->nbComments); + $I->assertEquals($this->nbComments, Quote::find($this->quotes[0]->id)->total_comments); + } + + public function postACommentIsRequired(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('leave an empty comment on a quote'); + + // Go to the quote, verify that we have the right number of comments + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeNumberOfElements('.comment', $this->nbComments); + + // Try to post a new comment + $I->fillAddCommentForm(''); + + // Assert that we have got an error + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeFormError('The content field is required.'); + + // The comment was not posted + $I->seeNumberOfElements('.comment', $this->nbComments); + $I->assertEquals($this->nbComments, Quote::find($this->quotes[0]->id)->total_comments); + } +} diff --git a/tests/functional/Comment/DeleteCommentCest.php b/tests/functional/Comment/DeleteCommentCest.php index 53529ffd..7be9bbb0 100644 --- a/tests/functional/Comment/DeleteCommentCest.php +++ b/tests/functional/Comment/DeleteCommentCest.php @@ -2,87 +2,90 @@ use TeenQuotes\Quotes\Models\Quote; -class DeleteCommentCest { - - /** - * The number of comments to add of the first quote. - * The last comment is posted by the logged in user. - * @var integer - */ - private $nbComments = 5; - - /** - * The created quotes - * @var array - */ - private $quotes; - - /** - * The logged in user - * @var \TeenQuotes\Users\Models\User - */ - private $user; - - public function _before(FunctionalTester $I) - { - $this->user = $I->logANewUser(); - $this->quotes = $I->createSomePublishedQuotes(); - - // Insert some comments, the last one should have been written by the logged in user - $I->insertInDatabase($this->nbComments - 1, 'Comment', ['quote_id' => $this->quotes[0]->id]); - $I->insertInDatabase(1, 'Comment', ['quote_id' => $this->quotes[0]->id, 'user_id' => $this->user->id]); - } - - public function deleteACommentOnAQuote(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("delete a comment on a quote"); - - // Go to the quote, verify that we have the right number of comments - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeNumberOfElements('.comment', $this->nbComments); - - // I see the delete button on my comment - $I->seeNumberOfElements('.controls-large i.fa-times', 1); - $I->seeElement('.comment[data-id='.$this->nbComments.'] .controls-large i.fa-times'); - - // Send the Ajax request to delete my comment - $I->sendAjaxDeleteRequest(URL::route('comments.destroy', $this->nbComments)); - - // The comment should be removed thanks to jQuery - // Go back to the page and verify that the comment has disappeared - $I->amOnRoute('quotes.show', $this->quotes[0]->id); - $I->seeNumberOfElements('.comment', $this->nbComments - 1); - $I->dontSeeElement('i.fa-times'); - $I->assertEquals(0, Auth::user()->getTotalComments()); - } - - public function deleteACommentFromMyProfile(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("delete a comment on a quote from my profile"); - - $I->navigateToMyProfile(); - // Should have been auto redirected to the comments section since - // we have no published quotes and no favorites - $I->seeCurrentRouteIs('users.show', [$this->user->login, 'comments']); - - // I see the delete button on my comment - $I->seeNumberOfElements('.comment', 1); - $I->seeNumberOfElements('.controls-large i.fa-times', 1); - $I->seeElement('.comment[data-id='.$this->nbComments.'] .controls-large i.fa-times'); - - // Send the Ajax request to delete my comment - $I->sendAjaxDeleteRequest(URL::route('comments.destroy', $this->nbComments)); - - // "Refresh" the page - $I->amOnRoute('users.show', [$this->user->login, 'comments']); - // Since we have no longer comments, we should see the welcome tutorial - $I->seeElement('#welcome-profile'); - - // Run assertions about the number of comments - $I->assertEquals(0, Auth::user()->getTotalComments()); - $I->dontSeeElement('.comment'); - $I->assertEquals($this->nbComments - 1, Quote::find($this->quotes[0]->id)->total_comments); - } -} \ No newline at end of file +class DeleteCommentCest +{ + /** + * The number of comments to add of the first quote. + * The last comment is posted by the logged in user. + * + * @var int + */ + private $nbComments = 5; + + /** + * The created quotes. + * + * @var array + */ + private $quotes; + + /** + * The logged in user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + public function _before(FunctionalTester $I) + { + $this->user = $I->logANewUser(); + $this->quotes = $I->createSomePublishedQuotes(); + + // Insert some comments, the last one should have been written by the logged in user + $I->insertInDatabase($this->nbComments - 1, 'Comment', ['quote_id' => $this->quotes[0]->id]); + $I->insertInDatabase(1, 'Comment', ['quote_id' => $this->quotes[0]->id, 'user_id' => $this->user->id]); + } + + public function deleteACommentOnAQuote(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('delete a comment on a quote'); + + // Go to the quote, verify that we have the right number of comments + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeNumberOfElements('.comment', $this->nbComments); + + // I see the delete button on my comment + $I->seeNumberOfElements('.controls-large i.fa-times', 1); + $I->seeElement('.comment[data-id='.$this->nbComments.'] .controls-large i.fa-times'); + + // Send the Ajax request to delete my comment + $I->sendAjaxDeleteRequest(URL::route('comments.destroy', $this->nbComments)); + + // The comment should be removed thanks to jQuery + // Go back to the page and verify that the comment has disappeared + $I->amOnRoute('quotes.show', $this->quotes[0]->id); + $I->seeNumberOfElements('.comment', $this->nbComments - 1); + $I->dontSeeElement('i.fa-times'); + $I->assertEquals(0, Auth::user()->getTotalComments()); + } + + public function deleteACommentFromMyProfile(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('delete a comment on a quote from my profile'); + + $I->navigateToMyProfile(); + // Should have been auto redirected to the comments section since + // we have no published quotes and no favorites + $I->seeCurrentRouteIs('users.show', [$this->user->login, 'comments']); + + // I see the delete button on my comment + $I->seeNumberOfElements('.comment', 1); + $I->seeNumberOfElements('.controls-large i.fa-times', 1); + $I->seeElement('.comment[data-id='.$this->nbComments.'] .controls-large i.fa-times'); + + // Send the Ajax request to delete my comment + $I->sendAjaxDeleteRequest(URL::route('comments.destroy', $this->nbComments)); + + // "Refresh" the page + $I->amOnRoute('users.show', [$this->user->login, 'comments']); + // Since we have no longer comments, we should see the welcome tutorial + $I->seeElement('#welcome-profile'); + + // Run assertions about the number of comments + $I->assertEquals(0, Auth::user()->getTotalComments()); + $I->dontSeeElement('.comment'); + $I->assertEquals($this->nbComments - 1, Quote::find($this->quotes[0]->id)->total_comments); + } +} diff --git a/tests/functional/Comment/EditCommentCest.php b/tests/functional/Comment/EditCommentCest.php index e475cb0a..da034c45 100644 --- a/tests/functional/Comment/EditCommentCest.php +++ b/tests/functional/Comment/EditCommentCest.php @@ -2,97 +2,100 @@ use TeenQuotes\Quotes\Models\Quote; -class EditCommentCest { - - /** - * The number of comments to add to the first quote - * @var integer - */ - private $nbComments = 5; - - /** - * The first quote that contains comments - * @var integer - */ - private $firstQuoteId; - - /** - * My comment - * @var \TeenQuotes\Comments\Models\Comment - */ - private $myComment; - - public function _before(FunctionalTester $I) - { - $u = $I->logANewUser(); - - // Create some quotes and add some comments to the first quote - $this->firstQuoteId = array_values($I->createSomePublishedQuotes())[0]->id; - $I->insertInDatabase($this->nbComments, 'Comment', ['quote_id' => $this->firstQuoteId]); - - // Create a comment posted by the user - $this->myComment = $I->insertInDatabase(1, 'Comment', ['quote_id' => $this->firstQuoteId, 'user_id' => $u->id]); - } - - public function editACommentFromAQuote(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("edit one of my comments from a quote page"); - - $newContent = Str::random(15); - - // Go to the quote, verify that I can edit my comment - $I->amOnRoute('quotes.show', $this->firstQuoteId); - $I->seeNumberOfElements('.controls-large a.edit-comment', 1); - $I->seeElement('.comment[data-id='.$this->myComment->id.'] a.edit-comment'); - - // Go to the edit comment page and fill the form - $this->goToTheEditFormForMyComment($I); - $I->fillEditCommentForm($newContent); - - // I am redirected back to the quote page - $I->seeCurrentRouteIs('quotes.show', $this->firstQuoteId); - // And the comment has got the new content - $I->see($newContent, '.comment[data-id='.$this->myComment->id.']'); - } - - public function editACommentFromAQuoteWithTooSmallContent(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("edit a comment with a too small content"); - - $newContent = Str::random(9); - $this->fillEditFormAndSeeFormError($I, $newContent, "The content must be at least 10 characters."); - } - - public function editACommentFromAQuoteWithTooLongContent(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("edit a comment with a too long content"); - - $newContent = Str::random(501); - $this->fillEditFormAndSeeFormError($I, $newContent, "The content may not be greater than 500 characters."); - } - - private function fillEditFormAndSeeFormError(FunctionalTester $I, $toFill, $expectedError) - { - $I->amOnRoute('quotes.show', $this->firstQuoteId); - - // Go to the edit comment page and fill the form - $this->goToTheEditFormForMyComment($I); - $I->fillEditCommentForm($toFill); - - // I am still on the form - $I->seeCurrentRouteIs('comments.edit', $this->myComment->id); - // And we have got a form error - $I->seeFormError($expectedError); - } - - private function goToTheEditFormForMyComment(FunctionalTester $I) - { - $I->click('.comment[data-id='.$this->myComment->id.'] a.edit-comment'); - $I->seeCurrentRouteIs('comments.edit', $this->myComment->id); - $I->see('Update my comment', 'h2'); - $I->seeInTitle('Update my comment'); - } -} \ No newline at end of file +class EditCommentCest +{ + /** + * The number of comments to add to the first quote. + * + * @var int + */ + private $nbComments = 5; + + /** + * The first quote that contains comments. + * + * @var int + */ + private $firstQuoteId; + + /** + * My comment. + * + * @var \TeenQuotes\Comments\Models\Comment + */ + private $myComment; + + public function _before(FunctionalTester $I) + { + $u = $I->logANewUser(); + + // Create some quotes and add some comments to the first quote + $this->firstQuoteId = array_values($I->createSomePublishedQuotes())[0]->id; + $I->insertInDatabase($this->nbComments, 'Comment', ['quote_id' => $this->firstQuoteId]); + + // Create a comment posted by the user + $this->myComment = $I->insertInDatabase(1, 'Comment', ['quote_id' => $this->firstQuoteId, 'user_id' => $u->id]); + } + + public function editACommentFromAQuote(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('edit one of my comments from a quote page'); + + $newContent = Str::random(15); + + // Go to the quote, verify that I can edit my comment + $I->amOnRoute('quotes.show', $this->firstQuoteId); + $I->seeNumberOfElements('.controls-large a.edit-comment', 1); + $I->seeElement('.comment[data-id='.$this->myComment->id.'] a.edit-comment'); + + // Go to the edit comment page and fill the form + $this->goToTheEditFormForMyComment($I); + $I->fillEditCommentForm($newContent); + + // I am redirected back to the quote page + $I->seeCurrentRouteIs('quotes.show', $this->firstQuoteId); + // And the comment has got the new content + $I->see($newContent, '.comment[data-id='.$this->myComment->id.']'); + } + + public function editACommentFromAQuoteWithTooSmallContent(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('edit a comment with a too small content'); + + $newContent = Str::random(9); + $this->fillEditFormAndSeeFormError($I, $newContent, 'The content must be at least 10 characters.'); + } + + public function editACommentFromAQuoteWithTooLongContent(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('edit a comment with a too long content'); + + $newContent = Str::random(501); + $this->fillEditFormAndSeeFormError($I, $newContent, 'The content may not be greater than 500 characters.'); + } + + private function fillEditFormAndSeeFormError(FunctionalTester $I, $toFill, $expectedError) + { + $I->amOnRoute('quotes.show', $this->firstQuoteId); + + // Go to the edit comment page and fill the form + $this->goToTheEditFormForMyComment($I); + $I->fillEditCommentForm($toFill); + + // I am still on the form + $I->seeCurrentRouteIs('comments.edit', $this->myComment->id); + // And we have got a form error + $I->seeFormError($expectedError); + } + + private function goToTheEditFormForMyComment(FunctionalTester $I) + { + $I->click('.comment[data-id='.$this->myComment->id.'] a.edit-comment'); + $I->seeCurrentRouteIs('comments.edit', $this->myComment->id); + $I->see('Update my comment', 'h2'); + $I->seeInTitle('Update my comment'); + } +} diff --git a/tests/functional/FavoriteQuote/AddFavoriteCest.php b/tests/functional/FavoriteQuote/AddFavoriteCest.php index bf304821..20626ffc 100644 --- a/tests/functional/FavoriteQuote/AddFavoriteCest.php +++ b/tests/functional/FavoriteQuote/AddFavoriteCest.php @@ -1,72 +1,74 @@ createSomePublishedQuotes(); - - // Create a new user and a fresh published quote - $this->user = $I->logANewUser(); - $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); - } - - public function addAQuoteToFavorite(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a quote to my favorites"); - - $this->goToFirstQuote($I); - - // I can add the quote to my favorites - $I->seeElement('.quote i.fa-heart-o'); - $I->assertEquals(0, $this->firstQuote->total_favorites); - $I->assertFalse($this->firstQuote->isFavoriteForCurrentUser()); - - // Add the quote to my favorites - $I->sendAjaxPostRequest(URL::route('favorite', $this->firstQuote->id)); - - // Run our assertions - $I->assertEquals(1, $this->firstQuote->total_favorites); - $I->assertTrue($this->firstQuote->isFavoriteForCurrentUser()); - - // Check that the single quote shows that the quote is in my favorites - $I->amOnRoute('quotes.show', $this->firstQuote->id); - $I->dontSeeElement('.quote .favorite-action i.fa-heart-o'); - $I->seeElement('.quote .favorite-action i.fa-heart'); - } - - public function iCanNotAddAQuoteToMyFavoritesAsAGuest(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("verify that I can't add a quote to my favorites"); - - $I->logout(); - - $this->goToFirstQuote($I); - // Verify that we don't have any heart displayed - $I->dontSeeElement('.quote .favorite-action i.fa-heart-o'); - $I->dontSeeElement('.quote .favorite-action i.fa-heart'); - } - - private function goToFirstQuote(FunctionalTester $I) - { - $I->amOnRoute('home'); - - // Go to the single quote page - $I->click('#'.$this->firstQuote->id); - $I->seeCurrentRouteIs('quotes.show', $this->firstQuote->id); - } -} \ No newline at end of file +class AddFavoriteCest +{ + /** + * The logged in user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + /** + * The first quote on the first page. + * + * @var \TeenQuotes\Quotes\Models\Quote + */ + private $firstQuote; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + + // Create a new user and a fresh published quote + $this->user = $I->logANewUser(); + $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); + } + + public function addAQuoteToFavorite(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a quote to my favorites'); + + $this->goToFirstQuote($I); + + // I can add the quote to my favorites + $I->seeElement('.quote i.fa-heart-o'); + $I->assertEquals(0, $this->firstQuote->total_favorites); + $I->assertFalse($this->firstQuote->isFavoriteForCurrentUser()); + + // Add the quote to my favorites + $I->sendAjaxPostRequest(URL::route('favorite', $this->firstQuote->id)); + + // Run our assertions + $I->assertEquals(1, $this->firstQuote->total_favorites); + $I->assertTrue($this->firstQuote->isFavoriteForCurrentUser()); + + // Check that the single quote shows that the quote is in my favorites + $I->amOnRoute('quotes.show', $this->firstQuote->id); + $I->dontSeeElement('.quote .favorite-action i.fa-heart-o'); + $I->seeElement('.quote .favorite-action i.fa-heart'); + } + + public function iCanNotAddAQuoteToMyFavoritesAsAGuest(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo("verify that I can't add a quote to my favorites"); + + $I->logout(); + + $this->goToFirstQuote($I); + // Verify that we don't have any heart displayed + $I->dontSeeElement('.quote .favorite-action i.fa-heart-o'); + $I->dontSeeElement('.quote .favorite-action i.fa-heart'); + } + + private function goToFirstQuote(FunctionalTester $I) + { + $I->amOnRoute('home'); + + // Go to the single quote page + $I->click('#'.$this->firstQuote->id); + $I->seeCurrentRouteIs('quotes.show', $this->firstQuote->id); + } +} diff --git a/tests/functional/FavoriteQuote/DeleteFavoriteCest.php b/tests/functional/FavoriteQuote/DeleteFavoriteCest.php index fcc51359..f1d3ad73 100644 --- a/tests/functional/FavoriteQuote/DeleteFavoriteCest.php +++ b/tests/functional/FavoriteQuote/DeleteFavoriteCest.php @@ -1,64 +1,66 @@ createSomePublishedQuotes(); - public function _before(FunctionalTester $I) - { - $I->createSomePublishedQuotes(); + // Create a new user and a fresh published quote + $this->user = $I->logANewUser(); + $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); - // Create a new user and a fresh published quote - $this->user = $I->logANewUser(); - $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); + // Add to the user's favorites the first quote + $I->addAFavoriteForUser($this->firstQuote->id, $this->user->id); + } - // Add to the user's favorites the first quote - $I->addAFavoriteForUser($this->firstQuote->id, $this->user->id); - } + public function addAQuoteToFavorite(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('remove a quote from my favorites'); - public function addAQuoteToFavorite(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("remove a quote from my favorites"); + $this->goToFirstQuote($I); - $this->goToFirstQuote($I); + // The quote is in my favorites + $I->seeElement('.quote i.fa-heart'); + $I->assertEquals(1, $this->firstQuote->total_favorites); + $I->assertTrue($this->firstQuote->isFavoriteForCurrentUser()); + $I->assertEquals([$this->firstQuote->id], $this->user->quotesFavorited()); - // The quote is in my favorites - $I->seeElement('.quote i.fa-heart'); - $I->assertEquals(1, $this->firstQuote->total_favorites); - $I->assertTrue($this->firstQuote->isFavoriteForCurrentUser()); - $I->assertEquals([$this->firstQuote->id], $this->user->quotesFavorited()); + // Remove the quote from my favorites + $I->sendAjaxPostRequest(URL::route('unfavorite', $this->firstQuote->id)); - // Remove the quote from my favorites - $I->sendAjaxPostRequest(URL::route('unfavorite', $this->firstQuote->id)); + // Run our assertions + $I->assertEquals(0, $this->firstQuote->total_favorites); + $I->assertFalse($this->firstQuote->isFavoriteForCurrentUser()); + $I->assertEquals([], $this->user->quotesFavorited()); - // Run our assertions - $I->assertEquals(0, $this->firstQuote->total_favorites); - $I->assertFalse($this->firstQuote->isFavoriteForCurrentUser()); - $I->assertEquals([], $this->user->quotesFavorited()); + // Check that the single quote offers me to add the quote to my favorites + $I->amOnRoute('quotes.show', $this->firstQuote->id); + $I->seeElement('.quote i.fa-heart-o'); + $I->dontSeeElement('.quote i.fa-heart'); + } - // Check that the single quote offers me to add the quote to my favorites - $I->amOnRoute('quotes.show', $this->firstQuote->id); - $I->seeElement('.quote i.fa-heart-o'); - $I->dontSeeElement('.quote i.fa-heart'); - } + private function goToFirstQuote(FunctionalTester $I) + { + $I->amOnRoute('home'); - private function goToFirstQuote(FunctionalTester $I) - { - $I->amOnRoute('home'); - - // Go to the single quote page - $I->click('#'.$this->firstQuote->id); - $I->seeCurrentRouteIs('quotes.show', $this->firstQuote->id); - } -} \ No newline at end of file + // Go to the single quote page + $I->click('#'.$this->firstQuote->id); + $I->seeCurrentRouteIs('quotes.show', $this->firstQuote->id); + } +} diff --git a/tests/functional/Quote/AddQuoteCest.php b/tests/functional/Quote/AddQuoteCest.php index cf864b41..1741df4e 100644 --- a/tests/functional/Quote/AddQuoteCest.php +++ b/tests/functional/Quote/AddQuoteCest.php @@ -1,53 +1,54 @@ logANewUser(); - $I->createSomePublishedQuotes(); - } - - public function submitAQuote(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("submit a new quote"); - - $I->submitANewQuote(); - } - - public function submitTooMuchQuotes(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("submit too much quotes for today"); - - // Submit the maximum allowed number of quotes per day - for ($i = 1; $i <= $this->maxPublishQuotesPerDay(); $i++) - $I->submitANewQuote(); - - // Try to add another quote, we should exceed the quota - $I->cantSubmitANewQuote(); - } - - public function aGuestShouldBeRedirectedToTheSigninPage(FunctionalTester $I) - { - $I->am('a guest'); - $I->wantTo("submit a new quote as a guest"); - - $I->logout(); - - // Navigate to the "add your quote" page - $I->amOnRoute('home'); - $I->click('Add your quote'); - - // Assert that I should be redirected to the signin / signup page - $I->amOnRoute('signin'); - // With a friendly message :) - $I->see('Before adding a quote, you need to be logged in.', "#addquote-warning"); - } - - private function maxPublishQuotesPerDay() - { - return Config::get('app.quotes.maxSubmitPerDay'); - } -} \ No newline at end of file +class AddQuoteCest +{ + public function _before(FunctionalTester $I) + { + $I->logANewUser(); + $I->createSomePublishedQuotes(); + } + + public function submitAQuote(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('submit a new quote'); + + $I->submitANewQuote(); + } + + public function submitTooMuchQuotes(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('submit too much quotes for today'); + + // Submit the maximum allowed number of quotes per day + for ($i = 1; $i <= $this->maxPublishQuotesPerDay(); $i++) { + $I->submitANewQuote(); + } + + // Try to add another quote, we should exceed the quota + $I->cantSubmitANewQuote(); + } + + public function aGuestShouldBeRedirectedToTheSigninPage(FunctionalTester $I) + { + $I->am('a guest'); + $I->wantTo('submit a new quote as a guest'); + + $I->logout(); + + // Navigate to the "add your quote" page + $I->amOnRoute('home'); + $I->click('Add your quote'); + + // Assert that I should be redirected to the signin / signup page + $I->amOnRoute('signin'); + // With a friendly message :) + $I->see('Before adding a quote, you need to be logged in.', '#addquote-warning'); + } + + private function maxPublishQuotesPerDay() + { + return Config::get('app.quotes.maxSubmitPerDay'); + } +} diff --git a/tests/functional/Quote/IndexQuotesCest.php b/tests/functional/Quote/IndexQuotesCest.php index ff7f622c..188e7b98 100644 --- a/tests/functional/Quote/IndexQuotesCest.php +++ b/tests/functional/Quote/IndexQuotesCest.php @@ -1,100 +1,102 @@ createSomePublishedQuotes(['nb_quotes' => $I->getTotalNumberOfQuotesToCreate()]); - - // Create a new user, a fresh published quote and some comments to it - $this->user = $I->logANewUser(); - $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); - $I->insertInDatabase($I->getNbComments(), 'Comment', ['quote_id' => $this->firstQuote->id]); - } - - public function browseLastQuotesOnHomepage(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("browse last quotes"); - - // Try the homepage - $I->amOnRoute('home'); - $this->assertPageOfQuotesContainsRequiredElements($I); - } - - public function browseLastRandomQuotes(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("browse last random quotes"); - - // Try the random page - $I->amOnRoute('home'); - $I->click('Random quotes', '.navbar'); - $this->assertPageOfQuotesContainsRequiredElements($I); - } - - public function checkCommentsAndFavoritesAreSet(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("view comments and favorites on last quotes"); - - // Add to the user's favorites the first quote - $I->addAFavoriteForUser($this->firstQuote->id, $this->user->id); - - // Go to the homepage - $I->amOnRoute('home'); - - // Assert that the number of comments is displayed - $I->see($I->getNbComments().' comments', '.color-1'); - // Assert that the quote is marked as favorited - $I->seeElement('.color-1 i.fa-heart'); - // Assert that the author of the quote is displayed - $I->see($this->user->login, '.color-1 .link-author-profile'); - - // I can view my profile when clicking on the author of a quote - $I->click('.color-1 .link-author-profile'); - $I->seeCurrentRouteIs('users.show', $this->user->login); - } - - private function assertPageOfQuotesContainsRequiredElements(FunctionalTester $I) - { - $I->seeNumberOfElements('.quote', $I->getNbQuotesPerPage()); - - for ($i = 1; $i <= $I->getNbQuotesPerPage(); $i++) - { - // Verify that we have got our quotes with different colors - $I->seeElement('.color-'.$i); - - // All of them are not in my favorites - $I->seeElement('.color-'.$i.' .favorite-action i.fa-heart-o'); - - // All of them contain social media buttons - $I->seeElement('.color-'.$i.' i.fa-facebook'); - $I->seeElement('.color-'.$i.' i.fa-twitter'); - } - - // I am on the first page - $I->see('1', '#paginator-quotes ul li.active'); - - // I can see that we have got our links to pages - for ($i = 2; $i <= $I->getNbPagesToCreate(); $i++) - $I->see($i, '#paginator-quotes li a'); - - // Go to the second page and check that the page - // parameter has been set in the URL - $I->click('2', '#paginator-quotes li a'); - $I->seeCurrentUrlMatches('#page=2#'); - } -} \ No newline at end of file +class IndexQuotesCest +{ + /** + * The logged in user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + /** + * The first quote on the first page. + * + * @var \TeenQuotes\Quotes\Models\Quote + */ + private $firstQuote; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(['nb_quotes' => $I->getTotalNumberOfQuotesToCreate()]); + + // Create a new user, a fresh published quote and some comments to it + $this->user = $I->logANewUser(); + $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); + $I->insertInDatabase($I->getNbComments(), 'Comment', ['quote_id' => $this->firstQuote->id]); + } + + public function browseLastQuotesOnHomepage(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('browse last quotes'); + + // Try the homepage + $I->amOnRoute('home'); + $this->assertPageOfQuotesContainsRequiredElements($I); + } + + public function browseLastRandomQuotes(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('browse last random quotes'); + + // Try the random page + $I->amOnRoute('home'); + $I->click('Random quotes', '.navbar'); + $this->assertPageOfQuotesContainsRequiredElements($I); + } + + public function checkCommentsAndFavoritesAreSet(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('view comments and favorites on last quotes'); + + // Add to the user's favorites the first quote + $I->addAFavoriteForUser($this->firstQuote->id, $this->user->id); + + // Go to the homepage + $I->amOnRoute('home'); + + // Assert that the number of comments is displayed + $I->see($I->getNbComments().' comments', '.color-1'); + // Assert that the quote is marked as favorited + $I->seeElement('.color-1 i.fa-heart'); + // Assert that the author of the quote is displayed + $I->see($this->user->login, '.color-1 .link-author-profile'); + + // I can view my profile when clicking on the author of a quote + $I->click('.color-1 .link-author-profile'); + $I->seeCurrentRouteIs('users.show', $this->user->login); + } + + private function assertPageOfQuotesContainsRequiredElements(FunctionalTester $I) + { + $I->seeNumberOfElements('.quote', $I->getNbQuotesPerPage()); + + for ($i = 1; $i <= $I->getNbQuotesPerPage(); $i++) { + // Verify that we have got our quotes with different colors + $I->seeElement('.color-'.$i); + + // All of them are not in my favorites + $I->seeElement('.color-'.$i.' .favorite-action i.fa-heart-o'); + + // All of them contain social media buttons + $I->seeElement('.color-'.$i.' i.fa-facebook'); + $I->seeElement('.color-'.$i.' i.fa-twitter'); + } + + // I am on the first page + $I->see('1', '#paginator-quotes ul li.active'); + + // I can see that we have got our links to pages + for ($i = 2; $i <= $I->getNbPagesToCreate(); $i++) { + $I->see($i, '#paginator-quotes li a'); + } + + // Go to the second page and check that the page + // parameter has been set in the URL + $I->click('2', '#paginator-quotes li a'); + $I->seeCurrentUrlMatches('#page=2#'); + } +} diff --git a/tests/functional/Quote/ShowQuoteCest.php b/tests/functional/Quote/ShowQuoteCest.php index 0e7007a8..ea4b3b2d 100644 --- a/tests/functional/Quote/ShowQuoteCest.php +++ b/tests/functional/Quote/ShowQuoteCest.php @@ -1,90 +1,92 @@ createSomePublishedQuotes(['nb_quotes' => $I->getTotalNumberOfQuotesToCreate()]); - - // Create a new user, a fresh published quote - $this->user = $I->logANewUser(); - $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); - - // Add some comments to the quote - $I->insertInDatabase($I->getNbComments(), 'Comment', ['quote_id' => $this->firstQuote->id]); - - // Associate a tag to the quote - $tagRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); - $loveTag = $tagRepo->create('love'); - $tagRepo->tagQuote($this->firstQuote, $loveTag); - - // Add to the user's favorites the first quote - $I->addAFavoriteForUser($this->firstQuote->id, $this->user->id); - } - - public function browseAQuoteWhenLoggedIn(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("browse a quote when logged in"); - - $this->assertSingleQuoteContainsRequiredInformation($I); - - // The quote is in my favorites - $I->seeElement('.quote .favorite-action i.fa-heart'); - - // I can add a comment - $I->seeElement('form.form-horizontal'); - } - - public function browseAQuoteWhenNotLoggedIn(FunctionalTester $I) - { - $I->am('a guest'); - $I->wantTo("browse a quote as a guest"); - - $I->performLogoutFlow(); - $this->assertSingleQuoteContainsRequiredInformation($I); - - // It offers me to log in / sign up - $I->see('I have an account!'); - $I->see('I want an account!'); - - // The quote is not in my favorites - $I->dontSeeElement('.quote .favorite-action i.fa-heart'); - - // I can't add a comment - $I->dontSeeElement('form.form-horizontal'); - } - - private function assertSingleQuoteContainsRequiredInformation(FunctionalTester $I) - { - $I->amOnRoute('home'); - - // Go to the single quote page - $I->click('#'.$this->firstQuote->id); - $I->seeCurrentRouteIs('quotes.show', $this->firstQuote->id); - $I->seeInTitle('Quote #'.$this->firstQuote->id); - - // We have got the right number of comments - $I->see($I->getNbComments(). ' comments', '.quote'); - $I->seeNumberOfElements('.comment', $I->getNbComments()); - - // We see the love tag - $I->seeNumberOfElements('.quotes__tags-tag', 1); - $I->see('#Love', '.quotes__tags-tag'); - - // The favorites info text - $I->see($this->user->login.' favorited this quote.', '.favorites-info'); - } -} \ No newline at end of file +class ShowQuoteCest +{ + /** + * The logged in user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + /** + * The first quote on the first page. + * + * @var \TeenQuotes\Quotes\Models\Quote + */ + private $firstQuote; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(['nb_quotes' => $I->getTotalNumberOfQuotesToCreate()]); + + // Create a new user, a fresh published quote + $this->user = $I->logANewUser(); + $this->firstQuote = $I->insertInDatabase(1, 'Quote', ['created_at' => Carbon::now()->addMonth(), 'user_id' => $this->user->id]); + + // Add some comments to the quote + $I->insertInDatabase($I->getNbComments(), 'Comment', ['quote_id' => $this->firstQuote->id]); + + // Associate a tag to the quote + $tagRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); + $loveTag = $tagRepo->create('love'); + $tagRepo->tagQuote($this->firstQuote, $loveTag); + + // Add to the user's favorites the first quote + $I->addAFavoriteForUser($this->firstQuote->id, $this->user->id); + } + + public function browseAQuoteWhenLoggedIn(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('browse a quote when logged in'); + + $this->assertSingleQuoteContainsRequiredInformation($I); + + // The quote is in my favorites + $I->seeElement('.quote .favorite-action i.fa-heart'); + + // I can add a comment + $I->seeElement('form.form-horizontal'); + } + + public function browseAQuoteWhenNotLoggedIn(FunctionalTester $I) + { + $I->am('a guest'); + $I->wantTo('browse a quote as a guest'); + + $I->performLogoutFlow(); + $this->assertSingleQuoteContainsRequiredInformation($I); + + // It offers me to log in / sign up + $I->see('I have an account!'); + $I->see('I want an account!'); + + // The quote is not in my favorites + $I->dontSeeElement('.quote .favorite-action i.fa-heart'); + + // I can't add a comment + $I->dontSeeElement('form.form-horizontal'); + } + + private function assertSingleQuoteContainsRequiredInformation(FunctionalTester $I) + { + $I->amOnRoute('home'); + + // Go to the single quote page + $I->click('#'.$this->firstQuote->id); + $I->seeCurrentRouteIs('quotes.show', $this->firstQuote->id); + $I->seeInTitle('Quote #'.$this->firstQuote->id); + + // We have got the right number of comments + $I->see($I->getNbComments().' comments', '.quote'); + $I->seeNumberOfElements('.comment', $I->getNbComments()); + + // We see the love tag + $I->seeNumberOfElements('.quotes__tags-tag', 1); + $I->see('#Love', '.quotes__tags-tag'); + + // The favorites info text + $I->see($this->user->login.' favorited this quote.', '.favorites-info'); + } +} diff --git a/tests/functional/Story/AddStoryCest.php b/tests/functional/Story/AddStoryCest.php index ce367760..27eedc74 100644 --- a/tests/functional/Story/AddStoryCest.php +++ b/tests/functional/Story/AddStoryCest.php @@ -1,94 +1,97 @@ createSomePublishedQuotes(); - $I->createSomeStories(); - - // Create a new user - $this->user = $I->logANewUser(); - $I->navigateToTheStoryPage(); - } - - public function addStorySuccess(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add successfully my story"); - - // Post a story - list($represent, $frequence) = $this->postStory($I, 200, 200); - - // Assert story has been posted - $I->seeSuccessFlashMessage('Your story has been added '.$this->user->login); - $I->see($represent, '.story'); - $I->see($frequence, '.story'); - } - - public function tooSmallRepresentAndFrequence(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a story with a too small content"); - - $this->postStory($I, 99, 99); - - $I->seeFormError('The represent txt must be at least 100 characters.'); - $I->seeFormError('The frequence txt must be at least 100 characters.'); - } - - public function tooLargeRepresentAndFrequence(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a story with a too large content"); - - $this->postStory($I, 1001, 1001); - - $I->seeFormError('The represent txt may not be greater than 1000 characters.'); - $I->seeFormError('The frequence txt may not be greater than 1000 characters.'); - } - - public function noContentAdded(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("add a story with no content"); - - $this->postStory($I, 0, 0); - - $I->seeFormError('The represent txt field is required.'); - $I->seeFormError('The frequence txt field is required.'); - } - - public function seeWarningWhenLoggedOut(FunctionalTester $I) - { - $I->am('a visitor of Teen Quotes'); - $I->wantTo("add a story"); - - $I->logout(); - - $I->navigateToTheStoryPage(); - $I->see('You must be logged in if you want to add your story'); - } - - private function postStory(FunctionalTester $I, $representLength, $frequenceLength) - { - $represent = ''; - $frequence = ''; - - if ($representLength > 0) - $represent = Str::random($representLength); - if ($frequenceLength > 0) - $frequence = Str::random($frequenceLength); - - $I->fillStoryForm($represent, $frequence); - - return [$represent, $frequence]; - } -} \ No newline at end of file +class AddStoryCest +{ + /** + * The logged in user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + public function _before(FunctionalTester $I) + { + // Create some published quotes and some stories + $I->createSomePublishedQuotes(); + $I->createSomeStories(); + + // Create a new user + $this->user = $I->logANewUser(); + $I->navigateToTheStoryPage(); + } + + public function addStorySuccess(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add successfully my story'); + + // Post a story + list($represent, $frequence) = $this->postStory($I, 200, 200); + + // Assert story has been posted + $I->seeSuccessFlashMessage('Your story has been added '.$this->user->login); + $I->see($represent, '.story'); + $I->see($frequence, '.story'); + } + + public function tooSmallRepresentAndFrequence(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a story with a too small content'); + + $this->postStory($I, 99, 99); + + $I->seeFormError('The represent txt must be at least 100 characters.'); + $I->seeFormError('The frequence txt must be at least 100 characters.'); + } + + public function tooLargeRepresentAndFrequence(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a story with a too large content'); + + $this->postStory($I, 1001, 1001); + + $I->seeFormError('The represent txt may not be greater than 1000 characters.'); + $I->seeFormError('The frequence txt may not be greater than 1000 characters.'); + } + + public function noContentAdded(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('add a story with no content'); + + $this->postStory($I, 0, 0); + + $I->seeFormError('The represent txt field is required.'); + $I->seeFormError('The frequence txt field is required.'); + } + + public function seeWarningWhenLoggedOut(FunctionalTester $I) + { + $I->am('a visitor of Teen Quotes'); + $I->wantTo('add a story'); + + $I->logout(); + + $I->navigateToTheStoryPage(); + $I->see('You must be logged in if you want to add your story'); + } + + private function postStory(FunctionalTester $I, $representLength, $frequenceLength) + { + $represent = ''; + $frequence = ''; + + if ($representLength > 0) { + $represent = Str::random($representLength); + } + if ($frequenceLength > 0) { + $frequence = Str::random($frequenceLength); + } + + $I->fillStoryForm($represent, $frequence); + + return [$represent, $frequence]; + } +} diff --git a/tests/functional/Story/IndexStoriesCest.php b/tests/functional/Story/IndexStoriesCest.php index 7d4b7b79..ae96107d 100644 --- a/tests/functional/Story/IndexStoriesCest.php +++ b/tests/functional/Story/IndexStoriesCest.php @@ -1,64 +1,65 @@ createSomePublishedQuotes(); + $I->createSomeStories(); - public function _before(FunctionalTester $I) - { - // Create some published quotes and some stories - $I->createSomePublishedQuotes(); - $I->createSomeStories(); + // Create a new user + $this->user = $I->logANewUser(); + $I->navigateToTheStoryPage(); + } - // Create a new user - $this->user = $I->logANewUser(); - $I->navigateToTheStoryPage(); - } + public function browseLastStories(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('browse last stories'); - public function browseLastStories(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("browse last stories"); + $this->assertPageOfStoriesContainsRequiredElements($I); + } - $this->assertPageOfStoriesContainsRequiredElements($I); - } + private function assertPageOfStoriesContainsRequiredElements(FunctionalTester $I) + { + $I->seeNumberOfElements('.story', $I->getNbStoriesPerPage()); - private function assertPageOfStoriesContainsRequiredElements(FunctionalTester $I) - { - $I->seeNumberOfElements('.story', $I->getNbStoriesPerPage()); + // Start with the ID of the story on the first page + $id = 1; - // Start with the ID of the story on the first page - $id = 1; + for ($i = 1; $i <= $I->getNbStoriesPerPage(); $i++) { + // Avatar of the author of the story + $I->seeElement('.story[data-id="'.$id.'"] img.avatar'); + // Date of the story + $I->seeElement('.story[data-id="'.$id.'"] .story-date'); + // Link to the single story + $I->seeElement('.story[data-id="'.$id.'"] .story-id a'); - for ($i = 1; $i <= $I->getNbStoriesPerPage(); $i++) - { - // Avatar of the author of the story - $I->seeElement('.story[data-id="'.$id.'"] img.avatar'); - // Date of the story - $I->seeElement('.story[data-id="'.$id.'"] .story-date'); - // Link to the single story - $I->seeElement('.story[data-id="'.$id.'"] .story-id a'); + $id++; + } - $id++; - } + // I am on the first page + $I->see('1', 'ul.pagination li.active'); - // I am on the first page - $I->see('1', 'ul.pagination li.active'); + // I can see that we have got our links to pages + for ($i = 2; $i <= $I->getNbPagesToCreate(); $i++) { + $I->see($i, 'ul.pagination li a'); + } - // I can see that we have got our links to pages - for ($i = 2; $i <= $I->getNbPagesToCreate(); $i++) - $I->see($i, 'ul.pagination li a'); + // Go to the second page + $I->click('2', 'ul.pagination li a'); - // Go to the second page - $I->click('2', 'ul.pagination li a'); - - // Check that the page parameter has been set in the URL - // and the paginator has been updated - $I->seeCurrentUrlMatches('#page=2#'); - $I->see('2', 'ul.pagination li.active'); - } -} \ No newline at end of file + // Check that the page parameter has been set in the URL + // and the paginator has been updated + $I->seeCurrentUrlMatches('#page=2#'); + $I->see('2', 'ul.pagination li.active'); + } +} diff --git a/tests/functional/Story/ShowStoryCest.php b/tests/functional/Story/ShowStoryCest.php index a70fe32a..d4413e57 100644 --- a/tests/functional/Story/ShowStoryCest.php +++ b/tests/functional/Story/ShowStoryCest.php @@ -1,80 +1,82 @@ createSomePublishedQuotes(); - $I->createSomeStories(); - - // Create a new user - $this->user = $I->logANewUser(); - - // Create a hidden story - $this->hiddenStory = $I->createAStoryWithHiddenUser(); - - $I->navigateToTheStoryPage(); - } - - public function browseHiddenStory(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("browse a story with a hidden user"); - - $I->click('#'.$this->hiddenStory->id); - $I->seeCurrentRouteIs('story.show', $this->hiddenStory->id); - - // I don't see a link to the author's profile in the title - $I->dontSeeElement('.story[data-id="'.$this->hiddenStory->id.'"] h3 a.author-link'); - $I->seeElement('.story[data-id="'.$this->hiddenStory->id.'"] h3'); - - // I don't see a link to the author's profile on its avatar - $I->dontSeeElement('.story[data-id="'.$this->hiddenStory->id.'"] a img.avatar'); - $I->seeElement('.story[data-id="'.$this->hiddenStory->id.'"] img.avatar'); - - $this->seeStoryDisplaysRequiredInformation($I, $this->hiddenStory->id); - } - - public function browseRegularStory(FunctionalTester $I) - { - $I->am('a member of Teen Quotes'); - $I->wantTo("browse a story"); - - $id = 1; - - $I->click('#'.$id); - $I->seeCurrentRouteIs('story.show', $id); - - // I see a link to the author's profile in the title - $I->seeElement('.story[data-id="'.$id.'"] h3 a.author-link'); - - // I see a link to the author's profile on its avatar - $I->seeElement('.story[data-id="'.$id.'"] a img.avatar'); - - $this->seeStoryDisplaysRequiredInformation($I, $id); - } - - private function seeStoryDisplaysRequiredInformation(FunctionalTester $I, $id) - { - $I->seeElement('.story[data-id="'.$id.'"] .story-date'); - $I->seeElement('.story[data-id="'.$id.'"] .story-id'); - - $I->see('Tell us your story', '.story[data-id="'.$id.'"]'); - $I->see('Tell us how you use', '.story[data-id="'.$id.'"]'); - - $I->see('Go back'); - } -} \ No newline at end of file +class ShowStoryCest +{ + /** + * The logged in user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + /** + * The hidden story. + * + * @var \TeenQuotes\Stories\Models\Story + */ + private $hiddenStory; + + public function _before(FunctionalTester $I) + { + // Create some published quotes and some stories + $I->createSomePublishedQuotes(); + $I->createSomeStories(); + + // Create a new user + $this->user = $I->logANewUser(); + + // Create a hidden story + $this->hiddenStory = $I->createAStoryWithHiddenUser(); + + $I->navigateToTheStoryPage(); + } + + public function browseHiddenStory(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('browse a story with a hidden user'); + + $I->click('#'.$this->hiddenStory->id); + $I->seeCurrentRouteIs('story.show', $this->hiddenStory->id); + + // I don't see a link to the author's profile in the title + $I->dontSeeElement('.story[data-id="'.$this->hiddenStory->id.'"] h3 a.author-link'); + $I->seeElement('.story[data-id="'.$this->hiddenStory->id.'"] h3'); + + // I don't see a link to the author's profile on its avatar + $I->dontSeeElement('.story[data-id="'.$this->hiddenStory->id.'"] a img.avatar'); + $I->seeElement('.story[data-id="'.$this->hiddenStory->id.'"] img.avatar'); + + $this->seeStoryDisplaysRequiredInformation($I, $this->hiddenStory->id); + } + + public function browseRegularStory(FunctionalTester $I) + { + $I->am('a member of Teen Quotes'); + $I->wantTo('browse a story'); + + $id = 1; + + $I->click('#'.$id); + $I->seeCurrentRouteIs('story.show', $id); + + // I see a link to the author's profile in the title + $I->seeElement('.story[data-id="'.$id.'"] h3 a.author-link'); + + // I see a link to the author's profile on its avatar + $I->seeElement('.story[data-id="'.$id.'"] a img.avatar'); + + $this->seeStoryDisplaysRequiredInformation($I, $id); + } + + private function seeStoryDisplaysRequiredInformation(FunctionalTester $I, $id) + { + $I->seeElement('.story[data-id="'.$id.'"] .story-date'); + $I->seeElement('.story[data-id="'.$id.'"] .story-id'); + + $I->see('Tell us your story', '.story[data-id="'.$id.'"]'); + $I->see('Tell us how you use', '.story[data-id="'.$id.'"]'); + + $I->see('Go back'); + } +} diff --git a/tests/functional/User/DeleteAccountCest.php b/tests/functional/User/DeleteAccountCest.php index b93461d3..21e54bcd 100644 --- a/tests/functional/User/DeleteAccountCest.php +++ b/tests/functional/User/DeleteAccountCest.php @@ -1,48 +1,50 @@ createSomePublishedQuotes(); - - $I->signIn($this->userLogin, $this->userPassword); - } - - public function deleteMyAccount(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('delete my account'); - - $I->navigateToMyEditProfilePage(); - - $I->fillDeleteAccountForm($this->userPassword, "DELETE"); - - $I->dontSeeRecord('users', ['login' => $this->userLogin]); - $I->seeSuccessFlashMessage('Your account has been deleted successfully'); - } - - public function deleteMyAccountWithWrongConfirmation(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('delete my account with a wrong confirmation'); - - $I->navigateToMyEditProfilePage(); - - $I->fillDeleteAccountForm($this->userPassword, "foo"); - - $I->seeFormError('You need to write "DELETE" here'); - } -} \ No newline at end of file +class DeleteAccountCest +{ + /** + * The user's login. + * + * @var string + */ + private $userLogin = 'foobar'; + + /** + * The user's password. + * + * @var string + */ + private $userPassword = 'azerty22'; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + + $I->signIn($this->userLogin, $this->userPassword); + } + + public function deleteMyAccount(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('delete my account'); + + $I->navigateToMyEditProfilePage(); + + $I->fillDeleteAccountForm($this->userPassword, 'DELETE'); + + $I->dontSeeRecord('users', ['login' => $this->userLogin]); + $I->seeSuccessFlashMessage('Your account has been deleted successfully'); + } + + public function deleteMyAccountWithWrongConfirmation(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('delete my account with a wrong confirmation'); + + $I->navigateToMyEditProfilePage(); + + $I->fillDeleteAccountForm($this->userPassword, 'foo'); + + $I->seeFormError('You need to write "DELETE" here'); + } +} diff --git a/tests/functional/User/EditProfileCest.php b/tests/functional/User/EditProfileCest.php index 85db91e6..3465587b 100644 --- a/tests/functional/User/EditProfileCest.php +++ b/tests/functional/User/EditProfileCest.php @@ -1,63 +1,65 @@ createSomePublishedQuotes(); - $this->userParams = [ - 'about_me' => 'Lorem', - 'birthdate' => '2000-01-12', - 'city' => 'Paris', - // ID of Argentina - 'country' => 10, - 'country_name' => 'Argentina', - 'gender' => 'F', - ]; - - // Do not pass the country name to TestDummy - // We just want the country name to assert that - // the form is filled with the right values - $overrides = $this->userParams; - array_forget($overrides, 'country_name'); - - $this->user = $I->logANewUser($overrides); - } - - public function updateMyProfile(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('update my profile'); - - // Check that the form has got the values given - // at "sign up" - $I->navigateToMyEditProfilePage(); - $I->assertEditProfileFormIsFilledWith($this->userParams); - - // Edit the user's profile and assert that he has - // got a new profile - $newParams = [ - 'about_me' => 'I am a tester', - 'birthdate' => '1993-12-01', - 'city' => 'Rouen', - 'country_name' => 'France', - 'gender' => 'M', - 'avatar' => 'cage.jpg', - ]; - - $I->fillEditProfileFormWith($newParams); - $I->assertProfileHasBeenChangedWithParams($newParams); - } -} \ No newline at end of file +class EditProfileCest +{ + /** + * The authenticated user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + /** + * Params used to create the user. + * + * @var array + */ + private $userParams; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + $this->userParams = [ + 'about_me' => 'Lorem', + 'birthdate' => '2000-01-12', + 'city' => 'Paris', + // ID of Argentina + 'country' => 10, + 'country_name' => 'Argentina', + 'gender' => 'F', + ]; + + // Do not pass the country name to TestDummy + // We just want the country name to assert that + // the form is filled with the right values + $overrides = $this->userParams; + array_forget($overrides, 'country_name'); + + $this->user = $I->logANewUser($overrides); + } + + public function updateMyProfile(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('update my profile'); + + // Check that the form has got the values given + // at "sign up" + $I->navigateToMyEditProfilePage(); + $I->assertEditProfileFormIsFilledWith($this->userParams); + + // Edit the user's profile and assert that he has + // got a new profile + $newParams = [ + 'about_me' => 'I am a tester', + 'birthdate' => '1993-12-01', + 'city' => 'Rouen', + 'country_name' => 'France', + 'gender' => 'M', + 'avatar' => 'cage.jpg', + ]; + + $I->fillEditProfileFormWith($newParams); + $I->assertProfileHasBeenChangedWithParams($newParams); + } +} diff --git a/tests/functional/User/ShowProfileCest.php b/tests/functional/User/ShowProfileCest.php index 73d5085f..a8b12f2d 100644 --- a/tests/functional/User/ShowProfileCest.php +++ b/tests/functional/User/ShowProfileCest.php @@ -1,137 +1,139 @@ createSomePublishedQuotes(); - $this->userParams = [ - 'about_me' => 'Lorem', - 'birthdate' => '2000-01-12', - 'city' => 'Paris', - // ID of Argentina - 'country' => 10, - 'country_name' => 'Argentina', - 'gender' => 'F', - ]; - - // Do not pass the country name to TestDummy - // We just want the country name to assert that - // the form is filled with the right values - $overrides = $this->userParams; - array_forget($overrides, 'country_name'); - - $this->user = $I->logANewUser($overrides); - } - - public function testProfileContainsFullInformation(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('verify that my profile contains all my statistics'); - - // Expectations - $data = $this->userParams; - $data['quotes-published-count'] = 2; - $data['fav-count'] = 5; - $data['comments-count'] = 4; - $data['added-fav-count'] = 3; - - // Set the database - $quotes = $I->insertInDatabase($data['quotes-published-count'], 'Quote', ['user_id' => $this->user->id]); - $I->insertInDatabase($data['fav-count'], 'FavoriteQuote', ['user_id' => $this->user->id]); - $I->insertInDatabase($data['comments-count'], 'Comment', ['user_id' => $this->user->id]); - $I->insertInDatabase($data['added-fav-count'], 'FavoriteQuote', ['quote_id' => $quotes[0]->id]); - - // Assert that these statistics are displayed - $I->navigateToMyProfile(); - $I->assertProfileContainsInformation($data); - } - - public function testWarningProfileHidden(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('see a warning message if my profile is hidden'); - - $I->hideProfileForCurrentUser(); - $I->navigateToMyProfile(); - $I->see('Your profile is currently hidden.'); - } - - public function testRedirectToPublishedQuotesIfNoFavorites(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('be redirected to my published quotes if I have no favorites'); - - $I->insertInDatabase(5, 'Quote', ['user_id' => $this->user->id]); - - $I->amOnRoute('users.show', [$this->user->login, 'favorites']); - $I->seeCurrentRouteIs('users.show', $this->user->login); - } - - public function testRedirectToCommentsIfNoFavoritesAndNoPublishedQuotes(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('be redirected to my comments if I have no favorites and no published quotes'); - - $I->insertInDatabase(5, 'Comment', ['user_id' => $this->user->id]); - - $I->amOnRoute('users.show', [$this->user->login, 'favorites']); - $I->seeCurrentRouteIs('users.show', [$this->user->login, 'comments']); - } - - public function testRedirectToPublishedQuotesIfNoComments(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('be redirected to my published quotes if I have no comments'); - - $I->insertInDatabase(5, 'Quote', ['user_id' => $this->user->id]); - - $I->amOnRoute('users.show', [$this->user->login, 'comments']); - $I->seeCurrentRouteIs('users.show', $this->user->login); - } - - public function testRedirectToFavoritesIfNoCommentsAndPublishedQuotes(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('be redirected to my published quotes if I have no comments and published quotes'); - - $I->insertInDatabase(5, 'FavoriteQuote', ['user_id' => $this->user->id]); - - $I->amOnRoute('users.show', [$this->user->login, 'comments']); - $I->seeCurrentRouteIs('users.show', [$this->user->login, 'favorites']); - } - - public function testRedirectToFavoritesIfNoPublishedQuotes(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('be redirected to my favorites if I have no published quotes'); - - $I->insertInDatabase(5, 'FavoriteQuote', ['user_id' => $this->user->id]); - - $I->navigateToMyProfile(); - $I->seeCurrentRouteIs('users.show', [$this->user->login, 'favorites']); - } - - public function testRedirectToCommentsIfNoPublishedQuotesAndFavorites(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('be redirected to my comments if I have no published quotes and favorites'); - - $I->insertInDatabase(5, 'Comment', ['user_id' => $this->user->id]); - - $I->navigateToMyProfile(); - $I->seeCurrentRouteIs('users.show', [$this->user->login, 'comments']); - } -} \ No newline at end of file +class ShowProfileCest +{ + /** + * The authenticated user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + /** + * Params used to create the user. + * + * @var array + */ + private $userParams; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + $this->userParams = [ + 'about_me' => 'Lorem', + 'birthdate' => '2000-01-12', + 'city' => 'Paris', + // ID of Argentina + 'country' => 10, + 'country_name' => 'Argentina', + 'gender' => 'F', + ]; + + // Do not pass the country name to TestDummy + // We just want the country name to assert that + // the form is filled with the right values + $overrides = $this->userParams; + array_forget($overrides, 'country_name'); + + $this->user = $I->logANewUser($overrides); + } + + public function testProfileContainsFullInformation(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('verify that my profile contains all my statistics'); + + // Expectations + $data = $this->userParams; + $data['quotes-published-count'] = 2; + $data['fav-count'] = 5; + $data['comments-count'] = 4; + $data['added-fav-count'] = 3; + + // Set the database + $quotes = $I->insertInDatabase($data['quotes-published-count'], 'Quote', ['user_id' => $this->user->id]); + $I->insertInDatabase($data['fav-count'], 'FavoriteQuote', ['user_id' => $this->user->id]); + $I->insertInDatabase($data['comments-count'], 'Comment', ['user_id' => $this->user->id]); + $I->insertInDatabase($data['added-fav-count'], 'FavoriteQuote', ['quote_id' => $quotes[0]->id]); + + // Assert that these statistics are displayed + $I->navigateToMyProfile(); + $I->assertProfileContainsInformation($data); + } + + public function testWarningProfileHidden(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('see a warning message if my profile is hidden'); + + $I->hideProfileForCurrentUser(); + $I->navigateToMyProfile(); + $I->see('Your profile is currently hidden.'); + } + + public function testRedirectToPublishedQuotesIfNoFavorites(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('be redirected to my published quotes if I have no favorites'); + + $I->insertInDatabase(5, 'Quote', ['user_id' => $this->user->id]); + + $I->amOnRoute('users.show', [$this->user->login, 'favorites']); + $I->seeCurrentRouteIs('users.show', $this->user->login); + } + + public function testRedirectToCommentsIfNoFavoritesAndNoPublishedQuotes(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('be redirected to my comments if I have no favorites and no published quotes'); + + $I->insertInDatabase(5, 'Comment', ['user_id' => $this->user->id]); + + $I->amOnRoute('users.show', [$this->user->login, 'favorites']); + $I->seeCurrentRouteIs('users.show', [$this->user->login, 'comments']); + } + + public function testRedirectToPublishedQuotesIfNoComments(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('be redirected to my published quotes if I have no comments'); + + $I->insertInDatabase(5, 'Quote', ['user_id' => $this->user->id]); + + $I->amOnRoute('users.show', [$this->user->login, 'comments']); + $I->seeCurrentRouteIs('users.show', $this->user->login); + } + + public function testRedirectToFavoritesIfNoCommentsAndPublishedQuotes(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('be redirected to my published quotes if I have no comments and published quotes'); + + $I->insertInDatabase(5, 'FavoriteQuote', ['user_id' => $this->user->id]); + + $I->amOnRoute('users.show', [$this->user->login, 'comments']); + $I->seeCurrentRouteIs('users.show', [$this->user->login, 'favorites']); + } + + public function testRedirectToFavoritesIfNoPublishedQuotes(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('be redirected to my favorites if I have no published quotes'); + + $I->insertInDatabase(5, 'FavoriteQuote', ['user_id' => $this->user->id]); + + $I->navigateToMyProfile(); + $I->seeCurrentRouteIs('users.show', [$this->user->login, 'favorites']); + } + + public function testRedirectToCommentsIfNoPublishedQuotesAndFavorites(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('be redirected to my comments if I have no published quotes and favorites'); + + $I->insertInDatabase(5, 'Comment', ['user_id' => $this->user->id]); + + $I->navigateToMyProfile(); + $I->seeCurrentRouteIs('users.show', [$this->user->login, 'comments']); + } +} diff --git a/tests/functional/User/UpdatePasswordCest.php b/tests/functional/User/UpdatePasswordCest.php index 11f1c956..93eb1833 100644 --- a/tests/functional/User/UpdatePasswordCest.php +++ b/tests/functional/User/UpdatePasswordCest.php @@ -1,55 +1,56 @@ createSomePublishedQuotes(); - $this->user = $I->logANewUser(); - } - - public function updateMyPassword(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('update my password'); - - $newPassword = "azerty42"; - - // Update the user's password - $I->navigateToMyEditProfilePage(); - $I->fillChangePasswordForm($newPassword, $newPassword); - $I->assertPasswordHasBeenChanged(); - - // Log him out - $I->performLogoutFlow(); - - // Sign in again with the new password - $I->navigateToTheSignInPage(); - $I->fillSigninForm($this->user->login, $newPassword); - - // Assert that we have been authenticated - $I->assertTrue(Auth::check()); - } - - public function updateMyPasswordWithADifferentConfirmationPassword(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('update my password with a different confirmation password'); - - $newPassword = "azerty42"; - $confirmPassword = "azerty22"; - - // Try to update the user's password - $I->navigateToMyEditProfilePage(); - $I->fillChangePasswordForm($newPassword, $confirmPassword); - - // Assert that we can't change the password - $I->seeFormError('The password confirmation does not match.'); - } -} \ No newline at end of file +class UpdatePasswordCest +{ + /** + * The authenticated user. + * + * @var \TeenQuotes\Users\Models\User + */ + private $user; + + public function _before(FunctionalTester $I) + { + $I->createSomePublishedQuotes(); + $this->user = $I->logANewUser(); + } + + public function updateMyPassword(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('update my password'); + + $newPassword = 'azerty42'; + + // Update the user's password + $I->navigateToMyEditProfilePage(); + $I->fillChangePasswordForm($newPassword, $newPassword); + $I->assertPasswordHasBeenChanged(); + + // Log him out + $I->performLogoutFlow(); + + // Sign in again with the new password + $I->navigateToTheSignInPage(); + $I->fillSigninForm($this->user->login, $newPassword); + + // Assert that we have been authenticated + $I->assertTrue(Auth::check()); + } + + public function updateMyPasswordWithADifferentConfirmationPassword(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('update my password with a different confirmation password'); + + $newPassword = 'azerty42'; + $confirmPassword = 'azerty22'; + + // Try to update the user's password + $I->navigateToMyEditProfilePage(); + $I->fillChangePasswordForm($newPassword, $confirmPassword); + + // Assert that we can't change the password + $I->seeFormError('The password confirmation does not match.'); + } +} diff --git a/tests/functional/User/UpdateSettingsCest.php b/tests/functional/User/UpdateSettingsCest.php index 1e927ca5..c247e76b 100644 --- a/tests/functional/User/UpdateSettingsCest.php +++ b/tests/functional/User/UpdateSettingsCest.php @@ -1,43 +1,44 @@ user = $I->logANewUser(); + // Create some published quotes for the logged in user + $I->createSomePublishedQuotes(['user_id' => $this->user->id]); + } - public function _before(FunctionalTester $I) - { - $this->user = $I->logANewUser(); - // Create some published quotes for the logged in user - $I->createSomePublishedQuotes(['user_id' => $this->user->id]); - } + public function updateMySettings(FunctionalTester $I) + { + $I->am('a logged in Teen Quotes member'); + $I->wantTo('update my settings'); - public function updateMySettings(FunctionalTester $I) - { - $I->am('a logged in Teen Quotes member'); - $I->wantTo('update my settings'); + $I->navigateToMyEditProfilePage(); + $I->assertMySettingsHaveDefaultValues(); - $I->navigateToMyEditProfilePage(); - $I->assertMySettingsHaveDefaultValues(); + $newColor = 'red'; + $params = [ + 'color' => ucfirst($newColor), + 'notification_comment_quote' => 0, + 'hide_profile' => 1, + 'daily_newsletter' => 1, + 'weekly_newsletter' => 0, + ]; + $I->fillUserSettingsForm($params); + $I->assertMySettingsHaveTheseValues($params); - $newColor = 'red'; - $params = [ - 'color' => ucfirst($newColor), - 'notification_comment_quote' => 0, - 'hide_profile' => 1, - 'daily_newsletter' => 1, - 'weekly_newsletter' => 0 - ]; - $I->fillUserSettingsForm($params); - $I->assertMySettingsHaveTheseValues($params); - - $I->navigateToMyProfile(); - // Verify that the profile is hidden - $I->see('Your profile is currently hidden. Only you can see this!'); - // Verify the color of published quotes - $I->seeElement('.color-'.$newColor.'-1'); - } -} \ No newline at end of file + $I->navigateToMyProfile(); + // Verify that the profile is hidden + $I->see('Your profile is currently hidden. Only you can see this!'); + // Verify the color of published quotes + $I->seeElement('.color-'.$newColor.'-1'); + } +} diff --git a/tests/functional/_bootstrap.php b/tests/functional/_bootstrap.php index 94bf66cf..8a885558 100644 --- a/tests/functional/_bootstrap.php +++ b/tests/functional/_bootstrap.php @@ -1,2 +1,2 @@ repo = App::make('TeenQuotes\Comments\Repositories\CommentRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Comments\Repositories\CommentRepository'); - } + public function testFindById(IntegrationTester $I) + { + $c = $I->insertInDatabase(1, 'Comment'); - public function testFindById(IntegrationTester $I) - { - $c = $I->insertInDatabase(1, 'Comment'); + $comment = $this->repo->findById($c->id); - $comment = $this->repo->findById($c->id); + $I->assertEquals($c->content, $comment->content); + $I->assertEquals($c->user_id, $comment->user_id); + } - $I->assertEquals($c->content, $comment->content); - $I->assertEquals($c->user_id, $comment->user_id); - } + public function testFindByIdWithQuote(IntegrationTester $I) + { + $c = $I->insertInDatabase(1, 'Comment'); - public function testFindByIdWithQuote(IntegrationTester $I) - { - $c = $I->insertInDatabase(1, 'Comment'); + $comment = $this->repo->findById($c->id); - $comment = $this->repo->findById($c->id); + $I->assertTrue($c->quote instanceof TeenQuotes\Quotes\Models\Quote); + } - $I->assertTrue($c->quote instanceof TeenQuotes\Quotes\Models\Quote); - } + public function testIndexForQuote(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Comment'); + $q = $I->insertInDatabase(1, 'Quote'); + $I->insertInDatabase(2, 'Comment', ['quote_id' => $q->id]); - public function testIndexForQuote(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Comment'); - $q = $I->insertInDatabase(1, 'Quote'); - $I->insertInDatabase(2, 'Comment', ['quote_id' => $q->id]); + $comments = $this->repo->indexForQuote($q->id, 1, 5); - $comments = $this->repo->indexForQuote($q->id, 1, 5); + $I->assertIsCollection($comments); + $I->assertEquals(2, count($comments)); + } - $I->assertIsCollection($comments); - $I->assertEquals(2, count($comments)); - } + public function testIndexForQuoteWithQuote(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Comment'); + $q = $I->insertInDatabase(1, 'Quote'); + $I->insertInDatabase(2, 'Comment', ['quote_id' => $q->id]); - public function testIndexForQuoteWithQuote(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Comment'); - $q = $I->insertInDatabase(1, 'Quote'); - $I->insertInDatabase(2, 'Comment', ['quote_id' => $q->id]); + $comments = $this->repo->indexForQuote($q->id, 1, 5); - $comments = $this->repo->indexForQuote($q->id, 1, 5); + $I->assertIsCollection($comments); + $I->assertTrue($comments->first()->quote instanceof TeenQuotes\Quotes\Models\Quote); + } - $I->assertIsCollection($comments); - $I->assertTrue($comments->first()->quote instanceof TeenQuotes\Quotes\Models\Quote); - } + public function findForUser(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Comment'); + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Comment', ['user_id' => $u->id]); - public function findForUser(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Comment'); - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Comment', ['user_id' => $u->id]); + $comments = $this->repo->findForUser($u, 1, 1); + $I->assertIsCollection($comments); + $I->assertEquals(1, count($comments)); - $comments = $this->repo->findForUser($u, 1, 1); - $I->assertIsCollection($comments); - $I->assertEquals(1, count($comments)); + $comments = $this->repo->findForUser($u, 1, 3); + $I->assertEquals(2, count($comments)); + } - $comments = $this->repo->findForUser($u, 1, 3); - $I->assertEquals(2, count($comments)); - } + public function testCountForUser(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Comment'); + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Comment', ['user_id' => $u->id]); - public function testCountForUser(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Comment'); - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Comment', ['user_id' => $u->id]); + $I->assertEquals(2, $this->repo->countForUser($u)); + } - $I->assertEquals(2, $this->repo->countForUser($u)); - } + public function testCreate(IntegrationTester $I) + { + $q = $I->insertInDatabase(1, 'Quote'); + $u = $I->insertInDatabase(1, 'User'); - public function testCreate(IntegrationTester $I) - { - $q = $I->insertInDatabase(1, 'Quote'); - $u = $I->insertInDatabase(1, 'User'); + $this->repo->create($q, $u, 'Hello World'); - $this->repo->create($q, $u, "Hello World"); + $I->assertEquals(1, $this->repo->countForUser($u)); + } - $I->assertEquals(1, $this->repo->countForUser($u)); - } + public function testUpdate(IntegrationTester $I) + { + $c = $I->insertInDatabase(1, 'Comment'); + $newContent = 'Foobar'; - public function testUpdate(IntegrationTester $I) - { - $c = $I->insertInDatabase(1, 'Comment'); - $newContent = "Foobar"; + $this->repo->update($c, $newContent); - $this->repo->update($c, $newContent); + $comment = $this->repo->findById($c->id); + $I->assertEquals($comment->content, $newContent); + } - $comment = $this->repo->findById($c->id); - $I->assertEquals($comment->content, $newContent); - } + public function testDelete(IntegrationTester $I) + { + $c = $I->insertInDatabase(1, 'Comment'); - public function testDelete(IntegrationTester $I) - { - $c = $I->insertInDatabase(1, 'Comment'); + $this->repo->delete($c->id); - $this->repo->delete($c->id); + $I->assertNull($this->repo->findById($c->id)); + } - $I->assertNull($this->repo->findById($c->id)); - } + public function testGetTopQuotes(IntegrationTester $I) + { + $I->assertEquals([], $this->repo->getTopQuotes(1, 10)); - public function testGetTopQuotes(IntegrationTester $I) - { - $I->assertEquals([], $this->repo->getTopQuotes(1, 10)); + $I->insertInDatabase(2, 'Quote'); + $I->insertInDatabase(2, 'Comment', ['quote_id' => 2]); + $I->insertInDatabase(1, 'Comment', ['quote_id' => 1]); - $I->insertInDatabase(2, 'Quote'); - $I->insertInDatabase(2, 'Comment', ['quote_id' => 2]); - $I->insertInDatabase(1, 'Comment', ['quote_id' => 1]); + $I->assertEquals([2, 1], $this->repo->getTopQuotes(1, 10)); + } - $I->assertEquals([2, 1], $this->repo->getTopQuotes(1, 10)); - } + public function testGetNbCommentsForQuote(IntegrationTester $I) + { + $first = $I->insertInDatabase(1, 'Quote'); + $second = $I->insertInDatabase(1, 'Quote'); + $I->insertInDatabase(2, 'Comment', ['quote_id' => 2]); - public function testGetNbCommentsForQuote(IntegrationTester $I) - { - $first = $I->insertInDatabase(1, 'Quote'); - $second = $I->insertInDatabase(1, 'Quote'); - $I->insertInDatabase(2, 'Comment', ['quote_id' => 2]); - - $I->assertEquals(0, $this->repo->nbCommentsForQuote($first)); - $I->assertEquals(2, $this->repo->nbCommentsForQuote($second)); - } -} \ No newline at end of file + $I->assertEquals(0, $this->repo->nbCommentsForQuote($first)); + $I->assertEquals(2, $this->repo->nbCommentsForQuote($second)); + } +} diff --git a/tests/integration/CountryRepoCest.php b/tests/integration/CountryRepoCest.php index 7963e0dc..1447dedd 100644 --- a/tests/integration/CountryRepoCest.php +++ b/tests/integration/CountryRepoCest.php @@ -2,58 +2,58 @@ use TeenQuotes\Countries\Models\Country; -class CountryRepoCest { +class CountryRepoCest +{ + /** + * @var \TeenQuotes\Countries\Repositories\CountryRepository + */ + private $repo; - /** - * @var \TeenQuotes\Countries\Repositories\CountryRepository - */ - private $repo; + public function _before() + { + $this->repo = App::make('TeenQuotes\Countries\Repositories\CountryRepository'); - public function _before() - { - $this->repo = App::make('TeenQuotes\Countries\Repositories\CountryRepository'); + Country::truncate(); + } - Country::truncate(); - } + public function testFindById(IntegrationTester $I) + { + $c = $I->insertInDatabase(1, 'Country'); - public function testFindById(IntegrationTester $I) - { - $c = $I->insertInDatabase(1, 'Country'); + $country = $this->repo->findById($c->id); - $country = $this->repo->findById($c->id); + $I->assertEquals($c->name, $country->name); + $I->assertEquals($c->country_code, $country->country_code); + } - $I->assertEquals($c->name, $country->name); - $I->assertEquals($c->country_code, $country->country_code); - } + public function testListNameAndId(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Country', ['name' => 'ab']); + $I->insertInDatabase(1, 'Country', ['name' => 'cd']); - public function testListNameAndId(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Country', ['name' => 'ab']); - $I->insertInDatabase(1, 'Country', ['name' => 'cd']); + $expected = [ + 1 => 'ab', + 2 => 'cd', + ]; - $expected = [ - 1 => 'ab', - 2 => 'cd' - ]; + $I->assertEquals($expected, $this->repo->listNameAndId()); + } - $I->assertEquals($expected, $this->repo->listNameAndId()); - } + public function testGetAll(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Country', ['name' => 'ab']); + $I->insertInDatabase(1, 'Country', ['name' => 'cd']); - public function testGetAll(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Country', ['name' => 'ab']); - $I->insertInDatabase(1, 'Country', ['name' => 'cd']); + $countries = $this->repo->getAll(); - $countries = $this->repo->getAll(); + $I->assertIsCollection($countries); - $I->assertIsCollection($countries); + $ids = $countries->lists('id'); + sort($ids); + $I->assertEquals([1, 2], $ids); - $ids = $countries->lists('id'); - sort($ids); - $I->assertEquals([1, 2], $ids); - - $names = $countries->lists('name'); - sort($names); - $I->assertEquals(['ab', 'cd'], $names); - } -} \ No newline at end of file + $names = $countries->lists('name'); + sort($names); + $I->assertEquals(['ab', 'cd'], $names); + } +} diff --git a/tests/integration/FavoriteQuoteRepoCest.php b/tests/integration/FavoriteQuoteRepoCest.php index 004a27c5..2181b0e0 100644 --- a/tests/integration/FavoriteQuoteRepoCest.php +++ b/tests/integration/FavoriteQuoteRepoCest.php @@ -1,101 +1,101 @@ repo = App::make('TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository'); - } - - public function testIsFavoriteForUserAndQuote(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Quote'); - $this->fav(1, $u); - - $I->assertTrue($this->repo->isFavoriteForUserAndQuote($u, 1)); - $I->assertFalse($this->repo->isFavoriteForUserAndQuote($u->id, 2)); - } - - public function testDeleteForUserAndQuote(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Quote'); - $this->fav(1, $u); - - $this->repo->deleteForUserAndQuote($u, 1); - - $I->assertFalse($this->repo->isFavoriteForUserAndQuote($u, 1)); - } - - public function testNbFavoritesForQuotes(IntegrationTester $I) - { - $I->insertInDatabase(2, 'Quote'); - $I->insertInDatabase(2, 'FavoriteQuote', ['quote_id' => 1]); - $I->insertInDatabase(3, 'FavoriteQuote', ['quote_id' => 2]); - - $I->assertEquals(2, $this->repo->nbFavoritesForQuotes([1])); - $I->assertEquals(5, $this->repo->nbFavoritesForQuotes([1, 2])); - } - - public function quotesFavoritesForUser(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Quote'); - - $I->assertEquals([], $this->repo->quotesFavoritesForUser($u)); - - $this->fav(1, $u); - $I->assertEquals([1], $this->repo->quotesFavoritesForUser($u->id)); - - $this->fav(2, $u); - $out = $this->repo->quotesFavoritesForUser($u->id); - sort($out); - $I->assertEquals([1, 2], $out); - - $this->repo->deleteForUserAndQuote($u, 2); - $I->assertEquals([1], $this->repo->quotesFavoritesForUser($u->id)); - } - - public function testCreate(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(1, 'Quote'); - - $I->assertFalse($this->repo->isFavoriteForUserAndQuote(1, 1)); - - $this->repo->create($u, 1); - $I->assertTrue($this->repo->isFavoriteForUserAndQuote(1, 1)); - } - - public function testGetTopQuotes(IntegrationTester $I) - { - $I->insertInDatabase(2, 'Quote'); - $I->insertInDatabase(3, 'FavoriteQuote', ['quote_id' => 2]); - $I->insertInDatabase(2, 'FavoriteQuote', ['quote_id' => 1]); - - $I->assertEquals([2], $this->repo->getTopQuotes(1, 1)); - $I->assertEquals([2, 1], $this->repo->getTopQuotes(1, 3)); - } - - public function testNbFavoritesForQuote(IntegrationTester $I) - { - $I->insertInDatabase(2, 'Quote'); - $u = $I->insertInDatabase(1, 'User'); - - $I->assertEquals(0, $this->repo->nbFavoritesForQuote(1)); - - $this->fav(1, $u); - $I->assertEquals(1, $this->repo->nbFavoritesForQuote(1)); - } - - private function fav($quote_id, $user_id) - { - $this->repo->create($user_id, $quote_id); - } -} \ No newline at end of file +class FavoriteQuoteRepoCest +{ + /** + * @var \TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository + */ + private $repo; + + public function _before() + { + $this->repo = App::make('TeenQuotes\Quotes\Repositories\FavoriteQuoteRepository'); + } + + public function testIsFavoriteForUserAndQuote(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Quote'); + $this->fav(1, $u); + + $I->assertTrue($this->repo->isFavoriteForUserAndQuote($u, 1)); + $I->assertFalse($this->repo->isFavoriteForUserAndQuote($u->id, 2)); + } + + public function testDeleteForUserAndQuote(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Quote'); + $this->fav(1, $u); + + $this->repo->deleteForUserAndQuote($u, 1); + + $I->assertFalse($this->repo->isFavoriteForUserAndQuote($u, 1)); + } + + public function testNbFavoritesForQuotes(IntegrationTester $I) + { + $I->insertInDatabase(2, 'Quote'); + $I->insertInDatabase(2, 'FavoriteQuote', ['quote_id' => 1]); + $I->insertInDatabase(3, 'FavoriteQuote', ['quote_id' => 2]); + + $I->assertEquals(2, $this->repo->nbFavoritesForQuotes([1])); + $I->assertEquals(5, $this->repo->nbFavoritesForQuotes([1, 2])); + } + + public function quotesFavoritesForUser(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Quote'); + + $I->assertEquals([], $this->repo->quotesFavoritesForUser($u)); + + $this->fav(1, $u); + $I->assertEquals([1], $this->repo->quotesFavoritesForUser($u->id)); + + $this->fav(2, $u); + $out = $this->repo->quotesFavoritesForUser($u->id); + sort($out); + $I->assertEquals([1, 2], $out); + + $this->repo->deleteForUserAndQuote($u, 2); + $I->assertEquals([1], $this->repo->quotesFavoritesForUser($u->id)); + } + + public function testCreate(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(1, 'Quote'); + + $I->assertFalse($this->repo->isFavoriteForUserAndQuote(1, 1)); + + $this->repo->create($u, 1); + $I->assertTrue($this->repo->isFavoriteForUserAndQuote(1, 1)); + } + + public function testGetTopQuotes(IntegrationTester $I) + { + $I->insertInDatabase(2, 'Quote'); + $I->insertInDatabase(3, 'FavoriteQuote', ['quote_id' => 2]); + $I->insertInDatabase(2, 'FavoriteQuote', ['quote_id' => 1]); + + $I->assertEquals([2], $this->repo->getTopQuotes(1, 1)); + $I->assertEquals([2, 1], $this->repo->getTopQuotes(1, 3)); + } + + public function testNbFavoritesForQuote(IntegrationTester $I) + { + $I->insertInDatabase(2, 'Quote'); + $u = $I->insertInDatabase(1, 'User'); + + $I->assertEquals(0, $this->repo->nbFavoritesForQuote(1)); + + $this->fav(1, $u); + $I->assertEquals(1, $this->repo->nbFavoritesForQuote(1)); + } + + private function fav($quote_id, $user_id) + { + $this->repo->create($user_id, $quote_id); + } +} diff --git a/tests/integration/NewsletterRepoCest.php b/tests/integration/NewsletterRepoCest.php index 10b119f6..c1ac8ff0 100644 --- a/tests/integration/NewsletterRepoCest.php +++ b/tests/integration/NewsletterRepoCest.php @@ -3,90 +3,90 @@ use Illuminate\Support\Collection; use TeenQuotes\Newsletters\Models\Newsletter; -class NewsletterRepoCest { +class NewsletterRepoCest +{ + /** + * @var \TeenQuotes\Newsletters\Repositories\NewsletterRepository + */ + private $repo; - /** - * @var \TeenQuotes\Newsletters\Repositories\NewsletterRepository - */ - private $repo; + public function _before() + { + $this->repo = App::make('TeenQuotes\Newsletters\Repositories\NewsletterRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Newsletters\Repositories\NewsletterRepository'); - } + public function testUserIsSubscribedToNewsletterType(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(1, 'Newsletter', ['user_id' => $u->id, 'type' => Newsletter::WEEKLY]); - public function testUserIsSubscribedToNewsletterType(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(1, 'Newsletter', ['user_id' => $u->id, 'type' => Newsletter::WEEKLY]); + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); + $I->assertTrue($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); + } - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); - $I->assertTrue($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); - } + public function testGetForType(IntegrationTester $I) + { + $I->assertEmpty($this->repo->getForType(Newsletter::WEEKLY)); + $I->assertEmpty($this->repo->getForType(Newsletter::DAILY)); - public function testGetForType(IntegrationTester $I) - { - $I->assertEmpty($this->repo->getForType(Newsletter::WEEKLY)); - $I->assertEmpty($this->repo->getForType(Newsletter::DAILY)); + $I->insertInDatabase(3, 'Newsletter', ['type' => Newsletter::DAILY]); - $I->insertInDatabase(3, 'Newsletter', ['type' => Newsletter::DAILY]); + $newsletters = $this->repo->getForType(Newsletter::DAILY); - $newsletters = $this->repo->getForType(Newsletter::DAILY); + $I->assertIsCollection($newsletters); + $I->assertEquals(3, count($newsletters)); + } - $I->assertIsCollection($newsletters); - $I->assertEquals(3, count($newsletters)); - } + public function testCreateForUserAndType(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); - public function testCreateForUserAndType(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); + $this->repo->createForUserAndType($u, Newsletter::DAILY); - $this->repo->createForUserAndType($u, Newsletter::DAILY); + $I->assertTrue($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); + } - $I->assertTrue($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); - } + public function testDeleteForUserAndType(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); - public function testDeleteForUserAndType(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); + // A user is automatically subscribed to the weekly newsletter + // when signing up + $I->assertTrue($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); - // A user is automatically subscribed to the weekly newsletter - // when signing up - $I->assertTrue($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); + $this->repo->deleteForUserAndType($u, Newsletter::WEEKLY); - $this->repo->deleteForUserAndType($u, Newsletter::WEEKLY); + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); + } - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); - } + public function testDeleteForUser(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); - public function testDeleteForUser(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); + // User will be subscribed to the daily and weekly newsletters after + $this->repo->createForUserAndType($u, Newsletter::DAILY); - // User will be subscribed to the daily and weekly newsletters after - $this->repo->createForUserAndType($u, Newsletter::DAILY); + $this->repo->deleteForUser($u); - $this->repo->deleteForUser($u); + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); + } - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::WEEKLY)); - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($u, Newsletter::DAILY)); - } + public function testDeleteForUsers(IntegrationTester $I) + { + $usersArray = $I->insertInDatabase(2, 'User'); - public function testDeleteForUsers(IntegrationTester $I) - { - $usersArray = $I->insertInDatabase(2, 'User'); + // Subscribe them to the daily newsletter + $this->repo->createForUserAndType($usersArray[0], Newsletter::DAILY); + $this->repo->createForUserAndType($usersArray[1], Newsletter::DAILY); - // Subscribe them to the daily newsletter - $this->repo->createForUserAndType($usersArray[0], Newsletter::DAILY); - $this->repo->createForUserAndType($usersArray[1], Newsletter::DAILY); + // Remove all newsletters for these users + $this->repo->deleteForUsers(new Collection($usersArray)); - // Remove all newsletters for these users - $this->repo->deleteForUsers(new Collection($usersArray)); - - // Check that it has been done properly - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($usersArray[0], Newsletter::DAILY)); - $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($usersArray[1], Newsletter::DAILY)); - } -} \ No newline at end of file + // Check that it has been done properly + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($usersArray[0], Newsletter::DAILY)); + $I->assertFalse($this->repo->userIsSubscribedToNewsletterType($usersArray[1], Newsletter::DAILY)); + } +} diff --git a/tests/integration/ProfileVisitorRepoCest.php b/tests/integration/ProfileVisitorRepoCest.php index 17f6d31a..1717bfe8 100644 --- a/tests/integration/ProfileVisitorRepoCest.php +++ b/tests/integration/ProfileVisitorRepoCest.php @@ -1,77 +1,77 @@ repo = App::make('TeenQuotes\Users\Repositories\ProfileVisitorRepository'); - } - - public function testAddVisitor(IntegrationTester $I) - { - $I->insertInDatabase(2, 'User'); - - $this->repo->addVisitor(1, 2); - - $I->assertTrue($this->repo->hasVisited(2, 1)); - $I->assertFalse($this->repo->hasVisited(1, 2)); - - $this->repo->addVisitor(2, 1); - $I->assertTrue($this->repo->hasVisited(1, 2)); - } - - public function testGetVisitors(IntegrationTester $I) - { - $I->insertInDatabase(2, 'User'); - $I->insertInDatabase(1, 'User', ['hide_profile' => 1]); - $I->insertInDatabase(1, 'User'); - - $I->assertEmpty($this->repo->getVisitors(1, 1, 10)); - - $this->repo->addVisitor(1, 2); - $I->assertEquals(1, count($this->repo->getVisitors(1, 1, 10))); - - // A visitor with an hidden profile visits user #1 - $this->repo->addVisitor(1, 3); - $I->assertEquals(1, count($this->repo->getVisitors(1, 1, 10))); - - // It gets the last visitor first - $this->repo->addVisitor(1, 4); - $I->assertEquals(2, count($this->repo->getVisitors(1, 1, 10))); - $I->assertEquals(4, $this->repo->getVisitors(1, 1, 10)->first()->id); - - // We don't have duplicates - $this->repo->addVisitor(1, 2); - $visitorsIds = $this->repo->getVisitors(1, 1, 10)->lists('id'); - sort($visitorsIds); - $I->assertEquals([2, 4], $visitorsIds); - } - - public function testGetVisitorsInfo(IntegrationTester $I) - { - $urlAvatar = 'http://example.com/image.jpg'; - - $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(1, 'User', ['login' => 'foo', 'avatar' => $urlAvatar]); - $I->insertInDatabase(1, 'User', ['hide_profile' => 1]); - $I->insertInDatabase(1, 'User', ['login' => 'test', 'avatar' => $urlAvatar]); - - $this->repo->addVisitor(1, 2); - $expected = ['foo' => $urlAvatar]; - $I->assertEquals($expected, $this->repo->getVisitorsInfos(1, 1, 10)); - - // A visitor with an hidden profile - $this->repo->addVisitor(1, 3); - $I->assertEquals($expected, $this->repo->getVisitorsInfos(1, 1, 10)); - - // Add another valid visitor - $this->repo->addVisitor(1, 4); - $expected['test'] = $urlAvatar; - $I->assertEquals($expected, $this->repo->getVisitorsInfos(1, 1, 10)); - } -} \ No newline at end of file +class ProfileVisitorRepoCest +{ + /** + * @var \TeenQuotes\Users\Repositories\ProfileVisitorRepository + */ + private $repo; + + public function _before() + { + $this->repo = App::make('TeenQuotes\Users\Repositories\ProfileVisitorRepository'); + } + + public function testAddVisitor(IntegrationTester $I) + { + $I->insertInDatabase(2, 'User'); + + $this->repo->addVisitor(1, 2); + + $I->assertTrue($this->repo->hasVisited(2, 1)); + $I->assertFalse($this->repo->hasVisited(1, 2)); + + $this->repo->addVisitor(2, 1); + $I->assertTrue($this->repo->hasVisited(1, 2)); + } + + public function testGetVisitors(IntegrationTester $I) + { + $I->insertInDatabase(2, 'User'); + $I->insertInDatabase(1, 'User', ['hide_profile' => 1]); + $I->insertInDatabase(1, 'User'); + + $I->assertEmpty($this->repo->getVisitors(1, 1, 10)); + + $this->repo->addVisitor(1, 2); + $I->assertEquals(1, count($this->repo->getVisitors(1, 1, 10))); + + // A visitor with an hidden profile visits user #1 + $this->repo->addVisitor(1, 3); + $I->assertEquals(1, count($this->repo->getVisitors(1, 1, 10))); + + // It gets the last visitor first + $this->repo->addVisitor(1, 4); + $I->assertEquals(2, count($this->repo->getVisitors(1, 1, 10))); + $I->assertEquals(4, $this->repo->getVisitors(1, 1, 10)->first()->id); + + // We don't have duplicates + $this->repo->addVisitor(1, 2); + $visitorsIds = $this->repo->getVisitors(1, 1, 10)->lists('id'); + sort($visitorsIds); + $I->assertEquals([2, 4], array_values($visitorsIds)); + } + + public function testGetVisitorsInfo(IntegrationTester $I) + { + $urlAvatar = 'http://example.com/image.jpg'; + + $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(1, 'User', ['login' => 'foo', 'avatar' => $urlAvatar]); + $I->insertInDatabase(1, 'User', ['hide_profile' => 1]); + $I->insertInDatabase(1, 'User', ['login' => 'test', 'avatar' => $urlAvatar]); + + $this->repo->addVisitor(1, 2); + $expected = ['foo' => $urlAvatar]; + $I->assertEquals($expected, $this->repo->getVisitorsInfos(1, 1, 10)); + + // A visitor with an hidden profile + $this->repo->addVisitor(1, 3); + $I->assertEquals($expected, $this->repo->getVisitorsInfos(1, 1, 10)); + + // Add another valid visitor + $this->repo->addVisitor(1, 4); + $expected['test'] = $urlAvatar; + $I->assertEquals($expected, $this->repo->getVisitorsInfos(1, 1, 10)); + } +} diff --git a/tests/integration/QuoteRepoCest.php b/tests/integration/QuoteRepoCest.php index c0ca33ae..1d05d1d9 100644 --- a/tests/integration/QuoteRepoCest.php +++ b/tests/integration/QuoteRepoCest.php @@ -2,315 +2,317 @@ use TeenQuotes\Quotes\Models\Quote; -class QuoteRepoCest { +class QuoteRepoCest +{ + /** + * @var \TeenQuotes\Quotes\Repositories\QuoteRepository + */ + private $repo; - /** - * @var \TeenQuotes\Quotes\Repositories\QuoteRepository - */ - private $repo; + /** + * @var \TeenQuotes\Tags\Repositories\TagRepository + */ + private $tagRepo; - /** - * @var \TeenQuotes\Tags\Repositories\TagRepository - */ - private $tagRepo; + public function _before() + { + $this->repo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); + $this->tagRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Quotes\Repositories\QuoteRepository'); - $this->tagRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); - } + public function testRetrieveLastWaitingQuotes(IntegrationTester $I) + { + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); + $I->insertInDatabase(4, 'Quote', ['approved' => Quote::WAITING]); - public function testRetrieveLastWaitingQuotes(IntegrationTester $I) - { - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); - $I->insertInDatabase(4, 'Quote', ['approved' => Quote::WAITING]); + $quotes = $this->repo->lastWaitingQuotes(); - $quotes = $this->repo->lastWaitingQuotes(); + $I->assertIsCollection($quotes); + $I->assertEquals(4, count($quotes)); + } + + public function testNbPending(IntegrationTester $I) + { + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); + $I->insertInDatabase(4, 'Quote', ['approved' => Quote::PENDING]); - $I->assertIsCollection($quotes); - $I->assertEquals(4, count($quotes)); - } + $I->assertEquals(4, $this->repo->nbPending()); + } + + public function testNbWaiting(IntegrationTester $I) + { + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); + $I->insertInDatabase(4, 'Quote', ['approved' => Quote::WAITING]); - public function testNbPending(IntegrationTester $I) - { - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); - $I->insertInDatabase(4, 'Quote', ['approved' => Quote::PENDING]); + $I->assertEquals(4, $this->repo->nbWaiting()); + } - $I->assertEquals(4, $this->repo->nbPending()); - } - - public function testNbWaiting(IntegrationTester $I) - { - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); - $I->insertInDatabase(4, 'Quote', ['approved' => Quote::WAITING]); - - $I->assertEquals(4, $this->repo->nbWaiting()); - } - - public function testGetById(IntegrationTester $I) - { - $content = 'Testing you know'; - $I->insertInDatabase(1, 'Quote', ['content' => $content]); - - $quote = $this->repo->getById(1); - $I->assertEquals($content, $quote->content); - } - - public function testGetByIdWithUser(IntegrationTester $I) - { - $user = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(1, 'Quote', ['user_id' => $user->id]); - - $quote = $this->repo->getByIdWithUser(1); - - $I->assertEquals($user->id, $quote->user->id); - $I->assertEquals($user->login, $quote->user->login); - } - - public function testWaitingById(IntegrationTester $I) - { - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); - $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::WAITING]); - - $quote = $this->repo->waitingById($q->id); - - $I->assertEquals($q->content, $quote->content); - } - - public function testShowQuote(IntegrationTester $I) - { - $quotes = $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); - - $quote = $this->repo->showQuote(2); - - $I->assertEquals($quote->id, $quotes[1]->id); - } - - public function testCountQuotesByApprovedForUser(IntegrationTester $I) - { - $user = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::WAITING, 'user_id' => $user->id]); - $I->insertInDatabase(2, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); - - $I->assertEquals(3, $this->repo->countQuotesByApprovedForUser('waiting', $user)); - $I->assertEquals(2, $this->repo->countQuotesByApprovedForUser('published', $user)); - } - - public function testUpdateContentAndApproved(IntegrationTester $I) - { - $newContent = 'Hello World'; - $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::WAITING]); - - $this->repo->updateContentAndApproved($q->id, $newContent, Quote::PUBLISHED); - - $q = $this->repo->getById($q->id); - $I->assertEquals(Quote::PUBLISHED, $q->approved); - $I->assertEquals($newContent, $q->content); - } - - public function testUpdateApproved(IntegrationTester $I) - { - $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::WAITING]); - - $this->repo->updateApproved($q->id, Quote::PUBLISHED); - - $q = $this->repo->getById($q->id); - $I->assertEquals(Quote::PUBLISHED, $q->approved); - } - - public function testTotalPublished(IntegrationTester $I) - { - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::WAITING]); - $I->insertInDatabase(4, 'Quote', ['approved' => Quote::PUBLISHED]); - - $I->assertEquals(4, $this->repo->totalPublished()); - } - - public function testSubmittedTodayForUser(IntegrationTester $I) - { - $user = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Quote', ['user_id' => $user->id, 'created_at' => Carbon::now()->subMonth(1)]); - $I->insertInDatabase(3, 'Quote', ['user_id' => $user->id]); - - $I->assertEquals(3, $this->repo->submittedTodayForUser($user)); - } - - public function testCreateQuoteForUser(IntegrationTester $I) - { - $content = 'Hello World'; - $user = $I->insertInDatabase(1, 'User'); - - $q = $this->repo->createQuoteForUser($user, $content); - $q = $this->repo->getById($q->id); - - $I->assertEquals($content, $q->content); - $I->assertEquals(Quote::WAITING, $q->approved); - } - - public function testIndex(IntegrationTester $I) - { - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED, 'created_at' => Carbon::now()->subMonth(1)]); - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::WAITING]); - - $quotes = $this->repo->index(1, 5); - $ids = $quotes->lists('id'); - sort($ids); - $I->assertIsCollection($quotes); - $I->assertEquals(range(1, 5), $ids); - } - - public function testRandomPublished(IntegrationTester $I) - { - $I->insertInDatabase(10, 'Quote', ['approved' => Quote::PUBLISHED]); - $I->insertInDatabase(20, 'Quote', ['approved' => Quote::REFUSED]); - - $quote = $this->repo->randomPublished(1); - $I->assertTrue($quote instanceof Illuminate\Database\Eloquent\Collection); - $I->assertEquals(1, count($quote)); - $I->assertEquals(Quote::PUBLISHED, $quote->first()->approved); - } - - public function testRandomPublishedToday(IntegrationTester $I) - { - $lastMonth = Carbon::now()->subMonth(1); - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED, 'created_at' => $lastMonth, 'updated_at' => $lastMonth]); - $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::PUBLISHED]); - - $quote = $this->repo->randomPublishedToday(1); - $I->assertTrue($quote instanceof Illuminate\Database\Eloquent\Collection); - $I->assertEquals(1, count($quote)); - $I->assertEquals(Quote::PUBLISHED, $quote->first()->approved); - $I->assertEquals($q->id, $quote->first()->id); - } - - public function testIndexRandom(IntegrationTester $I) - { - $I->insertInDatabase(20, 'Quote', ['approved' => Quote::REFUSED]); - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); - - $quotes = $this->repo->indexRandom(1, 5); - $I->assertIsCollection($quotes); - $I->assertEquals(5, count($quotes)); - $ids = $quotes->lists('id'); - foreach ($quotes as $quote) { - $I->assertGreaterThan(20, $quote->id); - } - - // Check that for the second call we get the same quotes - $quotes = $this->repo->indexRandom(1, 5); - foreach ($quotes as $quote) { - $I->assertTrue(in_array($quote->id, $ids)); - } - } - - public function testListPublishedIdsForUser(IntegrationTester $I) - { - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); - $user = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); - - $ids = $this->repo->listPublishedIdsForUser($user); - $I->assertEquals([6, 7], $ids); - } - - public function testNbPublishedForUser(IntegrationTester $I) - { - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); - $user = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(2, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); - - $I->assertEquals(2, $this->repo->nbPublishedForUser($user)); - } - - public function testGetForIds(IntegrationTester $I) - { - $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); - $quotes = $this->repo->getForIds(range(1, 5), 1, 2); - - $I->assertEquals([1, 2], $quotes->lists('id')); - } - - public function testGetQuotesByApprovedForUser(IntegrationTester $I) - { - $user = $I->insertInDatabase(1, 'User'); - $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); - - $quotes = $this->repo->getQuotesByApprovedForUser($user, 'published', 1, 2); - $I->assertEquals([1, 2], $quotes->lists('id')); - } - - public function testNbDaysUntilPublication(IntegrationTester $I) - { - $nbQuotesPublishedPerDay = Config::get('app.quotes.nbQuotesToPublishPerDay'); - - $I->insertInDatabase(1, 'Quote'); - $firstQuote = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::PENDING]); - - // We can pass an ID - $I->assertEquals(1, $this->repo->nbDaysUntilPublication($firstQuote->id)); - $I->insertInDatabase($nbQuotesPublishedPerDay, 'Quote', ['approved' => Quote::PENDING]); - // We can pass an object - $I->assertEquals(1, $this->repo->nbDaysUntilPublication($firstQuote)); - // It computes the right number for multiple days - $I->assertEquals(1, $this->repo->nbDaysUntilPublication($nbQuotesPublishedPerDay + 1)); - $I->assertEquals(2, $this->repo->nbDaysUntilPublication($nbQuotesPublishedPerDay + 2)); - } - - public function testNbQuotesWithFavorites(IntegrationTester $I) - { - $I->insertInDatabase(2, 'Quote'); - $I->assertEquals(0, $this->repo->nbQuotesWithFavorites()); - - $I->insertInDatabase(1, 'FavoriteQuote', ['quote_id' => 1]); - $I->assertEquals(1, $this->repo->nbQuotesWithFavorites()); - - $I->insertInDatabase(2, 'FavoriteQuote', ['quote_id' => 2]); - $I->assertEquals(2, $this->repo->nbQuotesWithFavorites()); - } - - public function testGetQuotesForTag(IntegrationTester $I) - { - $quotes = $I->insertInDatabase(2, 'Quote'); - $tags = $I->insertInDatabase(2, 'Tag'); - - $I->assertEmpty($this->repo->getQuotesForTag($tags[0], 1, 10)); - - $this->tagRepo->tagQuote($quotes[0], $tags[0]); - - $quotesResult = $this->repo->getQuotesForTag($tags[0], 1, 10); - $I->assertIsCollection($quotesResult); - $I->assertEquals(1, count($quotesResult)); - - // Add another quote with this tag - $this->tagRepo->tagQuote($quotes[1], $tags[0]); - $quotesResult = $this->repo->getQuotesForTag($tags[0], 1, 10); - $I->assertEquals(2, count($quotesResult)); - } - - public function testCountWaitingQuotesSince(IntegrationTester $I) - { - $twoDaysAgo = $this->nbDaysAgo(2); - $threeDaysAgo = $this->nbDaysAgo(3); - $fourDaysAgo = $this->nbDaysAgo(4); - - // A published quote in the period - $I->insertInDatabase(1, 'Quote', ['created_at' => $twoDaysAgo]); - // A pending quote before the period - $I->insertInDatabase(1, 'Quote', ['created_at' => $fourDaysAgo, 'approved' => Quote::WAITING]); - // Quotes we should target - $I->insertInDatabase(2, 'Quote', ['created_at' => $twoDaysAgo, 'approved' => Quote::WAITING]); - - $I->assertEquals(2, $this->repo->countWaitingQuotesSince($threeDaysAgo)); - } - - /** - * Get a date from a number of days ago - * @param int $number - * @return \Carbon\Carbon - */ - private function nbDaysAgo($number) - { - return Carbon::now()->subDays($number); - } -} \ No newline at end of file + public function testGetById(IntegrationTester $I) + { + $content = 'Testing you know'; + $I->insertInDatabase(1, 'Quote', ['content' => $content]); + + $quote = $this->repo->getById(1); + $I->assertEquals($content, $quote->content); + } + + public function testGetByIdWithUser(IntegrationTester $I) + { + $user = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(1, 'Quote', ['user_id' => $user->id]); + + $quote = $this->repo->getByIdWithUser(1); + + $I->assertEquals($user->id, $quote->user->id); + $I->assertEquals($user->login, $quote->user->login); + } + + public function testWaitingById(IntegrationTester $I) + { + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); + $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::WAITING]); + + $quote = $this->repo->waitingById($q->id); + + $I->assertEquals($q->content, $quote->content); + } + + public function testShowQuote(IntegrationTester $I) + { + $quotes = $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED]); + + $quote = $this->repo->showQuote(2); + + $I->assertEquals($quote->id, $quotes[1]->id); + } + + public function testCountQuotesByApprovedForUser(IntegrationTester $I) + { + $user = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::WAITING, 'user_id' => $user->id]); + $I->insertInDatabase(2, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); + + $I->assertEquals(3, $this->repo->countQuotesByApprovedForUser('waiting', $user)); + $I->assertEquals(2, $this->repo->countQuotesByApprovedForUser('published', $user)); + } + + public function testUpdateContentAndApproved(IntegrationTester $I) + { + $newContent = 'Hello World'; + $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::WAITING]); + + $this->repo->updateContentAndApproved($q->id, $newContent, Quote::PUBLISHED); + + $q = $this->repo->getById($q->id); + $I->assertEquals(Quote::PUBLISHED, $q->approved); + $I->assertEquals($newContent, $q->content); + } + + public function testUpdateApproved(IntegrationTester $I) + { + $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::WAITING]); + + $this->repo->updateApproved($q->id, Quote::PUBLISHED); + + $q = $this->repo->getById($q->id); + $I->assertEquals(Quote::PUBLISHED, $q->approved); + } + + public function testTotalPublished(IntegrationTester $I) + { + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::WAITING]); + $I->insertInDatabase(4, 'Quote', ['approved' => Quote::PUBLISHED]); + + $I->assertEquals(4, $this->repo->totalPublished()); + } + + public function testSubmittedTodayForUser(IntegrationTester $I) + { + $user = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Quote', ['user_id' => $user->id, 'created_at' => Carbon::now()->subMonth(1)]); + $I->insertInDatabase(3, 'Quote', ['user_id' => $user->id]); + + $I->assertEquals(3, $this->repo->submittedTodayForUser($user)); + } + + public function testCreateQuoteForUser(IntegrationTester $I) + { + $content = 'Hello World'; + $user = $I->insertInDatabase(1, 'User'); + + $q = $this->repo->createQuoteForUser($user, $content); + $q = $this->repo->getById($q->id); + + $I->assertEquals($content, $q->content); + $I->assertEquals(Quote::WAITING, $q->approved); + } + + public function testIndex(IntegrationTester $I) + { + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED, 'created_at' => Carbon::now()->subMonth(1)]); + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::WAITING]); + + $quotes = $this->repo->index(1, 5); + $ids = $quotes->lists('id'); + sort($ids); + $I->assertIsCollection($quotes); + $I->assertEquals(range(1, 5), $ids); + } + + public function testRandomPublished(IntegrationTester $I) + { + $I->insertInDatabase(10, 'Quote', ['approved' => Quote::PUBLISHED]); + $I->insertInDatabase(20, 'Quote', ['approved' => Quote::REFUSED]); + + $quote = $this->repo->randomPublished(1); + $I->assertTrue($quote instanceof Illuminate\Database\Eloquent\Collection); + $I->assertEquals(1, count($quote)); + $I->assertEquals(Quote::PUBLISHED, $quote->first()->approved); + } + + public function testRandomPublishedToday(IntegrationTester $I) + { + $lastMonth = Carbon::now()->subMonth(1); + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED, 'created_at' => $lastMonth, 'updated_at' => $lastMonth]); + $q = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::PUBLISHED]); + + $quote = $this->repo->randomPublishedToday(1); + $I->assertTrue($quote instanceof Illuminate\Database\Eloquent\Collection); + $I->assertEquals(1, count($quote)); + $I->assertEquals(Quote::PUBLISHED, $quote->first()->approved); + $I->assertEquals($q->id, $quote->first()->id); + } + + public function testIndexRandom(IntegrationTester $I) + { + $I->insertInDatabase(20, 'Quote', ['approved' => Quote::REFUSED]); + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); + + $quotes = $this->repo->indexRandom(1, 5); + $I->assertIsCollection($quotes); + $I->assertEquals(5, count($quotes)); + $ids = $quotes->lists('id'); + foreach ($quotes as $quote) { + $I->assertGreaterThan(20, $quote->id); + } + + // Check that for the second call we get the same quotes + $quotes = $this->repo->indexRandom(1, 5); + foreach ($quotes as $quote) { + $I->assertTrue(in_array($quote->id, $ids)); + } + } + + public function testListPublishedIdsForUser(IntegrationTester $I) + { + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); + $user = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); + + $ids = $this->repo->listPublishedIdsForUser($user); + $I->assertEquals([6, 7], $ids); + } + + public function testNbPublishedForUser(IntegrationTester $I) + { + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); + $user = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(2, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); + + $I->assertEquals(2, $this->repo->nbPublishedForUser($user)); + } + + public function testGetForIds(IntegrationTester $I) + { + $I->insertInDatabase(5, 'Quote', ['approved' => Quote::PUBLISHED]); + $quotes = $this->repo->getForIds(range(1, 5), 1, 2); + + $I->assertEquals([1, 2], $quotes->lists('id')); + } + + public function testGetQuotesByApprovedForUser(IntegrationTester $I) + { + $user = $I->insertInDatabase(1, 'User'); + $I->insertInDatabase(3, 'Quote', ['approved' => Quote::PUBLISHED, 'user_id' => $user->id]); + + $quotes = $this->repo->getQuotesByApprovedForUser($user, 'published', 1, 2); + $I->assertEquals([1, 2], $quotes->lists('id')); + } + + public function testNbDaysUntilPublication(IntegrationTester $I) + { + $nbQuotesPublishedPerDay = Config::get('app.quotes.nbQuotesToPublishPerDay'); + + $I->insertInDatabase(1, 'Quote'); + $firstQuote = $I->insertInDatabase(1, 'Quote', ['approved' => Quote::PENDING]); + + // We can pass an ID + $I->assertEquals(1, $this->repo->nbDaysUntilPublication($firstQuote->id)); + $I->insertInDatabase($nbQuotesPublishedPerDay, 'Quote', ['approved' => Quote::PENDING]); + // We can pass an object + $I->assertEquals(1, $this->repo->nbDaysUntilPublication($firstQuote)); + // It computes the right number for multiple days + $I->assertEquals(1, $this->repo->nbDaysUntilPublication($nbQuotesPublishedPerDay + 1)); + $I->assertEquals(2, $this->repo->nbDaysUntilPublication($nbQuotesPublishedPerDay + 2)); + } + + public function testNbQuotesWithFavorites(IntegrationTester $I) + { + $I->insertInDatabase(2, 'Quote'); + $I->assertEquals(0, $this->repo->nbQuotesWithFavorites()); + + $I->insertInDatabase(1, 'FavoriteQuote', ['quote_id' => 1]); + $I->assertEquals(1, $this->repo->nbQuotesWithFavorites()); + + $I->insertInDatabase(2, 'FavoriteQuote', ['quote_id' => 2]); + $I->assertEquals(2, $this->repo->nbQuotesWithFavorites()); + } + + public function testGetQuotesForTag(IntegrationTester $I) + { + $quotes = $I->insertInDatabase(2, 'Quote'); + $tags = $I->insertInDatabase(2, 'Tag'); + + $I->assertEmpty($this->repo->getQuotesForTag($tags[0], 1, 10)); + + $this->tagRepo->tagQuote($quotes[0], $tags[0]); + + $quotesResult = $this->repo->getQuotesForTag($tags[0], 1, 10); + $I->assertIsCollection($quotesResult); + $I->assertEquals(1, count($quotesResult)); + + // Add another quote with this tag + $this->tagRepo->tagQuote($quotes[1], $tags[0]); + $quotesResult = $this->repo->getQuotesForTag($tags[0], 1, 10); + $I->assertEquals(2, count($quotesResult)); + } + + public function testCountWaitingQuotesSince(IntegrationTester $I) + { + $twoDaysAgo = $this->nbDaysAgo(2); + $threeDaysAgo = $this->nbDaysAgo(3); + $fourDaysAgo = $this->nbDaysAgo(4); + + // A published quote in the period + $I->insertInDatabase(1, 'Quote', ['created_at' => $twoDaysAgo]); + // A pending quote before the period + $I->insertInDatabase(1, 'Quote', ['created_at' => $fourDaysAgo, 'approved' => Quote::WAITING]); + // Quotes we should target + $I->insertInDatabase(2, 'Quote', ['created_at' => $twoDaysAgo, 'approved' => Quote::WAITING]); + + $I->assertEquals(2, $this->repo->countWaitingQuotesSince($threeDaysAgo)); + } + + /** + * Get a date from a number of days ago. + * + * @param int $number + * + * @return \Carbon\Carbon + */ + private function nbDaysAgo($number) + { + return Carbon::now()->subDays($number); + } +} diff --git a/tests/integration/SettingRepoCest.php b/tests/integration/SettingRepoCest.php index 738e27b2..f9b0dd7b 100644 --- a/tests/integration/SettingRepoCest.php +++ b/tests/integration/SettingRepoCest.php @@ -1,58 +1,58 @@ repo = App::make('TeenQuotes\Settings\Repositories\SettingRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Settings\Repositories\SettingRepository'); - } + public function testFindForUserAndKey(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $this->insertSetting($I, $u->id, 'foo', 'bar'); - public function testFindForUserAndKey(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $this->insertSetting($I, $u->id, 'foo', 'bar'); + $s = $this->repo->findForUserAndKey($u, 'foo'); - $s = $this->repo->findForUserAndKey($u, 'foo'); + $I->assertEquals('bar', $s->value); - $I->assertEquals('bar', $s->value); + // Unexisting key + $I->assertNull($this->repo->findForUserAndKey($u, 'notfound')); + } - // Unexisting key - $I->assertNull($this->repo->findForUserAndKey($u, 'notfound')); - } + public function testUpdateOrCreate(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $this->insertSetting($I, $u->id, 'foo', 'bar'); - public function testUpdateOrCreate(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $this->insertSetting($I, $u->id, 'foo', 'bar'); + // Update a value + $this->repo->updateOrCreate($u, 'foo', 'new'); - // Update a value - $this->repo->updateOrCreate($u, 'foo', 'new'); + $s = $this->repo->findForUserAndKey($u, 'foo'); - $s = $this->repo->findForUserAndKey($u, 'foo'); + $I->assertEquals('new', $s->value); + $I->assertEquals('foo', $s->key); + $I->assertEquals($u->id, $s->user_id); - $I->assertEquals('new', $s->value); - $I->assertEquals('foo', $s->key); - $I->assertEquals($u->id, $s->user_id); + // Create a new value + $this->repo->updateOrCreate($u, 'new', 'foo'); - // Create a new value - $this->repo->updateOrCreate($u, 'new', 'foo'); + $s = $this->repo->findForUserAndKey($u, 'new'); - $s = $this->repo->findForUserAndKey($u, 'new'); + $I->assertEquals('foo', $s->value); + $I->assertEquals('new', $s->key); + $I->assertEquals($u->id, $s->user_id); + } - $I->assertEquals('foo', $s->value); - $I->assertEquals('new', $s->key); - $I->assertEquals($u->id, $s->user_id); - } + private function insertSetting(IntegrationTester $I, $user_id, $key, $value) + { + $data = compact('user_id', 'key', 'value'); - private function insertSetting(IntegrationTester $I, $user_id, $key, $value) - { - $data = compact('user_id', 'key', 'value'); - - return $I->insertInDatabase(1, 'Setting', $data); - } -} \ No newline at end of file + return $I->insertInDatabase(1, 'Setting', $data); + } +} diff --git a/tests/integration/StoryRepoCest.php b/tests/integration/StoryRepoCest.php index d14e1a8e..a131d9c3 100644 --- a/tests/integration/StoryRepoCest.php +++ b/tests/integration/StoryRepoCest.php @@ -1,61 +1,61 @@ repo = App::make('TeenQuotes\Stories\Repositories\StoryRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Stories\Repositories\StoryRepository'); - } + public function testFindById(IntegrationTester $I) + { + $s = $I->insertInDatabase(1, 'Story'); + $I->insertInDatabase(2, 'Story'); - public function testFindById(IntegrationTester $I) - { - $s = $I->insertInDatabase(1, 'Story'); - $I->insertInDatabase(2, 'Story'); + $story = $this->repo->findById($s->id); - $story = $this->repo->findById($s->id); + $I->assertEquals($s->content, $story->content); + $I->assertEquals($s->user->id, $story->user->id); + } - $I->assertEquals($s->content, $story->content); - $I->assertEquals($s->user->id, $story->user->id); - } + public function testIndex(IntegrationTester $I) + { + $I->insertInDatabase(5, 'Story', ['created_at' => Carbon::now()->subMonth()]); + $I->insertInDatabase(1, 'Story'); - public function testIndex(IntegrationTester $I) - { - $I->insertInDatabase(5, 'Story', ['created_at' => Carbon::now()->subMonth()]); - $I->insertInDatabase(1, 'Story'); + $stories = $this->repo->index(1, 3); - $stories = $this->repo->index(1, 3); + $I->assertIsCollection($stories); + $I->assertEquals(3, count($stories)); + // It gets the latest story first + $I->assertEquals(6, $stories->first()->id); + } - $I->assertIsCollection($stories); - $I->assertEquals(3, count($stories)); - // It gets the latest story first - $I->assertEquals(6, $stories->first()->id); - } + public function testTotal(IntegrationTester $I) + { + $I->assertEquals(0, $this->repo->total()); - public function testTotal(IntegrationTester $I) - { - $I->assertEquals(0, $this->repo->total()); + $I->insertInDatabase(2, 'Story'); + $I->assertEquals(2, $this->repo->total()); + } - $I->insertInDatabase(2, 'Story'); - $I->assertEquals(2, $this->repo->total()); - } + public function testCreate(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); - public function testCreate(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); + $represent_txt = str_repeat('a', 20); + $frequence_txt = str_repeat('a', 20); - $represent_txt = str_repeat('a', 20); - $frequence_txt = str_repeat('a', 20); + $s = $this->repo->create($u, $represent_txt, $frequence_txt); - $s = $this->repo->create($u, $represent_txt, $frequence_txt); + $story = $this->repo->findById($s->id); - $story = $this->repo->findById($s->id); - - $I->assertEquals($represent_txt, $story->represent_txt); - $I->assertEquals($frequence_txt, $story->frequence_txt); - } -} \ No newline at end of file + $I->assertEquals($represent_txt, $story->represent_txt); + $I->assertEquals($frequence_txt, $story->frequence_txt); + } +} diff --git a/tests/integration/TagRepoCest.php b/tests/integration/TagRepoCest.php index 0bbd0321..784d4267 100644 --- a/tests/integration/TagRepoCest.php +++ b/tests/integration/TagRepoCest.php @@ -1,114 +1,113 @@ repo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); - } + public function testCreate(IntegrationTester $I) + { + $name = 'Foobar'; - public function testCreate(IntegrationTester $I) - { - $name = 'Foobar'; + $this->repo->create($name); - $this->repo->create($name); + $I->seeRecord('tags', compact('name')); + } - $I->seeRecord('tags', compact('name')); - } + public function testGetByName(IntegrationTester $I) + { + $name = 'Foobar'; - public function testGetByName(IntegrationTester $I) - { - $name = 'Foobar'; + $I->insertInDatabase(1, 'Tag', compact('name')); - $I->insertInDatabase(1, 'Tag', compact('name')); + $tag = $this->repo->getByName($name); - $tag = $this->repo->getByName($name); + $I->assertEquals($tag->name, $name); - $I->assertEquals($tag->name, $name); + // Non existing tag + $I->assertNull($this->repo->getByName('notfound')); + } - // Non existing tag - $I->assertNull($this->repo->getByName('notfound')); - } + public function testTagQuote(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Quote'); + $quote = $I->insertInDatabase(1, 'Quote'); + $tag = $I->insertInDatabase(1, 'Tag', compact('name')); - public function testTagQuote(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Quote'); - $quote = $I->insertInDatabase(1, 'Quote'); - $tag = $I->insertInDatabase(1, 'Tag', compact('name')); + $this->repo->tagQuote($quote, $tag); - $this->repo->tagQuote($quote, $tag); + $I->seeRecord('quote_tag', ['quote_id' => $quote->id, 'tag_id' => $tag->id]); + } - $I->seeRecord('quote_tag', ['quote_id' => $quote->id, 'tag_id' => $tag->id]); - } + public function testUntagQuote(IntegrationTester $I) + { + $I->insertInDatabase(1, 'Quote'); + $quote = $I->insertInDatabase(1, 'Quote'); + $tag = $I->insertInDatabase(1, 'Tag', compact('name')); - public function testUntagQuote(IntegrationTester $I) - { - $I->insertInDatabase(1, 'Quote'); - $quote = $I->insertInDatabase(1, 'Quote'); - $tag = $I->insertInDatabase(1, 'Tag', compact('name')); + $this->repo->tagQuote($quote, $tag); - $this->repo->tagQuote($quote, $tag); + // Assert quote was tagged + $I->seeRecord('quote_tag', ['quote_id' => $quote->id, 'tag_id' => $tag->id]); - // Assert quote was tagged - $I->seeRecord('quote_tag', ['quote_id' => $quote->id, 'tag_id' => $tag->id]); + // Untag the quote + $this->repo->untagQuote($quote, $tag); + $I->dontSeeRecord('quote_tag', ['quote_id' => $quote->id, 'tag_id' => $tag->id]); + } - // Untag the quote - $this->repo->untagQuote($quote, $tag); - $I->dontSeeRecord('quote_tag', ['quote_id' => $quote->id, 'tag_id' => $tag->id]); - } + public function testTagsForQuote(IntegrationTester $I) + { + $tags = ['love', 'family']; + foreach ($tags as $name) { + $I->insertInDatabase(1, 'Tag', compact('name')); + } - public function testTagsForQuote(IntegrationTester $I) - { - $tags = ['love', 'family']; - foreach($tags as $name) - { - $I->insertInDatabase(1, 'Tag', compact('name')); - } + $quote = $I->insertInDatabase(1, 'Quote'); - $quote = $I->insertInDatabase(1, 'Quote'); + // Add a first tag to the quote + $this->repo->tagQuote($quote, $this->repo->getByName('love')); + $I->assertEquals($this->repo->tagsForQuote($quote), ['love']); - // Add a first tag to the quote - $this->repo->tagQuote($quote, $this->repo->getByName('love')); - $I->assertEquals($this->repo->tagsForQuote($quote), ['love']); + // Add another tag to the quote + $this->repo->tagQuote($quote, $this->repo->getByName('family')); + $tagsResult = $this->repo->tagsForQuote($quote); + sort($tagsResult); - // Add another tag to the quote - $this->repo->tagQuote($quote, $this->repo->getByName('family')); - $tagsResult = $this->repo->tagsForQuote($quote); - sort($tagsResult); + $I->assertEquals($tagsResult, ['family', 'love']); - $I->assertEquals($tagsResult, ['family', 'love']); + // Remove a tag + $this->repo->untagQuote($quote, $this->repo->getByName('family')); + $I->assertEquals($this->repo->tagsForQuote($quote), ['love']); - // Remove a tag - $this->repo->untagQuote($quote, $this->repo->getByName('family')); - $I->assertEquals($this->repo->tagsForQuote($quote), ['love']); + // We get an empty array if we have no tags + $quoteTwo = $I->insertInDatabase(1, 'Quote'); + $I->assertEquals([], $this->repo->tagsForQuote($quoteTwo)); + } - // We get an empty array if we have no tags - $quoteTwo = $I->insertInDatabase(1, 'Quote'); - $I->assertEquals([], $this->repo->tagsForQuote($quoteTwo)); - } + public function testTotalQuotesForTag(IntegrationTester $I) + { + $quotes = $I->insertInDatabase(2, 'Quote'); + $tag = $I->insertInDatabase(1, 'Tag'); - public function testTotalQuotesForTag(IntegrationTester $I) - { - $quotes = $I->insertInDatabase(2, 'Quote'); - $tag = $I->insertInDatabase(1, 'Tag'); + $I->assertEquals(0, $this->repo->totalQuotesForTag($tag)); - $I->assertEquals(0, $this->repo->totalQuotesForTag($tag)); + // Tag a first quote + $this->repo->tagQuote($quotes[0], $tag); + $I->assertEquals(1, $this->repo->totalQuotesForTag($tag)); - // Tag a first quote - $this->repo->tagQuote($quotes[0], $tag); - $I->assertEquals(1, $this->repo->totalQuotesForTag($tag)); + // Add another quote + $this->repo->tagQuote($quotes[1], $tag); + $I->assertEquals(2, $this->repo->totalQuotesForTag($tag)); - // Add another quote - $this->repo->tagQuote($quotes[1], $tag); - $I->assertEquals(2, $this->repo->totalQuotesForTag($tag)); - - // Untag a quote - $this->repo->untagQuote($quotes[0], $tag); - $I->assertEquals(1, $this->repo->totalQuotesForTag($tag)); - } -} \ No newline at end of file + // Untag a quote + $this->repo->untagQuote($quotes[0], $tag); + $I->assertEquals(1, $this->repo->totalQuotesForTag($tag)); + } +} diff --git a/tests/integration/UserRepoCest.php b/tests/integration/UserRepoCest.php index f1e79c27..a5bd234e 100644 --- a/tests/integration/UserRepoCest.php +++ b/tests/integration/UserRepoCest.php @@ -1,304 +1,303 @@ repo = App::make('TeenQuotes\Users\Repositories\UserRepository'); + $this->newsletterRepo = App::make('TeenQuotes\Newsletters\Repositories\NewsletterRepository'); + $this->countryRepo = App::make('TeenQuotes\Countries\Repositories\CountryRepository'); + } - public function _before() - { - $this->repo = App::make('TeenQuotes\Users\Repositories\UserRepository'); - $this->newsletterRepo = App::make('TeenQuotes\Newsletters\Repositories\NewsletterRepository'); - $this->countryRepo = App::make('TeenQuotes\Countries\Repositories\CountryRepository'); - } + public function testGetById(IntegrationTester $I) + { + $I->insertInDatabase(1, 'User'); + $u = $I->insertInDatabase(1, 'User'); - public function testGetById(IntegrationTester $I) - { - $I->insertInDatabase(1, 'User'); - $u = $I->insertInDatabase(1, 'User'); + $user = $this->repo->getById($u->id); - $user = $this->repo->getById($u->id); + $I->assertEquals($u->login, $user->login); + $I->assertEquals($u->email, $user->email); + } - $I->assertEquals($u->login, $user->login); - $I->assertEquals($u->email, $user->email); - } + public function testGetByEmail(IntegrationTester $I) + { + $I->insertInDatabase(1, 'User'); + $u = $I->insertInDatabase(1, 'User'); - public function testGetByEmail(IntegrationTester $I) - { - $I->insertInDatabase(1, 'User'); - $u = $I->insertInDatabase(1, 'User'); + $user = $this->repo->getByEmail($u->email); - $user = $this->repo->getByEmail($u->email); + $I->assertEquals($u->login, $user->login); + $I->assertEquals($u->email, $user->email); + } - $I->assertEquals($u->login, $user->login); - $I->assertEquals($u->email, $user->email); - } + public function testGetByEmails(IntegrationTester $I) + { + $I->insertInDatabase(2, 'User'); + $user = $I->insertInDatabase(1, 'User', ['email' => 'foo@bar.com']); - public function testGetByEmails(IntegrationTester $I) - { - $I->insertInDatabase(2, 'User'); - $user = $I->insertInDatabase(1, 'User', ['email' => 'foo@bar.com']); + $users = $this->repo->getByEmails(['foo@bar.com']); - $users = $this->repo->getByEmails(['foo@bar.com']); + $I->assertIsCollection($users); + $I->assertEquals(1, count($users)); + $I->assertEquals($user->login, $users->first()->login); + } - $I->assertIsCollection($users); - $I->assertEquals(1, count($users)); - $I->assertEquals($user->login, $users->first()->login); - } + public function testGetByLogin(IntegrationTester $I) + { + $I->insertInDatabase(1, 'User'); + $u = $I->insertInDatabase(1, 'User'); - public function testGetByLogin(IntegrationTester $I) - { - $I->insertInDatabase(1, 'User'); - $u = $I->insertInDatabase(1, 'User'); + $user = $this->repo->getByLogin($u->login); - $user = $this->repo->getByLogin($u->login); + $I->assertEquals($u->login, $user->login); + $I->assertEquals($u->email, $user->email); + } - $I->assertEquals($u->login, $user->login); - $I->assertEquals($u->email, $user->email); - } + public function testCountByPartialLogin(IntegrationTester $I) + { + $partial = 'foo'; - public function testCountByPartialLogin(IntegrationTester $I) - { - $partial = 'foo'; + $count = $this->insertUsersForSearch($I, $partial); - $count = $this->insertUsersForSearch($I, $partial); + $I->assertEquals($count, $this->repo->countByPartialLogin($partial)); + } - $I->assertEquals($count, $this->repo->countByPartialLogin($partial)); - } + public function testUpdatePassword(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $newPassword = 'foobar22'; + $credentials = ['login' => $u->login, 'password' => $newPassword]; - public function testUpdatePassword(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $newPassword = 'foobar22'; - $credentials = ['login' => $u->login, 'password' => $newPassword]; + $this->repo->updatePassword($u, $newPassword); - $this->repo->updatePassword($u, $newPassword); + $I->assertTrue(Auth::validate($credentials)); + } - $I->assertTrue(Auth::validate($credentials)); - } + public function testUpdateEmail(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + $newEmail = 'foobar@bar.com'; - public function testUpdateEmail(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - $newEmail = 'foobar@bar.com'; + $this->repo->updateEmail($u, $newEmail); - $this->repo->updateEmail($u, $newEmail); + $user = $this->repo->getById(1); - $user = $this->repo->getById(1); + $I->assertEquals($newEmail, $user->email); + } - $I->assertEquals($newEmail, $user->email); - } + public function testUpdateProfile(IntegrationTester $I) + { + $gender = 'F'; + $country = 10; // Argentina + $city = 'Foobar'; + $about_me = 'Enjoying integration tests'; + $birthdate = '1900-12-01'; + $avatar = null; - public function testUpdateProfile(IntegrationTester $I) - { - $gender = 'F'; - $country = 10; // Argentina - $city = 'Foobar'; - $about_me = 'Enjoying integration tests'; - $birthdate = '1900-12-01'; - $avatar = null; + $u = $I->insertInDatabase(1, 'User'); - $u = $I->insertInDatabase(1, 'User'); + $this->repo->updateProfile($u, $gender, $country, $city, $about_me, $birthdate, $avatar); - $this->repo->updateProfile($u, $gender, $country, $city, $about_me, $birthdate, $avatar); + $user = $this->repo->getById($u->id); - $user = $this->repo->getById($u->id); + $I->assertTrue($user->isFemale()); + $I->assertEquals('Argentina', $user->country_object->name); + $I->assertEquals($city, $user->city); + $I->assertEquals($about_me, $user->about_me); + $I->assertEquals($birthdate, $user->birthdate); + // TODO: test the avatar + } - $I->assertTrue($user->isFemale()); - $I->assertEquals('Argentina', $user->country_object->name); - $I->assertEquals($city, $user->city); - $I->assertEquals($about_me, $user->about_me); - $I->assertEquals($birthdate, $user->birthdate); - // TODO: test the avatar - } + public function testUpdateSettings(IntegrationTester $I) + { + $notification_comment_quote = false; + $hide_profile = false; - public function testUpdateSettings(IntegrationTester $I) - { - $notification_comment_quote = false; - $hide_profile = false; + $u = $I->insertInDatabase(1, 'User', ['notification_comment_quote' => true, 'hide_profile' => true]); - $u = $I->insertInDatabase(1, 'User', ['notification_comment_quote' => true, 'hide_profile' => true]); + $this->repo->updateSettings($u, $notification_comment_quote, $hide_profile); - $this->repo->updateSettings($u, $notification_comment_quote, $hide_profile); + $user = $this->repo->getById($u->id); + $I->assertFalse($user->isHiddenProfile()); + $I->assertFalse($user->wantsEmailComment()); + } - $user = $this->repo->getById($u->id); - $I->assertFalse($user->isHiddenProfile()); - $I->assertFalse($user->wantsEmailComment()); - } + public function testGetAll(IntegrationTester $I) + { + $I->insertInDatabase(2, 'User'); + $I->insertInDatabase(1, 'User', ['hide_profile' => true]); - public function testGetAll(IntegrationTester $I) - { - $I->insertInDatabase(2, 'User'); - $I->insertInDatabase(1, 'User', ['hide_profile' => true]); + $users = $this->repo->getAll(); - $users = $this->repo->getAll(); + $I->assertIsCollection($users); + $I->assertEquals(3, count($users)); + } - $I->assertIsCollection($users); - $I->assertEquals(3, count($users)); - } + public function testBirthdayToday(IntegrationTester $I) + { + $birthDate = Carbon::now()->subYears(20)->format('Y-m-d'); + $notBirthDate = Carbon::now()->subYears(2)->subDays(5)->format('Y-m-d'); + $I->insertInDatabase(2, 'User', ['birthdate' => $notBirthDate]); + $u = $I->insertInDatabase(1, 'User', ['birthdate' => $birthDate]); - public function testBirthdayToday(IntegrationTester $I) - { - $birthDate = Carbon::now()->subYears(20)->format('Y-m-d'); - $notBirthDate = Carbon::now()->subYears(2)->subDays(5)->format('Y-m-d'); - $I->insertInDatabase(2, 'User', ['birthdate' => $notBirthDate]); - $u = $I->insertInDatabase(1, 'User', ['birthdate' => $birthDate]); + $users = $this->repo->birthdayToday(); - $users = $this->repo->birthdayToday(); + $I->assertIsCollection($users); + $I->assertEquals(1, count($users)); + $I->assertEquals($u->login, $users->first()->login); + } - $I->assertIsCollection($users); - $I->assertEquals(1, count($users)); - $I->assertEquals($u->login, $users->first()->login); - } + public function testShowByLoginOrId(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); - public function testShowByLoginOrId(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); + // Get by ID + $user = $this->repo->showByLoginOrId($u->id); + $I->assertEquals($u->login, $user->login); - // Get by ID - $user = $this->repo->showByLoginOrId($u->id); - $I->assertEquals($u->login, $user->login); + // Get by login + $user = $this->repo->showByLoginOrId($u->login); + $I->assertEquals($u->login, $user->login); + } + + public function testGetLoggedInSince(IntegrationTester $I) + { + $I->insertInDatabase(1, 'User', ['last_visit' => Carbon::now()->subMonths(2)]); + $I->insertInDatabase(2, 'User', ['last_visit' => Carbon::now()->subDays(10)]); + + $users = $this->repo->getLoggedInSince(Carbon::now()->subDays(15), 1, 10); - // Get by login - $user = $this->repo->showByLoginOrId($u->login); - $I->assertEquals($u->login, $user->login); - } - - public function testGetLoggedInSince(IntegrationTester $I) - { - $I->insertInDatabase(1, 'User', ['last_visit' => Carbon::now()->subMonths(2)]); - $I->insertInDatabase(2, 'User', ['last_visit' => Carbon::now()->subDays(10)]); - - $users = $this->repo->getLoggedInSince(Carbon::now()->subDays(15), 1, 10); - - $I->assertIsCollection($users); - $I->assertEquals(2, count($users)); - } - - public function testSearchByPartialLogin(IntegrationTester $I) - { - $partial = 'foo'; - - $count = $this->insertUsersForSearch($I, $partial); - $users = $this->repo->searchByPartialLogin($partial, 1, 20); - - $I->assertIsCollection($users); - $I->assertEquals($count, count($users)); - } - - public function testCreate(IntegrationTester $I) - { - $login = 'foobar'; - $email = 'foo@bar.com'; - $password = 'foobar22'; - $ip = '22.22.22.22'; - $lastVisit = Carbon::now(); - $country = 10; // Argentina - $city = 'Foo City'; - - $this->repo->create($login, $email, $password, $ip, $lastVisit, $country, $city); - - $user = $this->repo->getById(1); - - // Test default assigned values - $I->assertTrue($user->getIsSubscribedToWeekly()); - $I->assertFalse($user->getIsSubscribedToDaily()); - $I->assertTrue($user->wantsEmailComment()); - - $I->assertEquals($login, $user->login); - $I->assertEquals($email, $user->email); - $I->assertEquals($city, $user->city); - $I->assertEquals('Argentina', $user->country_object->name); - } - - public function testDestroy(IntegrationTester $I) - { - $u = $I->insertInDatabase(1, 'User'); - - $this->repo->destroy($u->id); - - $I->assertNull($this->repo->getById($u->id)); - } - - public function testMostCommon(IntegrationTester $I) - { - $mostCommonId = 42; - $I->insertInDatabase(2, 'User', ['country' => 2]); - $I->insertInDatabase(3, 'User', ['country' => $mostCommonId]); - - $I->assertEquals($mostCommonId, $this->repo->mostCommonCountryId()); - } - - public function testGetNonActiveHavingNewsletter(IntegrationTester $I) - { - $lastYear = Carbon::now()->subDays(370); - $u = $I->insertInDatabase(1, 'User', ['last_visit' => $lastYear]); - - // A user, who haven't logged in the last year, but without newsletters - $fake = $I->insertInDatabase(1, 'User', ['last_visit' => $lastYear]); - $this->newsletterRepo->deleteForUserAndType($fake, 'weekly'); - - $users = $this->repo->getNonActiveHavingNewsletter(); - - $I->assertIsCollection($users); - $I->assertEquals(1, count($users)); - $I->assertEquals($u->login, $users->first()->login); - } - - public function testFromCountry(IntegrationTester $I) - { - $firstCountry = $this->countryRepo->findById(1); - $secondCountry = $this->countryRepo->findById(2); - - // Create some users from the first country - $I->insertInDatabase(5, 'User', ['country' => $firstCountry->id]); - - // It shouldn't retrieve users from the 1st country - $I->assertEmpty($this->repo->fromCountry($secondCountry, 1, 10)); - // We should retrieve our users from the 2nd country - $I->assertEquals(5, count($this->repo->fromCountry($firstCountry, 1, 10))); - // We shouldn't retrieve too much users - $I->assertEquals(2, count($this->repo->fromCountry($firstCountry, 1, 2))); - } - - public function testCountFromCountry(IntegrationTester $I) - { - $firstCountry = $this->countryRepo->findById(1); - $secondCountry = $this->countryRepo->findById(2); - - // Create some users from the first country - $I->insertInDatabase(2, 'User', ['country' => $firstCountry->id]); - // One user with an hidden profile - $I->insertInDatabase(1, 'User', ['country' => $firstCountry->id, 'hide_profile' => 1]); - - // We shouldn't count the user with an hidden profile - $I->assertEquals(2, $this->repo->countFromCountry($firstCountry)); - - $I->assertEquals(0, $this->repo->countFromCountry($secondCountry)); - } - - private function insertUsersForSearch(IntegrationTester $I, $partial) - { - $I->insertInDatabase(2, 'User'); - $I->insertInDatabase(1, 'User', ['login' => 'ab'.$partial.'bar']); - $I->insertInDatabase(1, 'User', ['login' => 'abc'.$partial.'baz']); - // We shouldn't retrieve an hidden profile - $I->insertInDatabase(1, 'User', ['login' => 'hidden'.$partial, 'hide_profile' => true]); - - return 2; - } -} \ No newline at end of file + $I->assertIsCollection($users); + $I->assertEquals(2, count($users)); + } + + public function testSearchByPartialLogin(IntegrationTester $I) + { + $partial = 'foo'; + + $count = $this->insertUsersForSearch($I, $partial); + $users = $this->repo->searchByPartialLogin($partial, 1, 20); + + $I->assertIsCollection($users); + $I->assertEquals($count, count($users)); + } + + public function testCreate(IntegrationTester $I) + { + $login = 'foobar'; + $email = 'foo@bar.com'; + $password = 'foobar22'; + $ip = '22.22.22.22'; + $lastVisit = Carbon::now(); + $country = 10; // Argentina + $city = 'Foo City'; + + $this->repo->create($login, $email, $password, $ip, $lastVisit, $country, $city); + + $user = $this->repo->getById(1); + + // Test default assigned values + $I->assertTrue($user->getIsSubscribedToWeekly()); + $I->assertFalse($user->getIsSubscribedToDaily()); + $I->assertTrue($user->wantsEmailComment()); + + $I->assertEquals($login, $user->login); + $I->assertEquals($email, $user->email); + $I->assertEquals($city, $user->city); + $I->assertEquals('Argentina', $user->country_object->name); + } + + public function testDestroy(IntegrationTester $I) + { + $u = $I->insertInDatabase(1, 'User'); + + $this->repo->destroy($u->id); + + $I->assertNull($this->repo->getById($u->id)); + } + + public function testMostCommon(IntegrationTester $I) + { + $mostCommonId = 42; + $I->insertInDatabase(2, 'User', ['country' => 2]); + $I->insertInDatabase(3, 'User', ['country' => $mostCommonId]); + + $I->assertEquals($mostCommonId, $this->repo->mostCommonCountryId()); + } + + public function testGetNonActiveHavingNewsletter(IntegrationTester $I) + { + $lastYear = Carbon::now()->subDays(370); + $u = $I->insertInDatabase(1, 'User', ['last_visit' => $lastYear]); + + // A user, who haven't logged in the last year, but without newsletters + $fake = $I->insertInDatabase(1, 'User', ['last_visit' => $lastYear]); + $this->newsletterRepo->deleteForUserAndType($fake, 'weekly'); + + $users = $this->repo->getNonActiveHavingNewsletter(); + + $I->assertIsCollection($users); + $I->assertEquals(1, count($users)); + $I->assertEquals($u->login, $users->first()->login); + } + + public function testFromCountry(IntegrationTester $I) + { + $firstCountry = $this->countryRepo->findById(1); + $secondCountry = $this->countryRepo->findById(2); + + // Create some users from the first country + $I->insertInDatabase(5, 'User', ['country' => $firstCountry->id]); + + // It shouldn't retrieve users from the 1st country + $I->assertEmpty($this->repo->fromCountry($secondCountry, 1, 10)); + // We should retrieve our users from the 2nd country + $I->assertEquals(5, count($this->repo->fromCountry($firstCountry, 1, 10))); + // We shouldn't retrieve too much users + $I->assertEquals(2, count($this->repo->fromCountry($firstCountry, 1, 2))); + } + + public function testCountFromCountry(IntegrationTester $I) + { + $firstCountry = $this->countryRepo->findById(1); + $secondCountry = $this->countryRepo->findById(2); + + // Create some users from the first country + $I->insertInDatabase(2, 'User', ['country' => $firstCountry->id]); + // One user with an hidden profile + $I->insertInDatabase(1, 'User', ['country' => $firstCountry->id, 'hide_profile' => 1]); + + // We shouldn't count the user with an hidden profile + $I->assertEquals(2, $this->repo->countFromCountry($firstCountry)); + + $I->assertEquals(0, $this->repo->countFromCountry($secondCountry)); + } + + private function insertUsersForSearch(IntegrationTester $I, $partial) + { + $I->insertInDatabase(2, 'User'); + $I->insertInDatabase(1, 'User', ['login' => 'ab'.$partial.'bar']); + $I->insertInDatabase(1, 'User', ['login' => 'abc'.$partial.'baz']); + // We shouldn't retrieve an hidden profile + $I->insertInDatabase(1, 'User', ['login' => 'hidden'.$partial, 'hide_profile' => true]); + + return 2; + } +} diff --git a/tests/search.suite.yml b/tests/search.suite.yml index 993d1f4a..d74e6a60 100644 --- a/tests/search.suite.yml +++ b/tests/search.suite.yml @@ -21,4 +21,4 @@ modules: password: '' dump: tests/_data/dumpSearch.sql populate: true - cleanup: true \ No newline at end of file + cleanup: true diff --git a/tests/search/SearchQuoteCest.php b/tests/search/SearchQuoteCest.php index a31cadee..f053af29 100644 --- a/tests/search/SearchQuoteCest.php +++ b/tests/search/SearchQuoteCest.php @@ -1,23 +1,23 @@ nbQuotes; $i++) { + $I->insertInDatabase(1, 'Quote', ['content' => Str::random(50).' '.$this->searchFor.' '.Str::random(20)]); + } + } - public function _before(SearchTester $I) - { - for ($i = 1; $i <= $this->nbQuotes; $i++) { - $I->insertInDatabase(1, 'Quote', ['content' => Str::random(50).' '.$this->searchFor.' '.Str::random(20)]); - } - } + public function testSearchTooSmall(SearchTester $I) + { + $I->navigateToTheSearchPage(); + $I->fillSearchForm('ab'); - public function testSearchTooSmall(SearchTester $I) - { - $I->navigateToTheSearchPage(); - $I->fillSearchForm('ab'); - - $I->seeCurrentRouteIs('search.form'); - $I->seeFormError('The search must be at least 3 characters.'); - } -} \ No newline at end of file + $I->seeCurrentRouteIs('search.form'); + $I->seeFormError('The search must be at least 3 characters.'); + } +} diff --git a/tests/search/SearchUserCest.php b/tests/search/SearchUserCest.php index 03723b18..350e9152 100644 --- a/tests/search/SearchUserCest.php +++ b/tests/search/SearchUserCest.php @@ -1,30 +1,30 @@ createSomePublishedQuotes(); - public function _before(SearchTester $I) - { - $I->createSomePublishedQuotes(); - - for ($i = 1; $i <= $this->nbUsers; $i++) { - $I->insertInDatabase(1, 'User', ['login' => Str::random(2).$this->searchFor.$i]); - } + for ($i = 1; $i <= $this->nbUsers; $i++) { + $I->insertInDatabase(1, 'User', ['login' => Str::random(2).$this->searchFor.$i]); + } - // A matching user with an hidden profile - $I->insertInDatabase(1, 'User', ['login' => Str::random(2).$this->searchFor, 'hide_profile' => true]); - } + // A matching user with an hidden profile + $I->insertInDatabase(1, 'User', ['login' => Str::random(2).$this->searchFor, 'hide_profile' => true]); + } - public function testSearchSuccess(SearchTester $I) - { - $I->navigateToTheSearchPage(); - $I->fillSearchForm($this->searchFor); + public function testSearchSuccess(SearchTester $I) + { + $I->navigateToTheSearchPage(); + $I->fillSearchForm($this->searchFor); - $I->seeCurrentRouteIs('search.results', $this->searchFor); - $I->see('Users', "#users"); - $I->see($this->nbUsers." results"); - $I->seeNumberOfElements('.user-row', $this->nbUsers); - } -} \ No newline at end of file + $I->seeCurrentRouteIs('search.results', $this->searchFor); + $I->see('Users', '#users'); + $I->see($this->nbUsers.' results'); + $I->seeNumberOfElements('.user-row', $this->nbUsers); + } +} diff --git a/tests/search/_bootstrap.php b/tests/search/_bootstrap.php index 94bf66cf..8a885558 100644 --- a/tests/search/_bootstrap.php +++ b/tests/search/_bootstrap.php @@ -1,2 +1,2 @@ unitTester->setRequiredAttributes($this->requiredAttributes); - - $this->unitTester->setEmbedsRelation([]); - } - - protected function _after() - { - if (Auth::check()) - Auth::logout(); - - // Rollback the transaction - DB::rollBack(); - } -} \ No newline at end of file +abstract class ApiTest extends Test +{ + /** + * @var UnitTester + */ + protected $tester; + + protected function _before() + { + Artisan::call('migrate'); + + // We'll run all tests through a transaction, + // and then rollback afterward. + DB::beginTransaction(); + + // Set required attributes + $this->unitTester->setRequiredAttributes($this->requiredAttributes); + + $this->unitTester->setEmbedsRelation([]); + } + + protected function _after() + { + if (Auth::check()) { + Auth::logout(); + } + + // Rollback the transaction + DB::rollBack(); + } +} diff --git a/tests/unit/Api/v1/CommentsTest.php b/tests/unit/Api/v1/CommentsTest.php index 25cf2861..a18ebf69 100644 --- a/tests/unit/Api/v1/CommentsTest.php +++ b/tests/unit/Api/v1/CommentsTest.php @@ -1,347 +1,346 @@ unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\CommentsController')); - - $this->unitTester->setContentType('comments'); - - // Create a quote and add some comments to it - $q = $this->unitTester->insertInDatabase(1, 'Quote'); - $this->quoteId = $q['id']; - $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Comment', ['quote_id' => $this->quoteId]); - } - - public function testIndexWithoutQuote() - { - $this->doNotEmbedsQuote(); - - // Test with the middle page - $this->unitTester->tryMiddlePage('index', $this->quoteId); - - // Test first page - $this->unitTester->tryFirstPage('index', $this->quoteId); - } - - public function testIndexWithQuote() - { - // Test with the middle page - $this->activateEmbedsQuote(); - $this->unitTester->tryMiddlePage('index', $this->quoteId); - - // Test first page - $this->activateEmbedsQuote(); - $this->unitTester->tryFirstPage('index', $this->quoteId); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage comments - */ - public function testIndexNotFound() - { - // Test not found - $this->unitTester->tryPaginatedContentNotFound('index', $this->quoteId); - } - - public function testShowNotFound() - { - // Not found comment - $this->unitTester->tryShowNotFound($this->unitTester->getIdNonExistingRessource()) - ->withStatusMessage('comment_not_found') - ->withErrorMessage('The comment #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testShowFoundWithoutQuote() - { - $this->doNotEmbedsQuote(); - $this->unitTester->tryShowFound($this->quoteId); - } - - public function testShowFoundWithQuote() - { - $this->activateEmbedsQuote(); - $this->unitTester->tryShowFound($this->quoteId); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The content field is required. - */ - public function testStoreEmptyContent() - { - // Empty content - $this->unitTester->addInputReplace(['content' => '']); - - $this->assertStoreWithWrongContent(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The content must be at least 10 characters. - */ - public function testStoreTooSmallContent() - { - // Too small content - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(9)]); - - $this->assertStoreWithWrongContent(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The content may not be greater than 500 characters. - */ - public function testStoreTooLongContent() - { - // Too long content - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(501)]); - - $this->assertStoreWithWrongContent(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The selected quote id was not found. - */ - public function testStoreQuoteIdNotFound() - { - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(100)]); - - $this->store($this->unitTester->getIdNonExistingRessource()); - } - - public function testStoreSuccess() - { - $q = Quote::find($this->quoteId); - - // Check number of comments - $this->assertEquals($this->unitTester->getNbRessources(), $q->total_comments); - - $oldNbComments = $q->total_comments; - - // Store in a new comment - $this->unitTester->logUserWithId(1); - $this->unitTester->addInputReplace([ - 'content' => $this->unitTester->generateString(150), - ]); - - $this->store($q->id) - ->unitTester->assertStatusCodeIs(Response::HTTP_CREATED) - ->assertResponseHasRequiredAttributes(); - - // Verify the total number of comments - $this->assertEquals($oldNbComments + 1, $q->total_comments); - } - - public function testDestroyCommentNotFound() - { - $this->unitTester->logUserWithId(1); - - $this->destroy($this->unitTester->getIdNonExistingRessource()) - ->unitTester->assertStatusCodeIs(Response::HTTP_NOT_FOUND) - ->withStatusMessage('comment_not_found') - ->withErrorMessage('The comment #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testDestroyCommentNotOwned() - { - // Create a comment not owned by the logged in user - $u = $this->unitTester->insertInDatabase(1, 'Quote', ['id' => 500]); - $c = $this->unitTester->insertInDatabase(1, 'Comment', ['user_id' => $u['id']]); - - $idUserLoggedIn = 1; - $this->unitTester->logUserWithId($idUserLoggedIn); - - $this->destroy($c['id']) - ->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('comment_not_self') - ->withErrorMessage('The comment #'.$c['id'].' was not posted by user #'.$idUserLoggedIn.'.'); - } - - public function testDestroySuccess() - { - $c = Comment::first(); - - $this->unitTester->logUserWithId($c->user_id); - - $this->destroy($c->id) - ->unitTester->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('comment_deleted') - ->withSuccessMessage('The comment #'.$c->id.' was deleted.'); - - $this->assertEmpty(Comment::find($c->id)); - } - - public function testUpdateCommentNotFound() - { - $this->unitTester->logUserWithId(1); - - $this->update($this->unitTester->getIdNonExistingRessource()) - ->unitTester->assertStatusCodeIs(Response::HTTP_NOT_FOUND) - ->withStatusMessage('comment_not_found') - ->withErrorMessage('The comment #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testUpdateCommentNotOwned() - { - // Create a comment not owned by the logged in user - $u = $this->unitTester->insertInDatabase(1, 'Quote', ['id' => 500]); - $c = $this->unitTester->insertInDatabase(1, 'Comment', ['user_id' => $u['id']]); - - $idUserLoggedIn = 1; - $this->unitTester->logUserWithId($idUserLoggedIn); - - $this->update($c['id']) - ->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('comment_not_self') - ->withErrorMessage('The comment #'.$c['id'].' was not posted by user #'.$idUserLoggedIn.'.'); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The content must be at least 10 characters. - */ - public function testUpdateTooSmallContent() - { - // Too small content - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(9)]); - - $this->assertUpdateWithWrongContent(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The content may not be greater than 500 characters. - */ - public function testUpdateTooLongContent() - { - // Too long content - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(501)]); - - $this->assertUpdateWithWrongContent(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The content field is required. - */ - public function testUpdateRequiredContent() - { - // No content - $this->unitTester->addInputReplace(['content' => '']); - - $this->assertUpdateWithWrongContent(); - } - - public function testUpdateSuccess() - { - $c = Comment::first(); - - $this->unitTester->logUserWithId($c->user_id); - - $this->unitTester->addInputReplace([ - 'content' => $this->unitTester->generateString(150), - ]); - - $this->update($c->id) - ->unitTester->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('comment_updated') - ->withSuccessMessage('The comment #'.$c->id.' was updated.'); - } - - public function testIndexForUser() - { - $u = $this->unitTester->insertInDatabase(1, 'User'); - $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Comment', ['user_id' => $u->id]); - - $this->activateEmbedsQuote(); - - // Test first page - $this->unitTester->tryFirstPage('getCommentsForUser', $u->id); - - // Test with the middle page - $this->unitTester->tryMiddlePage('getCommentsForUser', $u->id); - } - - public function testIndexForUserNotFound() - { - $this->unitTester->doRequest('getCommentsForUser', 100); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('user_not_found') - ->withErrorMessage('The user #100 was not found.'); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage comments - */ - public function testIndexForUserNoComments() - { - $u = $this->unitTester->insertInDatabase(1, 'User'); - - // Try with a user with no comments - $this->unitTester->tryFirstPage('getCommentsForUser', $u->id); - } - - private function assertStoreWithWrongContent() - { - $this->unitTester->logUserWithId(1); - - $this->store($this->quoteId); - } - - private function assertUpdateWithWrongContent() - { - $c = Comment::first(); - $this->unitTester->logUserWithId($c->user_id); - - $this->store($c->id); - } - - private function store($id) - { - $this->unitTester->tryStore('store', $id); - - return $this; - } - - private function destroy($id) - { - $this->unitTester->doRequest('destroy', $id); - - return $this; - } - - private function update($id) - { - $this->unitTester->doRequest('update', $id); - - return $this; - } - - private function doNotEmbedsQuote() - { - $this->unitTester->setEmbedsRelation(['user_small']); - } - - private function activateEmbedsQuote() - { - $this->unitTester->setEmbedsRelation(['user_small', 'quote']); - $this->unitTester->addInputReplace(['quote' => true]); - } -} \ No newline at end of file +class CommentsTest extends ApiTest +{ + protected $requiredAttributes = ['id', 'content', 'quote_id', 'user_id', 'created_at']; + protected $embedsRelation = ['user_small', 'quote']; + protected $quoteId; + + protected function _before() + { + parent::_before(); + + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\CommentsController')); + + $this->unitTester->setContentType('comments'); + + // Create a quote and add some comments to it + $q = $this->unitTester->insertInDatabase(1, 'Quote'); + $this->quoteId = $q['id']; + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Comment', ['quote_id' => $this->quoteId]); + } + + public function testIndexWithoutQuote() + { + $this->doNotEmbedsQuote(); + + // Test with the middle page + $this->unitTester->tryMiddlePage('index', $this->quoteId); + + // Test first page + $this->unitTester->tryFirstPage('index', $this->quoteId); + } + + public function testIndexWithQuote() + { + // Test with the middle page + $this->activateEmbedsQuote(); + $this->unitTester->tryMiddlePage('index', $this->quoteId); + + // Test first page + $this->activateEmbedsQuote(); + $this->unitTester->tryFirstPage('index', $this->quoteId); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage comments + */ + public function testIndexNotFound() + { + // Test not found + $this->unitTester->tryPaginatedContentNotFound('index', $this->quoteId); + } + + public function testShowNotFound() + { + // Not found comment + $this->unitTester->tryShowNotFound($this->unitTester->getIdNonExistingRessource()) + ->withStatusMessage('comment_not_found') + ->withErrorMessage('The comment #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testShowFoundWithoutQuote() + { + $this->doNotEmbedsQuote(); + $this->unitTester->tryShowFound($this->quoteId); + } + + public function testShowFoundWithQuote() + { + $this->activateEmbedsQuote(); + $this->unitTester->tryShowFound($this->quoteId); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The content field is required. + */ + public function testStoreEmptyContent() + { + // Empty content + $this->unitTester->addInputReplace(['content' => '']); + + $this->assertStoreWithWrongContent(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The content must be at least 10 characters. + */ + public function testStoreTooSmallContent() + { + // Too small content + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(9)]); + + $this->assertStoreWithWrongContent(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The content may not be greater than 500 characters. + */ + public function testStoreTooLongContent() + { + // Too long content + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(501)]); + + $this->assertStoreWithWrongContent(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The selected quote id was not found. + */ + public function testStoreQuoteIdNotFound() + { + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(100)]); + + $this->store($this->unitTester->getIdNonExistingRessource()); + } + + public function testStoreSuccess() + { + $q = Quote::find($this->quoteId); + + // Check number of comments + $this->assertEquals($this->unitTester->getNbRessources(), $q->total_comments); + + $oldNbComments = $q->total_comments; + + // Store in a new comment + $this->unitTester->logUserWithId(1); + $this->unitTester->addInputReplace([ + 'content' => $this->unitTester->generateString(150), + ]); + + $this->store($q->id) + ->unitTester->assertStatusCodeIs(Response::HTTP_CREATED) + ->assertResponseHasRequiredAttributes(); + + // Verify the total number of comments + $this->assertEquals($oldNbComments + 1, $q->total_comments); + } + + public function testDestroyCommentNotFound() + { + $this->unitTester->logUserWithId(1); + + $this->destroy($this->unitTester->getIdNonExistingRessource()) + ->unitTester->assertStatusCodeIs(Response::HTTP_NOT_FOUND) + ->withStatusMessage('comment_not_found') + ->withErrorMessage('The comment #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testDestroyCommentNotOwned() + { + // Create a comment not owned by the logged in user + $u = $this->unitTester->insertInDatabase(1, 'Quote', ['id' => 500]); + $c = $this->unitTester->insertInDatabase(1, 'Comment', ['user_id' => $u['id']]); + + $idUserLoggedIn = 1; + $this->unitTester->logUserWithId($idUserLoggedIn); + + $this->destroy($c['id']) + ->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('comment_not_self') + ->withErrorMessage('The comment #'.$c['id'].' was not posted by user #'.$idUserLoggedIn.'.'); + } + + public function testDestroySuccess() + { + $c = Comment::first(); + + $this->unitTester->logUserWithId($c->user_id); + + $this->destroy($c->id) + ->unitTester->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('comment_deleted') + ->withSuccessMessage('The comment #'.$c->id.' was deleted.'); + + $this->assertEmpty(Comment::find($c->id)); + } + + public function testUpdateCommentNotFound() + { + $this->unitTester->logUserWithId(1); + + $this->update($this->unitTester->getIdNonExistingRessource()) + ->unitTester->assertStatusCodeIs(Response::HTTP_NOT_FOUND) + ->withStatusMessage('comment_not_found') + ->withErrorMessage('The comment #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testUpdateCommentNotOwned() + { + // Create a comment not owned by the logged in user + $u = $this->unitTester->insertInDatabase(1, 'Quote', ['id' => 500]); + $c = $this->unitTester->insertInDatabase(1, 'Comment', ['user_id' => $u['id']]); + + $idUserLoggedIn = 1; + $this->unitTester->logUserWithId($idUserLoggedIn); + + $this->update($c['id']) + ->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('comment_not_self') + ->withErrorMessage('The comment #'.$c['id'].' was not posted by user #'.$idUserLoggedIn.'.'); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The content must be at least 10 characters. + */ + public function testUpdateTooSmallContent() + { + // Too small content + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(9)]); + + $this->assertUpdateWithWrongContent(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The content may not be greater than 500 characters. + */ + public function testUpdateTooLongContent() + { + // Too long content + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(501)]); + + $this->assertUpdateWithWrongContent(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The content field is required. + */ + public function testUpdateRequiredContent() + { + // No content + $this->unitTester->addInputReplace(['content' => '']); + + $this->assertUpdateWithWrongContent(); + } + + public function testUpdateSuccess() + { + $c = Comment::first(); + + $this->unitTester->logUserWithId($c->user_id); + + $this->unitTester->addInputReplace([ + 'content' => $this->unitTester->generateString(150), + ]); + + $this->update($c->id) + ->unitTester->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('comment_updated') + ->withSuccessMessage('The comment #'.$c->id.' was updated.'); + } + + public function testIndexForUser() + { + $u = $this->unitTester->insertInDatabase(1, 'User'); + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Comment', ['user_id' => $u->id]); + + $this->activateEmbedsQuote(); + + // Test first page + $this->unitTester->tryFirstPage('getCommentsForUser', $u->id); + + // Test with the middle page + $this->unitTester->tryMiddlePage('getCommentsForUser', $u->id); + } + + public function testIndexForUserNotFound() + { + $this->unitTester->doRequest('getCommentsForUser', 100); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('user_not_found') + ->withErrorMessage('The user #100 was not found.'); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage comments + */ + public function testIndexForUserNoComments() + { + $u = $this->unitTester->insertInDatabase(1, 'User'); + + // Try with a user with no comments + $this->unitTester->tryFirstPage('getCommentsForUser', $u->id); + } + + private function assertStoreWithWrongContent() + { + $this->unitTester->logUserWithId(1); + + $this->store($this->quoteId); + } + + private function assertUpdateWithWrongContent() + { + $c = Comment::first(); + $this->unitTester->logUserWithId($c->user_id); + + $this->store($c->id); + } + + private function store($id) + { + $this->unitTester->tryStore('store', $id); + + return $this; + } + + private function destroy($id) + { + $this->unitTester->doRequest('destroy', $id); + + return $this; + } + + private function update($id) + { + $this->unitTester->doRequest('update', $id); + + return $this; + } + + private function doNotEmbedsQuote() + { + $this->unitTester->setEmbedsRelation(['user_small']); + } + + private function activateEmbedsQuote() + { + $this->unitTester->setEmbedsRelation(['user_small', 'quote']); + $this->unitTester->addInputReplace(['quote' => true]); + } +} diff --git a/tests/unit/Api/v1/CountriesTest.php b/tests/unit/Api/v1/CountriesTest.php index 3f8cad81..a2473ee0 100644 --- a/tests/unit/Api/v1/CountriesTest.php +++ b/tests/unit/Api/v1/CountriesTest.php @@ -1,45 +1,46 @@ unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Country'); - - $this->unitTester->setContentType('comments'); - - $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\CountriesController')); - } - - public function testShowNotFound() - { - // Not found country - $this->unitTester->tryShowNotFound() - ->withStatusMessage('country_not_found') - ->withErrorMessage('The country #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testShowFound() - { - // Regular country - for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) - $this->unitTester->tryShowFound($i); - } - - public function testListCountries() - { - // List all countries - $this->unitTester->doRequest('show'); - $object = $this->unitTester->getDecodedJson(); - - $this->assertCount($this->unitTester->getNbRessources(), $object); - foreach ($object as $country) - $this->unitTester->assertObjectHasRequiredAttributes($country); - } -} \ No newline at end of file +class CountriesTest extends ApiTest +{ + protected $requiredAttributes = ['id', 'name', 'country_code']; + + protected function _before() + { + parent::_before(); + + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Country'); + + $this->unitTester->setContentType('comments'); + + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\CountriesController')); + } + + public function testShowNotFound() + { + // Not found country + $this->unitTester->tryShowNotFound() + ->withStatusMessage('country_not_found') + ->withErrorMessage('The country #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testShowFound() + { + // Regular country + for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { + $this->unitTester->tryShowFound($i); + } + } + + public function testListCountries() + { + // List all countries + $this->unitTester->doRequest('show'); + $object = $this->unitTester->getDecodedJson(); + + $this->assertCount($this->unitTester->getNbRessources(), $object); + foreach ($object as $country) { + $this->unitTester->assertObjectHasRequiredAttributes($country); + } + } +} diff --git a/tests/unit/Api/v1/FavoriteQuotesTest.php b/tests/unit/Api/v1/FavoriteQuotesTest.php index aa17ca37..397aad25 100644 --- a/tests/unit/Api/v1/FavoriteQuotesTest.php +++ b/tests/unit/Api/v1/FavoriteQuotesTest.php @@ -4,138 +4,138 @@ use Illuminate\Support\Facades\Cache; use TeenQuotes\Quotes\Models\Quote; -class FavoriteQuotesTest extends ApiTest { +class FavoriteQuotesTest extends ApiTest +{ + protected $requiredAttributes = ['id', 'quote_id', 'user_id', 'created_at', 'updated_at']; + protected $user; + protected $idRefusedQuote; + protected $idPublishedQuote; - protected $requiredAttributes = ['id', 'quote_id', 'user_id', 'created_at', 'updated_at']; - protected $user; - protected $idRefusedQuote; - protected $idPublishedQuote; + protected function _before() + { + parent::_before(); - protected function _before() - { - parent::_before(); + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\QuotesFavoriteController')); + + // Create a user and log him in + $user = $this->unitTester->insertInDatabase(1, 'User'); + $this->user = $this->unitTester->logUserWithId($user['id']); + + $this->idRefusedQuote = $this->getIdRefusedQuote(); + $this->idPublishedQuote = $this->getIdPublishedQuote(); + } + + public function testPostQuoteNotFound() + { + $this->post($this->unitTester->getIdNonExistingRessource()); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('quote_not_found') + ->withErrorMessage('The quote #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testPostQuoteNotPublished() + { + $this->post($this->idRefusedQuote); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('quote_not_published') + ->withErrorMessage('The quote #'.$this->idRefusedQuote.' is not published.'); + } + + public function testPostQuoteSuccess() + { + $idPublishedQuote = $this->idPublishedQuote; + $quote = Quote::find($idPublishedQuote); + + $this->post($idPublishedQuote); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_CREATED) + ->assertResponseHasRequiredAttributes(); + + // Verify that the quote cache has been set + $this->assertEquals(1, $quote->total_favorites); + + // Verify that the user cache has been set properly + $this->assertEquals([$idPublishedQuote], $this->user->quotesFavorited()); + } + + public function testPostQuoteAlreadyFavorited() + { + // Add to favorite + $this->post($this->idPublishedQuote); + + // Add to favorite again + $this->post($this->idPublishedQuote); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('quote_already_favorited') + ->withErrorMessage('The quote #'.$this->idPublishedQuote.' was already favorited.'); + } + + public function testDeleteQuoteNotFound() + { + $this->delete($this->unitTester->getIdNonExistingRessource()); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('quote_not_found') + ->withErrorMessage('The quote #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testDeleteQuoteSuccess() + { + $quote = Quote::find($this->idPublishedQuote); + + // Add to favorite and run all assertions + $this->testPostQuoteSuccess(); + + // Delete it from favorites + $this->delete($this->idPublishedQuote); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('favorite_deleted') + ->withSuccessMessage('The quote #'.$this->idPublishedQuote.' was deleted from favorites.'); + + // Verify that the quote cache has been deleted + $this->assertEquals(0, $quote->total_favorites); + + // Verify that the user cache has been deleted properly + $this->assertEmpty($this->user->quotesFavorited()); + } + + private function post($quote_id) + { + $this->unitTester->setResponse( + $this->unitTester->getController()->postFavorite($quote_id) + ); - $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\QuotesFavoriteController')); + $this->unitTester->bindJson( + $this->unitTester->getResponse()->getContent() + ); + } - // Create a user and log him in - $user = $this->unitTester->insertInDatabase(1, 'User'); - $this->user = $this->unitTester->logUserWithId($user['id']); + private function delete($quote_id) + { + $this->unitTester->setResponse( + $this->unitTester->getController()->deleteFavorite($quote_id) + ); + + $this->unitTester->bindJson( + $this->unitTester->getResponse()->getContent() + ); + } - $this->idRefusedQuote = $this->getIdRefusedQuote(); - $this->idPublishedQuote = $this->getIdPublishedQuote(); - } + private function getIdRefusedQuote() + { + $quote = $this->unitTester->insertInDatabase(1, 'Quote', ['approved' => Quote::REFUSED]); - public function testPostQuoteNotFound() - { - $this->post($this->unitTester->getIdNonExistingRessource()); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('quote_not_found') - ->withErrorMessage("The quote #".$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testPostQuoteNotPublished() - { - $this->post($this->idRefusedQuote); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('quote_not_published') - ->withErrorMessage("The quote #".$this->idRefusedQuote.' is not published.'); - } - - public function testPostQuoteSuccess() - { - $idPublishedQuote = $this->idPublishedQuote; - $quote = Quote::find($idPublishedQuote); - - $this->post($idPublishedQuote); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_CREATED) - ->assertResponseHasRequiredAttributes(); - - // Verify that the quote cache has been set - $this->assertEquals(1, $quote->total_favorites); - - // Verify that the user cache has been set properly - $this->assertEquals([$idPublishedQuote], $this->user->quotesFavorited()); - } - - public function testPostQuoteAlreadyFavorited() - { - // Add to favorite - $this->post($this->idPublishedQuote); - - // Add to favorite again - $this->post($this->idPublishedQuote); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('quote_already_favorited') - ->withErrorMessage("The quote #".$this->idPublishedQuote.' was already favorited.'); - } - - public function testDeleteQuoteNotFound() - { - $this->delete($this->unitTester->getIdNonExistingRessource()); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('quote_not_found') - ->withErrorMessage("The quote #".$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testDeleteQuoteSuccess() - { - $quote = Quote::find($this->idPublishedQuote); - - // Add to favorite and run all assertions - $this->testPostQuoteSuccess(); - - // Delete it from favorites - $this->delete($this->idPublishedQuote); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('favorite_deleted') - ->withSuccessMessage("The quote #".$this->idPublishedQuote.' was deleted from favorites.'); - - // Verify that the quote cache has been deleted - $this->assertEquals(0, $quote->total_favorites); - - // Verify that the user cache has been deleted properly - $this->assertEmpty($this->user->quotesFavorited()); - } - - private function post($quote_id) - { - $this->unitTester->setResponse( - $this->unitTester->getController()->postFavorite($quote_id) - ); - - $this->unitTester->bindJson( - $this->unitTester->getResponse()->getContent() - ); - } - - private function delete($quote_id) - { - $this->unitTester->setResponse( - $this->unitTester->getController()->deleteFavorite($quote_id) - ); - - $this->unitTester->bindJson( - $this->unitTester->getResponse()->getContent() - ); - } - - private function getIdRefusedQuote() - { - $quote = $this->unitTester->insertInDatabase(1, 'Quote', ['approved' => Quote::REFUSED]); - - return $quote['id']; - } - - private function getIdPublishedQuote() - { - $quote = $this->unitTester->insertInDatabase(1, 'Quote', ['approved' => Quote::PUBLISHED]); - - return $quote['id']; - } -} \ No newline at end of file + return $quote['id']; + } + + private function getIdPublishedQuote() + { + $quote = $this->unitTester->insertInDatabase(1, 'Quote', ['approved' => Quote::PUBLISHED]); + + return $quote['id']; + } +} diff --git a/tests/unit/Api/v1/PasswordTest.php b/tests/unit/Api/v1/PasswordTest.php index edd5e90f..61655653 100644 --- a/tests/unit/Api/v1/PasswordTest.php +++ b/tests/unit/Api/v1/PasswordTest.php @@ -1,77 +1,77 @@ unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'User'); - - $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\PasswordController')); - } - - public function testRemindNotFound() - { - $this->unitTester->addInputReplace(['email' => 'foo']); - - $this->unitTester->doRequest('postRemind'); - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('wrong_user') - ->withErrorMessage("The email address doesn't match a user."); - } - - public function testRemindExistingUser() - { - $user = User::find(1); - - $this->unitTester->addInputReplace(['email' => $user->email]); - - $this->unitTester->doRequest('postRemind'); - $this->unitTester->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('reminder_sent') - ->withSuccessMessage('An email was sent to the user.'); - } - - public function testResetErrors() - { - $this->performInvalidReset(Password::INVALID_PASSWORD, 'wrong_password', "The password is wrong."); - $this->performInvalidReset(Password::INVALID_TOKEN, 'wrong_token', "The reset token is invalid."); - $this->performInvalidReset(Password::INVALID_USER, 'wrong_user', "The email address doesn't match a user."); - } - - public function testResetSuccess() - { - Password::shouldReceive('reset')->once()->andReturn(Password::PASSWORD_RESET); - - $this->unitTester->doRequest('postReset'); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('password_reset') - ->withSuccessMessage("The new password has been set."); - } - - /** - * Perform an invalid request to reset a password - * @param string $return The return of the Password::reset call - * @param string $status The expected status message - * @param string $error The expected error message - */ - private function performInvalidReset($return, $status, $error) - { - Password::shouldReceive('reset')->once()->andReturn($return); - - $this->unitTester->doRequest('postReset'); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage($status) - ->withErrorMessage($error); - } -} \ No newline at end of file +class PasswordTest extends ApiTest +{ + protected $requiredAttributes = []; + + protected function _before() + { + parent::_before(); + + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'User'); + + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\PasswordController')); + } + + public function testRemindNotFound() + { + $this->unitTester->addInputReplace(['email' => 'foo']); + + $this->unitTester->doRequest('postRemind'); + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('wrong_user') + ->withErrorMessage("The email address doesn't match a user."); + } + + public function testRemindExistingUser() + { + $user = User::find(1); + + $this->unitTester->addInputReplace(['email' => $user->email]); + + $this->unitTester->doRequest('postRemind'); + $this->unitTester->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('reminder_sent') + ->withSuccessMessage('An email was sent to the user.'); + } + + public function testResetErrors() + { + $this->performInvalidReset(Password::INVALID_PASSWORD, 'wrong_password', 'The password is wrong.'); + $this->performInvalidReset(Password::INVALID_TOKEN, 'wrong_token', 'The reset token is invalid.'); + $this->performInvalidReset(Password::INVALID_USER, 'wrong_user', "The email address doesn't match a user."); + } + + public function testResetSuccess() + { + Password::shouldReceive('reset')->once()->andReturn(Password::PASSWORD_RESET); + + $this->unitTester->doRequest('postReset'); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('password_reset') + ->withSuccessMessage('The new password has been set.'); + } + + /** + * Perform an invalid request to reset a password. + * + * @param string $return The return of the Password::reset call + * @param string $status The expected status message + * @param string $error The expected error message + */ + private function performInvalidReset($return, $status, $error) + { + Password::shouldReceive('reset')->once()->andReturn($return); + + $this->unitTester->doRequest('postReset'); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage($status) + ->withErrorMessage($error); + } +} diff --git a/tests/unit/Api/v1/QuotesTest.php b/tests/unit/Api/v1/QuotesTest.php index b1814224..86137105 100644 --- a/tests/unit/Api/v1/QuotesTest.php +++ b/tests/unit/Api/v1/QuotesTest.php @@ -4,299 +4,301 @@ use TeenQuotes\Quotes\Models\Quote; use TeenQuotes\Tags\Models\Tag; -class QuotesTest extends ApiTest { - - protected $requiredAttributes = ['id', 'content', 'user_id', 'approved', 'created_at', 'has_comments', 'total_comments', 'is_favorite', 'total_favorites', 'tags_list']; - protected $embedsRelation = ['user_small']; - protected $approvedTypes = ['waiting', 'refused', 'pending', 'published']; - - /** - * @var \TeenQuotes\Tags\Repositories\TagRepository - */ - private $tagRepo; - - protected function _before() - { - parent::_before(); - - $this->tagRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); - - $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\QuotesController')); - - $this->unitTester->setContentType('quotes'); - - $totalItems = $this->unitTester->getNbRessources(); - - $quotes = $this->unitTester->insertInDatabase($totalItems, 'Quote'); - foreach ($quotes as $quote) - $this->unitTester->insertInDatabase($quote->id, 'FavoriteQuote', ['quote_id' => $quote->id]); - } - - public function testShowNotFound() - { - // Not found quote - $this->unitTester->tryShowNotFound() - ->withStatusMessage('quote_not_found') - ->withErrorMessage('The quote #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); - } - - public function testShowFound() - { - // Regular quote - for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) - $this->unitTester->tryShowFound($i); - } - - public function testIndex() - { - // Test with the middle page - $this->unitTester->tryMiddlePage(); - - // Test first page - $this->unitTester->tryFirstPage(); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage quotes - */ - public function testIndexNotFound() - { - $this->unitTester->tryPaginatedContentNotFound(); - } - - public function testIndexRandom() - { - // Test with the middle page - $this->unitTester->tryMiddlePage('random'); - - // Test first page - $this->unitTester->tryFirstPage('random'); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage quotes - */ - public function testIndexRandomNotFound() - { - $this->unitTester->tryPaginatedContentNotFound('random'); - } - - public function testStoreContentTooSmall() - { - $this->unitTester->logUserWithId(1); - - // Content is too small - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(49)]); - - $this->assertStoreIsWrongContent(); - } - - public function testStoreContentTooLong() - { - $this->unitTester->logUserWithId(1); - - // Content is too long - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(301)]); - - $this->assertStoreIsWrongContent(); - } - - public function testStoreSuccess() - { - $this->unitTester->logUserWithId(1); - - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(100)]); - - $this->unitTester->tryStore() - ->assertStatusCodeIs(Response::HTTP_CREATED) - ->assertBelongsToLoggedInUser(); - } - - public function testStoreTooMuchSubmittedQuotes() - { - // Simulate that a user has already posted 5 quotes today - $u = $this->unitTester->insertInDatabase(1, 'User'); - $this->unitTester->insertInDatabase(5, 'Quote', ['user_id' => $u['id']]); - - $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(100)]); - - $this->unitTester->logUserWithId($u['id']); - - // Try to submit another quote but we should reach the limit - $this->unitTester->tryStore() - ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('too_much_submitted_quotes') - ->withErrorMessage('The maximum number of quotes you can submit is 5 per day.'); - } - - public function testQuotesFavoritesUnexistingUser() - { - $idNonExistingUser = 500; - - $this->unitTester->doRequest('indexFavoritesQuotes', $idNonExistingUser) - ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('user_not_found') - ->withErrorMessage('The user #'.$idNonExistingUser.' was not found.'); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage quotes - */ - public function testQuotesFavoritesWithoutFavorites() - { - $u = $this->unitTester->insertInDatabase(1, 'User'); - - $this->unitTester->doRequest('indexFavoritesQuotes', $u['id']); - } - - public function testQuotesFavoritesSuccess() - { - // Create favorites for a user - $u = $this->unitTester->insertInDatabase(1, 'User'); - for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) - $this->unitTester->insertInDatabase(1, 'FavoriteQuote', ['user_id' => $u->id, 'quote_id' => $i]); - - $this->unitTester->tryMiddlePage('indexFavoritesQuotes', $u['id']); - - $this->unitTester->tryFirstPage('indexFavoritesQuotes', $u['id']); - } - - public function testQuotesByApprovedUnexistingUser() - { - $idNonExistingUser = 500; - - foreach ($this->approvedTypes as $approved) { - - $this->unitTester->doRequest('indexByApprovedQuotes', [$approved, $idNonExistingUser]) - ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('user_not_found') - ->withErrorMessage('The user #'.$idNonExistingUser.' was not found.'); - } - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage quotes - */ - public function testQuotesByApprovedUnexistingQuotes() - { - foreach ($this->approvedTypes as $approved) { - - // Create a new user each time, with no quotes - $u = $this->unitTester->insertInDatabase(1, 'User'); - $idUser = $u['id']; - $this->unitTester->logUserWithId($idUser); - - // Create a quote with a different approved type for this user - $this->createQuotesForUserWithDifferentApproved($idUser, $approved); - - $this->unitTester->doRequest('indexByApprovedQuotes', [$approved, $idUser]); - } - } - - public function testQuotesByApprovedExistingQuotes() - { - $u = $this->unitTester->insertInDatabase(1, 'User'); - $idUser = $u['id']; - $this->unitTester->logUserWithId($idUser); - - foreach ($this->approvedTypes as $approved) { - - // Create some quotes with the given approved type for this user - $this->createQuotesForUserWithApproved($idUser, $approved); - - $this->unitTester->tryMiddlePage('indexByApprovedQuotes', [$approved, $idUser]); - - $this->unitTester->tryFirstPage('indexByApprovedQuotes', [$approved, $idUser]); - } - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage quotes - */ - public function testTopFavoritedQuotesNotFound() - { - $this->unitTester->tryPaginatedContentNotFound('getTopFavoritedQuotes'); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage tags - */ - public function testQuotesForTagTagNotFound() - { - $tagName = 'notfound'; - - $this->unitTester->tryPaginatedContentNotFound('getQuotesForTag', $tagName); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage quotes - */ - public function testQuotesForTagQuotesNotFound() - { - $name = 'love'; - $this->unitTester->insertInDatabase(1, 'Tag', compact('name')); - - $this->unitTester->tryPaginatedContentNotFound('getQuotesForTag', $name); - } - - public function testQuotesForTagSuccess() - { - // Create a tag - $name = 'love'; - $tag = $this->unitTester->insertInDatabase(1, 'Tag', compact('name')); - - // Associate quotes to this tag - $this->createQuotesWithTag($tag); - - // Call endpoints - $this->unitTester->tryMiddlePage('getQuotesForTag', $name); - - $this->unitTester->tryFirstPage('getQuotesForTag', $name); - } - - private function createQuotesWithTag(Tag $t) - { - $totalQuotes = $this->unitTester->getNbRessources(); - $quotes = $this->unitTester->insertInDatabase($totalQuotes, 'Quote'); - - foreach ($quotes as $quote) - { - $this->tagRepo->tagQuote($quote, $t); - } - } - - private function createQuotesForUserWithApproved($id, $approved) - { - $approvedType = constant("TeenQuotes\Quotes\Models\Quote::".strtoupper($approved)); - - $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Quote', ['user_id' => $id, 'approved' => $approvedType]); - } - - private function createQuotesForUserWithDifferentApproved($id, $approved) - { - if ($approved == 'published') - $this->unitTester->insertInDatabase(1, 'Quote', ['user_id' => $id, 'approved' => Quote::WAITING]); - - $this->unitTester->insertInDatabase(1, 'Quote', ['user_id' => $id, 'approved' => Quote::PUBLISHED]); - } - - private function assertStoreIsWrongContent() - { - $this->unitTester->tryStore() - ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('wrong_content') - ->withErrorMessage('Content of the quote should be between 50 and 300 characters.'); - } - - private function disableEmbedsSmallUser() - { - $this->unitTester->setEmbedsRelation([]); - } -} \ No newline at end of file +class QuotesTest extends ApiTest +{ + protected $requiredAttributes = ['id', 'content', 'user_id', 'approved', 'created_at', 'has_comments', 'total_comments', 'is_favorite', 'total_favorites', 'tags_list']; + protected $embedsRelation = ['user_small']; + protected $approvedTypes = ['waiting', 'refused', 'pending', 'published']; + + /** + * @var \TeenQuotes\Tags\Repositories\TagRepository + */ + private $tagRepo; + + protected function _before() + { + parent::_before(); + + $this->tagRepo = App::make('TeenQuotes\Tags\Repositories\TagRepository'); + + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\QuotesController')); + + $this->unitTester->setContentType('quotes'); + + $totalItems = $this->unitTester->getNbRessources(); + + $quotes = $this->unitTester->insertInDatabase($totalItems, 'Quote'); + foreach ($quotes as $quote) { + $this->unitTester->insertInDatabase($quote->id, 'FavoriteQuote', ['quote_id' => $quote->id]); + } + } + + public function testShowNotFound() + { + // Not found quote + $this->unitTester->tryShowNotFound() + ->withStatusMessage('quote_not_found') + ->withErrorMessage('The quote #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testShowFound() + { + // Regular quote + for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { + $this->unitTester->tryShowFound($i); + } + } + + public function testIndex() + { + // Test with the middle page + $this->unitTester->tryMiddlePage(); + + // Test first page + $this->unitTester->tryFirstPage(); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage quotes + */ + public function testIndexNotFound() + { + $this->unitTester->tryPaginatedContentNotFound(); + } + + public function testIndexRandom() + { + // Test with the middle page + $this->unitTester->tryMiddlePage('random'); + + // Test first page + $this->unitTester->tryFirstPage('random'); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage quotes + */ + public function testIndexRandomNotFound() + { + $this->unitTester->tryPaginatedContentNotFound('random'); + } + + public function testStoreContentTooSmall() + { + $this->unitTester->logUserWithId(1); + + // Content is too small + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(49)]); + + $this->assertStoreIsWrongContent(); + } + + public function testStoreContentTooLong() + { + $this->unitTester->logUserWithId(1); + + // Content is too long + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(301)]); + + $this->assertStoreIsWrongContent(); + } + + public function testStoreSuccess() + { + $this->unitTester->logUserWithId(1); + + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(100)]); + + $this->unitTester->tryStore() + ->assertStatusCodeIs(Response::HTTP_CREATED) + ->assertBelongsToLoggedInUser(); + } + + public function testStoreTooMuchSubmittedQuotes() + { + // Simulate that a user has already posted 5 quotes today + $u = $this->unitTester->insertInDatabase(1, 'User'); + $this->unitTester->insertInDatabase(5, 'Quote', ['user_id' => $u['id']]); + + $this->unitTester->addInputReplace(['content' => $this->unitTester->generateString(100)]); + + $this->unitTester->logUserWithId($u['id']); + + // Try to submit another quote but we should reach the limit + $this->unitTester->tryStore() + ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('too_much_submitted_quotes') + ->withErrorMessage('The maximum number of quotes you can submit is 5 per day.'); + } + + public function testQuotesFavoritesUnexistingUser() + { + $idNonExistingUser = 500; + + $this->unitTester->doRequest('indexFavoritesQuotes', $idNonExistingUser) + ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('user_not_found') + ->withErrorMessage('The user #'.$idNonExistingUser.' was not found.'); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage quotes + */ + public function testQuotesFavoritesWithoutFavorites() + { + $u = $this->unitTester->insertInDatabase(1, 'User'); + + $this->unitTester->doRequest('indexFavoritesQuotes', $u['id']); + } + + public function testQuotesFavoritesSuccess() + { + // Create favorites for a user + $u = $this->unitTester->insertInDatabase(1, 'User'); + for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { + $this->unitTester->insertInDatabase(1, 'FavoriteQuote', ['user_id' => $u->id, 'quote_id' => $i]); + } + + $this->unitTester->tryMiddlePage('indexFavoritesQuotes', $u['id']); + + $this->unitTester->tryFirstPage('indexFavoritesQuotes', $u['id']); + } + + public function testQuotesByApprovedUnexistingUser() + { + $idNonExistingUser = 500; + + foreach ($this->approvedTypes as $approved) { + $this->unitTester->doRequest('indexByApprovedQuotes', [$approved, $idNonExistingUser]) + ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('user_not_found') + ->withErrorMessage('The user #'.$idNonExistingUser.' was not found.'); + } + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage quotes + */ + public function testQuotesByApprovedUnexistingQuotes() + { + foreach ($this->approvedTypes as $approved) { + + // Create a new user each time, with no quotes + $u = $this->unitTester->insertInDatabase(1, 'User'); + $idUser = $u['id']; + $this->unitTester->logUserWithId($idUser); + + // Create a quote with a different approved type for this user + $this->createQuotesForUserWithDifferentApproved($idUser, $approved); + + $this->unitTester->doRequest('indexByApprovedQuotes', [$approved, $idUser]); + } + } + + public function testQuotesByApprovedExistingQuotes() + { + $u = $this->unitTester->insertInDatabase(1, 'User'); + $idUser = $u['id']; + $this->unitTester->logUserWithId($idUser); + + foreach ($this->approvedTypes as $approved) { + + // Create some quotes with the given approved type for this user + $this->createQuotesForUserWithApproved($idUser, $approved); + + $this->unitTester->tryMiddlePage('indexByApprovedQuotes', [$approved, $idUser]); + + $this->unitTester->tryFirstPage('indexByApprovedQuotes', [$approved, $idUser]); + } + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage quotes + */ + public function testTopFavoritedQuotesNotFound() + { + $this->unitTester->tryPaginatedContentNotFound('getTopFavoritedQuotes'); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage tags + */ + public function testQuotesForTagTagNotFound() + { + $tagName = 'notfound'; + + $this->unitTester->tryPaginatedContentNotFound('getQuotesForTag', $tagName); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage quotes + */ + public function testQuotesForTagQuotesNotFound() + { + $name = 'love'; + $this->unitTester->insertInDatabase(1, 'Tag', compact('name')); + + $this->unitTester->tryPaginatedContentNotFound('getQuotesForTag', $name); + } + + public function testQuotesForTagSuccess() + { + // Create a tag + $name = 'love'; + $tag = $this->unitTester->insertInDatabase(1, 'Tag', compact('name')); + + // Associate quotes to this tag + $this->createQuotesWithTag($tag); + + // Call endpoints + $this->unitTester->tryMiddlePage('getQuotesForTag', $name); + + $this->unitTester->tryFirstPage('getQuotesForTag', $name); + } + + private function createQuotesWithTag(Tag $t) + { + $totalQuotes = $this->unitTester->getNbRessources(); + $quotes = $this->unitTester->insertInDatabase($totalQuotes, 'Quote'); + + foreach ($quotes as $quote) { + $this->tagRepo->tagQuote($quote, $t); + } + } + + private function createQuotesForUserWithApproved($id, $approved) + { + $approvedType = constant("TeenQuotes\Quotes\Models\Quote::".strtoupper($approved)); + + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Quote', ['user_id' => $id, 'approved' => $approvedType]); + } + + private function createQuotesForUserWithDifferentApproved($id, $approved) + { + if ($approved == 'published') { + $this->unitTester->insertInDatabase(1, 'Quote', ['user_id' => $id, 'approved' => Quote::WAITING]); + } + + $this->unitTester->insertInDatabase(1, 'Quote', ['user_id' => $id, 'approved' => Quote::PUBLISHED]); + } + + private function assertStoreIsWrongContent() + { + $this->unitTester->tryStore() + ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('wrong_content') + ->withErrorMessage('Content of the quote should be between 50 and 300 characters.'); + } + + private function disableEmbedsSmallUser() + { + $this->unitTester->setEmbedsRelation([]); + } +} diff --git a/tests/unit/Api/v1/StoriesTest.php b/tests/unit/Api/v1/StoriesTest.php index 310a9d28..ff21b2dc 100644 --- a/tests/unit/Api/v1/StoriesTest.php +++ b/tests/unit/Api/v1/StoriesTest.php @@ -1,137 +1,137 @@ unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Story'); - - $this->unitTester->setContentType('stories'); - - $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\StoriesController')); - } - - public function testShowNotFound() - { - // Not found story - $this->unitTester->tryShowNotFound() - ->withStatusMessage('story_not_found') - ->withErrorMessage('The story #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); - - } - - public function testShowFound() - { - // Regular story - for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) - $this->unitTester->tryShowFound($i); - } - - public function testIndex() - { - // Test with the middle page - $this->unitTester->tryMiddlePage(); - - // Test first page - $this->unitTester->tryFirstPage(); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage stories - */ - public function testIndexNotFound() - { - $this->unitTester->tryPaginatedContentNotFound(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The frequence txt field is required. - */ - public function testStoreNoFrequence() - { - $this->hitStore(0, 200); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The frequence txt must be at least 100 characters. - */ - public function testStoreTooSmallFrequence() - { - $this->hitStore(50, 200); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The frequence txt may not be greater than 1000 characters. - */ - public function testStoreTooLargeFrequence() - { - $this->hitStore(1001, 200); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The represent txt field is required. - */ - public function testStoreNoRepresent() - { - $this->hitStore(200, 0); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The represent txt must be at least 100 characters. - */ - public function testStoreTooSmallRepresent() - { - $this->hitStore(200, 50); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The represent txt may not be greater than 1000 characters. - */ - public function testStoreTooLargeRepresent() - { - $this->hitStore(200, 1001); - } - - public function testStoreSuccess() - { - $this->hitStore(200, 200); - - $this->unitTester->assertStatusCodeIs(Response::HTTP_CREATED) - ->assertBelongsToLoggedInUser(); - - // Check that we can retrieve the new item - $this->unitTester->tryShowFound($this->unitTester->getNbRessources() + 1); - } - - /** - * Hit the store endpoint - * @param int $frequenceLength The length of the frequence_txt field - * @param int $representLength The length of the reprensent_txt field - */ - private function hitStore($frequenceLength, $representLength) - { - $this->unitTester->logUserWithId(1); - - $this->unitTester->addInputReplace([ - 'frequence_txt' => $this->unitTester->generateString($frequenceLength), - 'represent_txt' => $this->unitTester->generateString($representLength), - ]); - - $this->unitTester->tryStore(); - } -} \ No newline at end of file + +class StoriesTest extends ApiTest +{ + protected $embedsRelation = ['user_small']; + protected $requiredAttributes = ['id', 'represent_txt', 'frequence_txt', 'user_id', 'created_at', 'updated_at']; + + protected function _before() + { + parent::_before(); + + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'Story'); + + $this->unitTester->setContentType('stories'); + + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\StoriesController')); + } + + public function testShowNotFound() + { + // Not found story + $this->unitTester->tryShowNotFound() + ->withStatusMessage('story_not_found') + ->withErrorMessage('The story #'.$this->unitTester->getIdNonExistingRessource().' was not found.'); + } + + public function testShowFound() + { + // Regular story + for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { + $this->unitTester->tryShowFound($i); + } + } + + public function testIndex() + { + // Test with the middle page + $this->unitTester->tryMiddlePage(); + + // Test first page + $this->unitTester->tryFirstPage(); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage stories + */ + public function testIndexNotFound() + { + $this->unitTester->tryPaginatedContentNotFound(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The frequence txt field is required. + */ + public function testStoreNoFrequence() + { + $this->hitStore(0, 200); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The frequence txt must be at least 100 characters. + */ + public function testStoreTooSmallFrequence() + { + $this->hitStore(50, 200); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The frequence txt may not be greater than 1000 characters. + */ + public function testStoreTooLargeFrequence() + { + $this->hitStore(1001, 200); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The represent txt field is required. + */ + public function testStoreNoRepresent() + { + $this->hitStore(200, 0); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The represent txt must be at least 100 characters. + */ + public function testStoreTooSmallRepresent() + { + $this->hitStore(200, 50); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The represent txt may not be greater than 1000 characters. + */ + public function testStoreTooLargeRepresent() + { + $this->hitStore(200, 1001); + } + + public function testStoreSuccess() + { + $this->hitStore(200, 200); + + $this->unitTester->assertStatusCodeIs(Response::HTTP_CREATED) + ->assertBelongsToLoggedInUser(); + + // Check that we can retrieve the new item + $this->unitTester->tryShowFound($this->unitTester->getNbRessources() + 1); + } + + /** + * Hit the store endpoint. + * + * @param int $frequenceLength The length of the frequence_txt field + * @param int $representLength The length of the reprensent_txt field + */ + private function hitStore($frequenceLength, $representLength) + { + $this->unitTester->logUserWithId(1); + + $this->unitTester->addInputReplace([ + 'frequence_txt' => $this->unitTester->generateString($frequenceLength), + 'represent_txt' => $this->unitTester->generateString($representLength), + ]); + + $this->unitTester->tryStore(); + } +} diff --git a/tests/unit/Api/v1/UsersTest.php b/tests/unit/Api/v1/UsersTest.php index 976aa509..ba6191b3 100644 --- a/tests/unit/Api/v1/UsersTest.php +++ b/tests/unit/Api/v1/UsersTest.php @@ -1,541 +1,540 @@ unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\UsersController')); - - $this->unitTester->setContentType('users'); - - $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'User'); - - $this->attachCountryForAllUsers(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The login must be at least 3 characters. - */ - public function testStoreSmallLogin() - { - $this->unitTester->addInputReplace([ - 'login' => 'a', - 'email' => 'bob@example.com', - 'password' => 'azerty' - ]); - - $this->unitTester->tryStore(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The login has already been taken. - */ - public function testStoreAlreadyTakenLogin() - { - $u = User::find(1); - - $this->unitTester->addInputReplace([ - 'login' => $u['login'], - 'email' => 'bob@example.com', - 'password' => 'azerty' - ]); - - $this->unitTester->tryStore(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The login may only contain letters, numbers, and dashes. - */ - public function testStoreWrongLoginFormat() - { - $this->unitTester->addInputReplace([ - 'login' => '!$$$', - 'email' => 'bob@example.com', - 'password' => 'azerty' - ]); - - $this->unitTester->tryStore(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The login may not be greater than 20 characters. - */ - public function testStoreLongLogin() - { - $this->unitTester->addInputReplace([ - 'login' => $this->unitTester->generateString(21), - 'email' => 'bob@example.com', - 'password' => 'azerty' - ]); - - $this->unitTester->tryStore(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The password must be at least 6 characters. - */ - public function testStoreWrongPassword() - { - $this->unitTester->addInputReplace([ - 'login' => $this->unitTester->generateString(10), - 'email' => 'bob@example.com', - 'password' => 'azert' - ]); - - $this->unitTester->tryStore(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The email must be a valid email address. - */ - public function testStoreWrongEmail() - { - $this->unitTester->addInputReplace([ - 'login' => $this->unitTester->generateString(10), - 'email' => 'bob', - 'password' => 'azerty' - ]); - - $this->unitTester->tryStore(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The email has already been taken. - */ - public function testStoreAlreadyTakenEmail() - { - $u = User::find(1); - - $this->unitTester->addInputReplace([ - 'login' => $this->unitTester->generateString(10), - 'email' => $u['email'], - 'password' => 'azerty' - ]); - - $this->unitTester->tryStore(); - } - - public function testStoreSuccess() - { - $this->unitTester->addInputReplace([ - 'login' => $this->unitTester->generateString(10), - 'email' => 'bob@example.com', - 'password' => 'azerty' - ]); - - // Set a fake IP - $_SERVER['REMOTE_ADDR'] = '22.22.22.22'; - - $this->unitTester->tryStore() - ->assertStatusCodeIs(Response::HTTP_CREATED) - ->assertResponseHasRequiredAttributes(); - - // Check that the user has been subscribed to the weekly newsletter - $u = User::find($this->unitTester->getNbRessources() + 1); - $this->assertTrue($u->getIsSubscribedToWeekly()); - $this->assertFalse($u->getIsSubscribedToDaily()); - - // TODO: assert that the welcome e-mail was sent - } - - public function testDeleteSuccess() - { - $idUser = 1; - $this->unitTester->logUserWithId($idUser); - - $this->unitTester->doRequest('destroy') - ->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('user_deleted') - ->withSuccessMessage('The user has been deleted.'); - - $this->assertEmpty(User::find($idUser)); - } - - public function testGetInfoLoggedInUser() - { - $idUser = 1; - $this->unitTester->logUserWithId($idUser); - - $this->setFullAttributesAreRequired(); - - $this->unitTester->doRequest('getUsers') - ->assertStatusCodeIs(Response::HTTP_OK) - ->assertResponseMatchesExpectedSchema(); - - $this->unitTester->assertResponseKeyIs('id', $idUser); - } - - public function testUserShowNotFound() - { - $this->unitTester->tryShowNotFound() - ->withStatusMessage(404) - ->withErrorMessage('User not found.'); - } - - public function testShowFound() - { - $this->setFullAttributesAreRequired(); - - for ($i = 1; $i <= $this->unitTester->getNbRessources() ; $i++) - $this->unitTester->tryShowFound($i); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The password must be at least 6 characters. - */ - public function testPutPasswordTooSmall() - { - $this->unitTester->addInputReplace([ - 'password' => 'azert', - 'password_confirmation' => 'azert', - ]); - - $this->assertPutPasswordError(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The password confirmation does not match. - */ - public function testPutPasswordNotSame() - { - $this->unitTester->addInputReplace([ - 'password' => 'azerty', - 'password_confirmation' => 'azert', - ]); - - $this->assertPutPasswordError(); - } - - public function testPutPasswordSuccess() - { - $newPassword = 'azerty'; - $idUser = 1; - - $this->unitTester->addInputReplace([ - 'password' => $newPassword, - 'password_confirmation' => $newPassword, - ]); - - $u = $this->unitTester->logUserWithId($idUser); - - $this->unitTester->doRequest('putPassword') - ->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('password_updated') - ->withSuccessMessage('The new password has been set.'); - - // Check that the new password has been set - $this->assertTrue(Auth::attempt(['login' => $u['login'], 'password' => $newPassword])); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The selected gender is invalid. - */ - public function testPutProfileWrongGender() - { - $this->unitTester->addInputReplace([ - 'gender' => 'foo', - ]); - - $this->assertPutProfileError(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The birthdate does not match the format Y-m-d. - */ - public function testPutProfileWrongBirthdate() - { - $this->unitTester->addInputReplace([ - 'gender' => 'M', - 'birthdate' => '1975-01-32' - ]); - - $this->assertPutProfileError(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The selected country was not found. - */ - public function testPutProfileWrongCountry() - { - $this->unitTester->addInputReplace([ - 'gender' => 'M', - 'birthdate' => '1975-01-25', - 'country' => Country::all()->count() + 1 - ]); - - $this->assertPutProfileError(); - } - - /** - * @expectedException Laracasts\Validation\FormValidationException - * @expectedExceptionMessage The about me may not be greater than 500 characters. - */ - public function testPutProfileWrongAboutMe() - { - $this->unitTester->addInputReplace([ - 'gender' => 'M', - 'birthdate' => '1975-01-25', - 'country' => Country::first()->id, - 'about_me' => $this->unitTester->generateString(501) - ]); - - $this->assertPutProfileError(); - } - - // TODO: write tests for uploaded files - - public function testPutProfileSuccess() - { - $gender = 'M'; - $birthdate = '1975-01-25'; - $country = Country::first()->id; - $about_me = $this->unitTester->generateString(200); - - $data = compact('gender', 'birthdate', 'country', 'about_me'); - $this->unitTester->addInputReplace($data); - - $this->unitTester->logUserWithId(1); - - $this->unitTester->doRequest('putProfile') - ->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('profile_updated') - ->withSuccessMessage('The profile has been updated.'); - } - - public function testPutSettingsWrongColor() - { - $newColor = 'foo'; - $this->assertFalse(in_array($newColor, Config::get('app.users.colorsAvailableQuotesPublished'))); - - $this->unitTester->addInputReplace([ - 'notification_comment_quote' => true, - 'hide_profile' => true, - 'weekly_newsletter' => true, - 'daily_newsletter' => true, - 'colors' => $newColor - ]); - - $this->unitTester->logUserWithId(1); - - $this->unitTester->doRequest('putSettings') - ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) - ->withStatusMessage('wrong_color') - ->withErrorMessage('This color is not allowed.'); - } - - public function testPutSettingsSuccess() - { - $u = $this->unitTester->logUserWithId(1); - - // Check default values for a new profile - $this->assertTrue($u->getIsSubscribedToWeekly()); - $this->assertFalse($u->getIsSubscribedToDaily()); - $this->assertFalse($u->isHiddenProfile()); - $this->assertTrue($u->wantsEmailComment()); - $this->assertEquals($u->getColorsQuotesPublished(), Config::get('app.users.defaultColorQuotesPublished')); - - // New color for quotes published - $newColor = 'red'; - // Check that this is not the default value! - $this->assertNotEquals(Config::get('app.users.defaultColorQuotesPublished'), $newColor); - $this->assertTrue(in_array($newColor, Config::get('app.users.colorsAvailableQuotesPublished'))); - - $this->unitTester->addInputReplace([ - 'notification_comment_quote' => false, - 'hide_profile' => true, - 'weekly_newsletter' => false, - 'daily_newsletter' => true, - 'colors' => $newColor - ]); - - $this->unitTester->doRequest('putSettings') - ->assertStatusCodeIs(Response::HTTP_OK) - ->withStatusMessage('profile_updated') - ->withSuccessMessage('The profile has been updated.'); - - // Check that values have changed accordingly - $this->assertFalse($u->getIsSubscribedToWeekly()); - $this->assertTrue($u->getIsSubscribedToDaily()); - $this->assertTrue($u->isHiddenProfile()); - $this->assertFalse($u->wantsEmailComment()); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage users - */ - public function testSearchUsersNotFound() - { - $this->deleteAllUsers(); - - // Create a single user with a non-matching login - $this->unitTester->insertInDatabase(1, 'User', ['login' => 'abc']); - - $this->assertEquals(1, User::all()->count()); - - $this->unitTester->doRequest('getSearch', 'foo'); - } - - public function testSearchSuccess() - { - // We don't display newsletters info when searching for users - $this->disableEmbedsNewsletter(); - - $this->generateUsersWithPartialLogin('abc'); - - $this->assertEquals($this->unitTester->getNbRessources(), User::all()->count()); - - // Verify that we can retrieve our users even - // with partials login - $this->unitTester->tryFirstPage('getSearch', 'ab'); - $this->unitTester->tryFirstPage('getSearch', 'a'); - $this->unitTester->tryFirstPage('getSearch', 'abc'); - $this->unitTester->tryFirstPage('getSearch', 'c'); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage users - */ - public function testSearchMatchingUsersWithHiddenProfile() - { - $partLogin = 'abc'; - $this->generateUsersWithPartialLogin($partLogin); - - // Hide all users profile - User::all()->each(function($u) - { - $u->hide_profile = 1; - $u->save(); - }); - - // Search results should not display hidden profiles - $this->unitTester->doRequest('getSearch', $partLogin); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage users - */ - public function testSearchFailsWrongPage() - { - $this->generateUsersWithPartialLogin('abc'); - - // Go to a page where we should not find any results - // matching our query - $this->unitTester->addInputReplace([ - 'page' => 2, - 'pagesize' => $this->unitTester->getNbRessources() - ]); - - $this->unitTester->doRequest('getSearch', 'abc'); - } - - public function testFromCountryUnexistingCountry() - { - $countryId = 42000; - - $this->unitTester->doRequest('fromCountry', $countryId) - ->assertResponseIsNotFound() - ->withStatusMessage('country_not_found') - ->withErrorMessage('The country #'.$countryId.' was not found.'); - } - - /** - * @expectedException TeenQuotes\Exceptions\ApiNotFoundException - * @expectedExceptionMessage users - */ - public function testFromCountryNoUsers() - { - $country = $this->unitTester->insertInDatabase(1, 'Country'); - - $this->unitTester->doRequest('fromCountry', $country->id); - } - - public function testFromCountrySuccess() - { - $country = $this->unitTester->insertInDatabase(1, 'Country'); - - // Create users from this country - $nbUsers = $this->unitTester->getNbRessources(); - $this->unitTester->insertInDatabase($nbUsers, 'User', ['country' => $country->id]); - - $this->unitTester->tryFirstPage('fromCountry', $country->id); - $this->unitTester->tryMiddlePage('fromCountry', $country->id); - } - - private function generateUsersWithPartialLogin($string) - { - $this->deleteAllUsers(); - - for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { - $login = $this->unitTester->generateString(2).$string.$i; - $this->unitTester->insertInDatabase(1, 'User', compact('login')); - } - - $this->attachCountryForAllUsers(); - } - - private function assertPutPasswordError() - { - $this->unitTester->logUserWithId(1); - - $this->unitTester->doRequest('putPassword'); - } - - private function assertPutProfileError() - { - $this->unitTester->logUserWithId(1); - - $this->unitTester->doRequest('putProfile'); - } - - private function deleteAllUsers() - { - User::truncate(); - } - - private function attachCountryForAllUsers() - { - $instance = $this; - - User::all()->each(function($u) use ($instance) { - $c = $instance->unitTester->insertInDatabase(1, 'Country'); - $u->country = $c['id']; - $u->save(); - }); - } - - private function disableEmbedsNewsletter() - { - $this->unitTester->setEmbedsRelation(['country']); - } - - private function setFullAttributesAreRequired() - { - $this->unitTester->setRequiredAttributes($this->requiredFull); - } -} \ No newline at end of file +class UsersTest extends ApiTest +{ + protected $requiredAttributes = ['id', 'login', 'email', 'last_visit', 'created_at', 'profile_hidden', 'url_avatar', 'wants_notification_comment_quote', 'is_admin']; + protected $requiredFull = ['id', 'login', 'email', 'birthdate', 'gender', 'country', 'city', 'about_me', 'last_visit', 'created_at', 'profile_hidden', 'url_avatar', 'wants_notification_comment_quote', 'is_admin', 'total_comments', 'favorite_count', 'added_fav_count', 'published_quotes_count', 'is_subscribed_to_daily', 'is_subscribed_to_weekly']; + protected $embedsRelation = ['newsletters', 'country']; + + protected function _before() + { + parent::_before(); + + $this->unitTester->setController(App::make('TeenQuotes\Api\V1\Controllers\UsersController')); + + $this->unitTester->setContentType('users'); + + $this->unitTester->insertInDatabase($this->unitTester->getNbRessources(), 'User'); + + $this->attachCountryForAllUsers(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The login must be at least 3 characters. + */ + public function testStoreSmallLogin() + { + $this->unitTester->addInputReplace([ + 'login' => 'a', + 'email' => 'bob@example.com', + 'password' => 'azerty', + ]); + + $this->unitTester->tryStore(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The login has already been taken. + */ + public function testStoreAlreadyTakenLogin() + { + $u = User::find(1); + + $this->unitTester->addInputReplace([ + 'login' => $u['login'], + 'email' => 'bob@example.com', + 'password' => 'azerty', + ]); + + $this->unitTester->tryStore(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The login may only contain letters, numbers, and dashes. + */ + public function testStoreWrongLoginFormat() + { + $this->unitTester->addInputReplace([ + 'login' => '!$$$', + 'email' => 'bob@example.com', + 'password' => 'azerty', + ]); + + $this->unitTester->tryStore(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The login may not be greater than 20 characters. + */ + public function testStoreLongLogin() + { + $this->unitTester->addInputReplace([ + 'login' => $this->unitTester->generateString(21), + 'email' => 'bob@example.com', + 'password' => 'azerty', + ]); + + $this->unitTester->tryStore(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The password must be at least 6 characters. + */ + public function testStoreWrongPassword() + { + $this->unitTester->addInputReplace([ + 'login' => $this->unitTester->generateString(10), + 'email' => 'bob@example.com', + 'password' => 'azert', + ]); + + $this->unitTester->tryStore(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The email must be a valid email address. + */ + public function testStoreWrongEmail() + { + $this->unitTester->addInputReplace([ + 'login' => $this->unitTester->generateString(10), + 'email' => 'bob', + 'password' => 'azerty', + ]); + + $this->unitTester->tryStore(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The email has already been taken. + */ + public function testStoreAlreadyTakenEmail() + { + $u = User::find(1); + + $this->unitTester->addInputReplace([ + 'login' => $this->unitTester->generateString(10), + 'email' => $u['email'], + 'password' => 'azerty', + ]); + + $this->unitTester->tryStore(); + } + + public function testStoreSuccess() + { + $this->unitTester->addInputReplace([ + 'login' => $this->unitTester->generateString(10), + 'email' => 'bob@example.com', + 'password' => 'azerty', + ]); + + // Set a fake IP + $_SERVER['REMOTE_ADDR'] = '22.22.22.22'; + + $this->unitTester->tryStore() + ->assertStatusCodeIs(Response::HTTP_CREATED) + ->assertResponseHasRequiredAttributes(); + + // Check that the user has been subscribed to the weekly newsletter + $u = User::find($this->unitTester->getNbRessources() + 1); + $this->assertTrue($u->getIsSubscribedToWeekly()); + $this->assertFalse($u->getIsSubscribedToDaily()); + + // TODO: assert that the welcome e-mail was sent + } + + public function testDeleteSuccess() + { + $idUser = 1; + $this->unitTester->logUserWithId($idUser); + + $this->unitTester->doRequest('destroy') + ->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('user_deleted') + ->withSuccessMessage('The user has been deleted.'); + + $this->assertEmpty(User::find($idUser)); + } + + public function testGetInfoLoggedInUser() + { + $idUser = 1; + $this->unitTester->logUserWithId($idUser); + + $this->setFullAttributesAreRequired(); + + $this->unitTester->doRequest('getUsers') + ->assertStatusCodeIs(Response::HTTP_OK) + ->assertResponseMatchesExpectedSchema(); + + $this->unitTester->assertResponseKeyIs('id', $idUser); + } + + public function testUserShowNotFound() + { + $this->unitTester->tryShowNotFound() + ->withStatusMessage(404) + ->withErrorMessage('User not found.'); + } + + public function testShowFound() + { + $this->setFullAttributesAreRequired(); + + for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { + $this->unitTester->tryShowFound($i); + } + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The password must be at least 6 characters. + */ + public function testPutPasswordTooSmall() + { + $this->unitTester->addInputReplace([ + 'password' => 'azert', + 'password_confirmation' => 'azert', + ]); + + $this->assertPutPasswordError(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The password confirmation does not match. + */ + public function testPutPasswordNotSame() + { + $this->unitTester->addInputReplace([ + 'password' => 'azerty', + 'password_confirmation' => 'azert', + ]); + + $this->assertPutPasswordError(); + } + + public function testPutPasswordSuccess() + { + $newPassword = 'azerty'; + $idUser = 1; + + $this->unitTester->addInputReplace([ + 'password' => $newPassword, + 'password_confirmation' => $newPassword, + ]); + + $u = $this->unitTester->logUserWithId($idUser); + + $this->unitTester->doRequest('putPassword') + ->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('password_updated') + ->withSuccessMessage('The new password has been set.'); + + // Check that the new password has been set + $this->assertTrue(Auth::attempt(['login' => $u['login'], 'password' => $newPassword])); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The selected gender is invalid. + */ + public function testPutProfileWrongGender() + { + $this->unitTester->addInputReplace([ + 'gender' => 'foo', + ]); + + $this->assertPutProfileError(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The birthdate does not match the format Y-m-d. + */ + public function testPutProfileWrongBirthdate() + { + $this->unitTester->addInputReplace([ + 'gender' => 'M', + 'birthdate' => '1975-01-32', + ]); + + $this->assertPutProfileError(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The selected country was not found. + */ + public function testPutProfileWrongCountry() + { + $this->unitTester->addInputReplace([ + 'gender' => 'M', + 'birthdate' => '1975-01-25', + 'country' => Country::all()->count() + 1, + ]); + + $this->assertPutProfileError(); + } + + /** + * @expectedException Laracasts\Validation\FormValidationException + * @expectedExceptionMessage The about me may not be greater than 500 characters. + */ + public function testPutProfileWrongAboutMe() + { + $this->unitTester->addInputReplace([ + 'gender' => 'M', + 'birthdate' => '1975-01-25', + 'country' => Country::first()->id, + 'about_me' => $this->unitTester->generateString(501), + ]); + + $this->assertPutProfileError(); + } + + // TODO: write tests for uploaded files + + public function testPutProfileSuccess() + { + $gender = 'M'; + $birthdate = '1975-01-25'; + $country = Country::first()->id; + $about_me = $this->unitTester->generateString(200); + + $data = compact('gender', 'birthdate', 'country', 'about_me'); + $this->unitTester->addInputReplace($data); + + $this->unitTester->logUserWithId(1); + + $this->unitTester->doRequest('putProfile') + ->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('profile_updated') + ->withSuccessMessage('The profile has been updated.'); + } + + public function testPutSettingsWrongColor() + { + $newColor = 'foo'; + $this->assertFalse(in_array($newColor, Config::get('app.users.colorsAvailableQuotesPublished'))); + + $this->unitTester->addInputReplace([ + 'notification_comment_quote' => true, + 'hide_profile' => true, + 'weekly_newsletter' => true, + 'daily_newsletter' => true, + 'colors' => $newColor, + ]); + + $this->unitTester->logUserWithId(1); + + $this->unitTester->doRequest('putSettings') + ->assertStatusCodeIs(Response::HTTP_BAD_REQUEST) + ->withStatusMessage('wrong_color') + ->withErrorMessage('This color is not allowed.'); + } + + public function testPutSettingsSuccess() + { + $u = $this->unitTester->logUserWithId(1); + + // Check default values for a new profile + $this->assertTrue($u->getIsSubscribedToWeekly()); + $this->assertFalse($u->getIsSubscribedToDaily()); + $this->assertFalse($u->isHiddenProfile()); + $this->assertTrue($u->wantsEmailComment()); + $this->assertEquals($u->getColorsQuotesPublished(), Config::get('app.users.defaultColorQuotesPublished')); + + // New color for quotes published + $newColor = 'red'; + // Check that this is not the default value! + $this->assertNotEquals(Config::get('app.users.defaultColorQuotesPublished'), $newColor); + $this->assertTrue(in_array($newColor, Config::get('app.users.colorsAvailableQuotesPublished'))); + + $this->unitTester->addInputReplace([ + 'notification_comment_quote' => false, + 'hide_profile' => true, + 'weekly_newsletter' => false, + 'daily_newsletter' => true, + 'colors' => $newColor, + ]); + + $this->unitTester->doRequest('putSettings') + ->assertStatusCodeIs(Response::HTTP_OK) + ->withStatusMessage('profile_updated') + ->withSuccessMessage('The profile has been updated.'); + + // Check that values have changed accordingly + $this->assertFalse($u->getIsSubscribedToWeekly()); + $this->assertTrue($u->getIsSubscribedToDaily()); + $this->assertTrue($u->isHiddenProfile()); + $this->assertFalse($u->wantsEmailComment()); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage users + */ + public function testSearchUsersNotFound() + { + $this->deleteAllUsers(); + + // Create a single user with a non-matching login + $this->unitTester->insertInDatabase(1, 'User', ['login' => 'abc']); + + $this->assertEquals(1, User::all()->count()); + + $this->unitTester->doRequest('getSearch', 'foo'); + } + + public function testSearchSuccess() + { + // We don't display newsletters info when searching for users + $this->disableEmbedsNewsletter(); + + $this->generateUsersWithPartialLogin('abc'); + + $this->assertEquals($this->unitTester->getNbRessources(), User::all()->count()); + + // Verify that we can retrieve our users even + // with partials login + $this->unitTester->tryFirstPage('getSearch', 'ab'); + $this->unitTester->tryFirstPage('getSearch', 'a'); + $this->unitTester->tryFirstPage('getSearch', 'abc'); + $this->unitTester->tryFirstPage('getSearch', 'c'); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage users + */ + public function testSearchMatchingUsersWithHiddenProfile() + { + $partLogin = 'abc'; + $this->generateUsersWithPartialLogin($partLogin); + + // Hide all users profile + User::all()->each(function ($u) { + $u->hide_profile = 1; + $u->save(); + }); + + // Search results should not display hidden profiles + $this->unitTester->doRequest('getSearch', $partLogin); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage users + */ + public function testSearchFailsWrongPage() + { + $this->generateUsersWithPartialLogin('abc'); + + // Go to a page where we should not find any results + // matching our query + $this->unitTester->addInputReplace([ + 'page' => 2, + 'pagesize' => $this->unitTester->getNbRessources(), + ]); + + $this->unitTester->doRequest('getSearch', 'abc'); + } + + public function testFromCountryUnexistingCountry() + { + $countryId = 42000; + + $this->unitTester->doRequest('fromCountry', $countryId) + ->assertResponseIsNotFound() + ->withStatusMessage('country_not_found') + ->withErrorMessage('The country #'.$countryId.' was not found.'); + } + + /** + * @expectedException TeenQuotes\Exceptions\ApiNotFoundException + * @expectedExceptionMessage users + */ + public function testFromCountryNoUsers() + { + $country = $this->unitTester->insertInDatabase(1, 'Country'); + + $this->unitTester->doRequest('fromCountry', $country->id); + } + + public function testFromCountrySuccess() + { + $country = $this->unitTester->insertInDatabase(1, 'Country'); + + // Create users from this country + $nbUsers = $this->unitTester->getNbRessources(); + $this->unitTester->insertInDatabase($nbUsers, 'User', ['country' => $country->id]); + + $this->unitTester->tryFirstPage('fromCountry', $country->id); + $this->unitTester->tryMiddlePage('fromCountry', $country->id); + } + + private function generateUsersWithPartialLogin($string) + { + $this->deleteAllUsers(); + + for ($i = 1; $i <= $this->unitTester->getNbRessources(); $i++) { + $login = $this->unitTester->generateString(2).$string.$i; + $this->unitTester->insertInDatabase(1, 'User', compact('login')); + } + + $this->attachCountryForAllUsers(); + } + + private function assertPutPasswordError() + { + $this->unitTester->logUserWithId(1); + + $this->unitTester->doRequest('putPassword'); + } + + private function assertPutProfileError() + { + $this->unitTester->logUserWithId(1); + + $this->unitTester->doRequest('putProfile'); + } + + private function deleteAllUsers() + { + User::truncate(); + } + + private function attachCountryForAllUsers() + { + $instance = $this; + + User::all()->each(function ($u) use ($instance) { + $c = $instance->unitTester->insertInDatabase(1, 'Country'); + $u->country = $c['id']; + $u->save(); + }); + } + + private function disableEmbedsNewsletter() + { + $this->unitTester->setEmbedsRelation(['country']); + } + + private function setFullAttributesAreRequired() + { + $this->unitTester->setRequiredAttributes($this->requiredFull); + } +}