implement SiteUpdates: make the user reload on critical code changes
This commit is contained in:
parent
8503b2554c
commit
cdfef25034
7 changed files with 84 additions and 11 deletions
|
@ -418,7 +418,9 @@ class UpdatesViewSet(GenericViewSet):
|
|||
except ValueError:
|
||||
cache.set('api_updates_fetch_requests', 0, None)
|
||||
|
||||
from c3nav.site.models import SiteUpdate
|
||||
response = Response({
|
||||
'last_site_update': SiteUpdate.last_update(),
|
||||
'last_map_update': MapUpdate.current_processed_cache_key(),
|
||||
'user': get_user_data(request),
|
||||
})
|
||||
|
|
|
@ -163,7 +163,7 @@ class MapUpdate(models.Model):
|
|||
new_update.save()
|
||||
|
||||
transaction.on_commit(
|
||||
lambda: cache.set('mapdata:last_processed_update', new_updates[-1].to_tuple, 300)
|
||||
lambda: cache.set('mapdata:last_processed_update', new_updates[-1].to_tuple, None)
|
||||
)
|
||||
|
||||
return new_updates
|
||||
|
@ -188,7 +188,7 @@ class MapUpdate(models.Model):
|
|||
|
||||
if new:
|
||||
transaction.on_commit(
|
||||
lambda: cache.set('mapdata:last_update', self.to_tuple, 300)
|
||||
lambda: cache.set('mapdata:last_update', self.to_tuple, None)
|
||||
)
|
||||
if settings.HAS_CELERY:
|
||||
transaction.on_commit(
|
||||
|
|
|
@ -8,7 +8,7 @@ class Command(BaseCommand):
|
|||
result = input('Type YES to create a new site update: ')
|
||||
|
||||
if result == 'YES':
|
||||
from c3nav.mapdata.models import SiteUpdate
|
||||
from c3nav.site.models import SiteUpdate
|
||||
SiteUpdate.objects.create()
|
||||
print('New site update created.')
|
||||
else:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from contextlib import contextmanager
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -50,3 +52,42 @@ class SiteUpdate(models.Model):
|
|||
A site update that asks the user to reload the page.
|
||||
"""
|
||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_('create'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Site update')
|
||||
verbose_name_plural = _('Site updates')
|
||||
default_related_name = 'siteupdates'
|
||||
get_latest_by = 'created'
|
||||
|
||||
@classmethod
|
||||
@contextmanager
|
||||
def lock(cls):
|
||||
with transaction.atomic():
|
||||
try:
|
||||
yield cls.objects.select_for_update().get(pk=cls.objects.earliest().pk)
|
||||
except cls.DoesNotExist:
|
||||
yield
|
||||
|
||||
@classmethod
|
||||
def last_update(cls):
|
||||
last_update = cache.get('site:last_site_update', None)
|
||||
if last_update is not None:
|
||||
return last_update
|
||||
with cls.lock():
|
||||
try:
|
||||
last_update = cls.objects.latest()
|
||||
except cls.DoesNotExist:
|
||||
last_update = None
|
||||
else:
|
||||
last_update = last_update.pk
|
||||
cache.set('site:last_site_update', last_update, None)
|
||||
return last_update
|
||||
|
||||
def save(self, **kwargs):
|
||||
new = self.pk is None
|
||||
with transaction.atomic():
|
||||
super().save(**kwargs)
|
||||
if new:
|
||||
transaction.on_commit(
|
||||
lambda: cache.set('site:last_site_update', self.pk, None)
|
||||
)
|
||||
|
|
|
@ -68,6 +68,9 @@ c3nav = {
|
|||
state = JSON.parse($main.attr('data-state'));
|
||||
c3nav.embed = $main.is('[data-embed]');
|
||||
|
||||
c3nav.last_site_update = JSON.parse($main.attr('data-last-site-update'));
|
||||
c3nav.new_site_update = false;
|
||||
|
||||
history.replaceState(state, window.location.path);
|
||||
c3nav.load_state(state, true);
|
||||
c3nav.update_map_locations();
|
||||
|
@ -549,10 +552,13 @@ c3nav = {
|
|||
// console.log('state pushed');
|
||||
history.pushState(state, '', url);
|
||||
}
|
||||
|
||||
c3nav._maybe_load_site_update(state);
|
||||
},
|
||||
_onpopstate: function (e) {
|
||||
// console.log('state popped');
|
||||
c3nav.load_state(e.state);
|
||||
c3nav._maybe_load_site_update(e.state);
|
||||
},
|
||||
load_state: function (state, nofly) {
|
||||
if (state.modal) {
|
||||
|
@ -886,22 +892,24 @@ c3nav = {
|
|||
}
|
||||
},
|
||||
|
||||
open_modal: function (content) {
|
||||
modal_noclose: false,
|
||||
open_modal: function (content, no_close) {
|
||||
c3nav.modal_noclose = no_close;
|
||||
var $modal = $('#modal');
|
||||
c3nav._set_modal_content(content);
|
||||
c3nav._set_modal_content(content, no_close);
|
||||
if (!$modal.is('.show')) {
|
||||
c3nav._push_state({modal: true, sidebar: true});
|
||||
$modal.addClass('show');
|
||||
}
|
||||
},
|
||||
_set_modal_content: function(content) {
|
||||
_set_modal_content: function(content, no_close) {
|
||||
$('#modal').toggleClass('loading', !content)
|
||||
.find('#modal-content')
|
||||
.html('<button class="button-clear material-icons" id="close-modal">clear</button>')
|
||||
.html((!no_close) ? '<button class="button-clear material-icons" id="close-modal">clear</button>' :'')
|
||||
.append(content || '');
|
||||
},
|
||||
_modal_click: function(e) {
|
||||
if (e.target.id === 'modal' || e.target.id === 'close-modal') {
|
||||
if (!c3nav.modal_noclose && (e.target.id === 'modal' || e.target.id === 'close-modal')) {
|
||||
history.back();
|
||||
}
|
||||
},
|
||||
|
@ -1168,8 +1176,26 @@ c3nav = {
|
|||
},
|
||||
_fetch_updates_callback: function (data) {
|
||||
c3nav.schedule_fetch_updates();
|
||||
if (c3nav.last_site_update !== data.last_site_update) {
|
||||
c3nav.new_site_update = true;
|
||||
c3nav.last_site_update = data.last_site_update;
|
||||
c3nav._maybe_load_site_update(c3nav.state);
|
||||
}
|
||||
c3nav._set_user_data(data.user);
|
||||
},
|
||||
_maybe_load_site_update: function(state) {
|
||||
if (c3nav.new_site_update && !state.modal && (!state.routing || !state.origin || !state.destination)) {
|
||||
c3nav._load_site_update();
|
||||
}
|
||||
},
|
||||
_load_site_update: function() {
|
||||
$('#modal-content').css({
|
||||
width: 'auto',
|
||||
minHeight: 0
|
||||
});
|
||||
c3nav.open_modal($('.reload-msg').html(), true);
|
||||
window.location.reload();
|
||||
},
|
||||
_set_user_data: function (data) {
|
||||
var $user = $('header #user');
|
||||
$user.find('span').text(data.title);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<main class="map" data-state="{{ state }}"{% if embed %} data-embed{% endif %}>
|
||||
<main class="map" data-state="{{ state }}"{% if embed %} data-embed{% endif %} data-last-site-update="{{ last_site_update }}">
|
||||
<section id="attributions">
|
||||
{% if not embed %}
|
||||
{% get_current_language as CURRENT_LANGUAGE %}
|
||||
|
@ -37,6 +37,9 @@
|
|||
<button class="mobileclient-shortcut">{% trans 'create shortcut' %}</button>
|
||||
</p>
|
||||
</section>
|
||||
<section class="reload-msg">
|
||||
<img src="{% static 'img/loader.gif' %}">
|
||||
</section>
|
||||
<section id="sidebar">
|
||||
<section id="search" class="loading">
|
||||
<div class="location locationinput empty" id="origin-input">
|
||||
|
|
|
@ -28,7 +28,7 @@ from c3nav.mapdata.models.locations import LocationRedirect, SpecificLocation
|
|||
from c3nav.mapdata.utils.locations import get_location_by_slug_for_request, levels_by_short_label_for_request
|
||||
from c3nav.mapdata.utils.user import get_user_data
|
||||
from c3nav.mapdata.views import set_tile_access_cookie
|
||||
from c3nav.site.models import Announcement
|
||||
from c3nav.site.models import Announcement, SiteUpdate
|
||||
|
||||
|
||||
def check_location(location: Optional[str], request) -> Optional[SpecificLocation]:
|
||||
|
@ -120,6 +120,7 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N
|
|||
'tile_cache_server': settings.TILE_CACHE_SERVER,
|
||||
'initial_level': settings.INITIAL_LEVEL,
|
||||
'initial_bounds': json.dumps(settings.INITIAL_BOUNDS, separators=(',', ':')),
|
||||
'last_site_update': json.dumps(SiteUpdate.last_update()),
|
||||
'embed': bool(embed),
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue