From a2f7357f012830bdcdc40cc86e34215dc51fbc08 Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Mon, 4 Dec 2017 15:56:48 +1100 Subject: [PATCH 1/7] Added a Docker containerisation --- Dockerfile | 15 +++++++++++++++ README.md | 18 ++++++++++++++++++ docker-compose.yaml | 7 +++++++ 3 files changed, 40 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..9cdcb50d5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM php:apache +COPY . /var/www/html/ + +# Authorize these folders to be edited +RUN chmod -R 777 /var/www/html/storage +RUN chmod -R 777 /var/www/html/bootstrap/cache + +# Install ZIP extension +RUN apt-get update && \ + apt-get install -y --no-install-recommends zip libzip-dev +RUN pecl install zip && \ + docker-php-ext-enable zip + +# Allow rewrite +RUN a2enmod rewrite diff --git a/README.md b/README.md index bcce76a05..c20733b23 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,24 @@ Akaunting uses [Laravel](http://laravel.com), the best existing PHP framework, a * Run the following commands separately: `composer install` , `composer dump-autoload` * Finally, launch the [installer](https://akaunting.com/docs/installation) +## Docker + +It is possible to containerise Akounting using the [`docker-compose`](./docker-compose.yaml) file. Here are a few commands: + +``` +# Make sure you the dependencies are installed +composer install && composer dump-autoload + +# Build the app +docker-compose build + +# Run the app +docker-compose up + +# Access the container +docker exec -it CONTAINER_ID /bin/sh +``` + ## Contributing Fork the repository, make the code changes then submit a pull request. diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..11af63974 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,7 @@ +version: '3' +services: + web: + image: akaunting + build: . + ports: + - "80:80" \ No newline at end of file From 183f83e1d2f0beffb8ab128bc6ded02701fdd03d Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Sat, 30 Dec 2017 03:49:21 +1100 Subject: [PATCH 2/7] Updated DockerFile to add PHP extensions and reflect changes made by @beinbm I didn't keep the mysql service in the docker-compose file as it's also used to build the container. I'd recommand creating another docker-compose to do this. Preparations are made to push the Docker image to DockerHub --- Dockerfile | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9cdcb50d5..e1d84c142 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,18 @@ FROM php:apache + COPY . /var/www/html/ # Authorize these folders to be edited RUN chmod -R 777 /var/www/html/storage RUN chmod -R 777 /var/www/html/bootstrap/cache -# Install ZIP extension -RUN apt-get update && \ - apt-get install -y --no-install-recommends zip libzip-dev -RUN pecl install zip && \ - docker-php-ext-enable zip +RUN apt-get update && apt-get install -y zip libzip-dev libpng-dev \ + && docker-php-ext-install pdo_mysql gd zip \ + && rm -rf /var/lib/apt/lists/* # Allow rewrite RUN a2enmod rewrite + +#CMD ["/bin/bash", "/opt/your_app/init.sh"] +# php -f ... +# php artisan make:command ConfigureApp --command=app:configure \ No newline at end of file From ec5070e45f5546f7168965cbf8d34c2bcc4c56f8 Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Sun, 31 Dec 2017 05:21:10 +1100 Subject: [PATCH 3/7] Added a CLI configurer and extracted configuration function from Install controllers --- app/Console/Commands/ConfigureApp.php | 238 ++++++++++++ app/Console/Kernel.php | 1 + app/Http/Controllers/Install/Database.php | 145 ++----- app/Http/Controllers/Install/Requirements.php | 206 +--------- app/Http/Controllers/Install/Settings.php | 80 +--- app/Utilities/AppConfigurer.php | 365 ++++++++++++++++++ 6 files changed, 656 insertions(+), 379 deletions(-) create mode 100644 app/Console/Commands/ConfigureApp.php create mode 100644 app/Utilities/AppConfigurer.php diff --git a/app/Console/Commands/ConfigureApp.php b/app/Console/Commands/ConfigureApp.php new file mode 100644 index 000000000..fcedb1819 --- /dev/null +++ b/app/Console/Commands/ConfigureApp.php @@ -0,0 +1,238 @@ +checkOptions(); + if ( ! empty( $missingOptions ) && $this->option( self::OPT_NO_INTERACTION ) ) { + $this->line( '❌ Some options are missing and --no-interaction is present. Please run the following command for more informations :' ); + $this->line( '❌ php artisan help app:configure' ); + $this->line( '❌ Missing options are : ' . join( ', ', $missingOptions ) ); + + return self::CMD_ERROR; + } + + $this->line( 'Setting locale ' . $this->locale ); + Session::put( self::OPT_LOCALE, $this->locale ); + + $this->prompt(); + + $this->line( 'Configuring database' ); + if ( ! $this->configureDatabase() ) { + return self::CMD_ERROR; + } + + $this->line( 'Configuring company' ); + AppConfigurer::createCompany( $this->companyName, $this->companyEmail, $this->locale ); + + $this->line( 'Creating Admin user' ); + AppConfigurer::createUser( $this->adminEmail, $this->adminPassword, $this->locale ); + + $this->line( 'Applying the final touches' ); + AppConfigurer::finalTouches(); + + return self::CMD_SUCCESS; + } + + /** + * Check that all options are presents. otherwise returns an array of the missing options + */ + private function checkOptions() { + $missingOptions = array(); + + $this->locale = $this->option( self::OPT_LOCALE ); + if ( empty( $this->locale ) ) { + $missingOptions[] = self::OPT_LOCALE; + } + + $this->dbHost = $this->option( self::OPT_DB_HOST ); + if ( empty( $this->dbHost ) ) { + $missingOptions[] = self::OPT_DB_HOST; + } + + $this->dbPort = $this->option( self::OPT_DB_PORT ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_DB_PORT; + } + + $this->dbName = $this->option( self::OPT_DB_NAME ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_DB_NAME; + } + + $this->dbUsername = $this->option( self::OPT_DB_USERNAME ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_DB_USERNAME; + } + + $this->dbPassword = $this->option( self::OPT_DB_PASSWORD ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_DB_PASSWORD; + } + + $this->companyName = $this->option( self::OPT_COMPANY_NAME ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_COMPANY_NAME; + } + + $this->companyEmail = $this->option( self::OPT_COMPANY_EMAIL ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_COMPANY_EMAIL; + } + + $this->adminEmail = $this->option( self::OPT_ADMIN_EMAIL ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_ADMIN_EMAIL; + } + + $this->adminPassword = $this->option( self::OPT_ADMIN_PASSWORD ); + if ( empty( $this->dbPort ) ) { + $missingOptions[] = self::OPT_ADMIN_PASSWORD; + } + + return $missingOptions; + } + + /** + * Ask the user for data if some options are missing. + */ + private function prompt() { + if ( empty( $this->dbHost ) ) { + $this->dbHost = $this->ask( 'What is the database host?', 'localhost' ); + } + + if ( empty( $this->dbPort ) ) { + $this->dbPort = $this->ask( 'What is the database port?', '3606' ); + } + + if ( empty( $this->dbName ) ) { + $this->dbName = $this->ask( 'What is the database name?' ); + } + + if ( empty( $this->dbUsername ) ) { + $this->dbUsername = $this->ask( 'What is the database username?' ); + } + + if ( empty( $this->dbPassword ) ) { + $this->dbPassword = $this->secret( 'What is the database password?' ); + } + + if ( empty( $this->companyName ) ) { + $this->companyName = $this->ask( 'What is the company name?' ); + } + + if ( empty( $this->companyEmail ) ) { + $this->companyEmail = $this->ask( 'What is the company contact email?' ); + } + + if ( empty( $this->adminEmail ) ) { + $this->adminEmail = $this->ask( 'What is the admin email?', $this->companyEmail ); + } + + if ( empty( $this->adminPassword ) ) { + $this->adminPassword = $this->secret( 'What is the admin password?' ); + } + } + + private function configureDatabase() { + $this->dbHost = $this->option( self::OPT_DB_HOST ); + $this->dbPort = $this->option( self::OPT_DB_PORT ); + $this->dbName = $this->option( self::OPT_DB_NAME ); + $this->dbUsername = $this->option( self::OPT_DB_USERNAME ); + $this->dbPassword = $this->option( self::OPT_DB_PASSWORD ); + + $this->line( 'Connecting to database ' . $this->dbName . '@' . $this->dbHost . ':' . $this->dbPort ); + $isDbValid = AppConfigurer::isDbValid( $this->dbHost, $this->dbPort, $this->dbName, $this->dbUsername, $this->dbPassword ); + if ( ! $isDbValid ) { + $this->error( 'Error: Could not connect to the database! Please, make sure the details are correct.' ); + + return false; + } + + AppConfigurer::saveDbVariables( $this->dbHost, $this->dbPort, $this->dbName, $this->dbUsername, $this->dbPassword ); + + // Try to increase the maximum execution time + set_time_limit( 300 ); // 5 minutes + + // Create tables + Artisan::call( 'migrate', [ '--force' => true ] ); + + // Create Roles + Artisan::call( 'db:seed', [ '--class' => 'Database\Seeds\Roles', '--force' => true ] ); + + return true; + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 116597687..3e78423d2 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel Commands\BillReminder::class, Commands\InvoiceReminder::class, Commands\ModuleInstall::class, + Commands\ConfigureApp::class, ]; /** diff --git a/app/Http/Controllers/Install/Database.php b/app/Http/Controllers/Install/Database.php index 1afc0a9b8..bcaf03b9e 100644 --- a/app/Http/Controllers/Install/Database.php +++ b/app/Http/Controllers/Install/Database.php @@ -3,123 +3,56 @@ namespace App\Http\Controllers\Install; use Artisan; -use Config; -use DB; -use DotenvEditor; use App\Http\Requests\Install\Database as Request; +use App\Utilities\AppConfigurer; use Illuminate\Routing\Controller; -class Database extends Controller -{ - /** - * Show the form for creating a new resource. - * - * @return Response - */ - public function create() - { - return view('install.database.create'); - } +class Database extends Controller { + /** + * Show the form for creating a new resource. + * + * @return Response + */ + public function create() { + return view( 'install.database.create' ); + } - /** - * Store a newly created resource in storage. - * - * @param Request $request - * - * @return Response - */ - public function store(Request $request) - { - // Check database connection - if (!$this->canConnect($request)) { - $message = trans('install.error.connection'); + /** + * Store a newly created resource in storage. + * + * @param Request $request + * + * @return Response + */ + public function store( Request $request ) { + $host = $request['hostname']; + $port = env( 'DB_PORT', '3306' ); + $database = $request['database']; + $username = $request['username']; + $password = $request['password']; - flash($message)->error()->important(); + // Check database connection + if ( ! AppConfigurer::isDbValid($host,$port,$database,$username,$password) ) { + $message = trans( 'install.error.connection' ); - return redirect('install/database')->withInput(); - } + flash( $message )->error()->important(); - // Set database details - $this->saveVariables($request); + return redirect( 'install/database' )->withInput(); + } - // Try to increase the maximum execution time - set_time_limit(300); // 5 minutes + // Set database details + AppConfigurer::saveDbVariables($host, $port, $database, $username, $password); - // Create tables - Artisan::call('migrate', ['--force' => true]); + // Try to increase the maximum execution time + set_time_limit( 300 ); // 5 minutes - // Create Roles - Artisan::call('db:seed', ['--class' => 'Database\Seeds\Roles', '--force' => true]); + // Create tables + Artisan::call( 'migrate', [ '--force' => true ] ); - return redirect('install/settings'); - } + // Create Roles + Artisan::call( 'db:seed', [ '--class' => 'Database\Seeds\Roles', '--force' => true ] ); - private function canConnect($request) - { - Config::set('database.connections.install_test', [ - 'host' => $request['hostname'], - 'database' => $request['database'], - 'username' => $request['username'], - 'password' => $request['password'], - 'driver' => env('DB_CONNECTION', 'mysql'), - 'port' => env('DB_PORT', '3306'), - 'charset' => env('DB_CHARSET', 'utf8mb4'), - ]); + return redirect( 'install/settings' ); + } - try { - DB::connection('install_test')->getPdo(); - } catch (\Exception $e) { - return false; - } - - // Purge test connection - DB::purge('install_test'); - - return true; - } - - private function saveVariables($request) - { - $prefix = strtolower(str_random(3) . '_'); - - // Save to file - DotenvEditor::setKeys([ - [ - 'key' => 'DB_HOST', - 'value' => $request['hostname'], - ], - [ - 'key' => 'DB_DATABASE', - 'value' => $request['database'], - ], - [ - 'key' => 'DB_USERNAME', - 'value' => $request['username'], - ], - [ - 'key' => 'DB_PASSWORD', - 'value' => $request['password'], - ], - [ - 'key' => 'DB_PREFIX', - 'value' => $prefix, - ], - ])->save(); - - $con = env('DB_CONNECTION', 'mysql'); - - // Change current connection - $db = Config::get('database.connections.' . $con); - - $db['host'] = $request['hostname']; - $db['database'] = $request['database']; - $db['username'] = $request['username']; - $db['password'] = $request['password']; - $db['prefix'] = $prefix; - - Config::set('database.connections.' . $con, $db); - - DB::purge($con); - DB::reconnect($con); - } } diff --git a/app/Http/Controllers/Install/Requirements.php b/app/Http/Controllers/Install/Requirements.php index 3f76d7664..a09bfe706 100644 --- a/app/Http/Controllers/Install/Requirements.php +++ b/app/Http/Controllers/Install/Requirements.php @@ -2,8 +2,8 @@ namespace App\Http\Controllers\Install; -use DotenvEditor; use File; +use App\Utilities\AppConfigurer; use Illuminate\Routing\Controller; class Requirements extends Controller @@ -16,12 +16,12 @@ class Requirements extends Controller public function show() { // Check requirements - $requirements = $this->check(); + $requirements = AppConfigurer::checkServerRequirements(); if (empty($requirements)) { // Create the .env file if (!File::exists(base_path('.env'))) { - $this->createEnvFile(); + AppConfigurer::createDefaultEnvFile(); } redirect('install/language')->send(); @@ -33,204 +33,4 @@ class Requirements extends Controller return view('install.requirements.show'); } } - - /** - * Check the requirements. - * - * @return array - */ - private function check() - { - $requirements = array(); - - if (ini_get('safe_mode')) { - $requirements[] = trans('install.requirements.disabled', ['feature' => 'Safe Mode']); - } - - if (ini_get('register_globals')) { - $requirements[] = trans('install.requirements.disabled', ['feature' => 'Register Globals']); - } - - if (ini_get('magic_quotes_gpc')) { - $requirements[] = trans('install.requirements.disabled', ['feature' => 'Magic Quotes']); - } - - if (!ini_get('file_uploads')) { - $requirements[] = trans('install.requirements.enabled', ['feature' => 'File Uploads']); - } - - if (!class_exists('PDO')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'MySQL PDO']); - } - - if (!extension_loaded('openssl')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'OpenSSL']); - } - - if (!extension_loaded('tokenizer')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'Tokenizer']); - } - - if (!extension_loaded('mbstring')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'mbstring']); - } - - if (!extension_loaded('curl')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'cURL']); - } - - if (!extension_loaded('xml')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'XML']); - } - - if (!extension_loaded('zip')) { - $requirements[] = trans('install.requirements.extension', ['extension' => 'ZIP']); - } - - if (!is_writable(base_path('storage/app'))) { - $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/app']); - } - - if (!is_writable(base_path('storage/app/uploads'))) { - $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/app/uploads']); - } - - if (!is_writable(base_path('storage/framework'))) { - $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/framework']); - } - - if (!is_writable(base_path('storage/logs'))) { - $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/logs']); - } - - return $requirements; - } - - /** - * Create the .env file. - * - * @return void - */ - private function createEnvFile() - { - // App - DotenvEditor::setKeys([ - [ - 'key' => 'APP_NAME', - 'value' => 'Akaunting', - ], - [ - 'key' => 'APP_ENV', - 'value' => 'production', - ], - [ - 'key' => 'APP_INSTALLED', - 'value' => 'false', - ], - [ - 'key' => 'APP_KEY', - 'value' => 'base64:'.base64_encode(random_bytes(32)), - ], - [ - 'key' => 'APP_DEBUG', - 'value' => 'true', - ], - [ - 'key' => 'APP_LOG_LEVEL', - 'value' => 'debug', - ], - [ - 'key' => 'APP_URL', - 'value' => url('/'), - ], - ]); - - DotenvEditor::addEmpty(); - - // Database - DotenvEditor::setKeys([ - [ - 'key' => 'DB_CONNECTION', - 'value' => 'mysql', - ], - [ - 'key' => 'DB_HOST', - 'value' => 'localhost', - ], - [ - 'key' => 'DB_PORT', - 'value' => '3306', - ], - [ - 'key' => 'DB_DATABASE', - 'value' => '', - ], - [ - 'key' => 'DB_USERNAME', - 'value' => '', - ], - [ - 'key' => 'DB_PASSWORD', - 'value' => '', - ], - [ - 'key' => 'DB_PREFIX', - 'value' => '', - ], - ]); - - DotenvEditor::addEmpty(); - - // Drivers - DotenvEditor::setKeys([ - [ - 'key' => 'BROADCAST_DRIVER', - 'value' => 'log', - ], - [ - 'key' => 'CACHE_DRIVER', - 'value' => 'file', - ], - [ - 'key' => 'SESSION_DRIVER', - 'value' => 'file', - ], - [ - 'key' => 'QUEUE_DRIVER', - 'value' => 'database', - ], - ]); - - DotenvEditor::addEmpty(); - - // Mail - DotenvEditor::setKeys([ - [ - 'key' => 'MAIL_DRIVER', - 'value' => 'mail', - ], - [ - 'key' => 'MAIL_HOST', - 'value' => 'localhost', - ], - [ - 'key' => 'MAIL_PORT', - 'value' => '2525', - ], - [ - 'key' => 'MAIL_USERNAME', - 'value' => 'null', - ], - [ - 'key' => 'MAIL_PASSWORD', - 'value' => 'null', - ], - [ - 'key' => 'MAIL_ENCRYPTION', - 'value' => 'null', - ], - ]); - - DotenvEditor::save(); - } } diff --git a/app/Http/Controllers/Install/Settings.php b/app/Http/Controllers/Install/Settings.php index 9ed7580d0..80f80e4ae 100644 --- a/app/Http/Controllers/Install/Settings.php +++ b/app/Http/Controllers/Install/Settings.php @@ -2,14 +2,9 @@ namespace App\Http\Controllers\Install; -use Artisan; use App\Http\Requests\Install\Setting as Request; -use App\Models\Auth\User; -use App\Models\Company\Company; -use DotenvEditor; -use File; +use App\Utilities\AppConfigurer; use Illuminate\Routing\Controller; -use Setting; class Settings extends Controller { @@ -33,76 +28,21 @@ class Settings extends Controller public function store(Request $request) { // Create company - $this->createCompany($request); + $companyName = $request['company_name']; + $companyEmail= $request['company_email']; + $locale= session('locale'); + AppConfigurer::createCompany($companyName, $companyEmail, $locale); // Create user - $this->createUser($request); + $adminEmail = $request['user_email']; + $adminPassword = $request['user_password']; + $locale= session('locale'); + AppConfigurer::createUser($adminEmail, $adminPassword, $locale); // Make the final touches - $this->finalTouches(); + AppConfigurer::finalTouches(); // Redirect to dashboard return redirect('auth/login'); } - - private function createCompany($request) - { - // Create company - $company = Company::create([ - 'domain' => '', - ]); - - // Set settings - Setting::set([ - 'general.company_name' => $request['company_name'], - 'general.company_email' => $request['company_email'], - 'general.default_currency' => 'USD', - 'general.default_locale' => session('locale'), - ]); - Setting::setExtraColumns(['company_id' => $company->id]); - Setting::save(); - } - - private function createUser($request) - { - // Create the user - $user = User::create([ - 'name' => $request[''], - 'email' => $request['user_email'], - 'password' => $request['user_password'], - 'locale' => session('locale'), - ]); - - // Attach admin role - $user->roles()->attach('1'); - - // Attach company - $user->companies()->attach('1'); - } - - private function finalTouches() - { - // Caching the config and route - //Artisan::call('config:cache'); - //Artisan::call('route:cache'); - - // Update .env file - DotenvEditor::setKeys([ - [ - 'key' => 'APP_INSTALLED', - 'value' => 'true', - ], - [ - 'key' => 'APP_DEBUG', - 'value' => 'false', - ], - ])->save(); - - // Rename the robots.txt file - try { - File::move(base_path('robots.txt.dist'), base_path('robots.txt')); - } catch (\Exception $e) { - // nothing to do - } - } } diff --git a/app/Utilities/AppConfigurer.php b/app/Utilities/AppConfigurer.php new file mode 100644 index 000000000..501ba10b9 --- /dev/null +++ b/app/Utilities/AppConfigurer.php @@ -0,0 +1,365 @@ + 'Safe Mode']); + } + + if (ini_get('register_globals')) { + $requirements[] = trans('install.requirements.disabled', ['feature' => 'Register Globals']); + } + + if (ini_get('magic_quotes_gpc')) { + $requirements[] = trans('install.requirements.disabled', ['feature' => 'Magic Quotes']); + } + + if (!ini_get('file_uploads')) { + $requirements[] = trans('install.requirements.enabled', ['feature' => 'File Uploads']); + } + + if (!class_exists('PDO')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'MySQL PDO']); + } + + if (!extension_loaded('openssl')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'OpenSSL']); + } + + if (!extension_loaded('tokenizer')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'Tokenizer']); + } + + if (!extension_loaded('mbstring')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'mbstring']); + } + + if (!extension_loaded('curl')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'cURL']); + } + + if (!extension_loaded('xml')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'XML']); + } + + if (!extension_loaded('zip')) { + $requirements[] = trans('install.requirements.extension', ['extension' => 'ZIP']); + } + + if (!is_writable(base_path('storage/app'))) { + $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/app']); + } + + if (!is_writable(base_path('storage/app/uploads'))) { + $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/app/uploads']); + } + + if (!is_writable(base_path('storage/framework'))) { + $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/framework']); + } + + if (!is_writable(base_path('storage/logs'))) { + $requirements[] = trans('install.requirements.directory', ['directory' => 'storage/logs']); + } + + return $requirements; + } + + + /** + * Create a default .env file. + * + * @return void + */ + public static function createDefaultEnvFile() + { + // App + DotenvEditor::setKeys([ + [ + 'key' => 'APP_NAME', + 'value' => 'Akaunting', + ], + [ + 'key' => 'APP_ENV', + 'value' => 'production', + ], + [ + 'key' => 'APP_INSTALLED', + 'value' => 'false', + ], + [ + 'key' => 'APP_KEY', + 'value' => 'base64:'.base64_encode(random_bytes(32)), + ], + [ + 'key' => 'APP_DEBUG', + 'value' => 'true', + ], + [ + 'key' => 'APP_LOG_LEVEL', + 'value' => 'debug', + ], + [ + 'key' => 'APP_URL', + 'value' => url('/'), + ], + ]); + + DotenvEditor::addEmpty(); + + // Database + DotenvEditor::setKeys([ + [ + 'key' => 'DB_CONNECTION', + 'value' => 'mysql', + ], + [ + 'key' => 'DB_HOST', + 'value' => 'localhost', + ], + [ + 'key' => 'DB_PORT', + 'value' => '3306', + ], + [ + 'key' => 'DB_DATABASE', + 'value' => '', + ], + [ + 'key' => 'DB_USERNAME', + 'value' => '', + ], + [ + 'key' => 'DB_PASSWORD', + 'value' => '', + ], + [ + 'key' => 'DB_PREFIX', + 'value' => '', + ], + ]); + + DotenvEditor::addEmpty(); + + // Drivers + DotenvEditor::setKeys([ + [ + 'key' => 'BROADCAST_DRIVER', + 'value' => 'log', + ], + [ + 'key' => 'CACHE_DRIVER', + 'value' => 'file', + ], + [ + 'key' => 'SESSION_DRIVER', + 'value' => 'file', + ], + [ + 'key' => 'QUEUE_DRIVER', + 'value' => 'database', + ], + ]); + + DotenvEditor::addEmpty(); + + // Mail + DotenvEditor::setKeys([ + [ + 'key' => 'MAIL_DRIVER', + 'value' => 'mail', + ], + [ + 'key' => 'MAIL_HOST', + 'value' => 'localhost', + ], + [ + 'key' => 'MAIL_PORT', + 'value' => '2525', + ], + [ + 'key' => 'MAIL_USERNAME', + 'value' => 'null', + ], + [ + 'key' => 'MAIL_PASSWORD', + 'value' => 'null', + ], + [ + 'key' => 'MAIL_ENCRYPTION', + 'value' => 'null', + ], + ]); + + DotenvEditor::save(); + } + + /** + * Check if the database exists and is accessible. + * + * @param $host + * @param $port + * @param $database + * @param $host + * @param $database + * @param $username + * @param $password + * + * @return bool + */ + public static function isDbValid($host, $port, $database, $username, $password){ + Config::set('database.connections.install_test', [ + 'host' => $host, + 'port' => $port, + 'database' => $database, + 'username' => $username, + 'password' => $password, + 'driver' => env('DB_CONNECTION', 'mysql'), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + ]); + + try { + DB::connection('install_test')->getPdo(); + } catch (\Exception $e) {; + return false; + } + + // Purge test connection + DB::purge('install_test'); + + return true; + } + + public static function saveDbVariables($host, $port, $database, $username, $password) + { + $prefix = strtolower(str_random(3) . '_'); + + // Save to file + DotenvEditor::setKeys([ + [ + 'key' => 'DB_HOST', + 'value' => $host, + ], + [ + 'key' => 'DB_PORT', + 'value' => $port, + ], + [ + 'key' => 'DB_DATABASE', + 'value' => $database, + ], + [ + 'key' => 'DB_USERNAME', + 'value' => $username, + ], + [ + 'key' => 'DB_PASSWORD', + 'value' => $password, + ], + [ + 'key' => 'DB_PREFIX', + 'value' => $prefix, + ], + ])->save(); + + $con = env('DB_CONNECTION', 'mysql'); + + // Change current connection + $db = Config::get('database.connections.' . $con); + + $db['host'] = $host; + $db['database'] = $database; + $db['username'] = $username; + $db['password'] = $password; + $db['prefix'] = $prefix; + + Config::set('database.connections.' . $con, $db); + + DB::purge($con); + DB::reconnect($con); + } + + public static function createCompany($companyName, $companyEmail, $locale) + { + // Create company + $company = Company::create([ + 'domain' => '', + ]); + + // Set settings + Setting::set([ + 'general.company_name' => $companyName, + 'general.company_email' => $companyEmail, + 'general.default_currency' => 'USD', + 'general.default_locale' => $locale, + ]); + Setting::setExtraColumns(['company_id' => $company->id]); + Setting::save(); + } + + public static function createUser($email, $password, $locale) + { + // Create the user + $user = User::create([ + 'name' => '', + 'email' => $email, + 'password' => $password, + 'locale' => $locale, + ]); + + // Attach admin role + $user->roles()->attach('1'); + + // Attach company + $user->companies()->attach('1'); + } + + public static function finalTouches() + { + // Update .env file + DotenvEditor::setKeys([ + [ + 'key' => 'APP_INSTALLED', + 'value' => 'true', + ], + [ + 'key' => 'APP_DEBUG', + 'value' => 'false', + ], + ])->save(); + + // Rename the robots.txt file + try { + File::move(base_path('robots.txt.dist'), base_path('robots.txt')); + } catch (\Exception $e) { + // nothing to do + } + } +} \ No newline at end of file From 21366add045023172d7cea1d3a5d0380ec4b0d48 Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Sun, 31 Dec 2017 05:29:02 +1100 Subject: [PATCH 4/7] Updated the Docker files --- README.md | 7 ++++-- .../docker-compose.build.yaml | 2 +- docker/docker-compose.mysql.yaml | 22 +++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) rename docker-compose.yaml => docker/docker-compose.build.yaml (67%) create mode 100644 docker/docker-compose.mysql.yaml diff --git a/README.md b/README.md index c20733b23..2539f72b0 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ Akaunting uses [Laravel](http://laravel.com), the best existing PHP framework, a ## Docker -It is possible to containerise Akounting using the [`docker-compose`](./docker-compose.yaml) file. Here are a few commands: +It is possible to containerise Akaunting using the [`docker-compose`](docker/docker-compose.build.yaml) file. Here are a few commands: ``` # Make sure you the dependencies are installed composer install && composer dump-autoload # Build the app -docker-compose build +docker-compose -f docker/docker-compose.build.yaml build # Run the app docker-compose up @@ -46,6 +46,9 @@ docker-compose up docker exec -it CONTAINER_ID /bin/sh ``` +## docker-compose examples +In the `docker/` folder you'll find some example file to run the image with several databases. + ## Contributing Fork the repository, make the code changes then submit a pull request. diff --git a/docker-compose.yaml b/docker/docker-compose.build.yaml similarity index 67% rename from docker-compose.yaml rename to docker/docker-compose.build.yaml index 11af63974..f24d8e392 100644 --- a/docker-compose.yaml +++ b/docker/docker-compose.build.yaml @@ -2,6 +2,6 @@ version: '3' services: web: image: akaunting - build: . + build: ../ ports: - "80:80" \ No newline at end of file diff --git a/docker/docker-compose.mysql.yaml b/docker/docker-compose.mysql.yaml new file mode 100644 index 000000000..f330cd829 --- /dev/null +++ b/docker/docker-compose.mysql.yaml @@ -0,0 +1,22 @@ +version: '3' +services: + mysql: + image: mysql + ports: + - 3306:3306 + environment: + MYSQL_ROOT_PASSWORD: akaunting_root_password + MYSQL_DATABASE: akaunting_db + MYSQL_USER: akaunting_admin + MYSQL_PASSWORD: akaunting_password + web: + image: akaunting + ## Uncomment if you wish to use this configuration as development environment. + # volumes: + # - ../:/var/www/html + ports: + - 8080:80 + environment: + APP_DEBUG: "true" + links: + - mysql \ No newline at end of file From feaa89e77f89ff01f69acab7a994fea228a7b2c2 Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Sun, 31 Dec 2017 06:13:11 +1100 Subject: [PATCH 5/7] Updated AppConfigurer --- app/Utilities/AppConfigurer.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/Utilities/AppConfigurer.php b/app/Utilities/AppConfigurer.php index 501ba10b9..b99a22ff9 100644 --- a/app/Utilities/AppConfigurer.php +++ b/app/Utilities/AppConfigurer.php @@ -92,7 +92,6 @@ class AppConfigurer { return $requirements; } - /** * Create a default .env file. * @@ -110,6 +109,10 @@ class AppConfigurer { 'key' => 'APP_ENV', 'value' => 'production', ], + [ + 'key' => 'APP_LOCALE', + 'value' => 'en-GB', + ], [ 'key' => 'APP_INSTALLED', 'value' => 'false', @@ -345,6 +348,10 @@ class AppConfigurer { { // Update .env file DotenvEditor::setKeys([ + [ + 'key' => 'APP_LOCALE', + 'value' => session('locale'), + ], [ 'key' => 'APP_INSTALLED', 'value' => 'true', From a7dc653a291b0a881fb0148e48d934e15fb4cb82 Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Sat, 6 Jan 2018 21:15:47 +1100 Subject: [PATCH 6/7] Formatted the Dockerfile --- Dockerfile | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index e1d84c142..1562590ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,14 @@ FROM php:apache +RUN apt-get update && apt-get install -y zip libzip-dev libpng-dev \ + && docker-php-ext-install pdo_mysql gd zip \ + && rm -rf /var/lib/apt/lists/* + COPY . /var/www/html/ # Authorize these folders to be edited RUN chmod -R 777 /var/www/html/storage RUN chmod -R 777 /var/www/html/bootstrap/cache -RUN apt-get update && apt-get install -y zip libzip-dev libpng-dev \ - && docker-php-ext-install pdo_mysql gd zip \ - && rm -rf /var/lib/apt/lists/* - # Allow rewrite RUN a2enmod rewrite - -#CMD ["/bin/bash", "/opt/your_app/init.sh"] -# php -f ... -# php artisan make:command ConfigureApp --command=app:configure \ No newline at end of file From 847d89e8ff194c3488ddcf73d9734164e9395c43 Mon Sep 17 00:00:00 2001 From: Carvallegro Date: Tue, 9 Jan 2018 09:16:01 +1100 Subject: [PATCH 7/7] Removed `composer dump-autoload` from the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6889fe717..83315acf9 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ It is possible to containerise Akaunting using the [`docker-compose`](docker/doc ``` # Make sure you the dependencies are installed -composer install && composer dump-autoload +composer install # Build the app docker-compose -f docker/docker-compose.build.yaml build