diff --git a/.coveralls.yml b/.coveralls.yml
new file mode 100644
index 0000000..c1bdfd1
--- /dev/null
+++ b/.coveralls.yml
@@ -0,0 +1,9 @@
+# .coveralls.yml example configuration
+
+# service name
+service_name: travis-ci
+
+# for php-coveralls
+src_dir: src
+coverage_clover: build/logs/clover.xml
+json_path: build/logs/coveralls-upload.json
diff --git a/.gitignore b/.gitignore
index fc7ea17..8b7ef35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
/vendor
composer.lock
-.DS_Store
diff --git a/.travis.yml b/.travis.yml
index b51d696..44fc78a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,22 @@
language: php
-php:
- - 5.3
+php:
- 5.4
+ - 5.5
+ - 5.6
+ - hhvm
+
+matrix:
+ allow_failures:
+ - php: 5.6
before_script:
- - curl -s http://getcomposer.org/installer | php
- - php composer.phar install --dev
+ - travis_retry composer self-update
+ - travis_retry composer install --no-interaction --prefer-source --dev
+
+script:
+ - mkdir -p build/logs
+ - vendor/bin/phpunit -c phpunit.xml.dist --verbose
-script: phpunit
+after_script:
+ - php vendor/bin/coveralls -v
diff --git a/README.md b/README.md
index cc6c579..116e4e7 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,18 @@
-# Confide (Laravel4 Package)
+# Confide _(A Laravel4 Package)_
![Confide Poster](https://dl.dropbox.com/u/12506137/libs_bundles/confide.png)
[![Build Status](https://api.travis-ci.org/Zizaco/confide.png)](https://travis-ci.org/Zizaco/confide)
+[![Coverage Status](https://coveralls.io/repos/Zizaco/confide/badge.png?branch=master)](https://coveralls.io/r/Zizaco/confide?branch=master)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Zizaco/confide/badges/quality-score.png)](https://scrutinizer-ci.com/g/Zizaco/confide/)
[![ProjectStatus](http://stillmaintained.com/Zizaco/confide.png)](http://stillmaintained.com/Zizaco/confide)
+[![Latest Stable Version](https://poser.pugx.org/zizaco/confide/v/stable.png)](https://packagist.org/packages/zizaco/confide)
+[![Total Downloads](https://poser.pugx.org/zizaco/confide/downloads.png)](https://packagist.org/packages/zizaco/confide)
+[![License](https://poser.pugx.org/zizaco/confide/license.png)](http://opensource.org/licenses/MIT)
-Confide is a authentication solution for **Laravel4** made to eliminate repetitive tasks involving the management of users: Account creation, login, logout, confirmation by e-mail, password reset, etc.
+[![SensioLabsInsight](https://insight.sensiolabs.com/projects/ec420846-0af4-4df4-b424-be90d9c3f98e/small.png)](https://insight.sensiolabs.com/projects/ec420846-0af4-4df4-b424-be90d9c3f98e)
+
+Confide is an authentication solution for **Laravel4** made to eliminate repetitive tasks involving the management of users: Account creation, login, logout, confirmation by e-mail, password reset, etc.
Confide aims to be simple to use, quick to configure and flexible.
@@ -17,11 +24,11 @@ Confide aims to be simple to use, quick to configure and flexible.
- Account confirmation (through confirmation link).
- Password reset (sending email with a change password link).
- Easily render forms for login, signup and password reset.
-- Generate customizable routes for login, signup, password reset, confirmation, etc.
+- Generate routes for login, signup, password reset, confirmation, etc.
- Generate a customizable controller that handles the basic user account actions.
-- Contains a set of methods to help basic user features.
-- Integrated with the Laravel Auth component/configs.
-- Field/model validation (Powered by [Ardent](http://laravelbook.github.com/ardent "Ardent")).
+- Contains a set of methods to help with basic user features.
+- Integrated with the Laravel _Auth_ and _Reminders_ component/configs.
+- User validation.
- Login throttling.
- Redirecting to previous route after authentication.
- Checks for unique email and username in signup
@@ -30,15 +37,10 @@ If you are looking for user roles and permissions see [Entrust](https://github.c
For MongoDB support see [Confide Mongo](https://github.com/Zizaco/confide-mongo)
-**Planned:**
-- Captcha in user signup and password reset.
-
-**Warning:**
-
-By default a confirmation email is sent and users are required to confirm the email address.
+**Warning:** _By default a confirmation email is sent and users are required to confirm the email address.
It is easy to change this in the confide config file.
-Change signup_email and signup_confirm to false if you do not want to send them an email and they do not need
-to be confirmed to be able to login to the website.
+Change `signup_email` and `signup_confirm` to false if you do not want to send them an email and they do not need
+to be confirmed to be able to login to the website._
## Quick start
@@ -46,31 +48,31 @@ to be confirmed to be able to login to the website.
In the `require` key of `composer.json` file add the following
- "zizaco/confide": "3.2.x"
+ "zizaco/confide": "~4.0"
Run the Composer update comand
$ composer update
-In your `config/app.php` add `'Zizaco\Confide\ConfideServiceProvider'` to the end of the `$providers` array
+In your `config/app.php` add `'Zizaco\Confide\ServiceProvider'` to the end of the `providers` array
'providers' => array(
'Illuminate\Foundation\Providers\ArtisanServiceProvider',
'Illuminate\Auth\AuthServiceProvider',
...
- 'Zizaco\Confide\ConfideServiceProvider',
+ 'Zizaco\Confide\ServiceProvider',
),
-At the end of `config/app.php` add `'Confide' => 'Zizaco\Confide\ConfideFacade'` to the `$aliases` array
+At the end of `config/app.php` add `'Confide' => 'Zizaco\Confide\Facade'` to the `aliases` array
'aliases' => array(
'App' => 'Illuminate\Support\Facades\App',
'Artisan' => 'Illuminate\Support\Facades\Artisan',
...
- 'Confide' => 'Zizaco\Confide\ConfideFacade',
+ 'Confide' => 'Zizaco\Confide\Facade',
),
@@ -80,6 +82,7 @@ Set the properly values to the `config/auth.php`. This values will be used by co
Set the `address` and `name` from the `from` array in `config/mail.php`. Those will be used to send account confirmation and password reset emails to the users.
+
### User model
Now generate the Confide migration and the reminder password table migration:
@@ -90,23 +93,24 @@ It will generate the `_confide_setup_users_table.php` migration. You
$ php artisan migrate
-It will setup a table containing `email`, `password`, `confirmation_code` and `confirmed` fields, which are the default fields needed for Confide use. Feel free to add more fields to the database.
+It will setup a table containing `email`, `password`, `remember_token`, `confirmation_code` and `confirmed` columns, which are the default fields needed for Confide use. Feel free to add more columns to the table later.
Change your User model in `app/models/User.php` to:
'Zizaco\Confide\Facade'` entry in `config/app.php` `'providers'` and `'aliases'` respectively.
+2. User model (with the same name as in `config/auth.php`) should implement `Zizaco\Confide\ConfideUserInterface` interface. This will cause to methods like `forgotPassword()` and `confirm()` to be available.
**Optional steps:**
-1. Use `Confide` facade to dump login and signup forms easly with `makeLoginForm()` and `makeSignupForm()`. You can render the forms within your views by doing `{{ Confide::makeLoginForm()->render() }}`.
-2. Generate a controller with the template contained in Confide throught the artisan command `$ php artisan confide:controller`. If a controller with the same name exists it will **NOT** be overwritten.
-3. Generate routes matching the controller template throught the artisan command `$ php artisan confide:routes`. Your `routes.php` will **NOT** be overwritten.
+1. Optionally you can use the trait `Zizaco\Confide\ConfideUser` in your user model. This will save a lot of time and will use "confide's default" implementation for the user. If you wish more customization you can write your own code.
+2. Use `Confide` facade to dump login and signup forms easly with `makeLoginForm()` and `makeSignupForm()`. You can render the forms within your views by doing `{{ Confide::makeLoginForm()->render() }}`.
+3. Generate a **controller** and a **repository** with the template contained in Confide throught the artisan command `$ php artisan confide:controller`. If a controller with the same name exists it will **NOT** be overwritten.
+4. Generate routes matching the controller template throught the artisan command `$ php artisan confide:routes`. Don't worry, your `routes.php` will **NOT** be overwritten.
### Advanced
-#### Using custom table / model name
+#### The `UserRepository` class
-You can change the model name that will be authenticated in the `config/auth.php` file.
+You may have noticed that when generating the controller a `UserRepository` class has also been created. This class contains some code that doesn't belong to the "controller" purpose and will make your users controller a cleaner and more testable class. If you still have no idea why that class exists I recommend you to google _"Creating flexible Controllers in Laravel 4 using Repositories"_. _(wink)_
+
+#### Using custom class, table or model name
+
+You can change the model name that will be considered the user in the `config/auth.php` file.
Confide uses the values present in that configuration file.
To change the controller name when dumping the default controller template you can use the --name option.
- $ php artisan confide:controller --name Employee
+ $ php artisan confide:controller --name=Employee
Will result in `EmployeeController`
Then, when dumping the routes, you should use the --controller option to match the existing controller.
- $ php artisan confide:routes --controller Employee
+ $ php artisan confide:routes --controller=Employee
+
+You can also generate controllers with namespace
+
+ $ php artisan confide:controller --name=MyProject\\Auth\\User
+
+**Warning:** In bash, you will need to use double '\\\\' backslashes. This will result in `MyProject\Auth\UserController`. Also the generated file will be inside a directory equivalent to the namespace. _(wink)_
#### Using custom form or emails
@@ -162,86 +177,44 @@ First, publish the config files:
Then edit the view names in `app/config/packages/zizaco/confide/config.php`.
-#### Update a User
+#### Custom user validation
-To update an user already in the database you'll Need to make sure your ruleset is using the unique validator within the User model.
+You can implement your own validator by creating a class that implements the `UserValidatorInterface` and registering that class as *"confide.user_validator"*.
- 'unique:users,username',
- 'email' => 'email'
- );
-
- ?>
-
- email = Input::get('email');
-
- // Save
- // This was previously update, but Ardent changed.
- $user->updateUniques();
-
+ // app/models/MyOwnValidator.php
+ class MyOwnValidator implements UserValidatorInterface {
+
+ public function validate(ConfideUserInterface $user)
+ {
+ unset($user->password_confirmation);
+ return true; // If the user valid
}
}
-
- ?>
-
-This will allow you to update the current user.
-#### Validate model fields
+Then register it in IoC container as *"confide.user_validator"*
-To change the validation rules of the User model you can take a look at [Ardent](http://laravelbook.github.com/ardent/#validation "Ardent Validation Rulez"). For example:
+ // app/start/global.php
+ ...
+ App::bind('confide.user_validator', 'MyOwnValidator');
- 'required|email',
- 'password' => 'required|between:4,11|confirmed',
- );
-
- }
-
-Feel free to add more fields to your table and to the validation array. Then you should build your own sign-up form with the additional fields.
-
-NOTE: If you add fields to your validation rules into your model like above, do not forget you have to add those fields to the UserController store function also. If you forget this, the form will always return with an error.
-Example: $user->terms = Input::get('terms');
-
-#### Passing additional information to the make methods
-
-If you want to pass additional parameters to the forms, you can use an alternate syntax to achieve this.
+If you want to pass additional parameters to the forms being rendered, you can use an alternate syntax to achieve this.
Instead of using the make method:
-
+
Confide::makeResetPasswordForm( $token ):
You would use:
View::make(Config::get('confide::reset_password_form'))
->with('token', $token);
-
+
It produces the same output, but you would be able to add more inputs using 'with' just like any other view.
#### RESTful controller
@@ -255,71 +228,94 @@ Will result in a [RESTful controller](https://github.com/laravel/docs/blob/maste
Then, when dumping the routes, you should use the --restful option to match the existing controller.
$ php artisan confide:routes --restful
-
+
#### User roles and permissions
-In order not to bloat Confide with not related features, the role and permission was developed as another package: [Entrust](https://github.com/Zizaco/entrust). This package couples very well with Confide.
+In order not to bloat Confide with not related features, the role and permission was developed as another package: [Entrust](https://github.com/Zizaco/entrust). Enstrust couples very well with Confide.
See [Entrust](https://github.com/Zizaco/entrust)
#### Redirecting to previous route after login
-When defining your filter you should use the Redirect::guest('user/login') within your auth filter. For example:
+When defining your filter you should use the Redirect::guest('users/login') within your auth filter. For example:
// filters.php
- Route::filter('auth', function()
- {
- if ( Auth::guest() ) // If the user is not logged in
- {
- return Redirect::guest('user/login');
+ Route::filter('auth', function() {
+ // If the user is not logged in
+ if (Auth::guest()) {
+ return Redirect::guest('users/login');
}
});
// Only authenticated users will be able to access routes that begins with
// 'admin'. Ex: 'admin/posts', 'admin/categories'.
- Route::when('admin*', 'auth');
+ Route::when('admin*', 'auth');
or, if you are using [Entrust](https://github.com/Zizaco/entrust) ;)
// filters.php
Entrust::routeNeedsRole( 'admin*', 'Admin', function(){
- return Redirect::guest('user/login');
+ return Redirect::guest('users/login');
} );
-Finally, it'll auto redirect if your controller's user/login function uses Redirect:intended('a/default/url/here') after a successful login.
+Finally, it'll auto redirect if your controller's users/login function uses Redirect:intended('a/default/url/here') after a successful login.
The [generated controller](https://github.com/Zizaco/confide/blob/master/src/views/generators/controller.blade.php) does exactly this.
-
-#### Validating a route
-
-If you want to validate whether a route exists, the `Confide::checkAction` function is what you are looking for.
-
-Currently it is used within the views to determine Non-RESTful vs RESTful routes.
## Troubleshooting
-__[Exception] SQLSTATE[HY000]: General error: 1364 Field 'confirmation_code' doesn't have a default value...__
+__[2014-07-18 01:13:15] production.ERROR: exception 'Illuminate\Database\QueryException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'password_confirmation' in 'field list' (SQL: insert into \`users\` ...__
-If you overwrite the `beforeSave()` method in your model, make sure to call `parent::beforeSave()`:
+The `password_confirmation` attribute should be removed from the object before being sent to the database. Make sure your user model implement the `ConfideUserInterface` and that it use the `ConfideUser` trait [as described above](#user-model). Otherwise if you are using a custom validator, you will have to unset `password_confirmation` before saving the user.
- public function beforeSave( $forced = false ){
+__I receive a "Your account may not be confirmed" when trying to login__
- parent::beforeSave( $forced) // Don't forget this
+You need to confirm a newly created user _(by "reaching" its `confirm()` method)_, otherwise you can disable the confirmation as a requirement to login in in the config file _(see bellow)_. You can easly confirm an user manually using Laravel's `artisan tinker` tool.
- // Your stuff
- }
+__I'm not able to generate a controller with namespaces__
-__Confirmation link is not sent when user signup__
+In bash, you will need to use double '\\\\' backslashes. Also the generated file will be inside a directory equivalent to the namespace:
-Same as above. If you overwrite the `afterSave()` method in your model, make sure to call `parent::afterSave()`:
+ $ php artisan confide:controller --name=MyProject\\Auth\\User
__Users are able to login without confirming account__
If you want only confirmed users to login, in your `UserController`, instead of simply calling `logAttempt( $input )`, call `logAttempt( $input, true )`. The second parameter stands for _"confirmed_only"_.
+__My application is crashing since I ran composer update__
+
+*Confide 4.0.0* was a huge update where all the codebase has been rewritten. Some classes changed, the generators has been improved in order to match some better practices (like repositories and separated validator classes). See the _Release Notes_ bellow.
+
+If you have a legacy project that uses an older version of Confide, don't worry. You will be always able to specify a previous version in your `composer.json` file.
+
+For example: `"zizaco/confide": "~3.2"` will avoid composer download version 4.0 but will be able to download bugfixes of version 3.2.
+
## Release Notes
+### Version 4.0.0 Beta 3
+* Now you can customize how long will take for a password reset request to expire (default to 7 hours).
+* Reordered validations
+* Now all validations are called even if one of them fails. So all validation messages are sent at once.
+* `validateIsUnique` method now sends key to attachErrorMsg and also check for errors on each `$identity` field at once
+
+### Version 4.0.0 Beta 2
+* UserValidator now adds errors to an existing MessageBag instead of replacing it.
+* Password reset token will expire after 7 days.
+* Added support for custom connections using the $connection attribute of the model.
+* Password reset requests are deleted after being used.
+
+### Version 4.0.0 Beta 1
+* Dropped Ardent dependency.
+* Updated to support Laravel 4.2
+* Dropped support for PHP 5.3
+* ConfideUser is going to be a trait+interface from now on.
+* Controller generation now also generates an UserRepository class.
+* Removed deprecated variables, functions and classes.
+* All the codebase has been rewritten.
+
+__Upgrade note:__ A partial update from previous versions is not recommended. In order to upgrade from v3.* to v4.0.0 the best approach is to update the class names in the providers and aliases array, re-generate the user table with the new migration, re-write the "user" class and finally re-generate the controllers. It's very likely any customization made in your codebase will be affected.
+
### Version 3.0.0
Updated to support Laravel 4.1
diff --git a/composer.json b/composer.json
index 0d485e9..51d53ed 100644
--- a/composer.json
+++ b/composer.json
@@ -6,7 +6,6 @@
"authors": [
{
"name": "Zizaco Zizuini",
- "email": "zizaco@gmail.com",
"homepage": "http://www.zizaco.net"
},
{
@@ -15,14 +14,16 @@
}
],
"require": {
- "php": ">=5.3.0",
- "illuminate/support": "~4.1",
- "laravelbook/ardent": "~2.4"
+ "php": ">=5.4.0",
+ "illuminate/support": "~4.2"
},
"require-dev": {
- "mockery/mockery": "~0.8",
- "illuminate/database": "~4.1",
- "illuminate/auth": "~4.1"
+ "illuminate/database": "~4.2",
+ "illuminate/auth": "~4.2",
+ "illuminate/console": "~4.2",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "~0.7",
+ "mockery/mockery": "~0.9"
},
"suggest": {
"zizaco/entrust":"add Role-based Permissions to Laravel 4"
@@ -38,7 +39,8 @@
},
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-huge-update": "4.0-dev"
}
- }
+ },
+ "minimum-stability": "dev"
}
diff --git a/phpunit.xml b/phpunit.xml
index 8425e15..d1a5852 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -10,9 +10,15 @@
stopOnFailure="false"
syntaxCheck="false"
>
+
+
+ ./src/Zizaco
+ ./src/commands
+
+ ./tests/
-
\ No newline at end of file
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..f778f56
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,27 @@
+
+
+
+
+ ./src/Zizaco
+ ./src/commands
+
+
+
+
+ ./tests/
+
+
+
+
+
+
diff --git a/src/Zizaco/Confide/CacheLoginThrottleService.php b/src/Zizaco/Confide/CacheLoginThrottleService.php
new file mode 100644
index 0000000..6f6ac02
--- /dev/null
+++ b/src/Zizaco/Confide/CacheLoginThrottleService.php
@@ -0,0 +1,106 @@
+app = $app ?: app();
+ }
+
+ /**
+ * Increments the count for the given identity by one and
+ * also returns the current value for that identity.
+ *
+ * @param mixed $identity The login identity
+ * @return integer How many times that same identity was used
+ */
+ public function throttleIdentity($identity)
+ {
+ $identity = $this->parseIdentity($identity);
+
+ // Increments and also retuns the current count
+ return $this->countThrottle($identity);
+ }
+
+ /**
+ * Tells if the given identity has reached the throttle_limit
+ * @param mixed $identity The login identity
+ * @return boolean True if the identity has reached the throttle_limit
+ */
+ public function isThrottled($identity)
+ {
+ $identity = $this->parseIdentity($identity);
+
+ // Retuns the current count
+ $count = $this->countThrottle($identity, 0);
+
+ return $count >= $this->app['config']->get('confide::throttle_limit');
+ }
+
+ /**
+ * Parse the given identity in order to return a string with
+ * the relevant fields. I.E: if the attacker tries to use a
+ * bunch of different passwords, the identity will still be the
+ * same.
+ * @param $mixed $identity
+ * @return string $identityString
+ */
+ protected function parseIdentity($identity)
+ {
+ // If is an array, remove password, remember and then
+ // transforms it into a string.
+ if (is_array($identity))
+ {
+ unset($identity['password']);
+ unset($identity['remember']);
+ $identity = serialize($identity);
+ }
+
+ return $identity;
+ }
+
+ /**
+ * Increments the count for the given string by one stores
+ * it into cache and returns the current value for that
+ * identity.
+ *
+ * @param string $identityString
+ * @param integer $increments Amount that is going to be added to the throttling attemps for the given identity
+ * @return integer How many times that same string was used
+ */
+ protected function countThrottle($identityString, $increments = 1)
+ {
+ $count = $this->app['cache']
+ ->get('login_throttling:'.md5($identityString), 0);
+
+ $count = $count + $increments;
+
+ $ttl = $this->app['config']->get('confide::throttle_time_period');
+
+ $this->app['cache']
+ ->put('login_throttling:'.md5($identityString), $count, $ttl);
+
+ return $count;
+ }
+}
diff --git a/src/Zizaco/Confide/Confide.php b/src/Zizaco/Confide/Confide.php
index 1077296..a91b60e 100644
--- a/src/Zizaco/Confide/Confide.php
+++ b/src/Zizaco/Confide/Confide.php
@@ -1,52 +1,69 @@
repo = $repo;
- $this->app = app();
- }
+ public $passService;
/**
- * Returns the Laravel application
- *
- * @return Illuminate\Foundation\Application
+ * Confide login throttling service instance
+ *
+ * @var \Zizaco\Confide\LoginThrottleServiceInterface
+ */
+ public $loginThrottler;
+
+ /**
+ * Create a new Confide class
+ *
+ * @param \Zizaco\Confide\RepositoryInterface $repo
+ * @param \Zizaco\Confide\PasswordServiceInterface $passService
+ * @param \Zizaco\Confide\LoginThrottleServiceInterface $loginThrottler
+ * @param \Illuminate\Foundation\Application $app Laravel application object
+ * @return void
*/
- public function app()
+ public function __construct(
+ RepositoryInterface $repo,
+ PasswordServiceInterface $passService,
+ LoginThrottleServiceInterface $loginThrottler,
+ $app = null
+ )
{
- return $this->app;
+ $this->repo = $repo;
+ $this->passService = $passService;
+ $this->loginThrottler = $loginThrottler;
+ $this->app = $app ?: app();
}
/**
* Returns an object of the model set in auth config
*
- * @return object
+ * @return mixed
*/
public function model()
{
@@ -56,7 +73,7 @@ public function model()
/**
* Get the currently authenticated user or null.
*
- * @return Zizaco\Confide\ConfideUser|null
+ * @return \Zizaco\Confide\ConfideUserInterface|null
*/
public function user()
{
@@ -64,261 +81,244 @@ public function user()
}
/**
- * Set the user confirmation to true.
+ * Sets the 'confirmed' field of the user with the
+ * matching code to true.
*
* @param string $code
- * @return bool
+ * @return bool Success
*/
- public function confirm( $code )
+ public function confirm($code)
{
- return $this->repo->confirm( $code );
+ return $this->repo->confirmByCode($code);
+ }
+
+ /**
+ * Checks if a user with the given identity (email or username) already
+ * exists and retrieve it
+ *
+ * @param array $identity Array containing at least 'username' or 'email'.
+ * @return \Zizaco\Confide\ConfideUserInterface|null
+ */
+ public function getUserByEmailOrUsername($identity)
+ {
+ if (is_array($identity))
+ $identity = $this->extractIdentityFromArray($identity);
+
+ return $this->repo->getUserByEmailOrUsername($identity);
}
/**
* Attempt to log a user into the application with
* password and identity field(s), usually email or username.
*
- * @param array $credentials
- * @param bool $confirmed_only
- * @param mixed $identity_columns
+ * @param array $input Array containing at least 'username' or 'email' and 'password'. Optionally the 'remember' boolean.
+ * @param bool $mustBeConfirmed If true, the user must have confirmed his email account in order to log-in.
* @return boolean Success
*/
- public function logAttempt( $credentials, $confirmed_only = false, $identity_columns = array() )
+ public function logAttempt($input, $mustBeConfirmed = true)
{
- // If identity columns is not provided, use all columns of credentials
- // except password and remember.
- if(empty($identity_columns))
- {
- $identity_columns = array_diff(
- array_keys($credentials),
- array('password','remember')
+ $remember = $this->extractRememberFromArray($input);
+ $emailOrUsername = $this->extractIdentityFromArray($input);
+
+ if (!$this->loginThrottling($emailOrUsername))
+ return false;
+
+ $user = $this->repo->getUserByEmailOrUsername($emailOrUsername);
+
+ if ($user) {
+ if (! $user->confirmed && $mustBeConfirmed )
+ return false;
+
+ $correctPassword = $this->app['hash']->check(
+ isset($input['password']) ? $input['password'] : false,
+ $user->password
);
- }
- // Check for throttle limit then log-in
- if(! $this->reachedThrottleLimit( $credentials ) )
- {
- $user = $this->repo->getUserByIdentity($credentials, $identity_columns);
-
- if(
- $user &&
- ($user->confirmed || ! $confirmed_only ) &&
- $this->app['hash']->check(
- $credentials['password'],
- $user->password
- )
- )
- {
- $remember = isset($credentials['remember']) ? $credentials['remember'] : false;
-
- $this->app['auth']->login( $user, $remember );
- return true;
- }
- }
+ if (! $correctPassword)
+ return false;
- $this->throttleCount( $credentials );
+ $this->app['auth']->login($user, $remember);
+ return true;
+ }
return false;
}
/**
- * Checks if the credentials has been throttled by too
- * much failed login attempts
- *
- * @param array $credentials
- * @return mixed Value.
+ * Extracts the value of the remember key of the given
+ * array
+ * @param array $input An array containing the key 'remember'
+ * @return boolean
*/
- public function isThrottled( $credentials )
+ protected function extractRememberFromArray($input)
{
- // Check how many failed tries have been done
- $attempt_key = $this->attemptCacheKey( $credentials );
- $attempts = $this->app['cache']->get($attempt_key, 0);
-
- if( $attempts >= $this->app['config']->get('confide::throttle_limit') )
- {
- return true;
- }
- else
- {
+ if (isset($input['remember'])) {
+ return $input['remember'];
+ } else {
return false;
}
}
/**
- * Send email with information about password reset
- *
- * @param string $email
- * @return bool
+ * Extracts the email or the username key of the given
+ * array
+ * @param array $input An array containing the key 'email' or 'username'
+ * @return mixed
*/
- public function forgotPassword( $email )
+ protected function extractIdentityFromArray($input)
{
- $user = $this->repo->getUserByMail( $email );
- if( $user )
- {
- $user->forgotPassword();
- return true;
- }
- else
- {
+ if (isset($input['email'])) {
+ return $input['email'];
+ } elseif (isset($input['username'])) {
+ return $input['username'];
+ } else {
return false;
}
}
/**
- * Checks to see if the user has a valid token.
- *
- * @param $token
- * @return bool
+ * Calls throttleIdentity of the loginThrottler and returns false
+ * if the throttleCount is grater then the 'throttle_limit' config.
+ * Also sleeps a little in order to avoid dicionary attacks.
+ * @param mixed $identity
+ * @return boolean False if the identity has reached the 'throttle_limit'
*/
- public function isValidToken( $token )
+ protected function loginThrottling($identity)
{
- $count = $this->repo->getPasswordRemindersCount( $token );
-
- return ($count != 0);
- }
+ $count = $this->loginThrottler
+ ->throttleIdentity($identity);
- /**
- * Change user password
- *
- * @return string
- */
- public function resetPassword( $params )
- {
- $token = array_get($params, 'token', '');
- $email = $this->repo->getEmailByReminderToken( $token );
- $user = $this->repo->getUserByMail( $email );
-
- if( $user )
- {
- if($user->resetPassword( $params ))
- {
- // Password reset success, remove token from database
- $this->repo->deleteEmailByReminderToken( $token );
-
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
+ if ($count >= $this->app['config']->get('confide::throttle_limit'))
return false;
- }
+
+ // Throttling delay!
+ // See: http://www.codinghorror.com/blog/2009/01/dictionary-attacks-101.html
+ if($count > 2)
+ usleep(($count-1) * 400000);
+
+ return true;
}
/**
- * Log the user out of the application.
- *
- * @return void
+ * Asks the loginThrottler service if the given identity has reached the
+ * throttle_limit
+ * @param mixed $identity The login identity
+ * @return boolean True if the identity has reached the throttle_limit
*/
- public function logout()
+ public function isThrottled($identity)
{
- $this->app['auth']->logout();
+ return $this->loginThrottler->isThrottled($identity);
}
/**
- * Display the default login view
+ * If an user with the given email exists then generate
+ * a token for password change and saves it in the
+ * 'password_reminders' table with the email of the
+ * user.
*
- * @deprecated
- * @return Illuminate\View\View
+ * @param string $email
+ * @return string $token
*/
- public function makeLoginForm()
+ public function forgotPassword($email)
{
- return $this->app['view']->make($this->app['config']->get('confide::login_form'));
+ $user = $this->repo->getUserByEmail($email);
+
+ if ($user)
+ return $this->passService->requestChangePassword($user);
+
+ return false;
}
/**
- * Display the default signup view
+ * Delete the record of the given token from 'password_reminders'
+ * table.
*
- * @deprecated
- * @return Illuminate\View\View
+ * @param string $token Token retrieved from a forgotPassword
+ * @return boolean Success
*/
- public function makeSignupForm()
+ public function destroyForgotPasswordToken($token)
{
- return $this->app['view']->make( $this->app['config']->get('confide::signup_form') );
+ return $this->passService->destroyToken($token);
}
/**
- * Display the forget password view
- *
- * @deprecated
- * @return Illuminate\View\View
+ * Returns a user that corresponds to the given reset
+ * password token or false if there is no user with the
+ * given token.
+ * @param string $token
+ * @return ConfideUser
*/
- public function makeForgotPasswordForm()
+ public function userByResetPasswordToken($token)
{
- return $this->app['view']->make( $this->app['config']->get('confide::forgot_password_form') );
+ $email = $this->passService->getEmailByToken($token);
+
+ if ($email) {
+ return $this->repo->getUserByEmail($email);
+ }
+
+ return false;
}
/**
- * Display the forget password view
+ * Log the user out of the application.
*
- * @deprecated
- * @return Illuminate\View\View
+ * @return void
*/
- public function makeResetPasswordForm( $token )
+ public function logout()
{
- return $this->app['view']->make( $this->app['config']->get('confide::reset_password_form') , array('token'=>$token));
+ return $this->app['auth']->logout();
}
/**
- * Check whether the controller's action exists.
- * Returns the url if it does. Otherwise false.
- * @param $controllerAction
- * @return string
+ * Display the default login view
+ *
+ * @return \Illuminate\View\View
*/
- public function checkAction( $action, $parameters = array(), $absolute = true )
+ public function makeLoginForm()
{
- try {
- $url = $this->app['url']->action($action, $parameters, $absolute);
- } catch( InvalidArgumentException $e ) {
- return false;
- }
-
- return $url;
+ return $this->app['view']
+ ->make(
+ $this->app['config']->get('confide::login_form')
+ );
}
/**
- * Returns the name of the cache key that will be used
- * to store the failed attempts
+ * Display the default signup view
*
- * @param array $credentials.
- * @return string.
+ * @return \Illuminate\View\View
*/
- protected function attemptCacheKey( $credentials )
+ public function makeSignupForm()
{
- return 'confide_flogin_attempt_'
- .$this->app['request']->server('REMOTE_ADDR')
- .$credentials[$this->app['config']->get('confide::login_cache_field')];
+ return $this->app['view']
+ ->make(
+ $this->app['config']->get('confide::signup_form')
+ );
}
/**
- * Checks if the current IP / email has reached the throttle
- * limit
- *
- * @param array $credentials
- * @return bool Value.
+ * Display the forget password view
+ *
+ * @return \Illuminate\View\View
*/
- protected function reachedThrottleLimit( $credentials )
+ public function makeForgotPasswordForm()
{
- $attempt_key = $this->attemptCacheKey( $credentials );
- $attempts = $this->app['cache']->get($attempt_key, 0);
-
- return $attempts >= $this->app['config']->get('confide::throttle_limit');
+ return $this->app['view']
+ ->make(
+ $this->app['config']->get('confide::forgot_password_form')
+ );
}
/**
- * Increment IP / email throttle count
- *
- * @param array $credentials
- * @return void
+ * Display the forget password view
+ *
+ * @return \Illuminate\View\View
*/
- protected function throttleCount( $credentials )
+ public function makeResetPasswordForm( $token )
{
- $attempt_key = $this->attemptCacheKey( $credentials );
- $attempts = $this->app['cache']->get($attempt_key, 0);
-
- $this->app['cache']->put($attempt_key, $attempts+1, $this->app['config']->get('confide::throttle_time_period')); // used throttling login attempts
+ return $this->app['view']
+ ->make(
+ $this->app['config']->get('confide::reset_password_form'),
+ array('token'=>$token)
+ );
}
}
diff --git a/src/Zizaco/Confide/ConfideEloquentRepository.php b/src/Zizaco/Confide/ConfideEloquentRepository.php
deleted file mode 100644
index ed17758..0000000
--- a/src/Zizaco/Confide/ConfideEloquentRepository.php
+++ /dev/null
@@ -1,300 +0,0 @@
-app = app();
- }
-
- /**
- * Returns the model set in auth config
- *
- * @return mixed Instantiated object of the 'auth.model' class
- */
- public function model()
- {
- if (! $this->model)
- {
- $this->model = $this->app['config']->get('auth.model');
- }
-
- if(is_object($this->model))
- {
- return $this->model;
- }
- elseif(is_string($this->model))
- {
- return new $this->model;
- }
-
- throw new \Exception("Model not specified in config/auth.php", 639);
- }
-
- /**
- * Set the user confirmation to true.
- *
- * @param string $code
- * @return bool
- */
- public function confirm( $code )
- {
- $user = $this->model()->where('confirmation_code', '=', $code)->get()->first();
- if( $user )
- {
- return $user->confirm();
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Find a user by the given email
- *
- * @param string $email The email to be used in the query
- * @return ConfideUser User object
- */
- public function getUserByMail( $email )
- {
- $user = $this->model()->where('email', '=', $email)->get()->first();
-
- return $user;
- }
-
- /**
- * Find a user by it's credentials. Perform a 'where' within
- * the fields contained in the $identityColumns.
- *
- * @param array $credentials An array containing the attributes to search for
- * @param mixed $identityColumns Array of attribute names or string (for one atribute)
- * @return ConfideUser User object
- */
- public function getUserByIdentity( $credentials, $identityColumns = array('email') )
- {
- if(empty($credentials))
- {
- return null;
- }
-
- $identityColumns = (array)$identityColumns;
-
- $user = $this->model();
-
- $first = true;
- $hasWhere = false;
-
- foreach ($identityColumns as $attribute) {
-
- if(isset($credentials[$attribute]))
- {
- $hasWhere = true;
-
- if($first)
- {
- $user = $user->where($attribute, $credentials[$attribute]);
- $first = false;
- }
- else
- {
- $user = $user->orWhere($attribute, $credentials[$attribute]);
- }
- }
- else
- {
- continue;
- }
- }
-
- if($hasWhere)
- {
- $user = $user->get();
-
- if(! empty($user))
- {
- return $user->first();
- }
-
- }
-
- return null;
- }
-
- /**
- * Get password reminders count by the given token
- *
- * @param string $token
- * @return int Password reminders count
- */
- public function getPasswordRemindersCount( $token )
- {
- $count = $this->app['db']->connection()->table('password_reminders')
- ->where('token','=',$token)->count();
-
- return $count;
- }
-
- /**
- * Get email of password reminder by the given token
- *
- * @param string $token
- * @return string Email
- */
- public function getEmailByReminderToken( $token )
- {
- $email = $this->app['db']->connection()->table('password_reminders')
- ->select('email')->where('token','=',$token)
- ->first();
-
- if ($email && is_object($email))
- {
- $email = $email->email;
- }
- elseif ($email && is_array($email))
- {
- $email = $email['email'];
- }
-
- return $email;
- }
-
- /**
- * Remove password reminder from database by the given token
- *
- * @param string $token
- * @return void
- */
- public function deleteEmailByReminderToken( $token )
- {
- $this->app['db']->connection()->table('password_reminders')
- ->select('email')->where('token','=',$token)
- ->delete();
- }
-
- /**
- * Change the password of the given user. Make sure to hash
- * the $password before calling this method.
- *
- * @param ConfideUser $user An existent user
- * @param string $password The password hash to be used
- * @return boolean Success
- */
- public function changePassword( $user, $password )
- {
- $usersTable = $user->getTable();
- $id = $user->getKey();
- $idColumn = $user->getKeyName();
-
- $this->app['db']->connection()->table($usersTable)
- ->where($idColumn,$id)->update(array('password'=>$password));
- // I.E: DB::table('users')->where('id',3)->update(array('password'=>$password));
-
- return true;
- }
-
- /**
- * Generate a token for password change and saves it in
- * the 'password_reminders' table with the email of the
- * user.
- *
- * @param ConfideUser $user An existent user
- * @return string Password reset token
- */
- public function forgotPassword( $user )
- {
- $token = md5( uniqid(mt_rand(), true) );
-
- $values = array(
- 'email'=> $user->email,
- 'token'=> $token,
- 'created_at'=> new \DateTime
- );
-
- $this->app['db']->connection()->table('password_reminders')
- ->insert( $values );
- // I.E:
- // DB::table('password_reminders')->insert(array(
- // 'email'=> $this->email,
- // 'token'=> $token,
- // 'created_at'=> new \DateTime
- //));
-
- return $token;
- }
-
- /**
- * Checks if an non saved user has duplicated credentials
- * (email and/or username)
- *
- * @param ConfideUser $user The non-saved user to be checked
- * @return int The number of duplicated entry founds. Probably 0 or 1.
- */
- public function userExists( $user )
- {
- $usersTable = $user->getTable();
-
- $query = $this->app['db']->connection()->table($usersTable)
- ->where('email',$user->email);
-
- if($user->username)
- {
- $query = $query->orWhere('username',$user->username);
- }
-
- $count = $query->count();
- // I.E: DB::table('users')->where('email', 'bob@sample.com')->orWhere('username', 'bob')->count();
-
- return $count;
- }
-
- /**
- * Set the 'confirmed' column of the given user to 1
- *
- * @param ConfideUser $user An existent user
- * @return boolean Success
- */
- public function confirmUser( $user )
- {
- $usersTable = $user->getTable();
- $id = $user->getKey();
- $idColumn = $user->getKeyName();
-
- $this->app['db']->connection()->table($usersTable)
- ->where($idColumn,$id)->update(array('confirmed'=>1));
- // I.E: DB::table('users')->where('id',3)->update(array('confirmed'=>1));
-
- return true;
- }
-
- public function validate($user, array $rules = array(), array $customMessages = array())
- {
- return $user->validate($rules, $customMessages);
- }
-
-}
diff --git a/src/Zizaco/Confide/ConfideRepository.php b/src/Zizaco/Confide/ConfideRepository.php
deleted file mode 100644
index 738a135..0000000
--- a/src/Zizaco/Confide/ConfideRepository.php
+++ /dev/null
@@ -1,104 +0,0 @@
-package('zizaco/confide');
- }
-
- /**
- * Register the service provider.
- *
- * @return void
- */
- public function register()
- {
- $this->registerRepository();
-
- $this->registerConfide();
-
- $this->registerCommands();
- }
-
- /**
- * Register the repository that will handle all the database interaction.
- *
- * @return void
- */
- protected function registerRepository()
- {
- $this->app->bind('confide.repository', function($app)
- {
- return new ConfideEloquentRepository;
- });
- }
-
- /**
- * Register the application bindings.
- *
- * @return void
- */
- protected function registerConfide()
- {
- $this->app->bind('confide', function($app)
- {
- return new Confide($app->make('confide.repository'));
- });
- }
-
- /**
- * Register the artisan commands.
- *
- * @return void
- */
- protected function registerCommands()
- {
- $this->app['command.confide.controller'] = $this->app->share(function($app)
- {
- return new ControllerCommand($app);
- });
-
- $this->app['command.confide.routes'] = $this->app->share(function($app)
- {
- return new RoutesCommand($app);
- });
-
- $this->app['command.confide.migration'] = $this->app->share(function($app)
- {
- return new MigrationCommand($app);
- });
-
- $this->commands(
- 'command.confide.controller',
- 'command.confide.routes',
- 'command.confide.migration'
- );
- }
-
-}
diff --git a/src/Zizaco/Confide/ConfideUser.php b/src/Zizaco/Confide/ConfideUser.php
index 655651b..d16afa3 100644
--- a/src/Zizaco/Confide/ConfideUser.php
+++ b/src/Zizaco/Confide/ConfideUser.php
@@ -1,159 +1,118 @@
confirmed = true;
- /**
- * This way the model will automatically replace the plain-text password
- * attribute (from $passwordAttributes) with the hash checksum on save
- *
- * @var bool
- */
- public $autoHashPasswordAttributes = true;
+ return ConfideFacade::confirm($this->confirmation_code);
+ }
/**
- * Ardent validation rules
+ * Generates a token for password change and saves it in the
+ * 'password_reminders' table with the email of the
+ * user.
*
- * @var array
- */
- public static $rules = array(
- 'username' => 'required|alpha_dash|unique:users',
- 'email' => 'required|email|unique:users',
- 'password' => 'required|min:4|confirmed',
- 'password_confirmation' => 'min:4',
- );
-
- /**
- * Create a new ConfideUser instance.
+ * @return string $token
*/
- public function __construct( array $attributes = array() )
+ public function forgotPassword()
{
- parent::__construct( $attributes );
-
- if ( ! static::$app )
- static::$app = app();
-
- $this->table = static::$app['config']->get('auth.table');
+ return ConfideFacade::forgotPassword($this->email);
}
/**
- * Get the unique identifier for the user.
+ * Checks if the current user is valid using the ConfideUserValidator
*
- * @return mixed
+ * @return boolean
*/
- public function getAuthIdentifier()
+ public function isValid()
{
- return $this->getKey();
+ // Instantiate the Zizaco\Confide\UserValidator and calls the
+ // validate method. Feel free to use your own validation
+ // class.
+ $validator = App::make('confide.user_validator');
+
+ return $validator->validate($this);
}
/**
- * Get the password for the user.
+ * Overwrites the original save method in order to perform
+ * validation before actually saving the object.
*
- * @return string
+ * @param array $options
+ * @return bool
*/
- public function getAuthPassword()
+ public function save(array $options = array())
{
- return $this->password;
+ if ($this->isValid()) {
+ return parent::save($options);
+ } else {
+ return false;
+ }
}
/**
- * Confirm the user (usually means that the user)
- * email is valid.
+ * Returns a MessageBag object that store any error
+ * regarding the user validation
*
- * @return bool
+ * @var \Illuminate\Support\MessageBag
*/
- public function confirm()
+ public function errors()
{
- $this->confirmed = 1;
-
- // ConfideRepository will update the database
- static::$app['confide.repository']
- ->confirmUser( $this );
+ if (!$this->errors)
+ $this->errors = App::make('Illuminate\Support\MessageBag');
- return true;
+ return $this->errors;
}
/**
- * Send email with information about password reset
+ * Get the unique identifier for the user.
*
- * @return string
+ * @see \Illuminate\Auth\UserInterface
+ * @return mixed
*/
- public function forgotPassword()
+ public function getAuthIdentifier()
{
- // ConfideRepository will generate token (and save it into database)
- $token = static::$app['confide.repository']
- ->forgotPassword( $this );
-
- $view = static::$app['config']->get('confide::email_reset_password');
-
- $this->sendEmail( 'confide::confide.email.password_reset.subject', $view, array('user'=>$this, 'token'=>$token) );
-
- return true;
+ // Get the value of the model's primary key.
+ return $this->getKey();
}
/**
- * Change user password
+ * Get the password for the user.
*
- * @param $params
+ * @see \Illuminate\Auth\UserInterface
* @return string
*/
- public function resetPassword( $params )
+ public function getAuthPassword()
{
- $password = array_get($params, 'password', '');
- $passwordConfirmation = array_get($params, 'password_confirmation', '');
-
- $passwordValidators = array(
- 'password' => static::$rules['password'],
- 'password_confirmation' => static::$rules['password_confirmation'],
- );
- $user = static::$app['confide.repository']->model();
- $user->unguard();
- $user->fill(array(
- 'password' => $password,
- 'password_confirmation' => $passwordConfirmation,
- ));
- $user->reguard();
- $validationResult = static::$app['confide.repository']->validate($user, $passwordValidators);
-
- if ( $validationResult )
- {
- return static::$app['confide.repository']
- ->changePassword( $this, static::$app['hash']->make($password) );
- }
- else{
- return false;
- }
+ return $this->password;
}
/**
@@ -191,343 +150,13 @@ public function getRememberTokenName()
}
/**
- * Overwrite the Ardent save method. Saves model into
- * database
- *
- * @param array $rules:array
- * @param array $customMessages
- * @param array $options
- * @param \Closure $beforeSave
- * @param \Closure $afterSave
- * @return bool
- */
- public function save( array $rules = array(), array $customMessages = array(), array $options = array(), \Closure $beforeSave = null, \Closure $afterSave = null )
- {
- $duplicated = false;
-
- /*
- * When EloquentUserProvider call updateRememberToken
- * it doesn't retrieve rules, so validation on Ardent fails
- */
- if (!empty($this->remember_token) && empty($rules))
- {
- $rules = static::$rules;
- $rules = array_diff(array_keys($rules), array('password_confirmation'));
- }
-
- if(! $this->getKey())
- {
- $duplicated = static::$app['confide.repository']->userExists( $this );
- }
-
- if(! $duplicated)
- {
- return $this->real_save( $rules, $customMessages, $options, $beforeSave, $afterSave );
- }
- else
- {
- $this->validationErrors->add(
- 'duplicated',
- static::$app['translator']->get('confide::confide.alerts.duplicated_credentials')
- );
-
- return false;
- }
- }
-
- /**
- * Ardent method overloading:
- * Before save the user. Generate a confirmation
- * code if is a new user.
- *
- * @param bool $forced
- * @return bool
- */
- public function beforeSave($forced = false)
- {
- $id=$this->getKey();
- if ( empty($id) )
- {
- $this->confirmation_code = md5( uniqid(mt_rand(), true) );
- }
-
- /*
- * Remove password_confirmation field before save to
- * database.
- */
- if ( isset($this->password_confirmation) )
- {
- unset( $this->password_confirmation );
- }
-
- return true;
- }
-
- /**
- * Ardent method overloading:
- * After save, delivers the confirmation link email.
- * code if is a new user.
- *
- * @param $success
- * @param bool $forced
- * @return bool
- */
- public function afterSave($success=true, $forced = false)
- {
- if (! $this->confirmed && ! static::$app['cache']->get('confirmation_email_'.$this->getKey()) )
- {
- // on behalf or the config file we should send and email or not
- if (static::$app['config']->get('confide::signup_email') == true)
- {
- $view = static::$app['config']->get('confide::email_account_confirmation');
- $this->sendEmail( 'confide::confide.email.account_confirmation.subject', $view, array('user' => $this) );
- }
- // Save in cache that the email has been sent.
- $signup_cache = (int)static::$app['config']->get('confide::signup_cache');
- if ($signup_cache !== 0)
- {
- static::$app['cache']->put('confirmation_email_'.$this->getKey(), true, $signup_cache);
- }
- }
-
- return true;
- }
-
- /**
- * Runs the real eloquent save method or returns
- * true if it's under testing. Because Eloquent
- * and Ardent save methods are not Confide's
- * responsibility.
+ * Get the e-mail address where password reminders are sent.
*
- * @param array $rules
- * @param array $customMessages
- * @param array $options
- * @param \Closure $beforeSave
- * @param \Closure $afterSave
- * @return bool
- */
- protected function real_save( array $rules = array(), array $customMessages = array(), array $options = array(), \Closure $beforeSave = null, \Closure $afterSave = null )
- {
- if ( defined('CONFIDE_TEST') )
- {
- $this->beforeSave();
- $this->afterSave(true);
- return true;
- }
- else{
-
- /*
- * This will make sure that a non modified password
- * will not trigger validation error.
- * @fixed Pull #110
- */
- if( isset($rules['password']) && $this->password == $this->getOriginal('password') )
- {
- unset($rules['password']);
- unset($rules['password_confirmation']);
- }
-
- return parent::save( $rules, $customMessages, $options, $beforeSave, $afterSave );
- }
- }
-
- /**
- * Add the namespace 'confide::' to view hints.
- * this makes possible to send emails using package views from
- * the command line.
- *
- * @return void
- */
- protected static function fixViewHint()
- {
- if (isset(static::$app['view.finder']))
- static::$app['view.finder']->addNamespace('confide', __DIR__.'/../../views');
- }
-
- /**
- * Send email using the lang sentence as subject and the viewname
- *
- * @param mixed $subject_translation
- * @param mixed $view_name
- * @param array $params
- * @return voi.
- */
- protected function sendEmail( $subject_translation, $view_name, $params = array() )
- {
- if ( static::$app['config']->getEnvironment() == 'testing' )
- return;
-
- static::fixViewHint();
-
- $user = $this;
-
- static::$app['mailer']->send($view_name, $params, function($m) use ($subject_translation, $user)
- {
- $m->to( $user->email )
- ->subject( ConfideUser::$app['translator']->get($subject_translation) );
- });
- }
-
- /*
- |--------------------------------------------------------------------------
- | Deprecated variables and methods
- |--------------------------------------------------------------------------
- |
- */
-
- /**
- * Rules for when updating a user.
- *
- * @deprecated
- * @var array
- */
- protected $updateRules = array(
- 'username' => 'required|alpha_dash',
- 'email' => 'required|email',
- 'password' => 'min:4|confirmed',
- 'password_confirmation' => 'min:4',
- );
-
- /**
- * Alias of save but uses updateRules instead of rules.
- * @deprecated use updateUnique() instead
- * @param array $rules
- * @param array $customMessages
- * @param array $options
- * @param Closure $beforeSave
- * @param Closure $afterSave
- * @return bool
- */
- public function amend( array $rules = array(), array $customMessages = array(), array $options = array(), \Closure $beforeSave = null, \Closure $afterSave = null )
- {
- if (empty($rules)) {
- $rules = $this->getUpdateRules();
- }
- return $this->save( $rules, $customMessages, $options, $beforeSave, $afterSave );
- }
-
- /**
- * [Deprecated] Generates UUID and checks it for uniqueness against a table/column.
- *
- * @deprecated
- * @param $table
- * @param $field
+ * @see \Illuminate\Auth\Reminders\RemindableInterface
* @return string
*/
- protected function generateUuid($table, $field)
- {
- return md5( uniqid(mt_rand(), true) );
- }
-
- /**
- * [Deprecated]
- *
- * @deprecated
- */
- public function getUpdateRules()
- {
- return $this->updateRules;
- }
-
- /**
- * [Deprecated] Parses the two given users and compares the unique fields.
- *
- * @deprecated
- * @param $oldUser
- * @param $updatedUser
- * @param array $rules
- */
- public function prepareRules($oldUser, $updatedUser, $rules=array())
- {
- if(empty($rules)) {
- $rules = $this->getRules();
- }
-
- foreach($rules as $rule => $validation) {
- // get the rules with unique.
- if (strpos($validation, 'unique')) {
- // Compare old vs new
- if($oldUser->$rule != $updatedUser->$rule) {
- // Set update rule to creation rule
- $updateRules = $this->getUpdateRules();
- $updateRules[$rule] = $validation;
- $this->setUpdateRules($updateRules);
- }
- }
- }
- }
-
- /**
- * [Deprecated]
- *
- * @deprecated
- */
- public function getRules()
- {
- return self::$rules;
- }
-
- /**
- * [Deprecated]
- *
- * @deprecated
- */
- public function setUpdateRules($set)
- {
- $this->updateRules = $set;
- }
-
- /**
- * [Deprecated] Find an user by it's credentials. Perform a 'where' within
- * the fields contained in the $identityColumns.
- *
- * @deprecated Use ConfideRepository getUserByIdentity instead.
- * @param array $credentials An array containing the attributes to search for
- * @param mixed $identityColumns Array of attribute names or string (for one atribute)
- * @return ConfideUser User object
- */
- public function getUserFromCredsIdentity($credentials, $identity_columns = array('username', 'email'))
- {
- return static::$app['confide.repository']->getUserByIdentity($credentials, $identity_columns);
- }
-
- /**
- * [Deprecated] Checks if an user exists by it's credentials. Perform a 'where' within
- * the fields contained in the $identityColumns.
- *
- * @deprecated Use ConfideRepository getUserByIdentity instead.
- * @param array $credentials An array containing the attributes to search for
- * @param mixed $identityColumns Array of attribute names or string (for one atribute)
- * @return boolean Exists?
- */
- public function checkUserExists($credentials, $identity_columns = array('username', 'email'))
+ public function getReminderEmail()
{
- $user = static::$app['confide.repository']->getUserByIdentity($credentials, $identity_columns);
-
- if ($user) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * [Deprecated] Checks if an user is confirmed by it's credentials. Perform a 'where' within
- * the fields contained in the $identityColumns.
- *
- * @deprecated Use ConfideRepository getUserByIdentity instead.
- * @param array $credentials An array containing the attributes to search for
- * @param mixed $identityColumns Array of attribute names or string (for one atribute)
- * @return boolean Is confirmed?
- */
- public function isConfirmed($credentials, $identity_columns = array('username', 'email'))
- {
- $user = static::$app['confide.repository']->getUserByIdentity($credentials, $identity_columns);
-
- if (! is_null($user) and $user->confirmed) {
- return true;
- } else {
- return false;
- }
+ return $this->email;
}
}
diff --git a/src/Zizaco/Confide/ConfideUserInterface.php b/src/Zizaco/Confide/ConfideUserInterface.php
new file mode 100644
index 0000000..d049eb6
--- /dev/null
+++ b/src/Zizaco/Confide/ConfideUserInterface.php
@@ -0,0 +1,40 @@
+app = $app ?: app();
+ }
+
+ /**
+ * Generate a token for password change and saves it in
+ * the 'password_reminders' table with the email of the
+ * user.
+ *
+ * @param RemindableInterface $user An existent user
+ * @return string Password reset token
+ */
+ public function requestChangePassword(RemindableInterface $user)
+ {
+ $email = $user->getReminderEmail();
+ $token = $this->generateToken();
+
+ $values = array(
+ 'email'=> $email,
+ 'token'=> $token,
+ 'created_at'=> new \DateTime
+ );
+
+ $this->app['db']
+ ->connection($user->getConnectionName())
+ ->table('password_reminders')
+ ->insert($values);
+
+ $this->sendEmail($user, $token);
+
+ return $token;
+ }
+
+ /**
+ * Returns the email associated with the given reset
+ * password token
+ * @param string $token
+ * @return string Email
+ */
+ public function getEmailByToken($token)
+ {
+ $connection = $this->getConnection();
+
+ $email = $this->app['db']
+ ->connection($connection)
+ ->table('password_reminders')
+ ->select('email')
+ ->where('token','=',$token)
+ ->where('created_at','>=',$this->getOldestValidDate())
+ ->first();
+
+ $email = $this->unwrapEmail($email);
+
+ return $email;
+ }
+
+ /**
+ * Delete the record of the given token from database
+ *
+ * @param string $token
+ * @return boolean Success
+ */
+ public function destroyToken($token)
+ {
+ $connection = $this->getConnection();
+
+ $affected = $this->app['db']
+ ->connection($connection)
+ ->table('password_reminders')
+ ->where('token','=',$token)
+ ->delete();
+
+ return $affected > 0;
+ }
+
+ /**
+ * Returns a possible custom connection that may has being used
+ * for the user model. If null is returned by this method than
+ * the default connection is going to be used.
+ *
+ * @return string Original $connection value of the user model.
+ */
+ protected function getConnection()
+ {
+ return $this->app['confide.repository']
+ ->model()->getConnectionName();
+ }
+
+ /**
+ * Generates a random password change token
+ *
+ * @return string
+ */
+ protected function generateToken()
+ {
+ return md5(uniqid(mt_rand(), true));
+ }
+
+ /**
+ * Extracts the email of the given object or array
+ * @param mixed $email An object, array or email string
+ * @return string The email address
+ */
+ protected function unwrapEmail($email)
+ {
+ if ($email && is_object($email))
+ {
+ $email = $email->email;
+ }
+ elseif ($email && is_array($email))
+ {
+ $email = $email['email'];
+ }
+
+ return $email;
+ }
+
+ /**
+ * Sends an email containing the reset password link with the
+ * given token to the user
+ *
+ * @param RemindableInterface $user An existent user
+ * @param string $token Password reset token
+ * @return void
+ */
+ protected function sendEmail($user, $token)
+ {
+ $config = $this->app['config'];
+ $lang = $this->app['translator'];
+
+ $this->app['mailer']->send($config->get('confide::email_reset_password'), compact('user', 'token'), function($message) use ($user, $token, $lang) {
+ $message
+ ->to($user->email, $user->username)
+ ->subject($lang->get('confide::confide.email.password_reset.subject'));
+ });
+ }
+
+ /**
+ * Returns a date to limit the acceptable password reset
+ * requests.
+ *
+ * @return string 'Y-m-d H:i:s' formated string
+ */
+ protected function getOldestValidDate()
+ {
+ // Instantiate a carbon object (that is a dependency of
+ // 'illuminate/database')
+ $carbon = $this->app['Carbon\Carbon'];
+ $config = $this->app['config'];
+
+ return $carbon->now()
+ ->subHours($config->get('confide::confide.password_reset_expiration', 7))
+ ->toDateTimeString();
+ }
+}
diff --git a/src/Zizaco/Confide/EloquentRepository.php b/src/Zizaco/Confide/EloquentRepository.php
new file mode 100644
index 0000000..4eebeb2
--- /dev/null
+++ b/src/Zizaco/Confide/EloquentRepository.php
@@ -0,0 +1,144 @@
+app = $app ?: app();
+ }
+
+ /**
+ * Returns the model set in auth config
+ *
+ * @return mixed Instantiated object of the 'auth.model' class
+ */
+ public function model()
+ {
+ if (! $this->model) {
+ $this->model = $this->app['config']->get('auth.model');
+ }
+
+ if ($this->model) {
+ return $this->app[$this->model];
+ }
+
+ throw new \Exception("Wrong model specified in config/auth.php", 639);
+ }
+
+ /**
+ * Find a user by one of the fields given as $identity.
+ * If one of the fields in the $identity array matches the user
+ * will be retrieved.
+ * @param array $identity An array of attributes and values to search for
+ * @return ConfideUser User object
+ */
+ public function getUserByIdentity($identity)
+ {
+ $user = $this->model();
+
+ $firstWhere = true;
+ foreach ($identity as $attribute => $value) {
+
+ if ($firstWhere) {
+ $user = $user->where($attribute, '=', $value);
+ } else {
+ $user = $user->orWhere($attribute, '=', $value);
+ }
+
+ $firstWhere = false;
+ }
+
+ $user = $user->get()->first();
+
+ return $user;
+ }
+
+ /**
+ * Find a user by the given email
+ *
+ * @param string $email The email to be used in the query
+ * @return ConfideUser User object
+ */
+ public function getUserByEmail($email)
+ {
+ return $this->getUserByIdentity(['email'=>$email]);
+ }
+
+ /**
+ * Find a user by the given email or username
+ *
+ * @param string $emailOrUsername Username of email to be used in the query
+ * @return ConfideUser User object
+ */
+ public function getUserByEmailOrUsername($emailOrUsername)
+ {
+ $identity = [
+ 'email' => $emailOrUsername,
+ 'username' => strtolower($emailOrUsername)
+ ];
+
+ return $this->getUserByIdentity($identity);
+ }
+
+ /**
+ * Update the confirmation status of a user to true if a user
+ * is found with the given confirmation code.
+ *
+ * @param string $code
+ * @return bool Success
+ */
+ public function confirmByCode($code)
+ {
+ $identity = ['confirmation_code' => $code];
+
+ $user = $this->getUserByIdentity($identity);
+
+ if ($user) {
+ return $this->confirmUser($user);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Updated the given user in the database. Set the 'confirmed' attribute to
+ * true.
+ * @param ConfideUser User object
+ * @return bool Success
+ */
+ protected function confirmUser($user)
+ {
+ $user->confirmed = true;
+
+ return $user->save();
+ }
+}
diff --git a/src/Zizaco/Confide/ConfideFacade.php b/src/Zizaco/Confide/Facade.php
similarity index 55%
rename from src/Zizaco/Confide/ConfideFacade.php
rename to src/Zizaco/Confide/Facade.php
index cb78b4d..c398342 100644
--- a/src/Zizaco/Confide/ConfideFacade.php
+++ b/src/Zizaco/Confide/Facade.php
@@ -1,6 +1,12 @@
package('zizaco/confide');
+ }
+
+ /**
+ * Register the service provider.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ $this->registerRepository();
+
+ $this->registerPasswordService();
+
+ $this->registerLoginThrottleService();
+
+ $this->registerUserValidator();
+
+ $this->registerConfide();
+
+ $this->registerCommands();
+ }
+
+ /**
+ * Register the repository that will handle all the database
+ * interaction.
+ *
+ * @return void
+ */
+ protected function registerRepository()
+ {
+ $this->app->bind('confide.repository', function($app)
+ {
+ return new EloquentRepository($app);
+ });
+ }
+
+ /**
+ * Register the service that abstracts all user password management
+ * related methods
+ *
+ * @return void
+ */
+ protected function registerPasswordService()
+ {
+ $this->app->bind('confide.password', function($app)
+ {
+ return new EloquentPasswordService($app);
+ });
+ }
+
+ /**
+ * Register the service that Throttles login after
+ * too many failed attempts. This is a secure measure in
+ * order to avoid brute force attacks.
+ *
+ * @return void
+ */
+ protected function registerLoginThrottleService()
+ {
+ $this->app->bind('confide.throttle', function($app)
+ {
+ return new CacheLoginThrottleService($app);
+ });
+ }
+
+ /**
+ * Register the UserValidator class. The default class that
+ * used for user validation
+ *
+ * @return void
+ */
+ protected function registerUserValidator()
+ {
+ $this->app->bind('confide.user_validator', function($app)
+ {
+ return new UserValidator();
+ });
+ }
+
+ /**
+ * Register the application bindings.
+ *
+ * @return void
+ */
+ protected function registerConfide()
+ {
+ $this->app->bind('confide', function($app)
+ {
+ return new Confide(
+ $app->make('confide.repository'),
+ $app->make('confide.password'),
+ $app->make('confide.throttle'),
+ $app
+ );
+ });
+ }
+
+ /**
+ * Register the artisan commands.
+ *
+ * @return void
+ */
+ protected function registerCommands()
+ {
+ $this->app->bind('command.confide.controller', function($app)
+ {
+ return new ControllerCommand($app);
+ });
+
+ $this->app->bind('command.confide.routes', function($app)
+ {
+ return new RoutesCommand($app);
+ });
+
+ $this->app->bind('command.confide.migration', function($app)
+ {
+ return new MigrationCommand($app);
+ });
+
+ $this->commands(
+ 'command.confide.controller',
+ 'command.confide.routes',
+ 'command.confide.migration'
+ );
+ }
+}
diff --git a/src/Zizaco/Confide/Support/GenerateCommand.php b/src/Zizaco/Confide/Support/GenerateCommand.php
new file mode 100644
index 0000000..2d70b77
--- /dev/null
+++ b/src/Zizaco/Confide/Support/GenerateCommand.php
@@ -0,0 +1,104 @@
+app = $app ?: app();
+ }
+
+ /**
+ * Generates the given file with the rendered view
+ * @param string $filename Path to the file within the app directory
+ * @param string $view View file
+ * @param array $viewVars Variables that are going to be passed to the view
+ * @return bool Success
+ */
+ protected function generateFile($filename, $view, $viewVars)
+ {
+ $output = $this->app['view']->make('confide::'.$view, $viewVars)
+ ->render();
+
+ $filename = $this->app['path'].'/'.trim($filename,'/');
+ $directory = dirname($filename);
+
+ $this->makeDir($directory, 0755, true);
+ $this->filePutContents($filename, $output);
+
+ return true;
+ }
+
+ /**
+ * Append the rendered view to the given file. Same as generateFile but
+ * the 'file_put_contents' is called with the FILE_APPEND flag.
+ * @param string $filename Path to the file within the app directory
+ * @param string $view View file
+ * @param array $viewVars Variables that are going to be passed to the view
+ * @return bool Success
+ */
+ protected function appendInFile($filename, $view, $viewVars)
+ {
+ $output = $this->app['view']->make('confide::'.$view, $viewVars)
+ ->render();
+
+ $filename = $this->app['path'].'/'.trim($filename,'/');
+ $directory = dirname($filename);
+
+ $this->makeDir($directory, 0755, true);
+ $this->filePutContents($filename, $output, FILE_APPEND);
+
+ return true;
+ }
+
+ /**
+ * Encapsulates mkdir function
+ * @codeCoverageIgnore
+ * @param string $directory
+ * @param int $mode
+ * @param bool $recursive
+ * @return void
+ */
+ protected function makeDir($directory, $mode, $recursive)
+ {
+ if (! is_dir($directory))
+ @mkdir($directory, $mode, $recursive);
+ }
+
+ /**
+ * Encapsulates file_put_contents function
+ * @codeCoverageIgnore
+ * @param string $filename
+ * @param string $data
+ * @param int $flags
+ * @return void
+ */
+ protected function filePutContents($filename, $data, $flags = 0)
+ {
+ @file_put_contents($filename, $data, $flags);
+ }
+}
diff --git a/src/Zizaco/Confide/UserValidator.php b/src/Zizaco/Confide/UserValidator.php
new file mode 100644
index 0000000..c8ea445
--- /dev/null
+++ b/src/Zizaco/Confide/UserValidator.php
@@ -0,0 +1,188 @@
+ [
+ 'username' => 'required|alpha_dash',
+ 'email' => 'required|email',
+ 'password' => 'required|min:4',
+ ],
+ 'update' => [
+ 'username' => 'required|alpha_dash',
+ 'email' => 'required|email',
+ 'password' => 'required|min:4',
+ ]
+ ];
+
+ /**
+ * Validates the given user. Should check if all the fields are correctly
+ * @param ConfideUserInterface $user Instance to be tested
+ * @return boolean True if the $user is valid
+ */
+ public function validate(ConfideUserInterface $user, $ruleset = 'create')
+ {
+ // Set the $repo as a ConfideRepository object
+ $this->repo = App::make('confide.repository');
+
+ // Validate object
+ $result = $this->validateAttributes($user, $ruleset) ? true : false;
+ $result = ($this->validatePassword($user) && $result) ? true : false;
+ $result = ($this->validateIsUnique($user) && $result) ? true : false;
+
+ return $result;
+ }
+
+ /**
+ * Validates the password and password_confirmation of the given
+ * user
+ * @param ConfideUserInterface $user
+ * @return boolean True if password is valid
+ */
+ public function validatePassword(ConfideUserInterface $user)
+ {
+ $hash = App::make('hash');
+
+ if($user->getOriginal('password') != $user->password) {
+ if ($user->password == $user->password_confirmation) {
+
+ // Hashes password and unset password_confirmation field
+ $user->password = $hash->make($user->password);
+ unset($user->password_confirmation);
+
+ return true;
+ } else {
+ $this->attachErrorMsg(
+ $user,
+ 'validation.confirmed::confide.alerts.wrong_confirmation',
+ 'password_confirmation'
+ );
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Validates if the given user is unique. If there is another
+ * user with the same credentials but a different id, this
+ * method will return false.
+ * @param ConfideUserInterface $user
+ * @return boolean True if user is unique
+ */
+ public function validateIsUnique(ConfideUserInterface $user)
+ {
+ $identity = [
+ 'email' => $user->email,
+ 'username' => $user->username,
+ ];
+
+ foreach($identity as $attribute => $value) {
+
+ $similar = $this->repo->getUserByIdentity([$attribute => $value]);
+
+ if (!$similar || $similar->getKey() == $user->getKey()) {
+ unset($identity[$attribute]);
+ } else {
+ $this->attachErrorMsg(
+ $user, 'confide::confide.alerts.duplicated_credentials', $attribute
+ );
+ }
+
+ }
+
+ if(!$identity) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Uses Laravel Validator in order to check if the attributes of the
+ * $user object are valid for the given $ruleset
+ * @param ConfideUserInterface $user
+ * @param string $ruleset The name of the key in the UserValidator->$rules array
+ * @return boolean True if the attributes are valid
+ */
+ public function validateAttributes(ConfideUserInterface $user, $ruleset = 'create')
+ {
+ $attributes = $user->toArray();
+
+ // Force getting password since it may be hidden from array form
+ $attributes['password'] = $user->getAuthPassword();
+
+ $rules = $this->rules[$ruleset];
+
+ $validator = App::make('validator')
+ ->make( $attributes, $rules );
+
+ // Validate and attach errors
+ if ($validator->fails()) {
+ $user->errors = $validator->errors();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Creates a \Illuminate\Support\MessageBag object, add the error message
+ * to it and then set the errors attribute of the user with that bag
+ * @param ConfideUserInterface $user
+ * @param string $errorMsg The error message
+ * @param string $key The key if the error message
+ * @return void
+ */
+ public function attachErrorMsg(ConfideUserInterface $user, $errorMsg, $key = 'confide')
+ {
+ $messageBag = $user->errors;
+
+ if (! $messageBag instanceof MessageBag) {
+ $messageBag = App::make('Illuminate\Support\MessageBag');
+ }
+
+ $messageBag->add($key, Lang::get($errorMsg));
+ $user->errors = $messageBag;
+ }
+}
diff --git a/src/Zizaco/Confide/UserValidatorInterface.php b/src/Zizaco/Confide/UserValidatorInterface.php
new file mode 100644
index 0000000..361dafa
--- /dev/null
+++ b/src/Zizaco/Confide/UserValidatorInterface.php
@@ -0,0 +1,21 @@
+addNamespace('confide',substr(__DIR__,0,-8).'views');
+ return array(
+ array('name', null, InputOption::VALUE_OPTIONAL, 'Name of the controller.', 'Users'),
+ array('--restful', '-r', InputOption::VALUE_NONE, 'Generate RESTful controller.')
+ );
}
/**
@@ -39,68 +47,55 @@ public function __construct()
*/
public function fire()
{
- $name = $this->prepareName($this->option('name'));
+ // Prepare variables
+ $class = $this->getControllerName($this->option('name'));
+ $namespace = $this->getNamespace($this->option('name'));
+ $model = $this->app['config']->get('auth.model');
$restful = $this->option('restful');
- $this->line('');
- $this->info( "Controller name: $name".(($restful) ? "\nRESTful: Yes" : '') );
- $message = "An authentication ".(($restful) ? 'RESTful ' : '')."controller template with the name $name.php".
- " will be created in app/controllers directory and will NOT overwrite any ".
- " file.";
+ $viewVars = compact(
+ 'class','namespace','model','restful'
+ );
- $this->comment( $message );
+ // Prompt
+ $this->line('');
+ $this->info("Controller name: $class".(($restful) ? "\nRESTful: Yes" : '') );
+ $this->comment("An authentication ".(($restful) ? 'RESTful ' : '')."controller template with the name ".($namespace ? $namespace.'\\' : '')."$class.php".
+ " will be created in app/controllers directory");
$this->line('');
if ( $this->confirm("Proceed with the controller creation? [Yes|no]") )
{
- $this->line('');
-
- $this->info( "Creating $name..." );
- if( $this->createController( $name, $restful ) )
- {
- $this->info( "$name.php Successfully created!" );
- }
- else{
- $this->error(
- "Coudn't create app/controllers/$name.php.\nCheck the".
- " write permissions within the controllers directory".
- " or if $name.php already exists. (This command will".
- " not overwrite any file. delete the existing $name.php".
- " if you wish to continue)."
- );
- }
-
- $this->line('');
-
+ $this->info( "Creating $class..." );
+ // Generate
+ $filename = 'controllers/'.($namespace ? str_replace('\\', '/', $namespace).'/' : '').$class.'.php';
+ $this->generateFile($filename, 'generators.controller', $viewVars);
+ $this->info( "$class.php Successfully created!" );
+
+ // Generate repository
+ $filename = 'models/'.str_replace('\\', '/', $model).'Repository.php';
+ $this->generateFile($filename, 'generators.repository', $viewVars);
+ $this->info( $model.'Repository.php Successfully created!');
}
}
/**
- * Get the console command options.
- *
- * @return array
+ * Returns the name of the controller class that will handle a
+ * resource with the given name.
+ * @param string $name Resource name
+ * @return string Controller class name
*/
- protected function getOptions()
+ protected function getControllerName($name)
{
- $app = app();
+ if (strstr($name, '\\'))
+ {
+ $name = explode('\\', $name);
+ $name = array_pop($name);
+ }
- return array(
- array('name', null, InputOption::VALUE_OPTIONAL, 'Name of the controller.', $app['config']->get('auth.model')),
- array('--restful', '-r', InputOption::VALUE_NONE, 'Generate RESTful controller.'),
- );
- }
+ $name = ( $name != '') ? ucfirst($name) : 'Users';
- /**
- * Prepare the controller name
- *
- * @param string $name
- * @return string
- */
- protected function prepareName($name = '')
- {
- $name = ( $name != '') ? ucfirst($name) : 'User';
-
- if( substr($name,-10) == 'controller' )
+ if( substr(strtolower($name),-10) == 'controller' )
{
$name = substr($name, 0, -10).'Controller';
}
@@ -113,39 +108,21 @@ protected function prepareName($name = '')
}
/**
- * Create the controller
- *
- * @param string $name
- * @return bool
+ * Returns the namespace of the given class name
+ * @param string $name Class name
+ * @return string Namespace
*/
- protected function createController( $name = '', $restful = false )
+ protected function getNamespace($name)
{
- $app = app();
-
- $controller_file = $this->laravel->path."/controllers/$name.php";
- $output = $app['view']->make('confide::generators.controller')
- ->with('name', $name)
- ->with('restful', $restful)
- ->render();
-
- if( ! file_exists( $controller_file ) )
- {
- $fs = fopen($controller_file, 'x');
- if ( $fs )
- {
- fwrite($fs, $output);
- fclose($fs);
- return true;
- }
- else
- {
- return false;
- }
- }
- else
+ if (strstr($name, '\\'))
{
- return false;
+ $name = explode('\\', $name);
+ array_pop($name);
+ $name = implode('\\', $name);
+ } else {
+ $name = '';
}
- }
+ return $name;
+ }
}
diff --git a/src/commands/MigrationCommand.php b/src/commands/MigrationCommand.php
index 20f027d..9c53139 100644
--- a/src/commands/MigrationCommand.php
+++ b/src/commands/MigrationCommand.php
@@ -1,11 +1,17 @@
addNamespace('confide',substr(__DIR__,0,-8).'views');
+ return array(
+ array('table', null, InputOption::VALUE_OPTIONAL, 'Table name.', 'users'),
+ );
}
/**
@@ -39,81 +45,29 @@ public function __construct()
*/
public function fire()
{
+ // Prepare variables
$table = lcfirst($this->option('table'));
+ $viewVars = compact(
+ 'table'
+ );
+
+ // Prompt
$this->line('');
$this->info( "Table name: $table" );
- $message = "A migration that creates the $table table will".
- " be created in app/database/migrations directory";
-
- $this->comment( $message );
+ $this->comment("A migration that creates the $table table will".
+ " be created in app/database/migrations directory");
$this->line('');
if ( $this->confirm("Proceed with the migration creation? [Yes|no]") )
{
- $this->line('');
-
$this->info( "Creating migration..." );
- if( $this->createMigration( $table ) )
- {
- $this->info( "Migration successfully created!" );
- }
- else{
- $this->error(
- "Coudn't create migration.\n Check the write permissions".
- " within the app/database/migrations directory."
- );
- }
-
- $this->line('');
-
- }
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions()
- {
- $app = app();
-
- return array(
- array('table', null, InputOption::VALUE_OPTIONAL, 'Table name.', $app['config']->get('auth.table')),
- );
- }
+ // Generate
+ $filename = 'database/migrations/'.
+ date('Y_m_d_His')."_confide_setup_users_table.php";
+ $this->generateFile($filename, 'generators.migration', $viewVars);
- /**
- * Create the migration
- *
- * @param string $name
- * @return bool
- */
- protected function createMigration( $table = 'users' )
- {
- $app = app();
- $migration_file = $this->laravel->path."/database/migrations/".date('Y_m_d_His')."_confide_setup_users_table.php";
- $output = $app['view']->make('confide::generators.migration')->with('table', $table)->render();
-
- if( ! file_exists( $migration_file ) )
- {
- $fs = fopen($migration_file, 'x');
- if ( $fs )
- {
- fwrite($fs, $output);
- fclose($fs);
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
+ $this->info( "Migration successfully created!" );
}
}
-
}
diff --git a/src/commands/RoutesCommand.php b/src/commands/RoutesCommand.php
index 68c2df3..25eef97 100644
--- a/src/commands/RoutesCommand.php
+++ b/src/commands/RoutesCommand.php
@@ -1,11 +1,18 @@
addNamespace('confide',substr(__DIR__,0,-8).'views');
+ return array(
+ array('controller', null, InputOption::VALUE_OPTIONAL, 'Name of the controller.', 'UsersController'),
+ array('--restful', '-r', InputOption::VALUE_NONE, 'Generate RESTful controller.'),
+ );
}
/**
@@ -39,120 +47,52 @@ public function __construct()
*/
public function fire()
{
- $name = $this->prepareName($this->option('controller'));
+ // Prepare variables
+ $controllerName = $this->option('controller');
$restful = $this->option('restful');
+ $url = 'users';
+
+ $viewVars = compact(
+ 'controllerName',
+ 'url',
+ 'restful'
+ );
+
+ // Prompt
$this->line('');
$this->info( "Routes file: app/routes.php" );
- if(! $restful)
- {
- $message = "The default Confide routes (to use with the Controller template)".
- " will be appended to your routes.php file.";
- }
- else
- {
- $message = "A single route to handle every action in a RESTful controller".
- " will be appended to your routes.php file. This may be used with a confide".
- " controller generated using [-r|--restful] option.";
- }
-
+ $message = $this->getFireMessage($restful);
- $this->comment( $message );
+ $this->comment($message);
$this->line('');
if ( $this->confirm("Proceed with the append? [Yes|no]") )
{
- $this->line('');
-
$this->info( "Appending routes..." );
- if( $this->appendRoutes( $name, $restful ) )
- {
- $this->info( "app/routes.php Patched successfully!" );
- }
- else{
- $this->error(
- "Coudn't append content to app/routes.php\nCheck the".
- " write permissions within the file."
- );
- }
-
- $this->line('');
+ // Generate
+ $filename = 'routes.php';
+ $this->appendInFile($filename, 'generators.routes', $viewVars);
+ $this->info("app/routes.php Patched successfully!");
}
}
/**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions()
- {
- $app = app();
-
- return array(
- array('controller', null, InputOption::VALUE_OPTIONAL, 'Name of the controller.', $app['config']->get('auth.model')),
- array('--restful', '-r', InputOption::VALUE_NONE, 'Generate RESTful controller.'),
- );
- }
-
- /**
- * Prepare the controller name
- *
- * @param string $name
- * @return string
+ * Returns a message that should explain what is about to be done.
+ * @param boolean $restful If the restful option is being used
+ * @return string The message
*/
- protected function prepareName( $name = '' )
+ protected function getFireMessage($restful = false)
{
- $name = ( $name != '') ? ucfirst($name) : 'User';
-
- if( substr($name,-10) == 'controller' )
- {
- $name = substr($name, 0, -10).'Controller';
- }
- else
- {
- $name .= 'Controller';
- }
-
- return $name;
- }
-
- /**
- * Create the controller
- *
- * @param string $name
- * @return bool
- */
- protected function appendRoutes( $name = '', $restful = false )
- {
- $app = app();
- $routes_file = $this->laravel->path.'/routes.php';
- $confide_routes = $app['view']->make('confide::generators.routes')
- ->with('name', $name)
- ->with('restful', $restful)
- ->render();
-
- if( file_exists( $routes_file ) )
- {
- $fs = fopen($routes_file, 'a');
- if ( $fs )
- {
- fwrite($fs, $confide_routes);
- $this->line($confide_routes);
- fclose($fs);
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
+ if(! $restful) {
+ return "The default Confide routes (to use with the Controller template)".
+ " will be appended to your routes.php file.";
+ } else {
+ return "A single route to handle every action in a RESTful controller".
+ " will be appended to your routes.php file. This may be used with a confide".
+ " controller generated using [-r|--restful] option.";
}
}
-
}
diff --git a/src/config/config.php b/src/config/config.php
index 8a6fc61..c21d319 100644
--- a/src/config/config.php
+++ b/src/config/config.php
@@ -75,20 +75,16 @@
/*
|--------------------------------------------------------------------------
- | Signup (create) Cache
+ | Password reset expiration
|--------------------------------------------------------------------------
|
- | By default you will only can only register once every 2 hours
- | (120 minutes) because you are not able to receive a registration
- | email more often then that.
- |
- | You can adjust that limitation here, set to 0 for no caching.
- | Time is in minutes.
- |
+ | By default. A password reset request will expire after 7 hours. With the
+ | line below you will be able to customize the duration of the reset
+ | requests here.
|
*/
- 'signup_cache' => 120,
-
+ 'password_reset_expiration' => 7, // hours
+
/*
|--------------------------------------------------------------------------
| Signup E-mail and confirmation (true or false)
@@ -106,7 +102,7 @@
| signup_confirm:
| is to decide of a member needs to be confirmed before he is able to login
| so when you set this to true, then a member has to be confirmed before
- | he is able to login, so if you want to use an IPN for confirmation, be
+ | he is able to login, so if you want to use an IPN for confirmation, be
| sure that the ipn process also changes the confirmed flag in the member
| table, otherwise they will not be able to login after the payment.
|
diff --git a/src/lang/nl/confide.php b/src/lang/nl/confide.php
index 5be0816..c239806 100644
--- a/src/lang/nl/confide.php
+++ b/src/lang/nl/confide.php
@@ -1,8 +1,7 @@
'Gebruikersnaam',
- 'password' => 'Wachtwoord',
- 'password_confirmation' => 'Bevestig wachtwoord',
- 'e_mail' => 'E-mail',
- 'username_e_mail' => 'Gebruikersnaam of e-mailadres',
-
- 'signup' => array(
- 'title' => 'Registreren',
- 'desc' => 'Registreer een nieuw account',
- 'confirmation_required' => 'Bevestiging vereist',
- 'submit' => 'Maak nieuw account',
- ),
-
- 'login' => array(
- 'title' => 'Inloggen',
- 'desc' => 'Vul je gegevens in',
- 'forgot_password' => '(wachtwoord vergeten)',
- 'remember' => 'Onthoud mij',
- 'submit' => 'Inloggen',
- ),
-
- 'forgot' => array(
- 'title' => 'Wachtwoord vergeten',
- 'submit' => 'Doorgaan',
- ),
-
- 'alerts' => array(
- 'account_created' => 'Je account is succesvol aangemaakt. Controleer je e-mailinbox voor instructies om je account the bevestigen.',
- 'too_many_attempts' => 'Te veel pogingen. Probeer het over een enkele minuten nog eens.',
- 'wrong_credentials' => 'Verkeerde gebruikersnaam, e-mailadres of wachtwoord.',
- 'not_confirmed' => 'Je account is waarschijnlijk niet bevestigd. Controleer je e-mailinbox voor de bevestigingslink.',
- 'confirmation' => 'Je account is bevestigd! Je kunt nu inloggen.',
- 'wrong_confirmation' => 'Verkeerde bevestigingscode.',
- 'password_forgot' => 'De informatie voor het opnieuw instellen van je wachtwoord is verstuurd naar je e-mailadres.',
- 'wrong_password_forgot' => 'Gebruiker niet gevonden.',
- 'password_reset' => 'Je wachtwoord is succesvol veranderd.',
- 'wrong_password_reset' => 'Verkeerd wachtwoord. Probeer het nog eens.',
- 'wrong_token' => 'Het token om je wachtwoord opnieuw in te stellen is niet geldig.',
- 'duplicated_credentials' => 'De ingevulde gegevens zijn al in gebruik. Probeer het eens met andere gegevens.',
- ),
-
- 'email' => array(
- 'account_confirmation' => array(
- 'subject' => 'Accountbevestiging',
- 'greetings' => 'Hallo :name',
- 'body' => 'Klik op de onderstaande link om je account te bevestigen.',
- 'farewell' => 'Met vriendelijke groet',
- ),
-
- 'password_reset' => array(
- 'subject' => 'Wachtwoord opnieuw instellen',
- 'greetings' => 'Hallo :name',
- 'body' => 'Klik op de onderstaande link om je wachtwoord opnieuw in te stellen.',
- 'farewell' => 'Met vriendelijke groet',
- ),
- ),
-
-);
-*/
diff --git a/src/lang/nl_NL/confide.php b/src/lang/nl_NL/confide.php
new file mode 100644
index 0000000..a7b70af
--- /dev/null
+++ b/src/lang/nl_NL/confide.php
@@ -0,0 +1,66 @@
+ 'Gebruikersnaam',
+ 'password' => 'Wachtwoord',
+ 'password_confirmation' => 'Bevestig wachtwoord',
+ 'e_mail' => 'E-mail',
+ 'username_e_mail' => 'Gebruikersnaam of e-mailadres',
+
+ 'signup' => array(
+ 'title' => 'Registreren',
+ 'desc' => 'Registreer een nieuw account',
+ 'confirmation_required' => 'Bevestiging vereist',
+ 'submit' => 'Maak nieuw account',
+ ),
+
+ 'login' => array(
+ 'title' => 'Inloggen',
+ 'desc' => 'Vul je gegevens in',
+ 'forgot_password' => '(wachtwoord vergeten)',
+ 'remember' => 'Onthoud mij',
+ 'submit' => 'Inloggen',
+ ),
+
+ 'forgot' => array(
+ 'title' => 'Wachtwoord vergeten',
+ 'submit' => 'Doorgaan',
+ ),
+
+ 'alerts' => array(
+ 'account_created' => 'Je account is succesvol aangemaakt. Controleer je e-mailinbox voor instructies om je account the bevestigen.',
+ 'too_many_attempts' => 'Te veel pogingen. Probeer het over een enkele minuten nog eens.',
+ 'wrong_credentials' => 'Verkeerde gebruikersnaam, e-mailadres of wachtwoord.',
+ 'not_confirmed' => 'Je account is waarschijnlijk niet bevestigd. Controleer je e-mailinbox voor de bevestigingslink.',
+ 'confirmation' => 'Je account is bevestigd! Je kunt nu inloggen.',
+ 'wrong_confirmation' => 'Verkeerde bevestigingscode.',
+ 'password_forgot' => 'De informatie voor het opnieuw instellen van je wachtwoord is verstuurd naar je e-mailadres.',
+ 'wrong_password_forgot' => 'Gebruiker niet gevonden.',
+ 'password_reset' => 'Je wachtwoord is succesvol veranderd.',
+ 'wrong_password_reset' => 'Verkeerd wachtwoord. Probeer het nog eens.',
+ 'wrong_token' => 'Het token om je wachtwoord opnieuw in te stellen is niet geldig.',
+ 'duplicated_credentials' => 'De ingevulde gegevens zijn al in gebruik. Probeer het eens met andere gegevens.',
+ ),
+
+ 'email' => array(
+ 'account_confirmation' => array(
+ 'subject' => 'Accountbevestiging',
+ 'greetings' => 'Hallo :name',
+ 'body' => 'Klik op de onderstaande link om je account te bevestigen.',
+ 'farewell' => 'Met vriendelijke groet',
+ ),
+
+ 'password_reset' => array(
+ 'subject' => 'Wachtwoord opnieuw instellen',
+ 'greetings' => 'Hallo :name',
+ 'body' => 'Klik op de onderstaande link om je wachtwoord opnieuw in te stellen.',
+ 'farewell' => 'Met vriendelijke groet',
+ ),
+ ),
+
+);
diff --git a/src/migrations/2013_01_13_172956_confide_setup_users_table.php b/src/migrations/2013_01_13_172956_confide_setup_users_table.php
index 0242339..40df062 100644
--- a/src/migrations/2013_01_13_172956_confide_setup_users_table.php
+++ b/src/migrations/2013_01_13_172956_confide_setup_users_table.php
@@ -12,17 +12,25 @@ class ConfideSetupUsersTable extends Migration {
public function up()
{
// Creates the users table
- Schema::create('users', function($table)
- {
- $table->increments('id');
- $table->string('username');
- $table->string('email');
- $table->string('password');
- $table->string('confirmation_code');
- $table->boolean('confirmed')->default(false);
- $table->string('remember_token')->nullable();
- $table->timestamps();
- });
+ Schema::create('users', function($table)
+ {
+ $table->increments('id');
+ $table->string('username')->unique();
+ $table->string('email')->unique();
+ $table->string('password');
+ $table->string('confirmation_code');
+ $table->string('remember_token');
+ $table->boolean('confirmed')->default(false);
+ $table->timestamps();
+ });
+
+ // Creates password reminders table
+ Schema::create('password_reminders', function($t)
+ {
+ $t->string('email');
+ $t->string('token');
+ $t->timestamp('created_at');
+ });
}
/**
@@ -32,6 +40,7 @@ public function up()
*/
public function down()
{
+ Schema::drop('password_reminders');
Schema::drop('users');
}
diff --git a/src/views/emails/confirm.blade.php b/src/views/emails/confirm.blade.php
index a939f0c..847d630 100644
--- a/src/views/emails/confirm.blade.php
+++ b/src/views/emails/confirm.blade.php
@@ -3,8 +3,8 @@