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> <words>
<w>pinia</w> <w>pinia</w>
<w>selfhosted</w> <w>selfhosted</w>
<w>unapplied</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

View File

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

View File

@ -96,6 +96,49 @@
</h4> </h4>
{{ postgres_message }} {{ postgres_message }}
<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>
<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 %}
</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">#} {# <h4 class="mt-3">#}
{# {% trans 'Orphaned Files' %}#} {# {% trans 'Orphaned Files' %}#}
{##} {##}
@ -107,20 +150,20 @@
{# </span>#} {# </span>#}
{# </h4>#} {# </h4>#}
{% if orphans|length == 0 %} {# {% if orphans|length == 0 %}#}
{% trans 'Everything is fine!' %} {# {% trans 'Everything is fine!' %}#}
{% else %} {# {% else %}#}
{% blocktrans with orphan_count=orphans|length %} {# {% blocktrans with orphan_count=orphans|length %}#}
There are currently {{ orphan_count }} orphaned files. {# There are currently {{ orphan_count }} orphaned files.#}
{% endblocktrans %} {# {% endblocktrans %}#}
<br> {# <br>#}
<button id="toggle-button" class="btn btn-info btn-sm" onclick="toggleOrphans()">{% trans 'Show' %}</button> {# <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> {# <button class="btn btn-info btn-sm" onclick="deleteOrphans()">{% trans 'Delete' %}</button>#}
{% endif %} {# {% endif %}#}
<textarea id="orphans-list" style="display:none;" class="form-control" rows="20"> {# <textarea id="orphans-list" style="display:none;" class="form-control" rows="20">#}
{% for orphan in orphans %}{{ orphan }} {#{% for orphan in orphans %}{{ orphan }}#}
{% endfor %} {#{% endfor %}#}
</textarea> {# </textarea>#}
<h4 class="mt-3">Debug</h4> <h4 class="mt-3">Debug</h4>
<textarea class="form-control" rows="20"> <textarea class="form-control" rows="20">
@ -156,6 +199,7 @@ Debug: {{ debug }}
button.innerText = "{% trans 'Show' %}"; button.innerText = "{% trans 'Show' %}";
} }
} }
function deleteOrphans() { function deleteOrphans() {
document.getElementById('delete-form').delete_orphans.value = 'true'; document.getElementById('delete-form').delete_orphans.value = 'true';
document.getElementById('delete-form').submit(); document.getElementById('delete-form').submit();

View File

@ -1,7 +1,9 @@
import os import os
import re import re
from datetime import datetime from datetime import datetime
from io import StringIO
from uuid import UUID from uuid import UUID
import subprocess
from django.apps import apps from django.apps import apps
from django.conf import settings 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.models import Group
from django.contrib.auth.password_validation import validate_password from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.management import call_command
from django.db import models from django.db import models
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render 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) ShareLink, Space, UserSpace, ViewLog)
from cookbook.tables import CookLogTable, ViewLogTable from cookbook.tables import CookLogTable, ViewLogTable
from cookbook.version_info import VERSION_INFO from cookbook.version_info import VERSION_INFO
from recipes.settings import PLUGINS from recipes.settings import PLUGINS, BASE_DIR
def index(request): def index(request):
@ -348,6 +351,26 @@ def system(request):
else: else:
orphans = get_orphan_files() 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', { return render(request, 'system.html', {
'gunicorn_media': settings.GUNICORN_MEDIA, 'gunicorn_media': settings.GUNICORN_MEDIA,
'debug': settings.DEBUG, 'debug': settings.DEBUG,
@ -358,7 +381,9 @@ def system(request):
'version_info': VERSION_INFO, 'version_info': VERSION_INFO,
'plugins': PLUGINS, 'plugins': PLUGINS,
'secret_key': secret_key, '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 # Check each image file against model image fields
return [img for img in image_files if img[0] not in image_paths] return [img for img in image_files if img[0] not in image_paths]
orphans = find_orphans() orphans = find_orphans()
if delete_orphans: if delete_orphans:
for f in [img[1] for img in 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 djangorestframework==3.14.0
drf-writable-nested==0.7.0 drf-writable-nested==0.7.0
django-oauth-toolkit==2.3.0 django-oauth-toolkit==2.3.0
django-debug-toolbar==3.8.1 django-debug-toolbar==4.2.0
bleach==6.0.0 bleach==6.0.0
gunicorn==20.1.0 gunicorn==20.1.0
lxml==4.9.3 lxml==4.9.3