mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-12-23 00:26:33 +00:00
Merge pull request #3185 from bookwyrm-social/check-version-number
Check version number asynchronously
This commit is contained in:
commit
6b1ffbc634
15 changed files with 275 additions and 108 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.7.1
|
||||
0.6.1
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
""" Get your admin code to allow install """
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from bookwyrm import models
|
||||
from bookwyrm.settings import VERSION
|
||||
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
class Command(BaseCommand):
|
||||
"""command-line options"""
|
||||
|
||||
help = "What version is this?"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""specify which function to run"""
|
||||
parser.add_argument(
|
||||
"--current",
|
||||
action="store_true",
|
||||
help="Version stored in database",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
action="store_true",
|
||||
help="Version stored in settings",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--update",
|
||||
action="store_true",
|
||||
help="Update database version",
|
||||
)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def handle(self, *args, **options):
|
||||
"""execute init"""
|
||||
site = models.SiteSettings.objects.get()
|
||||
current = site.version or "0.0.1"
|
||||
target = VERSION
|
||||
if options.get("current"):
|
||||
print(current)
|
||||
return
|
||||
|
||||
if options.get("target"):
|
||||
print(target)
|
||||
return
|
||||
|
||||
if options.get("update"):
|
||||
site.version = target
|
||||
site.save()
|
||||
return
|
||||
|
||||
if current != target:
|
||||
print(f"{current}/{target}")
|
||||
else:
|
||||
print(current)
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.23 on 2024-01-02 19:36
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0191_merge_20240102_0326"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="sitesettings",
|
||||
old_name="version",
|
||||
new_name="available_version",
|
||||
),
|
||||
]
|
13
bookwyrm/migrations/0194_merge_20240203_1619.py
Normal file
13
bookwyrm/migrations/0194_merge_20240203_1619.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Generated by Django 3.2.23 on 2024-02-03 16:19
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0192_rename_version_sitesettings_available_version"),
|
||||
("bookwyrm", "0193_merge_20240203_1539"),
|
||||
]
|
||||
|
||||
operations = []
|
|
@ -10,8 +10,11 @@ from django.dispatch import receiver
|
|||
from django.utils import timezone
|
||||
from model_utils import FieldTracker
|
||||
|
||||
from bookwyrm.connectors.abstract_connector import get_data
|
||||
from bookwyrm.preview_images import generate_site_preview_image_task
|
||||
from bookwyrm.settings import DOMAIN, ENABLE_PREVIEW_IMAGES, STATIC_FULL_URL
|
||||
from bookwyrm.settings import RELEASE_API
|
||||
from bookwyrm.tasks import app, MISC
|
||||
from .base_model import BookWyrmModel, new_access_code
|
||||
from .user import User
|
||||
from .fields import get_absolute_url
|
||||
|
@ -45,7 +48,7 @@ class SiteSettings(SiteModel):
|
|||
default_theme = models.ForeignKey(
|
||||
"Theme", null=True, blank=True, on_delete=models.SET_NULL
|
||||
)
|
||||
version = models.CharField(null=True, blank=True, max_length=10)
|
||||
available_version = models.CharField(null=True, blank=True, max_length=10)
|
||||
|
||||
# admin setup options
|
||||
install_mode = models.BooleanField(default=False)
|
||||
|
@ -245,3 +248,14 @@ def preview_image(instance, *args, **kwargs):
|
|||
|
||||
if len(changed_fields) > 0:
|
||||
generate_site_preview_image_task.delay()
|
||||
|
||||
|
||||
@app.task(queue=MISC)
|
||||
def check_for_updates_task():
|
||||
"""See if git remote knows about a new version"""
|
||||
site = SiteSettings.objects.get()
|
||||
release = get_data(RELEASE_API, timeout=3)
|
||||
available_version = release.get("tag_name", None)
|
||||
if available_version:
|
||||
site.available_version = available_version
|
||||
site.save(update_fields=["available_version"])
|
||||
|
|
|
@ -45,6 +45,10 @@
|
|||
{% include 'settings/dashboard/warnings/update_version.html' with warning_level="warning" fullwidth=True %}
|
||||
{% endif %}
|
||||
|
||||
{% if schedule_form %}
|
||||
{% include 'settings/dashboard/warnings/check_for_updates.html' with warning_level="success" fullwidth=True %}
|
||||
{% endif %}
|
||||
|
||||
{% if missing_privacy or missing_conduct %}
|
||||
<div class="column is-12 columns m-0 p-0">
|
||||
{% if missing_privacy %}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
{% extends 'settings/dashboard/warnings/layout.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block warning_link %}#{% endblock %}
|
||||
|
||||
{% block warning_text %}
|
||||
|
||||
<form name="check-version" method="POST" action="{% url 'settings-dashboard' %}" class="is-flex is-align-items-center">
|
||||
{% csrf_token %}
|
||||
|
||||
<p class="pr-2">
|
||||
{% blocktrans trimmed with current=current_version available=available_version %}
|
||||
Would you like to automatically check for new BookWyrm releases? (recommended)
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
{{ schedule_form.every.as_hidden }}
|
||||
{{ schedule_form.period.as_hidden }}
|
||||
|
||||
<button class="button is-small" type="submit">{% trans "Schedule checks" %}</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -85,6 +85,10 @@
|
|||
{% url 'settings-celery' as url %}
|
||||
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Celery status" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
{% url 'settings-schedules' as url %}
|
||||
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Scheduled tasks" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
{% url 'settings-email-config' as url %}
|
||||
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Email Configuration" %}</a>
|
||||
|
|
127
bookwyrm/templates/settings/schedules.html
Normal file
127
bookwyrm/templates/settings/schedules.html
Normal file
|
@ -0,0 +1,127 @@
|
|||
{% extends 'settings/layout.html' %}
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
{% load utilities %}
|
||||
|
||||
{% block title %}
|
||||
{% trans "Scheduled tasks" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
{% trans "Scheduled tasks" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block panel %}
|
||||
|
||||
<div class="block content">
|
||||
<h3>{% trans "Tasks" %}</h3>
|
||||
<div class="table-container">
|
||||
<table class="table is-striped is-fullwidth">
|
||||
<tr>
|
||||
<th>
|
||||
{% trans "Name" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Celery task" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Date changed" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Last run at" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Schedule" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Schedule ID" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Enabled" %}
|
||||
</th>
|
||||
</tr>
|
||||
{% for task in tasks %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ task.name }}
|
||||
</td>
|
||||
<td class="overflow-wrap-anywhere">
|
||||
{{ task.task }}
|
||||
</td>
|
||||
<td>
|
||||
{{ task.date_changed }}
|
||||
</td>
|
||||
<td>
|
||||
{{ task.last_run_at }}
|
||||
</td>
|
||||
<td>
|
||||
{% firstof task.interval task.crontab "None" %}
|
||||
</td>
|
||||
<td>
|
||||
{{ task.interval.id }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="tag">
|
||||
{% if task.enabled %}
|
||||
<span class="icon icon-check" aria-hidden="true"></span>
|
||||
{% endif %}
|
||||
{{ task.enabled|yesno }}
|
||||
</span>
|
||||
{% if task.name != "celery.backend_cleanup" %}
|
||||
<form name="unschedule-{{ task.id }}" method="POST" action="{% url 'settings-schedules' task.id %}">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="button is-danger is-small">{% trans "Un-schedule" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% trans "No scheduled tasks" %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block content">
|
||||
<h3>{% trans "Schedules" %}</h3>
|
||||
<div class="table-container">
|
||||
<table class="table is-striped is-fullwidth">
|
||||
<tr>
|
||||
<th>
|
||||
{% trans "ID" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Schedule" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Tasks" %}
|
||||
</th>
|
||||
</tr>
|
||||
{% for schedule in schedules %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ schedule.id }}
|
||||
</td>
|
||||
<td class="overflow-wrap-anywhere">
|
||||
{{ schedule }}
|
||||
</td>
|
||||
<td>
|
||||
{{ schedule.periodictask_set.count }}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% trans "No schedules found" %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -369,6 +369,11 @@ urlpatterns = [
|
|||
re_path(
|
||||
r"^settings/celery/ping/?$", views.celery_ping, name="settings-celery-ping"
|
||||
),
|
||||
re_path(
|
||||
r"^settings/schedules/(?P<task_id>\d+)?$",
|
||||
views.ScheduledTasks.as_view(),
|
||||
name="settings-schedules",
|
||||
),
|
||||
re_path(
|
||||
r"^settings/email-config/?$",
|
||||
views.EmailConfig.as_view(),
|
||||
|
|
|
@ -5,6 +5,7 @@ from .admin.announcements import EditAnnouncement, delete_announcement
|
|||
from .admin.automod import AutoMod, automod_delete, run_automod
|
||||
from .admin.automod import schedule_automod_task, unschedule_automod_task
|
||||
from .admin.celery_status import CeleryStatus, celery_ping
|
||||
from .admin.schedule import ScheduledTasks
|
||||
from .admin.dashboard import Dashboard
|
||||
from .admin.federation import Federation, FederatedServer
|
||||
from .admin.federation import AddFederatedServer, ImportServerBlocklist
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.template.response import TemplateResponse
|
|||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.http import require_POST
|
||||
from django_celery_beat.models import PeriodicTask
|
||||
from django_celery_beat.models import PeriodicTask, IntervalSchedule
|
||||
|
||||
from bookwyrm import forms, models
|
||||
|
||||
|
@ -54,7 +54,7 @@ def schedule_automod_task(request):
|
|||
return TemplateResponse(request, "settings/automod/rules.html", data)
|
||||
|
||||
with transaction.atomic():
|
||||
schedule = form.save(request)
|
||||
schedule, _ = IntervalSchedule.objects.get_or_create(**form.cleaned_data)
|
||||
PeriodicTask.objects.get_or_create(
|
||||
interval=schedule,
|
||||
name="automod-task",
|
||||
|
|
|
@ -6,16 +6,18 @@ from dateutil.parser import parse
|
|||
from packaging import version
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils import timezone
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django_celery_beat.models import PeriodicTask, IntervalSchedule
|
||||
|
||||
from csp.decorators import csp_update
|
||||
|
||||
from bookwyrm import models, settings
|
||||
from bookwyrm.connectors.abstract_connector import get_data
|
||||
from bookwyrm import forms, models, settings
|
||||
from bookwyrm.utils import regex
|
||||
|
||||
|
||||
|
@ -59,21 +61,36 @@ class Dashboard(View):
|
|||
== site._meta.get_field("privacy_policy").get_default()
|
||||
)
|
||||
|
||||
# check version
|
||||
if site.available_version and version.parse(
|
||||
site.available_version
|
||||
) > version.parse(settings.VERSION):
|
||||
data["current_version"] = settings.VERSION
|
||||
data["available_version"] = site.available_version
|
||||
|
||||
try:
|
||||
release = get_data(settings.RELEASE_API, timeout=3)
|
||||
available_version = release.get("tag_name", None)
|
||||
if available_version and version.parse(available_version) > version.parse(
|
||||
settings.VERSION
|
||||
):
|
||||
data["current_version"] = settings.VERSION
|
||||
data["available_version"] = available_version
|
||||
except: # pylint: disable= bare-except
|
||||
pass
|
||||
if not PeriodicTask.objects.filter(name="check-for-updates").exists():
|
||||
data["schedule_form"] = forms.IntervalScheduleForm(
|
||||
{"every": 1, "period": "days"}
|
||||
)
|
||||
|
||||
return TemplateResponse(request, "settings/dashboard/dashboard.html", data)
|
||||
|
||||
def post(self, request):
|
||||
"""Create a schedule task to check for updates"""
|
||||
schedule_form = forms.IntervalScheduleForm(request.POST)
|
||||
if not schedule_form.is_valid():
|
||||
raise schedule_form.ValidationError(schedule_form.errors)
|
||||
|
||||
with transaction.atomic():
|
||||
schedule, _ = IntervalSchedule.objects.get_or_create(
|
||||
**schedule_form.cleaned_data
|
||||
)
|
||||
PeriodicTask.objects.get_or_create(
|
||||
interval=schedule,
|
||||
name="check-for-updates",
|
||||
task="bookwyrm.models.site.check_for_updates_task",
|
||||
)
|
||||
return redirect("settings-dashboard")
|
||||
|
||||
|
||||
def get_charts_and_stats(request):
|
||||
"""Defines the dashboard charts"""
|
||||
|
|
31
bookwyrm/views/admin/schedule.py
Normal file
31
bookwyrm/views/admin/schedule.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
""" Scheduled celery tasks """
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.shortcuts import redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django_celery_beat.models import PeriodicTask, IntervalSchedule
|
||||
|
||||
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
@method_decorator(
|
||||
permission_required("bookwyrm.edit_instance_settings", raise_exception=True),
|
||||
name="dispatch",
|
||||
)
|
||||
# pylint: disable=no-self-use
|
||||
class ScheduledTasks(View):
|
||||
"""Manage automated flagging"""
|
||||
|
||||
def get(self, request):
|
||||
"""view schedules"""
|
||||
data = {}
|
||||
data["tasks"] = PeriodicTask.objects.all()
|
||||
data["schedules"] = IntervalSchedule.objects.all()
|
||||
return TemplateResponse(request, "settings/schedules.html", data)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def post(self, request, task_id):
|
||||
"""un-schedule a task"""
|
||||
task = PeriodicTask.objects.get(id=task_id)
|
||||
task.delete()
|
||||
return redirect("settings-schedules")
|
37
update.sh
37
update.sh
|
@ -1,37 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# determine inital and target versions
|
||||
initial_version="`./bw-dev runweb python manage.py instance_version --current`"
|
||||
target_version="`./bw-dev runweb python manage.py instance_version --target`"
|
||||
|
||||
initial_version="`echo $initial_version | tail -n 1 | xargs`"
|
||||
target_version="`echo $target_version | tail -n 1 | xargs`"
|
||||
if [[ "$initial_version" = "$target_version" ]]; then
|
||||
echo "Already up to date; version $initial_version"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "---------------------------------------"
|
||||
echo "Updating from version: $initial_version"
|
||||
echo ".......... to version: $target_version"
|
||||
echo "---------------------------------------"
|
||||
|
||||
function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
|
||||
|
||||
# execute scripts between initial and target
|
||||
for version in `ls -A updates/ | sort -V `; do
|
||||
if version_gt $initial_version $version; then
|
||||
# too early
|
||||
continue
|
||||
fi
|
||||
if version_gt $version $target_version; then
|
||||
# too late
|
||||
continue
|
||||
fi
|
||||
echo "Running tasks for version $version"
|
||||
./updates/$version
|
||||
done
|
||||
|
||||
./bw-dev runweb python manage.py instance_version --update
|
||||
echo "✨ ----------- Done! --------------- ✨"
|
Loading…
Reference in a new issue