mirror of
https://github.com/Kovah/LinkAce.git
synced 2025-01-16 20:58:22 +01:00
Adjust setup to support SQLite and PostgreSQL (#831)
This commit is contained in:
parent
edb71c888d
commit
fb73148216
@ -22,7 +22,6 @@ function setupCompleted(): ?bool
|
||||
try {
|
||||
return systemsettings('setup_completed');
|
||||
} catch (PDOException $e) {
|
||||
Log::error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use PDOException;
|
||||
|
||||
class DatabaseController extends Controller
|
||||
{
|
||||
protected string $connection;
|
||||
protected array $dbConfig;
|
||||
|
||||
public function index(): View
|
||||
@ -45,17 +46,22 @@ class DatabaseController extends Controller
|
||||
return redirect()->route('setup.account');
|
||||
}
|
||||
|
||||
protected function createTempDatabaseConnection(array $credentials): void
|
||||
protected function createTempDatabaseConnection(array $configuration): void
|
||||
{
|
||||
$this->dbConfig = config('database.connections.mysql');
|
||||
$this->connection = $configuration['connection'];
|
||||
$this->dbConfig = config('database.connections.' . $this->connection);
|
||||
|
||||
$this->dbConfig['host'] = $credentials['db_host'];
|
||||
$this->dbConfig['port'] = $credentials['db_port'];
|
||||
$this->dbConfig['database'] = $credentials['db_name'];
|
||||
$this->dbConfig['username'] = $credentials['db_user'];
|
||||
$this->dbConfig['password'] = $credentials['db_password'];
|
||||
if ($this->connection === 'sqlite') {
|
||||
$this->dbConfig['database'] = $configuration['db_path'];
|
||||
} else {
|
||||
$this->dbConfig['host'] = $configuration['db_host'];
|
||||
$this->dbConfig['port'] = $configuration['db_port'];
|
||||
$this->dbConfig['database'] = $configuration['db_name'];
|
||||
$this->dbConfig['username'] = $configuration['db_user'];
|
||||
$this->dbConfig['password'] = $configuration['db_password'];
|
||||
}
|
||||
|
||||
Config::set('database.connections.mysql', $this->dbConfig);
|
||||
Config::set('database.connections.' . $this->connection, $this->dbConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,7 +76,7 @@ class DatabaseController extends Controller
|
||||
{
|
||||
try {
|
||||
Artisan::call('migrate:fresh', [
|
||||
'--database' => 'mysql', // Specify the correct connection
|
||||
'--database' => $this->connection, // Specify the correct connection
|
||||
'--force' => true, // Needed for production
|
||||
'--no-interaction' => true,
|
||||
]);
|
||||
@ -93,17 +99,19 @@ class DatabaseController extends Controller
|
||||
$envContent = File::get(base_path('.env'));
|
||||
|
||||
$envContent = preg_replace([
|
||||
'/DB_CONNECTION=(.*)\S/',
|
||||
'/DB_HOST=(.*)\S/',
|
||||
'/DB_PORT=(.*)\S/',
|
||||
'/DB_DATABASE=(.*)\S/',
|
||||
'/DB_USERNAME=(.*)\S/',
|
||||
'/DB_PASSWORD=(.*)\S/',
|
||||
], [
|
||||
'DB_HOST=' . $this->dbConfig['host'],
|
||||
'DB_PORT=' . $this->dbConfig['port'],
|
||||
'DB_DATABASE=' . $this->dbConfig['database'],
|
||||
'DB_USERNAME=' . $this->dbConfig['username'],
|
||||
'DB_PASSWORD=' . $this->dbConfig['password'],
|
||||
'DB_CONNECTION=' . $this->connection,
|
||||
'DB_HOST=' . ($this->dbConfig['host'] ?? ''),
|
||||
'DB_PORT=' . ($this->dbConfig['port'] ?? ''),
|
||||
'DB_DATABASE=' . ($this->dbConfig['database'] ?? ''),
|
||||
'DB_USERNAME=' . ($this->dbConfig['username'] ?? ''),
|
||||
'DB_PASSWORD=' . ($this->dbConfig['password'] ?? ''),
|
||||
], $envContent);
|
||||
|
||||
if ($envContent !== null) {
|
||||
@ -121,7 +129,7 @@ class DatabaseController extends Controller
|
||||
protected function databaseHasData(): bool
|
||||
{
|
||||
try {
|
||||
$presentTables = DB::connection('mysql')
|
||||
$presentTables = DB::connection($this->connection)
|
||||
->getDoctrineSchemaManager()
|
||||
->listTableNames();
|
||||
} catch (PDOException|\Doctrine\DBAL\Exception $e) {
|
||||
|
@ -25,18 +25,33 @@ class RequirementsController extends Controller
|
||||
'php_version' => PHP_VERSION_ID >= 80110,
|
||||
'extension_bcmath' => extension_loaded('bcmath'),
|
||||
'extension_ctype' => extension_loaded('ctype'),
|
||||
'extension_curl' => extension_loaded('curl'),
|
||||
'extension_dom' => extension_loaded('dom'),
|
||||
'extension_fileinfo' => extension_loaded('fileinfo'),
|
||||
'extension_filter' => extension_loaded('filter'),
|
||||
'extension_hash' => extension_loaded('hash'),
|
||||
'extension_json' => extension_loaded('json'),
|
||||
'extension_mbstring' => extension_loaded('mbstring'),
|
||||
'extension_openssl' => extension_loaded('openssl'),
|
||||
'extension_pdo_mysql' => extension_loaded('pdo_mysql'),
|
||||
'extension_pcre' => extension_loaded('pcre'),
|
||||
'extension_session' => extension_loaded('session'),
|
||||
'extension_tokenizer' => extension_loaded('tokenizer'),
|
||||
'extension_xml' => extension_loaded('xml'),
|
||||
];
|
||||
|
||||
$dbResults = [
|
||||
'extension_pdo_mysql' => extension_loaded('pdo_mysql'),
|
||||
'extension_pdo_pgsql' => extension_loaded('pdo_pgsql'),
|
||||
'extension_pdo_sqlite' => extension_loaded('pdo_sqlite'),
|
||||
];
|
||||
|
||||
$additionalResults = [
|
||||
'env_writable' => File::isWritable(base_path('.env')),
|
||||
'storage_writable' => File::isWritable(storage_path()) && File::isWritable(storage_path('logs')),
|
||||
];
|
||||
|
||||
$success = !in_array(false, $results, true);
|
||||
$success = !in_array(false, $results, true) && !in_array(false, $additionalResults, true);
|
||||
|
||||
return [$success, $results];
|
||||
return [$success, array_merge($results, $dbResults, $additionalResults)];
|
||||
}
|
||||
}
|
||||
|
@ -9,18 +9,25 @@ class SetupDatabaseRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'db_host' => [
|
||||
'connection' => [
|
||||
'required',
|
||||
'in:sqlite,mysql,pgsql',
|
||||
],
|
||||
'db_path' => [
|
||||
'required_if:connection,sqlite',
|
||||
],
|
||||
'db_host' => [
|
||||
'required_unless:connection,sqlite',
|
||||
],
|
||||
'db_port' => [
|
||||
'required',
|
||||
'required_unless:connection,sqlite',
|
||||
'numeric',
|
||||
],
|
||||
'db_name' => [
|
||||
'required',
|
||||
'required_unless:connection,sqlite',
|
||||
],
|
||||
'db_user' => [
|
||||
'required',
|
||||
'required_unless:connection,sqlite',
|
||||
],
|
||||
'db_password' => [
|
||||
'nullable',
|
||||
|
@ -57,7 +57,7 @@ return [
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'engine' => env('DB_ENGINE', 'InnoDB'),
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
|
Binary file not shown.
@ -16,10 +16,19 @@ return [
|
||||
'requirements.php_version' => 'PHP version >= 7.4.0',
|
||||
'requirements.extension_bcmath' => 'PHP Extension: BCMath',
|
||||
'requirements.extension_ctype' => 'PHP Extension: Ctype',
|
||||
'requirements.extension_curl' => 'PHP Extension: Curl',
|
||||
'requirements.extension_dom' => 'PHP Extension: DOM',
|
||||
'requirements.extension_fileinfo' => 'PHP Extension: Fileinfo',
|
||||
'requirements.extension_filter' => 'PHP Extension: Filter',
|
||||
'requirements.extension_hash' => 'PHP Extension: Hash',
|
||||
'requirements.extension_json' => 'PHP Extension: JSON',
|
||||
'requirements.extension_mbstring' => 'PHP Extension: Mbstring',
|
||||
'requirements.extension_openssl' => 'PHP Extension: OpenSSL',
|
||||
'requirements.extension_pcre' => 'PHP Extension: PCRE',
|
||||
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO MySQL',
|
||||
'requirements.extension_pdo_pgsql' => 'PHP Extension: PDO PostgreSQL',
|
||||
'requirements.extension_pdo_sqlite' => 'PHP Extension: PDO SQLite',
|
||||
'requirements.extension_session' => 'PHP Extension: Session',
|
||||
'requirements.extension_tokenizer' => 'PHP Extension: Tokenizer',
|
||||
'requirements.extension_xml' => 'PHP Extension: XML',
|
||||
'requirements.env_writable' => '.env file is present and writable',
|
||||
@ -29,6 +38,8 @@ return [
|
||||
'database_configure' => 'Configure Database',
|
||||
'database.intro' => 'If you already filled the database details in your .env file the input fields should be pre-filled. Otherwise, fill the fields with the corresponding information for your database.',
|
||||
'database.config_error' => 'Database could not be configured. Please check your connection details. Details:',
|
||||
'database.connection' => 'Database Type',
|
||||
'database.db_path' => 'Database File Path',
|
||||
'database.db_host' => 'Database Host',
|
||||
'database.db_port' => 'Database Port',
|
||||
'database.db_name' => 'Database Name',
|
||||
|
4
resources/assets/js/app.js
vendored
4
resources/assets/js/app.js
vendored
@ -1,8 +1,9 @@
|
||||
import { register } from './lib/views';
|
||||
|
||||
import Base from './components/Base';
|
||||
|
||||
import BookmarkTimer from './components/BookmarkTimer';
|
||||
import BulkEdit from './components/BulkEdit';
|
||||
import DatabaseSetup from './components/Setup';
|
||||
import GenerateCronToken from './components/GenerateCronToken';
|
||||
import Import from './components/Import';
|
||||
import LoadingButton from './components/LoadingButton';
|
||||
@ -17,6 +18,7 @@ function registerViews () {
|
||||
register('#app', Base);
|
||||
register('.bm-timer', BookmarkTimer);
|
||||
register('.bulk-edit', BulkEdit);
|
||||
register('.database-setup', DatabaseSetup);
|
||||
register('.cron-token', GenerateCronToken);
|
||||
register('.import-form', Import);
|
||||
register('.share-toggle', ShareToggleAll);
|
||||
|
6
resources/assets/js/components/Base.js
vendored
6
resources/assets/js/components/Base.js
vendored
@ -7,8 +7,10 @@ export default class Base {
|
||||
|
||||
initAppData () {
|
||||
// Load data passed by the backend to the JS
|
||||
let data = document.querySelector('meta[property="la-app-data"]').getAttribute('content');
|
||||
window.appData = JSON.parse(data);
|
||||
let data = document.querySelector('meta[property="la-app-data"]')?.getAttribute('content');
|
||||
if (data) {
|
||||
window.appData = JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
initBootstrapTooltips () {
|
||||
|
30
resources/assets/js/components/Setup.js
vendored
Normal file
30
resources/assets/js/components/Setup.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
export default class DatabaseSetup {
|
||||
|
||||
constructor ($el) {
|
||||
this.$connection = $el.querySelector('#connection');
|
||||
this.$dbPath = $el.querySelector('.db-path');
|
||||
this.$dbHost = $el.querySelector('.db-host');
|
||||
this.$dbPort = $el.querySelector('.db-port');
|
||||
this.$dbName = $el.querySelector('.db-name');
|
||||
this.$dbUser = $el.querySelector('.db-user');
|
||||
this.$dbPass = $el.querySelector('.db-password');
|
||||
this.$submit = $el.querySelector('.db-submit');
|
||||
|
||||
this.$connection.addEventListener('change', this.handleConnectionChange.bind(this));
|
||||
this.handleConnectionChange();
|
||||
|
||||
$el.addEventListener('submit', () => {
|
||||
this.$submit.toggleAttribute('disabled');
|
||||
});
|
||||
}
|
||||
|
||||
handleConnectionChange () {
|
||||
const connection = this.$connection.options[this.$connection.selectedIndex].value;
|
||||
this.$dbPath.classList.toggle('d-none', connection !== 'sqlite');
|
||||
this.$dbHost.classList.toggle('d-none', connection === 'sqlite');
|
||||
this.$dbPort.classList.toggle('d-none', connection === 'sqlite');
|
||||
this.$dbName.classList.toggle('d-none', connection === 'sqlite');
|
||||
this.$dbUser.classList.toggle('d-none', connection === 'sqlite');
|
||||
this.$dbPass.classList.toggle('d-none', connection === 'sqlite');
|
||||
}
|
||||
}
|
@ -80,7 +80,10 @@ COPY --from=npm_builder --chown=www-data:www-data /srv/public/assets/dist/css /a
|
||||
COPY --from=npm_builder --chown=www-data:www-data /srv/public/mix-manifest.json /app/public/mix-manifest.json
|
||||
|
||||
# Create a SQLite database file ready to be used
|
||||
RUN touch ./database/database.sqlite
|
||||
RUN touch ./database/database.sqlite \
|
||||
&& chown www-data:www-data ./database/database.sqlite \
|
||||
&& chmod +w ./database/database.sqlite \
|
||||
&& chmod +r ./database
|
||||
|
||||
# Configure Supervisor for PHP + Caddy
|
||||
ENV PORT=80
|
||||
|
1
resources/views/components/icon/warning.blade.php
Normal file
1
resources/views/components/icon/warning.blade.php
Normal file
@ -0,0 +1 @@
|
||||
<svg {{ $attributes->merge(['class' => 'icon', 'viewBox' =>'0 0 512 512', 'xmlns' => 'http://www.w3.org/2000/svg', 'aria-hidden' => 'true', 'focusable' => 'false']) }}><path d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>
|
After Width: | Height: | Size: 490 B |
@ -15,10 +15,41 @@
|
||||
|
||||
@include('partials.alerts')
|
||||
|
||||
<form action="{{ route('setup.save-database') }}" method="POST">
|
||||
<form action="{{ route('setup.save-database') }}" method="POST" class="database-setup">
|
||||
@csrf
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="connection">
|
||||
@lang('setup.database.connection')
|
||||
</label>
|
||||
<select name="connection" id="connection"
|
||||
class="form-select{{ $errors->has('connection') ? ' is-invalid' : '' }}">
|
||||
<option value="mysql" @selected(old('connection') === 'mysql')>MySQL / MariaDB</option>
|
||||
<option value="sqlite" @selected(old('connection') === 'sqlite')>SQLite</option>
|
||||
<option value="pgsql" @selected(old('connection') === 'pgsql')>PostgreSQL</option>
|
||||
</select>
|
||||
@if ($errors->has('connection'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('connection') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mb-3 db-path">
|
||||
<label for="db_path">
|
||||
@lang('setup.database.db_path')
|
||||
</label>
|
||||
<input type="text" name="db_path" id="db_path" required
|
||||
class="form-control{{ $errors->has('db_path') ? ' is-invalid' : '' }}"
|
||||
placeholder="localhost" value="{{ old('db_path') ?: database_path('database.sqlite') }}">
|
||||
@if ($errors->has('db_path'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('db_path') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mb-3 db-host">
|
||||
<label for="db_host">
|
||||
@lang('setup.database.db_host')
|
||||
</label>
|
||||
@ -32,7 +63,7 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 db-port">
|
||||
<label for="db_port">
|
||||
@lang('setup.database.db_port')
|
||||
</label>
|
||||
@ -46,7 +77,7 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 db-name">
|
||||
<label for="db_name">
|
||||
@lang('setup.database.db_name')
|
||||
</label>
|
||||
@ -60,7 +91,7 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 db-user">
|
||||
<label for="db_user">
|
||||
@lang('setup.database.db_user')
|
||||
</label>
|
||||
@ -74,7 +105,7 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 db-password">
|
||||
<label for="db_password">
|
||||
@lang('setup.database.db_password')
|
||||
</label>
|
||||
@ -102,7 +133,7 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<button type="submit" class="btn btn-primary db-submit">
|
||||
@if($errors->any())
|
||||
@lang('setup.try_again')
|
||||
@else
|
||||
|
@ -17,6 +17,8 @@
|
||||
@lang('setup.requirements.' . $key)
|
||||
@if($successful)
|
||||
<x-icon.check class="text-success"/>
|
||||
@elseif(str_contains($key, 'pdo'))
|
||||
<x-icon.warning class="text-warning"/>
|
||||
@else
|
||||
<x-icon.ban class="text-danger"/>
|
||||
@endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user