added migration status to system page

This commit is contained in:
vabene1111 2023-12-16 14:03:32 +01:00
parent dd3e91e10d
commit 0fed6b9fb3
5 changed files with 127 additions and 55 deletions

View File

@ -3,6 +3,7 @@
<words>
<w>pinia</w>
<w>selfhosted</w>
<w>unapplied</w>
</words>
</dictionary>
</component>

View File

@ -1,5 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Default" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>

View File

@ -83,51 +83,94 @@
{% trans 'Everything is fine!' %}
{% endif %}
<h4 class="mt-3">{% trans 'Database' %}
<span class="badge badge-{{postgres_status}}">
<h4 class="mt-3">{% trans 'Database' %}
<span class="badge badge-{{ postgres_status }}">
{% if postgres_status == 'warning' %}
{% trans 'Info' %}
{% elif postgres_status == 'danger'%}
{% elif postgres_status == 'danger' %}
{% trans 'Warning' %}
{% else %}
{% trans 'Ok' %}
{% endif %}
</span>
</h4>
{{postgres_message}}
{{ postgres_message }}
{# <h4 class="mt-3">#}
{# {% trans 'Orphaned Files' %}#}
{##}
{# <span class="badge badge-{% if orphans|length == 0 %}success{% elif orphans|length <= 25 %}warning{% else %}danger{% endif %}">#}
{# {% if orphans|length == 0 %}{% trans 'Success' %}#}
{# {% elif orphans|length <= 25 %}{% trans 'Warning' %}#}
{# {% else %}{% trans 'Danger' %}#}
{# {% endif %}#}
{# </span>#}
{# </h4>#}
<h4 class="mt-3">{% trans 'Migrations' %}
<span
class="badge badge-{% if missing_migration %}danger{% else %}success{% endif %}">{% if missing_migration %}
{% trans 'Warning' %}{% else %}{% trans 'Ok' %}{% endif %}</span></h4>
{% if orphans|length == 0 %}
{% trans 'Everything is fine!' %}
{% else %}
{% blocktrans with orphan_count=orphans|length %}
There are currently {{ orphan_count }} orphaned files.
<p>
{% blocktrans %}
Migrations should never fail!
Failed migrations will likely cause major parts of the app to not function correctly.
If a migration fails make sure you are on the latest version and if so please post the migration log and the overview below in a GitHub issue.
{% endblocktrans %}
<br>
<button id="toggle-button" class="btn btn-info btn-sm" onclick="toggleOrphans()">{% trans 'Show' %}</button>
<button class="btn btn-info btn-sm" onclick="deleteOrphans()">{% trans 'Delete' %}</button>
{% endif %}
<textarea id="orphans-list" style="display:none;" class="form-control" rows="20">
{% for orphan in orphans %}{{ orphan }}
{% endfor %}
</textarea>
</p>
<table class="table mt-3">
<thead>
<tr>
<th>App</th>
<th class="text-right">{% trans 'Migrations' %}</th>
</tr>
</thead>
{% for key,value in migration_info.items %}
<tr>
<td>{{ value.app }}</td>
<td class="text-right">
<span class="badge badge-{% if value.unapplied_migrations|length > 0 %}danger{% else %}success{% endif %}">
{{ value.applied_migrations|length }} / {{ value.total }}
</span>
</td>
</tr>
{% for u in value.unapplied_migrations %}
<tr>
<td>
{{ u }}
</td>
<td></td>
</tr>
{% endfor %}
{% endfor %}
</table>
{# <h4 class="mt-3">#}
{# {% trans 'Orphaned Files' %}#}
{##}
{# <span class="badge badge-{% if orphans|length == 0 %}success{% elif orphans|length <= 25 %}warning{% else %}danger{% endif %}">#}
{# {% if orphans|length == 0 %}{% trans 'Success' %}#}
{# {% elif orphans|length <= 25 %}{% trans 'Warning' %}#}
{# {% else %}{% trans 'Danger' %}#}
{# {% endif %}#}
{# </span>#}
{# </h4>#}
{# {% if orphans|length == 0 %}#}
{# {% trans 'Everything is fine!' %}#}
{# {% else %}#}
{# {% blocktrans with orphan_count=orphans|length %}#}
{# There are currently {{ orphan_count }} orphaned files.#}
{# {% endblocktrans %}#}
{# <br>#}
{# <button id="toggle-button" class="btn btn-info btn-sm" onclick="toggleOrphans()">{% trans 'Show' %}</button>#}
{# <button class="btn btn-info btn-sm" onclick="deleteOrphans()">{% trans 'Delete' %}</button>#}
{# {% endif %}#}
{# <textarea id="orphans-list" style="display:none;" class="form-control" rows="20">#}
{#{% for orphan in orphans %}{{ orphan }}#}
{#{% endfor %}#}
{# </textarea>#}
<h4 class="mt-3">Debug</h4>
<textarea class="form-control" rows="20">
Gunicorn Media: {{ gunicorn_media }}
Sqlite: {% if postgres %} {% trans 'False' %} {% else %} {% trans 'True' %} {% endif %}
{% if postgres %}PostgreSQL: {{postgres_version}} {% endif %}
Debug: {{ debug }}
{% if postgres %}PostgreSQL: {{ postgres_version }} {% endif %}
Debug: {{ debug }}
{% for key,value in request.META.items %}{% if key in 'SERVER_PORT,REMOTE_HOST,REMOTE_ADDR,SERVER_PROTOCOL' %}{{ key }}:{{ value }}
{% endif %}{% endfor %}
@ -142,26 +185,27 @@ Debug: {{ debug }}
{% csrf_token %}
<input type="hidden" name="delete_orphans" value="false">
</form>
{% block script %}
<script>
function toggleOrphans() {
var orphansList = document.getElementById('orphans-list');
var button = document.getElementById('toggle-button');
{% block script %}
<script>
function toggleOrphans() {
var orphansList = document.getElementById('orphans-list');
var button = document.getElementById('toggle-button');
if (orphansList.style.display === 'none') {
orphansList.style.display = 'block';
button.innerText = "{% trans 'Hide' %}";
} else {
orphansList.style.display = 'none';
button.innerText = "{% trans 'Show' %}";
}
}
function deleteOrphans() {
document.getElementById('delete-form').delete_orphans.value = 'true';
document.getElementById('delete-form').submit();
}
</script>
{% endblock script %}
if (orphansList.style.display === 'none') {
orphansList.style.display = 'block';
button.innerText = "{% trans 'Hide' %}";
} else {
orphansList.style.display = 'none';
button.innerText = "{% trans 'Show' %}";
}
}
function deleteOrphans() {
document.getElementById('delete-form').delete_orphans.value = 'true';
document.getElementById('delete-form').submit();
}
</script>
{% endblock script %}
{% endblock %}

View File

@ -1,7 +1,9 @@
import os
import re
from datetime import datetime
from io import StringIO
from uuid import UUID
import subprocess
from django.apps import apps
from django.conf import settings
@ -10,6 +12,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.core.management import call_command
from django.db import models
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
@ -27,7 +30,7 @@ from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchP
ShareLink, Space, UserSpace, ViewLog)
from cookbook.tables import CookLogTable, ViewLogTable
from cookbook.version_info import VERSION_INFO
from recipes.settings import PLUGINS
from recipes.settings import PLUGINS, BASE_DIR
def index(request):
@ -228,10 +231,10 @@ def shopping_settings(request):
if not sp:
sp = SearchPreferenceForm(user=request.user)
fields_searched = (
len(search_form.cleaned_data['icontains'])
+ len(search_form.cleaned_data['istartswith'])
+ len(search_form.cleaned_data['trigram'])
+ len(search_form.cleaned_data['fulltext'])
len(search_form.cleaned_data['icontains'])
+ len(search_form.cleaned_data['istartswith'])
+ len(search_form.cleaned_data['trigram'])
+ len(search_form.cleaned_data['fulltext'])
)
if search_form.cleaned_data['preset'] == 'fuzzy':
sp.search = SearchPreference.SIMPLE
@ -348,6 +351,26 @@ def system(request):
else:
orphans = get_orphan_files()
out = StringIO()
call_command('showmigrations', stdout=out)
missing_migration = False
migration_info = {}
current_app = None
for row in out.getvalue().splitlines():
if '[ ]' in row and current_app:
migration_info[current_app]['unapplied_migrations'].append(row.replace('[ ]', ''))
missing_migration = True
elif '[X]' in row and current_app:
migration_info[current_app]['applied_migrations'].append(row.replace('[x]', ''))
elif '(no migrations)' in row and current_app:
pass
else:
current_app = row
migration_info[current_app] = {'app': current_app, 'unapplied_migrations': [], 'applied_migrations': [], 'total': 0}
for key in migration_info.keys():
migration_info[key]['total'] = len(migration_info[key]['unapplied_migrations']) + len(migration_info[key]['applied_migrations'])
return render(request, 'system.html', {
'gunicorn_media': settings.GUNICORN_MEDIA,
'debug': settings.DEBUG,
@ -358,7 +381,9 @@ def system(request):
'version_info': VERSION_INFO,
'plugins': PLUGINS,
'secret_key': secret_key,
'orphans': orphans
'orphans': orphans,
'migration_info': migration_info,
'missing_migration': missing_migration,
})
@ -514,6 +539,7 @@ def get_orphan_files(delete_orphans=False):
# Check each image file against model image fields
return [img for img in image_files if img[0] not in image_paths]
orphans = find_orphans()
if delete_orphans:
for f in [img[1] for img in orphans]:

View File

@ -9,7 +9,7 @@ django-tables2==2.5.3
djangorestframework==3.14.0
drf-writable-nested==0.7.0
django-oauth-toolkit==2.3.0
django-debug-toolbar==3.8.1
django-debug-toolbar==4.2.0
bleach==6.0.0
gunicorn==20.1.0
lxml==4.9.3