New stuff pertaining to the import procedure and user registration.

This commit is contained in:
James Cole
2014-07-05 16:19:15 +02:00
parent c3254c2351
commit a0c0dc288d
23 changed files with 305 additions and 63 deletions

View File

@@ -9,7 +9,7 @@ return [
'table' => 'password_reminders', 'table' => 'password_reminders',
'expire' => 60, 'expire' => 60,
], ],
'verify_mail' => false, 'verify_mail' => true,
'verify_reset' => true, 'verify_reset' => true,
'allow_register' => true 'allow_register' => true

View File

@@ -6,6 +6,12 @@ use Firefly\Storage\User\UserRepositoryInterface as URI;
class UserController extends BaseController class UserController extends BaseController
{ {
/**
* Constructor.
*
* @param URI $user
* @param EHI $email
*/
public function __construct(URI $user, EHI $email) public function __construct(URI $user, EHI $email)
{ {
$this->user = $user; $this->user = $user;
@@ -13,11 +19,22 @@ class UserController extends BaseController
} }
/**
* Show the login view.
*
* @return \Illuminate\View\View
*/
public function login() public function login()
{ {
return View::make('user.login'); return View::make('user.login');
} }
/**
* Login.
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function postLogin() public function postLogin()
{ {
$rememberMe = Input::get('remember_me') == '1'; $rememberMe = Input::get('remember_me') == '1';
@@ -33,6 +50,11 @@ class UserController extends BaseController
return View::make('user.login'); return View::make('user.login');
} }
/**
* If allowed, show the register form.
*
* @return $this|\Illuminate\View\View
*/
public function register() public function register()
{ {
if (Config::get('auth.allow_register') !== true) { if (Config::get('auth.allow_register') !== true) {
@@ -41,6 +63,16 @@ class UserController extends BaseController
return View::make('user.register'); return View::make('user.register');
} }
/**
* If allowed, register the user.
*
* Then:
*
* - Send password OR
* - Send reset code.
*
* @return $this|\Illuminate\View\View
*/
public function postRegister() public function postRegister()
{ {
if (Config::get('auth.allow_register') !== true) { if (Config::get('auth.allow_register') !== true) {
@@ -58,17 +90,34 @@ class UserController extends BaseController
return View::make('user.register'); return View::make('user.register');
} }
/**
* Logout user.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function logout() public function logout()
{ {
Auth::logout(); Auth::logout();
Session::flush();
return Redirect::route('index'); return Redirect::route('index');
} }
/**
* Show form to help user get a new password.
*
* @return \Illuminate\View\View
*/
public function remindme() public function remindme()
{ {
return View::make('user.remindme'); return View::make('user.remindme');
} }
/**
* If need to verify, send new reset code.
* Otherwise, send new password.
*
* @return \Illuminate\View\View
*/
public function postRemindme() public function postRemindme()
{ {
$user = $this->user->findByEmail(Input::get('email')); $user = $this->user->findByEmail(Input::get('email'));
@@ -85,16 +134,13 @@ class UserController extends BaseController
} }
public function verify($verification) /**
{ * Send a user a password based on his reset code.
$user = $this->user->findByVerification($verification); *
if ($user) { * @param $reset
$this->email->sendPasswordMail($user); *
return View::make('user.registered'); * @return $this|\Illuminate\View\View
} */
return View::make('error')->with('message', 'Yo no hablo verification code!');
}
public function reset($reset) public function reset($reset)
{ {
$user = $this->user->findByReset($reset); $user = $this->user->findByReset($reset);

View File

@@ -18,7 +18,6 @@ class CreateUsersTable extends Migration {
$table->timestamps(); $table->timestamps();
$table->string('email',100); $table->string('email',100);
$table->string('password',60); $table->string('password',60);
$table->string('verification',32)->nullable();
$table->string('reset',32)->nullable(); $table->string('reset',32)->nullable();
$table->string('remember_token',255)->nullable(); $table->string('remember_token',255)->nullable();
$table->boolean('migrated'); $table->boolean('migrated');

View File

@@ -16,7 +16,6 @@ class DefaultUserSeeder extends Seeder
[ [
'email' => 's@nder.be', 'email' => 's@nder.be',
'password' => Hash::make('sander'), 'password' => Hash::make('sander'),
'verification' => null,
'reset' => null, 'reset' => null,
'remember_token' => null, 'remember_token' => null,
'migrated' => false 'migrated' => false

View File

@@ -0,0 +1,14 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 04/07/14
* Time: 13:58
*/
namespace Firefly\Exception;
class FireflyException extends \Exception {
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 04/07/14
* Time: 13:55
*/
namespace Firefly\Helper;
class MigrationException extends \Exception {
}

View File

@@ -6,11 +6,11 @@ class EmailHelper implements EmailHelperInterface
public function sendVerificationMail(\User $user) public function sendVerificationMail(\User $user)
{ {
$verification = \Str::random(32); $reset = \Str::random(32);
$user->verification = $verification; $user->reset = $reset;
$user->save(); $user->save();
$email = $user->email; $email = $user->email;
$data = ['verification' => $verification]; $data = ['reset' => $reset];
\Mail::send( \Mail::send(
['emails.user.verify-html', 'emails.user.verify-text'], $data, function ($message) use ($email) { ['emails.user.verify-html', 'emails.user.verify-text'], $data, function ($message) use ($email) {
@@ -24,7 +24,7 @@ class EmailHelper implements EmailHelperInterface
$password = \Str::random(12); $password = \Str::random(12);
$user->password = \Hash::make($password); $user->password = \Hash::make($password);
$user->verification = \Str::random(32); // new one. $user->reset = \Str::random(32); // new one.
$user->save(); $user->save();
$email = $user->email; $email = $user->email;

View File

@@ -15,6 +15,12 @@ class HelperServiceProvider extends ServiceProvider
'Firefly\Helper\Email\EmailHelperInterface', 'Firefly\Helper\Email\EmailHelperInterface',
'Firefly\Helper\Email\EmailHelper' 'Firefly\Helper\Email\EmailHelper'
); );
// migration:
$this->app->bind(
'Firefly\Helper\Migration\MigrationHelperInterface',
'Firefly\Helper\Migration\MigrationHelper'
);
} }
} }

View File

@@ -24,6 +24,7 @@ class MigrationHelper implements MigrationHelperInterface
{ {
// file does not exist: // file does not exist:
if (!file_exists($this->path)) { if (!file_exists($this->path)) {
\Log::error('Migration file ' . $this->path . ' does not exist!');
return false; return false;
} }
@@ -38,20 +39,39 @@ class MigrationHelper implements MigrationHelperInterface
if (is_null($this->JSON)) { if (is_null($this->JSON)) {
return false; return false;
} }
\Log::info('Migration file ' . $this->path . ' is valid!');
return true;
} }
public function migrate() public function migrate()
{ {
\Log::info('Start of migration.');
\DB::beginTransaction();
// create the accounts: try {
$this->_createAccounts(); $this->_importAccounts();
$this->_importComponents();
$this->_importPiggybanks();
} catch (\Firefly\Exception\FireflyException $e) {
\DB::rollBack();
\Log::error('Rollback because of error!');
\Log::error($e->getMessage());
return false;
}
\DB::commit();
\Log::info('Done!');
return true;
} }
protected function _createAccounts() protected function _importAccounts()
{ {
$accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface'); /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
\Log::info('Going to import ' . count($this->JSON->accounts) . ' accounts.');
foreach ($this->JSON->accounts as $entry) { foreach ($this->JSON->accounts as $entry) {
// create account: // create account:
if ($entry->openingbalance == 0) { if ($entry->openingbalance == 0) {
@@ -59,13 +79,66 @@ class MigrationHelper implements MigrationHelperInterface
} else { } else {
$account = $accounts->storeWithInitialBalance( $account = $accounts->storeWithInitialBalance(
['name' => $entry->name], ['name' => $entry->name],
new Carbon($entry->openingbalancedate), new \Carbon\Carbon($entry->openingbalancedate),
floatval($entry->openingbalance) floatval($entry->openingbalance)
); );
} }
if ($account) { $this->map['accounts'][$entry->id] = $account->id;
$this->map['accounts'][$entry->id] = $account->id; \Log::info('Imported account "' . $entry->name . '" with balance ' . $entry->openingbalance);
}
} }
} }
protected function _importComponents()
{
$beneficiaryAT = \AccountType::where('description', 'Beneficiary account')->first();
$budgetType = \ComponentType::where('type', 'budget')->first();
$categoryType = \ComponentType::where('type', 'category')->first();
foreach ($this->JSON->components as $entry) {
switch ($entry->type->type) {
case 'beneficiary':
$beneficiary = $this->_importBeneficiary($entry, $beneficiaryAT);
$this->map['accounts'][$entry->id] = $beneficiary->id;
break;
case 'category':
$component = $this->_importComponent($entry, $categoryType);
$this->map['components'][$entry->id] = $component->id;
break;
case 'budget':
$component = $this->_importComponent($entry, $budgetType);
$this->map['components'][$entry->id] = $component->id;
break;
}
}
}
protected function _importPiggybanks() {
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
// get type for piggy:
$piggyAT = \AccountType::where('description', 'Piggy bank')->first();
foreach($this->JSON->piggybanks as $piggyBank) {
}
}
protected function _importBeneficiary($component, \AccountType $beneficiaryAT)
{
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
return $accounts->store(
[
'name' => $component->name,
'account_type' => $beneficiaryAT
]
);
}
protected function _importComponent($component, \ComponentType $type)
{
/** @var \Firefly\Storage\Component\ComponentRepositoryInterface $components */
$components = \App::make('Firefly\Storage\Component\ComponentRepositoryInterface');
return $components->store(['name' => $component->name, 'component_type' => $type]);
}
} }

View File

@@ -3,6 +3,8 @@
namespace Firefly\Storage\Account; namespace Firefly\Storage\Account;
use Firefly\Helper\MigrationException;
class EloquentAccountRepository implements AccountRepositoryInterface class EloquentAccountRepository implements AccountRepositoryInterface
{ {
public $validator; public $validator;
@@ -28,11 +30,17 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$initial->user()->associate(\Auth::user()); $initial->user()->associate(\Auth::user());
$initial->name = $data['name'] . ' initial balance'; $initial->name = $data['name'] . ' initial balance';
$initial->active = 0; $initial->active = 0;
$initial->save(); try {
$initial->save();
} catch (\Illuminate\Database\QueryException $e) {
\Log::error('DB ERROR: ' . $e->getMessage());
throw new FireflyException('Could not save counterbalance account for ' . $data['name']);
}
// create new transaction journal (and transactions): // create new transaction journal (and transactions):
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalInterface $transactionJournal */ /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $transactionJournal */
$transactionJournal = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalInterface'); $transactionJournal = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
$transactionJournal->createSimpleJournal( $transactionJournal->createSimpleJournal(
$initial, $account, 'Initial Balance for ' . $data['name'], $amount, $date $initial, $account, 'Initial Balance for ' . $data['name'], $amount, $date
); );
@@ -54,7 +62,13 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$account->user()->associate(\Auth::user()); $account->user()->associate(\Auth::user());
$account->name = $data['name']; $account->name = $data['name'];
$account->active = isset($data['active']) ? $data['active'] : 1; $account->active = isset($data['active']) ? $data['active'] : 1;
$account->save(); try {
$account->save();
} catch (\Illuminate\Database\QueryException $e) {
\Log::error('DB ERROR: ' . $e->getMessage());
throw new \Firefly\Exception\FireflyException('Could not save account ' . $data['name']);
}
return $account; return $account;
} }

View File

@@ -0,0 +1,14 @@
<?php
namespace Firefly\Storage\Component;
interface ComponentRepositoryInterface
{
public function count();
public function store($data);
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Firefly\Storage\Component;
class EloquentComponentRepository implements ComponentRepositoryInterface
{
public $validator;
public function __construct()
{
}
public function count()
{
return \Auth::user()->accounts()->count();
}
public function store($data)
{
if (!isset($data['component_type'])) {
throw new \Firefly\Exception\FireflyException('No component type present.');
}
$component = new \Component;
$component->componentType()->associate($data['component_type']);
$component->name = $data['name'];
$component->user()->associate(\Auth::user());
try {
$component->save();
} catch (\Illuminate\Database\QueryException $e) {
\Log::error('DB ERROR: ' . $e->getMessage());
throw new \Firefly\Exception\FireflyException('Could not save component ' . $data['name']);
}
return $component;
}
}

View File

@@ -21,9 +21,13 @@ class StorageServiceProvider extends ServiceProvider
'Firefly\Storage\Account\EloquentAccountRepository' 'Firefly\Storage\Account\EloquentAccountRepository'
); );
$this->app->bind( $this->app->bind(
'Firefly\Storage\TransactionJournal\TransactionJournalInterface', 'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface',
'Firefly\Storage\TransactionJournal\EloquentTransactionJournalRepository' 'Firefly\Storage\TransactionJournal\EloquentTransactionJournalRepository'
); );
$this->app->bind(
'Firefly\Storage\Component\ComponentRepositoryInterface',
'Firefly\Storage\Component\EloquentComponentRepository'
);
} }
} }

View File

@@ -9,7 +9,7 @@
namespace Firefly\Storage\TransactionJournal; namespace Firefly\Storage\TransactionJournal;
class EloquentTransactionJournalRepository implements TransactionJournalInterface class EloquentTransactionJournalRepository implements TransactionJournalRepositoryInterface
{ {
public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date) public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date)
@@ -45,6 +45,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalInterfac
$toAT = $to->accountType->description; $toAT = $to->accountType->description;
$fromAT = $from->accountType->description; $fromAT = $from->accountType->description;
$journalType = null;
switch (true) { switch (true) {
// is withdrawal from one of your own accounts: // is withdrawal from one of your own accounts:
@@ -66,8 +67,17 @@ class EloquentTransactionJournalRepository implements TransactionJournalInterfac
$journalType = \TransactionType::where('type', 'Deposit')->first(); $journalType = \TransactionType::where('type', 'Deposit')->first();
break; break;
} }
if (is_null($journalType)) {
\Log::error('Could not figure out transacion type!');
throw new \Firefly\Exception\FireflyException('Could not figure out transaction type.');
}
// always the same currency: // always the same currency:
$currency = \TransactionCurrency::where('code', 'EUR')->first(); $currency = \TransactionCurrency::where('code', 'EUR')->first();
if (is_null($currency)) {
\Log::error('No currency for journal!');
throw new \Firefly\Exception\FireflyException('No currency for journal!');
}
// new journal: // new journal:
$journal = new \TransactionJournal(); $journal = new \TransactionJournal();
@@ -77,7 +87,9 @@ class EloquentTransactionJournalRepository implements TransactionJournalInterfac
$journal->description = $description; $journal->description = $description;
$journal->date = $date; $journal->date = $date;
if (!$journal->isValid()) { if (!$journal->isValid()) {
return false; \Log::error('Cannot create valid journal.');
\Log::error('Errors: ' . print_r($journal->validator->messages()->all(), true));
throw new \Firefly\Exception\FireflyException('Cannot create valid journal.');
} }
$journal->save(); $journal->save();
@@ -88,7 +100,9 @@ class EloquentTransactionJournalRepository implements TransactionJournalInterfac
$fromTransaction->description = null; $fromTransaction->description = null;
$fromTransaction->amount = $amountFrom; $fromTransaction->amount = $amountFrom;
if (!$fromTransaction->isValid()) { if (!$fromTransaction->isValid()) {
return false; \Log::error('Cannot create valid transaction (from) for journal #' . $journal->id);
\Log::error('Errors: ' . print_r($fromTransaction->validator->messages()->all(), true));
throw new \Firefly\Exception\FireflyException('Cannot create valid transaction (from).');
} }
$fromTransaction->save(); $fromTransaction->save();
@@ -98,7 +112,11 @@ class EloquentTransactionJournalRepository implements TransactionJournalInterfac
$toTransaction->description = null; $toTransaction->description = null;
$toTransaction->amount = $amountTo; $toTransaction->amount = $amountTo;
if (!$toTransaction->isValid()) { if (!$toTransaction->isValid()) {
return false; if (!$toTransaction->isValid()) {
\Log::error('Cannot create valid transaction (to) for journal #' . $journal->id);
\Log::error('Errors: ' . print_r($toTransaction->validator->messages()->all(), true));
throw new \Firefly\Exception\FireflyException('Cannot create valid transaction (to).');
}
} }
$toTransaction->save(); $toTransaction->save();
@@ -107,7 +125,6 @@ class EloquentTransactionJournalRepository implements TransactionJournalInterfac
return; return;
echo 'saved!'; echo 'saved!';
} }

View File

@@ -9,7 +9,7 @@
namespace Firefly\Storage\TransactionJournal; namespace Firefly\Storage\TransactionJournal;
interface TransactionJournalInterface { interface TransactionJournalRepositoryInterface {
public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date); public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date);

View File

@@ -14,12 +14,12 @@ class EloquentUserRepository implements UserRepositoryInterface
$user = new \User; $user = new \User;
$user->email = isset($array['email']) ? $array['email'] : null; $user->email = isset($array['email']) ? $array['email'] : null;
$user->migrated = 0; $user->migrated = 0;
$user->verification = \Str::random(32); $user->reset = \Str::random(32);
$user->password = \Hash::make(\Str::random(12)); $user->password = \Hash::make(\Str::random(12));
if (!$user->isValid()) { if (!$user->isValid()) {
\Log::error('Invalid user'); \Log::error('Invalid user');
\Session::flash('error', 'Input invalid, please try again.'); \Session::flash('error', 'Input invalid, please try again: ' . $user->validator->messages()->first());
return false; return false;
} }
$user->save(); $user->save();
@@ -36,11 +36,6 @@ class EloquentUserRepository implements UserRepositoryInterface
return false; return false;
} }
public function findByVerification($verification)
{
return \User::where('verification', $verification)->first();
}
public function findByReset($reset) public function findByReset($reset)
{ {
return \User::where('reset', $reset)->first(); return \User::where('reset', $reset)->first();

View File

@@ -10,12 +10,11 @@ interface UserRepositoryInterface
public function auth($array); public function auth($array);
public function findByVerification($verification);
public function findByReset($reset); public function findByReset($reset);
public function findByEmail($email); public function findByEmail($email);
public function updatePassword(\User $user,$password); public function updatePassword(\User $user, $password);
} }

View File

@@ -1,8 +1,16 @@
<?php <?php
class Component extends Eloquent class Component extends Elegant
{ {
public static $rules
= [
'user_id' => 'exists:users,id|required',
'name' => 'required|between:1,255',
'component_type_id' => 'required|exists:component_types,id'
];
public function componentType() public function componentType()
{ {
return $this->belongsTo('ComponentType'); return $this->belongsTo('ComponentType');

View File

@@ -10,6 +10,7 @@ class TransactionJournal extends Elegant
'transaction_currency_id' => 'required|exists:transaction_currencies,id', 'transaction_currency_id' => 'required|exists:transaction_currencies,id',
'description' => 'between:1,255', 'description' => 'between:1,255',
'date' => 'date', 'date' => 'date',
'completed' => 'required|between:0,1'
]; ];
public function transactionType() public function transactionType()

View File

@@ -1,9 +1,9 @@
<?php <?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface; use Illuminate\Auth\Reminders\RemindableInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\UserTrait;
class User extends Elegant implements UserInterface, RemindableInterface class User extends Elegant implements UserInterface, RemindableInterface
{ {
@@ -11,21 +11,19 @@ class User extends Elegant implements UserInterface, RemindableInterface
use UserTrait, RemindableTrait; use UserTrait, RemindableTrait;
public static $rules
= [
'email' => 'required|email|unique:users,email',
'migrated' => 'required|numeric|between:0,1',
'password' => 'required|between:60,60',
'reset' => 'between:32,32',
];
/** /**
* The database table used by the model. * The database table used by the model.
* *
* @var string * @var string
*/ */
protected $table = 'users'; protected $table = 'users';
public static $rules
= [
'email' => 'required|email|unique:users,email',
'migrated' => 'required|numeric|between:0,1',
'password' => 'required|between:60,60',
'verification' => 'between:32,32',
];
/** /**
* The attributes excluded from the model's JSON form. * The attributes excluded from the model's JSON form.
* *
@@ -33,7 +31,8 @@ class User extends Elegant implements UserInterface, RemindableInterface
*/ */
protected $hidden = array('remember_token'); protected $hidden = array('remember_token');
public function accounts() { public function accounts()
{
return $this->hasMany('Account'); return $this->hasMany('Account');
} }

View File

@@ -30,7 +30,7 @@ Route::group(['before' => 'csrf|auth'], function () {
); );
// guest routes: // guest routes:
Route::group(['before' => 'csrf|auth'], function () { Route::group(['before' => 'guest'], function () {
// user controller // user controller
Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']); Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']);
Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register']); Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register']);

View File

@@ -9,7 +9,7 @@
Hi! Hi!
</p> </p>
<p> <p>
To verify your registration, please <a href="{{route('verify',$verification)}}">verify your e-mail address</a>. To verify your registration, please <a href="{{route('reset',$reset)}}">verify your e-mail address</a>.
</p> </p>
<p> <p>
Cya! Cya!

View File

@@ -2,6 +2,6 @@ Hi!
To verify your registration, please verify your e-mail address: To verify your registration, please verify your e-mail address:
{{route('verify',$verification)}} {{route('reset',$reset)}}
Cya! Cya!