diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 8b459675b868..011a28aafc71 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -402,6 +402,8 @@ class AccountController extends BaseController return AccountController::export(); } elseif ($section === ACCOUNT_INVOICE_SETTINGS) { return AccountController::saveInvoiceSettings(); + } elseif ($section === ACCOUNT_EMAIL_SETTINGS) { + return AccountController::saveEmailSettings(); } elseif ($section === ACCOUNT_INVOICE_DESIGN) { return AccountController::saveInvoiceDesign(); } elseif ($section === ACCOUNT_CUSTOMIZE_DESIGN) { @@ -432,11 +434,6 @@ class AccountController extends BaseController { if (Auth::user()->account->isPro()) { $account = Auth::user()->account; - $account->email_design_id = Input::get('email_design_id'); - - if (Utils::isNinja()) { - $account->enable_email_markup = Input::get('enable_email_markup') ? true : false; - } foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) { $subjectField = "email_subject_{$type}"; @@ -492,15 +489,10 @@ class AccountController extends BaseController return Redirect::to('settings/' . ACCOUNT_PRODUCTS); } - private function saveInvoiceSettings() + private function saveEmailSettings() { if (Auth::user()->account->isPro()) { - - $rules = [ - 'invoice_number_pattern' => 'has_counter', - 'quote_number_pattern' => 'has_counter', - ]; - + $rules = []; $user = Auth::user(); $iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH)); $iframeURL = rtrim($iframeURL, "/"); @@ -516,13 +508,45 @@ class AccountController extends BaseController $validator = Validator::make(Input::all(), $rules); if ($validator->fails()) { - return Redirect::to('settings/' . ACCOUNT_INVOICE_SETTINGS) + return Redirect::to('settings/' . ACCOUNT_EMAIL_SETTINGS) ->withErrors($validator) ->withInput(); } else { $account = Auth::user()->account; $account->subdomain = $subdomain; $account->iframe_url = $iframeURL; + $account->pdf_email_attachment = Input::get('pdf_email_attachment') ? true : false; + $account->email_design_id = Input::get('email_design_id'); + + if (Utils::isNinja()) { + $account->enable_email_markup = Input::get('enable_email_markup') ? true : false; + } + + $account->save(); + Session::flash('message', trans('texts.updated_settings')); + } + } + + return Redirect::to('settings/' . ACCOUNT_EMAIL_SETTINGS); + } + + private function saveInvoiceSettings() + { + if (Auth::user()->account->isPro()) { + + $rules = [ + 'invoice_number_pattern' => 'has_counter', + 'quote_number_pattern' => 'has_counter', + ]; + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('settings/' . ACCOUNT_INVOICE_SETTINGS) + ->withErrors($validator) + ->withInput(); + } else { + $account = Auth::user()->account; $account->custom_label1 = trim(Input::get('custom_label1')); $account->custom_value1 = trim(Input::get('custom_value1')); $account->custom_label2 = trim(Input::get('custom_label2')); @@ -539,7 +563,6 @@ class AccountController extends BaseController $account->invoice_number_counter = Input::get('invoice_number_counter'); $account->quote_number_prefix = Input::get('quote_number_prefix'); $account->share_counter = Input::get('share_counter') ? true : false; - $account->pdf_email_attachment = Input::get('pdf_email_attachment') ? true : false; $account->invoice_terms = Input::get('invoice_terms'); $account->invoice_footer = Input::get('invoice_footer'); $account->quote_terms = Input::get('quote_terms'); diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 9f28cfad6181..eb400a5e3d9b 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -27,6 +27,9 @@ class ImportController extends BaseController foreach (ImportService::$entityTypes as $entityType) { if (Input::file("{$entityType}_file")) { $files[$entityType] = Input::file("{$entityType}_file")->getRealPath(); + if ($source === IMPORT_CSV) { + Session::forget("{$entityType}-data"); + } } } @@ -36,22 +39,13 @@ class ImportController extends BaseController return View::make('accounts.import_map', ['data' => $data]); } else { $skipped = $this->importService->import($source, $files); - if (count($skipped)) { - $message = trans('texts.failed_to_import'); - foreach ($skipped as $skip) { - $message .= '
' . json_encode($skip); - } - Session::flash('warning', $message); - } else { - Session::flash('message', trans('texts.imported_file')); - } + return $this->showResult($skipped); } } catch (Exception $exception) { Utils::logError($exception); Session::flash('error', $exception->getMessage()); + return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); } - - return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); } public function doImportCSV() @@ -62,19 +56,24 @@ class ImportController extends BaseController try { $skipped = $this->importService->importCSV($map, $headers); - - if (count($skipped)) { - $message = trans('texts.failed_to_import'); - foreach ($skipped as $skip) { - $message .= '
' . json_encode($skip); - } - Session::flash('warning', $message); - } else { - Session::flash('message', trans('texts.imported_file')); - } + return $this->showResult($skipped); } catch (Exception $exception) { Utils::logError($exception); Session::flash('error', $exception->getMessage()); + return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); + } + } + + private function showResult($skipped) + { + if (count($skipped)) { + $message = trans('texts.failed_to_import'); + foreach ($skipped as $skip) { + $message .= '
' . json_encode($skip); + } + Session::flash('warning', $message); + } else { + Session::flash('message', trans('texts.imported_file')); } return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); diff --git a/app/Http/routes.php b/app/Http/routes.php index f7533941f4c2..71989afbd866 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -26,13 +26,6 @@ Route::post('/setup', 'AppController@doSetup'); Route::get('/install', 'AppController@install'); Route::get('/update', 'AppController@update'); -/* -// Codeception code coverage -Route::get('/c3.php', function () { - include '../c3.php'; -}); -*/ - // Public pages Route::get('/', 'HomeController@showIndex'); Route::get('/terms', 'HomeController@showTerms'); @@ -285,6 +278,7 @@ if (!defined('CONTACT_EMAIL')) { define('ACCOUNT_ADVANCED_SETTINGS', 'advanced_settings'); define('ACCOUNT_INVOICE_SETTINGS', 'invoice_settings'); define('ACCOUNT_INVOICE_DESIGN', 'invoice_design'); + define('ACCOUNT_EMAIL_SETTINGS', 'email_settings'); define('ACCOUNT_CHARTS_AND_REPORTS', 'charts_and_reports'); define('ACCOUNT_USER_MANAGEMENT', 'user_management'); define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations'); diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index 3f4e54657809..231c29abad93 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -896,5 +896,4 @@ class Utils return $url; } - } diff --git a/app/Models/Account.php b/app/Models/Account.php index fcd58ea5e436..3150f96a39fd 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -35,6 +35,7 @@ class Account extends Eloquent public static $advancedSettings = [ ACCOUNT_INVOICE_SETTINGS, ACCOUNT_INVOICE_DESIGN, + ACCOUNT_EMAIL_SETTINGS, ACCOUNT_TEMPLATES_AND_REMINDERS, ACCOUNT_CHARTS_AND_REPORTS, ACCOUNT_DATA_VISUALIZATIONS, diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 1bf19bbfdbc3..7b6d46688aec 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -56,22 +56,26 @@ class ImportService public function import($source, $files) { + $skipped = []; $imported_files = null; foreach ($files as $entityType => $file) { - $this->execute($source, $entityType, $file); + $result = $this->execute($source, $entityType, $file); + $skipped = array_merge($skipped, $result); } + + return $skipped; } private function execute($source, $entityType, $file) { $skipped = []; - Excel::load($file, function ($reader) use ($source, $entityType, $skipped) { + Excel::load($file, function ($reader) use ($source, $entityType, &$skipped) { $this->checkData($entityType, count($reader->all())); $maps = $this->createMaps(); - $reader->each(function ($row) use ($source, $entityType, $maps) { + $reader->each(function ($row) use ($source, $entityType, $maps, &$skipped) { $result = $this->saveData($source, $entityType, $row, $maps); if ( ! $result) { diff --git a/c3.php b/c3.php deleted file mode 100755 index cadb3a399b95..000000000000 --- a/c3.php +++ /dev/null @@ -1,258 +0,0 @@ - $value) { - $_SERVER["HTTP_X_CODECEPTION_".strtoupper($key)] = $value; - } - } -} - -if (!array_key_exists('HTTP_X_CODECEPTION_CODECOVERAGE', $_SERVER)) { - return; -} - -if (!function_exists('__c3_error')) { - function __c3_error($message) - { - $errorLogFile = defined('C3_CODECOVERAGE_ERROR_LOG_FILE') ? - C3_CODECOVERAGE_ERROR_LOG_FILE : - C3_CODECOVERAGE_MEDIATE_STORAGE . DIRECTORY_SEPARATOR . 'error.txt'; - if (is_writable($errorLogFile)) { - file_put_contents($errorLogFile, $message); - }else{ - $message = "Could not write error to log file ($errorLogFile), original message: $message"; - } - if (!headers_sent()) { - header('X-Codeception-CodeCoverage-Error: ' . str_replace("\n", ' ', $message), true, 500); - } - setcookie('CODECEPTION_CODECOVERAGE_ERROR', $message); - } -} - -// Autoload Codeception classes -if (!class_exists('\\Codeception\\Codecept')) { - if (file_exists(__DIR__ . '/codecept.phar')) { - require_once 'phar://'.__DIR__ . '/codecept.phar/autoload.php'; - } elseif (stream_resolve_include_path(__DIR__ . '/vendor/autoload.php')) { - require_once __DIR__ . '/vendor/autoload.php'; - // Required to load some methods only available at codeception/autoload.php - if (stream_resolve_include_path(__DIR__ . '/vendor/codeception/codeception/autoload.php')) { - require_once __DIR__ . '/vendor/codeception/codeception/autoload.php'; - } - } elseif (stream_resolve_include_path('Codeception/autoload.php')) { - require_once 'Codeception/autoload.php'; - } else { - __c3_error('Codeception is not loaded. Please check that either PHAR or Composer or PEAR package can be used'); - } -} - -// Load Codeception Config -$config_dist_file = realpath(__DIR__) . DIRECTORY_SEPARATOR . 'codeception.dist.yml'; -$config_file = realpath(__DIR__) . DIRECTORY_SEPARATOR . 'codeception.yml'; - -if (isset($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG'])) { - $config_file = realpath(__DIR__) . DIRECTORY_SEPARATOR . $_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG']; -} -if (file_exists($config_file)) { - // Use codeception.yml for configuration. -} elseif (file_exists($config_dist_file)) { - // Use codeception.dist.yml for configuration. - $config_file = $config_dist_file; -} else { - __c3_error(sprintf("Codeception config file '%s' not found", $config_file)); -} -try { - \Codeception\Configuration::config($config_file); -} catch (\Exception $e) { - __c3_error($e->getMessage()); -} - -if (!defined('C3_CODECOVERAGE_MEDIATE_STORAGE')) { - - // workaround for 'zend_mm_heap corrupted' problem - gc_disable(); - - if ((integer)ini_get('memory_limit') < 384) { - ini_set('memory_limit', '384M'); - } - - define('C3_CODECOVERAGE_MEDIATE_STORAGE', Codeception\Configuration::logDir() . 'c3tmp'); - define('C3_CODECOVERAGE_PROJECT_ROOT', Codeception\Configuration::projectDir()); - define('C3_CODECOVERAGE_TESTNAME', $_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE']); - - function __c3_build_html_report(PHP_CodeCoverage $codeCoverage, $path) - { - $writer = new PHP_CodeCoverage_Report_HTML(); - $writer->process($codeCoverage, $path . 'html'); - - if (file_exists($path . '.tar')) { - unlink($path . '.tar'); - } - - $phar = new PharData($path . '.tar'); - $phar->setSignatureAlgorithm(Phar::SHA1); - $files = $phar->buildFromDirectory($path . 'html'); - array_map('unlink', $files); - - if (in_array('GZ', Phar::getSupportedCompression())) { - if (file_exists($path . '.tar.gz')) { - unlink($path . '.tar.gz'); - } - - $phar->compress(\Phar::GZ); - - // close the file so that we can rename it - unset($phar); - - unlink($path . '.tar'); - rename($path . '.tar.gz', $path . '.tar'); - } - - return $path . '.tar'; - } - - function __c3_build_clover_report(PHP_CodeCoverage $codeCoverage, $path) - { - $writer = new PHP_CodeCoverage_Report_Clover(); - $writer->process($codeCoverage, $path . '.clover.xml'); - - return $path . '.clover.xml'; - } - - function __c3_send_file($filename) - { - if (!headers_sent()) { - readfile($filename); - } - - return __c3_exit(); - } - - /** - * @param $filename - * @return null|PHP_CodeCoverage - */ - function __c3_factory($filename) - { - $phpCoverage = is_readable($filename) - ? unserialize(file_get_contents($filename)) - : new PHP_CodeCoverage(); - - - if (isset($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_SUITE'])) { - $suite = $_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_SUITE']; - try { - $settings = \Codeception\Configuration::suiteSettings($suite, \Codeception\Configuration::config()); - } catch (Exception $e) { - __c3_error($e->getMessage()); - } - } else { - $settings = \Codeception\Configuration::config(); - } - - try { - \Codeception\Coverage\Filter::setup($phpCoverage) - ->whiteList($settings) - ->blackList($settings); - } catch (Exception $e) { - __c3_error($e->getMessage()); - } - - return $phpCoverage; - } - - function __c3_exit() - { - if (!isset($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_DEBUG'])) { - exit; - } - return null; - } - - function __c3_clear() - { - \Codeception\Util\FileSystem::doEmptyDir(C3_CODECOVERAGE_MEDIATE_STORAGE); - } -} - -if (!is_dir(C3_CODECOVERAGE_MEDIATE_STORAGE)) { - if (mkdir(C3_CODECOVERAGE_MEDIATE_STORAGE, 0777, true) === false) { - __c3_error('Failed to create directory "' . C3_CODECOVERAGE_MEDIATE_STORAGE . '"'); - } -} - -// evaluate base path for c3-related files -$path = realpath(C3_CODECOVERAGE_MEDIATE_STORAGE) . DIRECTORY_SEPARATOR . 'codecoverage'; - -$requested_c3_report = (strpos($_SERVER['REQUEST_URI'], 'c3/report') !== false); - -$complete_report = $current_report = $path . '.serialized'; -if ($requested_c3_report) { - set_time_limit(0); - - $route = ltrim(strrchr($_SERVER['REQUEST_URI'], '/'), '/'); - - if ($route == 'clear') { - __c3_clear(); - return __c3_exit(); - } - - $codeCoverage = __c3_factory($complete_report); - - switch ($route) { - case 'html': - try { - __c3_send_file(__c3_build_html_report($codeCoverage, $path)); - } catch (Exception $e) { - __c3_error($e->getMessage()); - } - return __c3_exit(); - case 'clover': - try { - __c3_send_file(__c3_build_clover_report($codeCoverage, $path)); - } catch (Exception $e) { - __c3_error($e->getMessage()); - } - return __c3_exit(); - case 'serialized': - try { - __c3_send_file($complete_report); - } catch (Exception $e) { - __c3_error($e->getMessage()); - } - return __c3_exit(); - } - -} else { - $codeCoverage = __c3_factory($current_report); - $codeCoverage->start(C3_CODECOVERAGE_TESTNAME); - if (!array_key_exists('HTTP_X_CODECEPTION_CODECOVERAGE_DEBUG', $_SERVER)) { - register_shutdown_function( - function () use ($codeCoverage, $current_report) { - $codeCoverage->stop(); - file_put_contents($current_report, serialize($codeCoverage)); - } - ); - } -} - -// @codeCoverageIgnoreEnd diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 7ddad61bc6af..e581000b9f30 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -976,5 +976,5 @@ return array( 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', 'token_expired' => 'Validation token was expired. Please try again.', - + 'invoice_link' => 'Invoice Link', ); diff --git a/resources/views/accounts/email_settings.blade.php b/resources/views/accounts/email_settings.blade.php new file mode 100644 index 000000000000..2bc11b45bb15 --- /dev/null +++ b/resources/views/accounts/email_settings.blade.php @@ -0,0 +1,135 @@ +@extends('header') + +@section('content') + @parent + @include('accounts.nav', ['selected' => ACCOUNT_EMAIL_SETTINGS, 'advanced' => true]) + + {!! Former::open()->addClass('warn-on-exit') !!} + {{ Former::populate($account) }} + {{ Former::populateField('pdf_email_attachment', intval($account->pdf_email_attachment)) }} + {{ Former::populateField('enable_email_markup', intval($account->enable_email_markup)) }} + +
+
+

{!! trans('texts.email_settings') !!}

+
+
+ {!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!} +   + {{-- Former::select('recurring_hour')->options($recurringHours) --}} + + {!! Former::inline_radios('custom_invoice_link') + ->onchange('onCustomLinkChange()') + ->label(trans('texts.invoice_link')) + ->radios([ + trans('texts.subdomain') => ['value' => 'subdomain', 'name' => 'custom_link'], + trans('texts.website') => ['value' => 'website', 'name' => 'custom_link'], + ])->check($account->iframe_url ? 'website' : 'subdomain') !!} + {{ Former::setOption('capitalize_translations', false) }} + + {!! Former::text('subdomain') + ->placeholder(trans('texts.www')) + ->onchange('onSubdomainChange()') + ->addGroupClass('subdomain') + ->label(' ') + ->help(trans('texts.subdomain_help')) !!} + + {!! Former::text('iframe_url') + ->placeholder('http://www.example.com/invoice') + ->appendIcon('question-sign') + ->addGroupClass('iframe_url') + ->label(' ') + ->help(trans('texts.subdomain_help')) !!} +   + {!! Former::select('email_design_id') + ->style('width: 200px') + ->addOption(trans('texts.plain'), 1) + ->addOption(trans('texts.light'), 2) + ->addOption(trans('texts.dark'), 3) + ->help(trans('texts.email_design_help')) !!} +   + @if (Utils::isNinja()) + {!! Former::checkbox('enable_email_markup') + ->text(trans('texts.enable') . + '' . Icon::create('question-sign') . ' ') + ->help(trans('texts.enable_email_markup_help')) !!} + @endif +
+
+ + @if (Auth::user()->isPro()) +
+ {!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!} +
+ @endif + + + + {!! Former::close() !!} + + +@stop \ No newline at end of file diff --git a/resources/views/accounts/invoice_settings.blade.php b/resources/views/accounts/invoice_settings.blade.php index c0a6a02a1ad2..6ff35bd4feca 100644 --- a/resources/views/accounts/invoice_settings.blade.php +++ b/resources/views/accounts/invoice_settings.blade.php @@ -25,41 +25,6 @@ {{ Former::populateField('custom_invoice_taxes1', intval($account->custom_invoice_taxes1)) }} {{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }} {{ Former::populateField('share_counter', intval($account->share_counter)) }} - {{ Former::populateField('pdf_email_attachment', intval($account->pdf_email_attachment)) }} - - -
-
-

{!! trans('texts.email_settings') !!}

-
-
- {!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!} - - {{-- Former::select('recurring_hour')->options($recurringHours) --}} - - {!! Former::inline_radios('custom_invoice_link') - ->onchange('onCustomLinkChange()') - ->radios([ - trans('texts.subdomain') => ['value' => 'subdomain', 'name' => 'custom_link'], - trans('texts.website') => ['value' => 'website', 'name' => 'custom_link'], - ])->check($account->iframe_url ? 'website' : 'subdomain') !!} - {{ Former::setOption('capitalize_translations', false) }} - - {!! Former::text('subdomain') - ->placeholder(trans('texts.www')) - ->onchange('onSubdomainChange()') - ->addGroupClass('subdomain') - ->label(' ') - ->help(trans('texts.subdomain_help')) !!} - - {!! Former::text('iframe_url') - ->placeholder('http://www.example.com/invoice') - ->appendIcon('question-sign') - ->addGroupClass('iframe_url') - ->label(' ') - ->help(trans('texts.subdomain_help')) !!} -
-
@@ -252,36 +217,6 @@ @endif - - -