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:
|
except ValueError:
|
||||||
cache.set('api_updates_fetch_requests', 0, None)
|
cache.set('api_updates_fetch_requests', 0, None)
|
||||||
|
|
||||||
|
from c3nav.site.models import SiteUpdate
|
||||||
response = Response({
|
response = Response({
|
||||||
|
'last_site_update': SiteUpdate.last_update(),
|
||||||
'last_map_update': MapUpdate.current_processed_cache_key(),
|
'last_map_update': MapUpdate.current_processed_cache_key(),
|
||||||
'user': get_user_data(request),
|
'user': get_user_data(request),
|
||||||
})
|
})
|
||||||
|
|
|
@ -163,7 +163,7 @@ class MapUpdate(models.Model):
|
||||||
new_update.save()
|
new_update.save()
|
||||||
|
|
||||||
transaction.on_commit(
|
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
|
return new_updates
|
||||||
|
@ -188,7 +188,7 @@ class MapUpdate(models.Model):
|
||||||
|
|
||||||
if new:
|
if new:
|
||||||
transaction.on_commit(
|
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:
|
if settings.HAS_CELERY:
|
||||||
transaction.on_commit(
|
transaction.on_commit(
|
||||||
|
|
|
@ -8,7 +8,7 @@ class Command(BaseCommand):
|
||||||
result = input('Type YES to create a new site update: ')
|
result = input('Type YES to create a new site update: ')
|
||||||
|
|
||||||
if result == 'YES':
|
if result == 'YES':
|
||||||
from c3nav.mapdata.models import SiteUpdate
|
from c3nav.site.models import SiteUpdate
|
||||||
SiteUpdate.objects.create()
|
SiteUpdate.objects.create()
|
||||||
print('New site update created.')
|
print('New site update created.')
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
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.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
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.
|
A site update that asks the user to reload the page.
|
||||||
"""
|
"""
|
||||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_('create'))
|
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'));
|
state = JSON.parse($main.attr('data-state'));
|
||||||
c3nav.embed = $main.is('[data-embed]');
|
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);
|
history.replaceState(state, window.location.path);
|
||||||
c3nav.load_state(state, true);
|
c3nav.load_state(state, true);
|
||||||
c3nav.update_map_locations();
|
c3nav.update_map_locations();
|
||||||
|
@ -549,10 +552,13 @@ c3nav = {
|
||||||
// console.log('state pushed');
|
// console.log('state pushed');
|
||||||
history.pushState(state, '', url);
|
history.pushState(state, '', url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c3nav._maybe_load_site_update(state);
|
||||||
},
|
},
|
||||||
_onpopstate: function (e) {
|
_onpopstate: function (e) {
|
||||||
// console.log('state popped');
|
// console.log('state popped');
|
||||||
c3nav.load_state(e.state);
|
c3nav.load_state(e.state);
|
||||||
|
c3nav._maybe_load_site_update(e.state);
|
||||||
},
|
},
|
||||||
load_state: function (state, nofly) {
|
load_state: function (state, nofly) {
|
||||||
if (state.modal) {
|
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');
|
var $modal = $('#modal');
|
||||||
c3nav._set_modal_content(content);
|
c3nav._set_modal_content(content, no_close);
|
||||||
if (!$modal.is('.show')) {
|
if (!$modal.is('.show')) {
|
||||||
c3nav._push_state({modal: true, sidebar: true});
|
c3nav._push_state({modal: true, sidebar: true});
|
||||||
$modal.addClass('show');
|
$modal.addClass('show');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_set_modal_content: function(content) {
|
_set_modal_content: function(content, no_close) {
|
||||||
$('#modal').toggleClass('loading', !content)
|
$('#modal').toggleClass('loading', !content)
|
||||||
.find('#modal-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 || '');
|
.append(content || '');
|
||||||
},
|
},
|
||||||
_modal_click: function(e) {
|
_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();
|
history.back();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1168,8 +1176,26 @@ c3nav = {
|
||||||
},
|
},
|
||||||
_fetch_updates_callback: function (data) {
|
_fetch_updates_callback: function (data) {
|
||||||
c3nav.schedule_fetch_updates();
|
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);
|
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) {
|
_set_user_data: function (data) {
|
||||||
var $user = $('header #user');
|
var $user = $('header #user');
|
||||||
$user.find('span').text(data.title);
|
$user.find('span').text(data.title);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% 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">
|
<section id="attributions">
|
||||||
{% if not embed %}
|
{% if not embed %}
|
||||||
{% get_current_language as CURRENT_LANGUAGE %}
|
{% get_current_language as CURRENT_LANGUAGE %}
|
||||||
|
@ -37,6 +37,9 @@
|
||||||
<button class="mobileclient-shortcut">{% trans 'create shortcut' %}</button>
|
<button class="mobileclient-shortcut">{% trans 'create shortcut' %}</button>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="reload-msg">
|
||||||
|
<img src="{% static 'img/loader.gif' %}">
|
||||||
|
</section>
|
||||||
<section id="sidebar">
|
<section id="sidebar">
|
||||||
<section id="search" class="loading">
|
<section id="search" class="loading">
|
||||||
<div class="location locationinput empty" id="origin-input">
|
<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.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.utils.user import get_user_data
|
||||||
from c3nav.mapdata.views import set_tile_access_cookie
|
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]:
|
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,
|
'tile_cache_server': settings.TILE_CACHE_SERVER,
|
||||||
'initial_level': settings.INITIAL_LEVEL,
|
'initial_level': settings.INITIAL_LEVEL,
|
||||||
'initial_bounds': json.dumps(settings.INITIAL_BOUNDS, separators=(',', ':')),
|
'initial_bounds': json.dumps(settings.INITIAL_BOUNDS, separators=(',', ':')),
|
||||||
|
'last_site_update': json.dumps(SiteUpdate.last_update()),
|
||||||
'embed': bool(embed),
|
'embed': bool(embed),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue