Implemented setup page

This commit is contained in:
Hillel Coren 2014-11-28 15:34:01 +02:00
parent a739429005
commit 2295a64bff
13 changed files with 520 additions and 264 deletions

View File

@ -47,17 +47,10 @@ Note: you may be prompted for your Github user/pass due to their API limits.
composer install composer install
Install JavaScript and HTML packages using Bower Install JavaScript and HTML packages using Bower. This is optional, it's only needed if you want to modify the JavaScript.
bower install bower install
Create the development environment configurations
mkdir app/config/development
cp app/config/app.php app/config/development/
cp app/config/database.php app/config/development/
cp app/config/mail.php app/config/development/
Create database user and a database for ninja Create database user and a database for ninja
CREATE SCHEMA `ninja` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE SCHEMA `ninja` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
@ -65,11 +58,7 @@ Create database user and a database for ninja
GRANT ALL PRIVILEGES ON `ninja`.* TO 'ninja'@'localhost'; GRANT ALL PRIVILEGES ON `ninja`.* TO 'ninja'@'localhost';
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
Configure development/config/database.php and development/config/mail.php and initialize the database. Add public/ to your web server root then load / to configure the application.
php artisan migrate --seed
Add public/ to your web server root
### Deleveloper Notes ### Deleveloper Notes

View File

@ -13,7 +13,7 @@ return array(
| |
*/ */
'debug' => true, 'debug' => false,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -28,7 +28,7 @@ return array(
| |
*/ */
'host' => '', //'host' => '',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -19,52 +19,6 @@ class AccountController extends \BaseController {
$this->contactMailer = $contactMailer; $this->contactMailer = $contactMailer;
} }
public function install()
{
if (!Utils::isNinja() && !Schema::hasTable('accounts')) {
try {
Artisan::call('migrate');
Artisan::call('db:seed');
} catch (Exception $e) {
Response::make($e->getMessage(), 500);
}
}
return Redirect::to('/');
}
public function update()
{
if (!Utils::isNinja()) {
try {
Artisan::call('migrate');
Cache::flush();
} catch (Exception $e) {
Response::make($e->getMessage(), 500);
}
}
return Redirect::to('/');
}
/*
public function reset()
{
if (Utils::isNinjaDev()) {
Confide::logout();
try {
Artisan::call('migrate:reset');
Artisan::call('migrate');
Artisan::call('db:seed');
} catch (Exception $e) {
Response::make($e->getMessage(), 500);
}
}
return Redirect::to('/');
}
*/
public function demo() public function demo()
{ {
$demoAccountId = Utils::getDemoAccountId(); $demoAccountId = Utils::getDemoAccountId();
@ -114,7 +68,7 @@ class AccountController extends \BaseController {
} }
Auth::login($user, true); Auth::login($user, true);
Event::fire('user.login'); Event::fire('user.login');
return Redirect::to('invoices/create'); return Redirect::to('invoices/create');
} }
@ -918,32 +872,7 @@ class AccountController extends \BaseController {
$user->registered = true; $user->registered = true;
$user->amend(); $user->amend();
if (Utils::isNinja()) $this->userMailer->sendConfirmation($user);
{
$this->userMailer->sendConfirmation($user);
}
else
{
/*
$url = NINJA_APP_URL . '/signup/register';
$data = '';
$fields = [
'first_name' => urlencode($user->first_name),
'last_name' => urlencode($user->last_name),
'email' => urlencode($user->email)
];
foreach($fields as $key=>$value) { $data .= $key.'='.$value.'&'; }
rtrim($data, '&');
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
curl_exec($ch);
curl_close($ch);
*/
}
$activities = Activity::scope()->get(); $activities = Activity::scope()->get();
foreach ($activities as $activity) foreach ($activities as $activity)

View File

@ -0,0 +1,202 @@
<?php
use ninja\mailers\Mailer;
use ninja\repositories\AccountRepository;
class AppController extends BaseController {
protected $accountRepo;
protected $mailer;
public function __construct(AccountRepository $accountRepo, Mailer $mailer)
{
parent::__construct();
$this->accountRepo = $accountRepo;
$this->mailer = $mailer;
}
public function showSetup()
{
if (Utils::isNinja() || Utils::isDatabaseSetup())
{
return Redirect::to('/');
}
return View::make('setup');
}
public function doSetup()
{
if (Utils::isNinja() || Utils::isDatabaseSetup())
{
return Redirect::to('/');
}
$valid = false;
$test = Input::get('test');
$app = Input::get('app');
$app['key'] = str_random(RANDOM_KEY_LENGTH);
$database = Input::get('database');
$dbType = $database['default'];
$database[$dbType] = $database['type'];
unset($database['type']);
$mail = Input::get('mail');
$email = $mail['username'];
$mail['from']['address'] = $email;
if ($test == 'mail')
{
return self::testMail($mail);
}
$valid = self::testDatabase($database);
if ($test == 'db')
{
return $valid ? 'Success' : 'Failed';
}
else if (!$valid)
{
return Redirect::to('/setup')->withInput();
}
$configDir = app_path() . '/config/production';
if (!file_exists($configDir))
{
mkdir($configDir);
}
foreach(['app' => $app, 'database' => $database, 'mail' => $mail] as $key => $config)
{
$content = '<?php return ' . var_export($config, true) . ';';
$fp = fopen(app_path() . "/config/production/{$key}.php" , 'w');
fwrite($fp, $content);
fclose($fp);
}
Artisan::call('migrate');
Artisan::call('db:seed');
$account = $this->accountRepo->create();
$user = $account->users()->first();
$user->first_name = trim(Input::get('first_name'));
$user->last_name = trim(Input::get('last_name'));
$user->email = trim(strtolower(Input::get('email')));
$user->username = $user->email;
$user->password = trim(Input::get('password'));
$user->password_confirmation = trim(Input::get('password'));
$user->registered = true;
$user->amend();
//Auth::login($user, true);
//self::register($user);
return Redirect::to('/invoices/create');
}
private function testDatabase($database)
{
$dbType = $database['default'];
Config::set('database.default', $dbType);
foreach ($database[$dbType] as $key => $val)
{
Config::set("database.connections.{$dbType}.{$key}", $val);
}
try
{
$valid = DB::connection()->getDatabaseName() ? true : false;
}
catch (Exception $e)
{
return $e->getMessage();
}
return $valid;
}
private function testMail($mail)
{
$email = $mail['username'];
$fromName = $mail['from']['name'];
foreach ($mail as $key => $val)
{
Config::set("mail.{$key}", $val);
}
Config::set('mail.from.address', $email);
Config::set('mail.from.name', $fromName);
$data = [
'text' => 'Test email'
];
try
{
$this->mailer->sendTo($email, $email, $fromName, 'Test email', 'contact', $data);
return 'Sent';
}
catch (Exception $e)
{
return $e->getMessage();
}
}
private function register($user)
{
$url = NINJA_APP_URL . '/signup/register';
$data = '';
$fields = [
'first_name' => urlencode($user->first_name),
'last_name' => urlencode($user->last_name),
'email' => urlencode($user->email)
];
foreach($fields as $key=>$value) { $data .= $key.'='.$value.'&'; }
rtrim($data, '&');
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
curl_exec($ch);
curl_close($ch);
}
public function install()
{
if (!Utils::isNinja() && !Utils::isDatabaseSetup()) {
try {
Artisan::call('migrate');
Artisan::call('db:seed');
} catch (Exception $e) {
Response::make($e->getMessage(), 500);
}
}
return Redirect::to('/');
}
public function update()
{
if (!Utils::isNinja()) {
try {
Artisan::call('migrate');
Cache::flush();
} catch (Exception $e) {
Response::make($e->getMessage(), 500);
}
}
return Redirect::to('/');
}
}

View File

@ -4,7 +4,6 @@ use ninja\mailers\Mailer;
class HomeController extends BaseController { class HomeController extends BaseController {
protected $layout = 'master';
protected $mailer; protected $mailer;
public function __construct(Mailer $mailer) public function __construct(Mailer $mailer)
@ -22,7 +21,11 @@ class HomeController extends BaseController {
} }
else else
{ {
if (Account::count() == 0) if (!Utils::isDatabaseSetup())
{
return Redirect::to('/setup');
}
else if (Account::count() == 0)
{ {
return Redirect::to('/invoice_now'); return Redirect::to('/invoice_now');
} }

View File

@ -13,6 +13,7 @@
App::before(function($request) App::before(function($request)
{ {
// Ensure all request are over HTTPS in production
if (App::environment() == ENV_PRODUCTION) if (App::environment() == ENV_PRODUCTION)
{ {
if (!Request::secure()) if (!Request::secure())
@ -21,12 +22,18 @@ App::before(function($request)
} }
} }
// If the database doens't yet exist we'll skip the rest
if (!Utils::isNinja() && !Utils::isDatabaseSetup())
{
return;
}
// check the application is up to date and for any news feed messages
if (Auth::check()) if (Auth::check())
{ {
$count = Session::get(SESSION_COUNTER, 0); $count = Session::get(SESSION_COUNTER, 0);
Session::put(SESSION_COUNTER, ++$count); Session::put(SESSION_COUNTER, ++$count);
// check the application is up to date and for any news feed messages
if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) { if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) {
$data = false; $data = false;
if (Utils::isNinja()) { if (Utils::isNinja()) {
@ -56,6 +63,7 @@ App::before(function($request)
} }
} }
// Check if we're requesting to change the account's language
if (Input::has('lang')) if (Input::has('lang'))
{ {
$locale = Input::get('lang'); $locale = Input::get('lang');
@ -78,6 +86,13 @@ App::before(function($request)
App::setLocale($locale); App::setLocale($locale);
} }
// Make sure the account/user localization settings are in the session
if (Auth::check() && !Session::has(SESSION_TIMEZONE))
{
Event::fire('user.refresh');
}
// Check if the user is claiming a license (ie, additional invoices, white label, etc.)
$claimingLicense = Utils::startsWith($_SERVER['REQUEST_URI'], '/claim_license'); $claimingLicense = Utils::startsWith($_SERVER['REQUEST_URI'], '/claim_license');
if (!$claimingLicense && Input::has('license_key') && Input::has('product_id')) if (!$claimingLicense && Input::has('license_key') && Input::has('product_id'))
{ {

View File

@ -12,6 +12,21 @@ class Utils
return Auth::check() && Auth::user()->confirmed; return Auth::check() && Auth::user()->confirmed;
} }
public static function isDatabaseSetup()
{
try
{
if (Schema::hasTable('accounts'))
{
return true;
}
}
catch (Exception $e)
{
return false;
}
}
public static function isProd() public static function isProd()
{ {
return App::environment() == ENV_PRODUCTION; return App::environment() == ENV_PRODUCTION;

View File

@ -17,7 +17,7 @@ class Mailer {
$replyEmail = $fromEmail; $replyEmail = $fromEmail;
// http://stackoverflow.com/questions/2421234/gmail-appearing-to-ignore-reply-to // http://stackoverflow.com/questions/2421234/gmail-appearing-to-ignore-reply-to
if ($toEmail != CONTACT_EMAIL) if (Utils::isNinja() && $toEmail != CONTACT_EMAIL)
{ {
$fromEmail = NINJA_FROM_EMAIL; $fromEmail = NINJA_FROM_EMAIL;
} }

View File

@ -1,13 +1,5 @@
<?php <?php
/*
$content = "some text here";
$fp = fopen("../myText.txt","wb");
fwrite($fp,$content);
fclose($fp);
*/
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Routes | Application Routes
@ -19,9 +11,8 @@ fclose($fp);
| |
*/ */
//apc_clear_cache();
//Cache::flush(); //Cache::flush();
//apc_clear_cache();
//dd(DB::getQueryLog()); //dd(DB::getQueryLog());
//dd(Client::getPrivateId(1)); //dd(Client::getPrivateId(1));
//dd(new DateTime()); //dd(new DateTime());
@ -30,10 +21,13 @@ fclose($fp);
//dd(gethostname()); //dd(gethostname());
//Log::error('test'); //Log::error('test');
Route::get('install', 'AccountController@install'); // Application setup
Route::get('update', 'AccountController@update'); Route::get('setup', 'AppController@showSetup');
Route::get('reset', 'AccountController@reset'); Route::post('setup', 'AppController@doSetup');
Route::get('install', 'AppController@install');
Route::get('update', 'AppController@update');
// Public pages
Route::get('/', 'HomeController@showIndex'); Route::get('/', 'HomeController@showIndex');
Route::get('/rocksteady', 'HomeController@showIndex'); Route::get('/rocksteady', 'HomeController@showIndex');
Route::get('/about', 'HomeController@showAboutUs'); Route::get('/about', 'HomeController@showAboutUs');
@ -399,14 +393,9 @@ function otrans($text)
} }
} }
if (Auth::check() && !Session::has(SESSION_TIMEZONE))
{
Event::fire('user.refresh');
}
Validator::extend('positive', function($attribute, $value, $parameters) Validator::extend('positive', function($attribute, $value, $parameters)
{ {
return Utils::parseFloat($value) > 0; return Utils::parseFloat($value) > 0;
}); });
Validator::extend('has_credit', function($attribute, $value, $parameters) Validator::extend('has_credit', function($attribute, $value, $parameters)

View File

@ -20,7 +20,7 @@
<link href='//fonts.googleapis.com/css?family=Roboto:400,700,900,100' rel='stylesheet' type='text/css'> <link href='//fonts.googleapis.com/css?family=Roboto:400,700,900,100' rel='stylesheet' type='text/css'>
<link href='//fonts.googleapis.com/css?family=Roboto+Slab:400,300,700' rel='stylesheet' type='text/css'> <link href='//fonts.googleapis.com/css?family=Roboto+Slab:400,300,700' rel='stylesheet' type='text/css'>
<link href="{{ asset('favicon.ico') }}" rel="icon" type="image/x-icon"> <link href="{{ asset('favicon.ico') }}" rel="icon" type="image/x-icon">
<link rel="canonical" href="{{ NINJA_APP_URL }}/{{ Request::path() }}"></link> <link rel="canonical" href="{{ NINJA_APP_URL }}/{{ Request::path() }}"></link>
<script src="{{ asset('built.js') }}?no_cache={{ NINJA_VERSION }}" type="text/javascript"></script> <script src="{{ asset('built.js') }}?no_cache={{ NINJA_VERSION }}" type="text/javascript"></script>

View File

@ -18,7 +18,7 @@
</div> </div>
</div> </div>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-md-3 center-block"> <div class="col-md-3 center-block">
@ -31,7 +31,7 @@
</div> </div>
</div> </div>
</section> </section>
<section class="features-splash"> <section class="features-splash">
@ -73,166 +73,166 @@
</div> </div>
</section> </section>
<section class="features-splash customContainer"> <section class="features-splash customContainer">
<div class="container"> <div class="container">
<div class="row col-md-12"> <div class="row col-md-12">
<div class="col-md-5 col-md-offset-4 customFontHead"> <div class="col-md-5 col-md-offset-4 customFontHead">
<div class="col-md-12"> <div class="col-md-12">
<span class="glyphicon glyphicon-ok"></span> <span class="glyphicon glyphicon-ok"></span>
</div> </div>
<div class="col-md-12 customTextBorder"> <div class="col-md-12 customTextBorder">
Invoice Ninja Does Everything You'd Expect Your Online Invoicing App to Do Invoice Ninja Does Everything You'd Expect Your Online Invoicing App to Do
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 customMenuOne"> <div class="col-md-2 customMenuOne">
<div class="customMenuDiv"> <div class="customMenuDiv">
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/InvoiceClientsViaEmail.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/InvoiceClientsViaEmail.png') }}"></span>
<span class="customSubMenu shiftLeft"> Invoice clients via email </span> <span class="customSubMenu shiftLeft"> Invoice clients via email </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/InTuitiveEditingInterface.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/InTuitiveEditingInterface.png') }}"></span>
<span class="customSubMenu shiftLeft"> Intuitive editing interface</span> <span class="customSubMenu shiftLeft"> Intuitive editing interface</span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/PrintablePDFInvoices.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/PrintablePDFInvoices.png') }}"></span>
<span class="customSubMenu shiftLeft"> Printable .pdf invoices</span> <span class="customSubMenu shiftLeft"> Printable .pdf invoices</span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/MultipleTaxSettings.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/MultipleTaxSettings.png') }}"></span>
<span class="customSubMenu shiftLeft"> Multiple tax settings</span> <span class="customSubMenu shiftLeft"> Multiple tax settings</span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/ImportExportRecords.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/ImportExportRecords.png') }}"></span>
<span class="customSubMenu shiftLeft"> Import/export records </span> <span class="customSubMenu shiftLeft"> Import/export records </span>
</div> </div>
</div> </div>
<div class="col-md-2 customMenuOne"> <div class="col-md-2 customMenuOne">
<div class="customMenuDiv"> <div class="customMenuDiv">
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/AcceptPaymentsOnline.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/AcceptPaymentsOnline.png') }}"></span>
<span class="customSubMenu shiftLeft"> Accept payments online</span> <span class="customSubMenu shiftLeft"> Accept payments online</span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/BestInClassSecurity.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/BestInClassSecurity.png') }}"></span>
<span class="customSubMenu shiftLeft"> Best-in-class security </span> <span class="customSubMenu shiftLeft"> Best-in-class security </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/AdjustablePaymentTerms.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/AdjustablePaymentTerms.png') }}"></span>
<span class="customSubMenu shiftLeft"> Adjustable payment terms </span> <span class="customSubMenu shiftLeft"> Adjustable payment terms </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/MultipleCurrencySupport.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/MultipleCurrencySupport.png') }}"></span>
<span class="customSubMenu shiftLeft"> Multiple currency support </span> <span class="customSubMenu shiftLeft"> Multiple currency support </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/RecurringInvoiceProfiles.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/RecurringInvoiceProfiles.png') }}"></span>
<span class="customSubMenu shiftLeft"> Recurring invoice profiles </span> <span class="customSubMenu shiftLeft"> Recurring invoice profiles </span>
</div> </div>
</div> </div>
<div class="col-md-2 customMenuOne"> <div class="col-md-2 customMenuOne">
<div class="customMenuDiv"> <div class="customMenuDiv">
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/FreeInvoicing.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/FreeInvoicing.png') }}"></span>
<span class="customSubMenu shiftLeft"> Free invoicing platform </span> <span class="customSubMenu shiftLeft"> Free invoicing platform </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/EstimatesProForma.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/EstimatesProForma.png') }}"></span>
<span class="customSubMenu shiftLeft"> Estimates & pro-forma </span> <span class="customSubMenu shiftLeft"> Estimates & pro-forma </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/PaymentTracking.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/PaymentTracking.png') }}"></span>
<span class="customSubMenu shiftLeft"> Payment tracking </span> <span class="customSubMenu shiftLeft"> Payment tracking </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/MultilingualSupport.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/MultilingualSupport.png') }}"></span>
<span class="customSubMenu shiftLeft"> Multilingual support </span> <span class="customSubMenu shiftLeft"> Multilingual support </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/SelfHostedAvailable.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/SelfHostedAvailable.png') }}"></span>
<span class="customSubMenu shiftLeft"> Self-hosted available </span> <span class="customSubMenu shiftLeft"> Self-hosted available </span>
</div> </div>
</div> </div>
<div class="col-md-2 customMenuOne"> <div class="col-md-2 customMenuOne">
<div class="customMenuDiv"> <div class="customMenuDiv">
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/LivePDFCreation.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/LivePDFCreation.png') }}"></span>
<span class="customSubMenu shiftLeft"> Live .pdf creation </span> <span class="customSubMenu shiftLeft"> Live .pdf creation </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/CloneInvoices.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/CloneInvoices.png') }}"></span>
<span class="customSubMenu shiftLeft"> Clone invoices </span> <span class="customSubMenu shiftLeft"> Clone invoices </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/CloudBasedApp.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/CloudBasedApp.png') }}"></span>
<span class="customSubMenu shiftLeft"> Cloud-based app </span> <span class="customSubMenu shiftLeft"> Cloud-based app </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/OpenSource.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/OpenSource.png') }}"></span>
<span class="customSubMenu shiftLeft"> Open source </span> <span class="customSubMenu shiftLeft"> Open source </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/BeautifulTemplates.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/BeautifulTemplates.png') }}"></span>
<span class="customSubMenu shiftLeft"> Beautiful templates </span> <span class="customSubMenu shiftLeft"> Beautiful templates </span>
</div> </div>
</div> </div>
<div class="col-md-4 customMenuOne"> <div class="col-md-4 customMenuOne">
<div class="customMenuDiv"> <div class="customMenuDiv">
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/CustomizeInvoices.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/CustomizeInvoices.png') }}"></span>
<span class="customSubMenu shiftLeft"> Cutomize invoices with your company logo </span> <span class="customSubMenu shiftLeft"> Cutomize invoices with your company logo </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/PersonalizeInvoiceColor.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/PersonalizeInvoiceColor.png') }}"></span>
<span class="customSubMenu shiftLeft"> Personalize invoice color schemes </span> <span class="customSubMenu shiftLeft"> Personalize invoice color schemes </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/InvoiceClientsViaEmail.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/InvoiceClientsViaEmail.png') }}"></span>
<span class="customSubMenu shiftLeft"> Alerts when invoices are viewed or paid </span> <span class="customSubMenu shiftLeft"> Alerts when invoices are viewed or paid </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/IntegrateWithPaymentGateways.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/IntegrateWithPaymentGateways.png') }}"></span>
<span class="customSubMenu shiftLeft"> Integrate with top payment gateways </span> <span class="customSubMenu shiftLeft"> Integrate with top payment gateways </span>
</div> </div>
<div class="customMenuDiv" > <div class="customMenuDiv" >
<span class="img-wrap shiftLeft" ><img src="{{ asset('images/ManualAutomaticInvoiceNumbers.png') }}"></span> <span class="img-wrap shiftLeft" ><img src="{{ asset('images/ManualAutomaticInvoiceNumbers.png') }}"></span>
<span class="customSubMenu shiftLeft"> Manual or automatic invoice numbers </span> <span class="customSubMenu shiftLeft"> Manual or automatic invoice numbers </span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<section class="blue"> <section class="blue">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-md-5"> <div class="col-md-5">
<h1>{{ trans('public.home.footer') }}</h1> <h1>{{ trans('public.home.footer') }}</h1>
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<a href="#"> <a href="#">
<div class="cta"> <div class="cta">
<h2 onclick="return getStarted()">{{ trans('public.invoice_now') }} <span>+</span></h2> <h2 onclick="return getStarted()">{{ trans('public.invoice_now') }} <span>+</span></h2>
</div> </div>
</a> </a>
</div>
</div> </div>
<p>{{ trans('public.no_signup_needed') }}</p>
</div>
<div class="col-md-7">
<img src="{{ asset('images/devices.png') }}">
</div> </div>
<p>{{ trans('public.no_signup_needed') }}</p>
</div>
<div class="col-md-7">
<img src="{{ asset('images/devices.png') }}">
</div> </div>
</div> </div>
</div>
</section> </section>

114
app/views/setup.blade.php Normal file
View File

@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Invoice Ninja | Setup</title>
<meta charset="utf-8">
<meta name="csrf-token" content="<?= csrf_token() ?>">
<script src="{{ asset('built.js') }}?no_cache={{ NINJA_VERSION }}" type="text/javascript"></script>
<link href="{{ asset('built.public.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="container">
&nbsp;
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="jumbotron">
<h2>Invoice Ninja Setup</h2>
<p>
<pre>-- Commands to create a MySQL database and user
CREATE SCHEMA `ninja` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE USER 'ninja'@'localhost' IDENTIFIED BY 'ninja';
GRANT ALL PRIVILEGES ON `ninja`.* TO 'ninja'@'localhost';
FLUSH PRIVILEGES;</pre>
</p>
If you need help you can either post to our <a href="https://groups.google.com/forum/#!forum/invoiceninja" target="_blank">Google Group</a>
or email us at <a href="mailto:contact@invoiceninja.com" target="_blank">contact@invoiceninja.com</a>.
</div>
{{ Former::open() }}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Application Settings</h3>
</div>
<div class="panel-body">
{{ Former::text('app[url]')->label('URL')->value(Request::root()) }}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Database Connection</h3>
</div>
<div class="panel-body">
{{ Former::select('database[default]')->label('Driver')->options(['mysql' => 'MySQL', 'pgsql' => 'PostgreSQL', 'sqlite' => 'SQLite']) }}
{{ Former::text('database[type][host]')->label('Host')->value('localhost') }}
{{ Former::text('database[type][database]')->label('Database')->value('ninja') }}
{{ Former::text('database[type][username]')->label('Username')->value('ninja') }}
{{ Former::text('database[type][password]')->label('Password')->value('ninja') }}
{{ Former::actions( Button::normal('Test connection', ['onclick' => 'testDatabase()']), '&nbsp;&nbsp;<span id="dbTestResult"/>' ) }}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Email Settings</h3>
</div>
<div class="panel-body">
{{ Former::select('mail[driver]')->label('Driver')->options(['smtp' => 'SMTP', 'mail' => 'Mail', 'sendmail' => 'Sendmail']) }}
{{ Former::text('mail[host]')->label('Host')->value('localhost') }}
{{ Former::text('mail[port]')->label('Port')->value('587') }}
{{ Former::select('mail[encryption]')->label('Encryption')->options(['tls' => 'TLS', 'ssl' => 'SSL']) }}
{{ Former::text('mail[from][name]')->label('From Name') }}
{{ Former::text('mail[username]')->label('Email') }}
{{ Former::text('mail[password]')->label('Password') }}
{{ Former::actions( Button::normal('Send test email', ['onclick' => 'testMail()']), '&nbsp;&nbsp;<span id="mailTestResult"/>' ) }}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">User Details</h3>
</div>
<div class="panel-body">
{{ Former::text('first_name') }}
{{ Former::text('last_name') }}
{{ Former::text('email') }}
{{ Former::text('password') }}
</div>
</div>
{{ Former::actions( Button::submit_lg('Submit') ) }}
{{ Former::close() }}
</div>
<script type="text/javascript">
function testDatabase()
{
$('#dbTestResult').html('Working...').css('color', 'black');
var data = $("form").serialize() + "&test=db";
$.post( "/setup", data, function( data ) {
$('#dbTestResult').html(data).css('color', data == 'Success' ? 'green' : 'red');
});
}
function testMail()
{
$('#mailTestResult').html('Working...').css('color', 'black');
var data = $("form").serialize() + "&test=mail";
$.post( "/setup", data, function( data ) {
$('#mailTestResult').html(data).css('color', data == 'Sent' ? 'green' : 'red');
});
}
</script>
</body>
</html>