164 lines
9.4 KiB
Twig
164 lines
9.4 KiB
Twig
{% extends 'base.html.twig' %}
|
|
{% block title %}Site Settings{% endblock %}
|
|
{% block body %}
|
|
<h1 class="h4 mb-3">Site Settings</h1>
|
|
{% for msg in app.flashes('success') %}<div class="alert alert-success">{{ msg }}</div>{% endfor %}
|
|
{% for msg in app.flashes('info') %}<div class="alert alert-info">{{ msg }}</div>{% endfor %}
|
|
{% for msg in app.flashes('warning') %}<div class="alert alert-warning">{{ msg }}</div>{% endfor %}
|
|
{% for msg in app.flashes('danger') %}<div class="alert alert-danger">{{ msg }}</div>{% endfor %}
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
{{ form_start(form, {attr: {id: 'site-settings-form', class: 'vstack gap-3', novalidate: 'novalidate'}}) }}
|
|
<div>
|
|
{{ form_label(form.EXTERNAL_ALBUM_PROVIDER) }}
|
|
{{ form_widget(form.EXTERNAL_ALBUM_PROVIDER, {attr: {class: 'form-select', 'data-initial-provider': storedProvider}}) }}
|
|
<div class="form-text">Switching provider clears album/review catalog data to prevent mixed-source duplicates.</div>
|
|
<div class="form-text">Stored provider: <strong>{{ providerLabelStored }}</strong> • Active provider: <strong>{{ providerLabelActive }}</strong> • Effective now: <strong>{{ providerLabelEffective }}</strong></div>
|
|
{% if envOverrideProvider %}
|
|
<div class="form-text text-warning">Environment override <code>EXTERNAL_ALBUM_PROVIDER={{ envOverrideProvider }}</code> is active and takes priority over saved settings.</div>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
{{ form_label(form.LASTFM_API_KEY) }}
|
|
{{ form_widget(form.LASTFM_API_KEY, {attr: {class: 'form-control'}}) }}
|
|
<div class="form-text">Environment override: <code>LASTFM_API_KEY</code>.</div>
|
|
</div>
|
|
<hr class="my-1">
|
|
<div>
|
|
{{ form_label(form.MUSICBRAINZ_CLIENT_ID) }}
|
|
{{ form_widget(form.MUSICBRAINZ_CLIENT_ID, {attr: {class: 'form-control'}}) }}
|
|
<div class="form-text">Optional. Not required for album search. Create OAuth app credentials at <a href="https://musicbrainz.org/account/applications" target="_blank" rel="noopener">MusicBrainz account applications</a>. Environment override: <code>MUSICBRAINZ_CLIENT_ID</code>.</div>
|
|
</div>
|
|
<div>
|
|
{{ form_label(form.MUSICBRAINZ_CLIENT_SECRET) }}
|
|
{{ form_widget(form.MUSICBRAINZ_CLIENT_SECRET, {attr: {class: 'form-control'}}) }}
|
|
<div class="form-text">Optional. Not required for album search. Pairs with client ID from <a href="https://musicbrainz.org/account/applications" target="_blank" rel="noopener">MusicBrainz account applications</a>. Environment override: <code>MUSICBRAINZ_CLIENT_SECRET</code>.</div>
|
|
</div>
|
|
<div>
|
|
{{ form_label(form.MUSICBRAINZ_ACCESS_TOKEN) }}
|
|
{{ form_widget(form.MUSICBRAINZ_ACCESS_TOKEN, {attr: {class: 'form-control'}}) }}
|
|
<div class="form-text">Optional. Leave empty for normal search.</div>
|
|
<div class="form-text">If you need authenticated MusicBrainz features, create an OAuth app under <a href="https://musicbrainz.org/account/applications" target="_blank" rel="noopener">MusicBrainz account applications</a>, authorize it, then paste the returned access token here. Environment override: <code>MUSICBRAINZ_ACCESS_TOKEN</code>.</div>
|
|
</div>
|
|
<hr class="my-1">
|
|
<div>
|
|
{{ form_label(form.TIDAL_CLIENT_ID) }}
|
|
{{ form_widget(form.TIDAL_CLIENT_ID, {attr: {class: 'form-control'}}) }}
|
|
<div class="form-text">Required for TIDAL provider. Create credentials at <a href="https://developer.tidal.com/" target="_blank" rel="noopener">developer.tidal.com</a>. Environment override: <code>TIDAL_CLIENT_ID</code>.</div>
|
|
</div>
|
|
<div>
|
|
{{ form_label(form.TIDAL_CLIENT_SECRET) }}
|
|
{{ form_widget(form.TIDAL_CLIENT_SECRET, {attr: {class: 'form-control'}}) }}
|
|
<div class="form-text">Required for TIDAL provider. Environment override: <code>TIDAL_CLIENT_SECRET</code>.</div>
|
|
</div>
|
|
<div>
|
|
{{ form_label(form.TIDAL_COUNTRY_CODE) }}
|
|
{{ form_widget(form.TIDAL_COUNTRY_CODE, {attr: {class: 'form-control', placeholder: 'US'}}) }}
|
|
<div class="form-text">Optional ISO 3166-1 alpha-2 country code used for catalog availability (defaults to <code>US</code>). Environment override: <code>TIDAL_COUNTRY_CODE</code>.</div>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
{% set registrationToggleAttrs = {class: 'form-check-input'} %}
|
|
{% if registrationImmutable %}
|
|
{% set registrationToggleAttrs = registrationToggleAttrs|merge({disabled: true}) %}
|
|
{% endif %}
|
|
{{ form_widget(form.REGISTRATION_ENABLED, {attr: registrationToggleAttrs}) }}
|
|
{{ form_label(form.REGISTRATION_ENABLED, null, {label_attr: {class: 'form-check-label'}}) }}
|
|
<div class="form-text">When disabled, public sign-up is blocked but admins can still create users from `/admin/users`.</div>
|
|
{% if registrationImmutable %}
|
|
<div class="form-text text-warning">Locked by <code>APP_ALLOW_REGISTRATION</code> ({{ registrationOverrideValue ? 'enabled' : 'disabled' }}).</div>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-success" type="submit">Save settings</button>
|
|
</div>
|
|
{{ form_end(form) }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
<h2 class="h6 mb-3">Maintenance</h2>
|
|
<form method="post" action="{{ path('admin_settings_reset_catalog') }}" onsubmit="return confirm('Delete all albums, tracks, and reviews? Users remain untouched.');">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('admin_settings_reset_catalog') }}">
|
|
<button class="btn btn-outline-danger" type="submit">Reset album & review data</button>
|
|
<div class="form-text mt-1">Deletes all albums (and tracks) plus reviews. Users and settings stay intact.</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h2 class="h6 mb-3">Generate demo data</h2>
|
|
<div class="vstack gap-4">
|
|
{% for key, command in demoCommands %}
|
|
<form class="p-3 border rounded" method="post" action="{{ path('admin_settings_generate_demo', {type: key}) }}">
|
|
<div class="row gy-3 align-items-center">
|
|
<div class="col-12 col-xl-4">
|
|
<div class="fw-semibold">{{ command.label }}</div>
|
|
<div class="text-secondary small">{{ command.description }}</div>
|
|
<div class="text-secondary small">Command: <code>php bin/console {{ command.command }}</code></div>
|
|
</div>
|
|
<div class="col-12 col-xl-8">
|
|
<div class="row g-3 align-items-end">
|
|
{% for field in command.fields %}
|
|
{% if field.type != 'checkbox' %}
|
|
<div class="col-auto">
|
|
<label class="form-label small mb-1" for="{{ key }}_{{ field.name }}">{{ field.label }}</label>
|
|
<input class="form-control form-control-sm" id="{{ key }}_{{ field.name }}" type="{{ field.type }}" name="{{ field.name }}" placeholder="{{ field.placeholder|default('') }}" value="{{ field.default|default('') }}">
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</div>
|
|
<div class="d-flex flex-wrap gap-3 mt-3">
|
|
{% for field in command.fields %}
|
|
{% if field.type == 'checkbox' %}
|
|
<div class="form-check form-switch" style="min-width: 220px;">
|
|
<input class="form-check-input" type="checkbox" name="{{ field.name }}" id="{{ key }}_{{ field.name }}" {% if field.default is defined and field.default %}checked{% endif %}>
|
|
<label class="form-check-label" for="{{ key }}_{{ field.name }}">{{ field.label }}</label>
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="text-end mt-3">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('admin_settings_generate_' ~ key) }}">
|
|
<button class="btn btn-outline-primary btn-sm" type="submit">Run</button>
|
|
</div>
|
|
</form>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block javascripts %}
|
|
{{ parent() }}
|
|
<script>
|
|
(function () {
|
|
const form = document.getElementById('site-settings-form');
|
|
const providerField = document.getElementById('{{ form.EXTERNAL_ALBUM_PROVIDER.vars.id }}');
|
|
if (!form || !providerField) {
|
|
return;
|
|
}
|
|
|
|
const initialProvider = providerField.dataset.initialProvider || providerField.value;
|
|
const envOverrideActive = {{ envOverrideProvider ? 'true' : 'false' }};
|
|
form.addEventListener('submit', function (event) {
|
|
if (providerField.value === initialProvider) {
|
|
return;
|
|
}
|
|
|
|
const message = envOverrideActive
|
|
? 'EXTERNAL_ALBUM_PROVIDER override is active. This change saves your preferred provider, but reset only occurs when the effective provider actually changes. Continue?'
|
|
: 'Changing the external provider will reset all albums, tracks, and reviews to avoid mixed-source duplicates. Continue?';
|
|
const ok = window.confirm(message);
|
|
if (!ok) {
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
{% endblock %}
|