From: Radek Czajka Date: Mon, 22 May 2023 13:32:31 +0000 (+0200) Subject: opt-in presence record X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/01e3154575d718ae51e55e7ea8d064718e7d0037?hp=c2103994301a743b0e3e620da80d795124d9ec47 opt-in presence record --- diff --git a/src/redakcja/settings/__init__.py b/src/redakcja/settings/__init__.py index ecebe40e..95956d9e 100644 --- a/src/redakcja/settings/__init__.py +++ b/src/redakcja/settings/__init__.py @@ -106,6 +106,7 @@ INSTALLED_APPS = ( 'email_mangler', 'wlxml.apps.WlxmlConfig', 'alerts', + 'team', ) if DEBUG: diff --git a/src/redakcja/static/js/wiki/loader.js b/src/redakcja/static/js/wiki/loader.js index 1573c763..7f7d1b11 100644 --- a/src/redakcja/static/js/wiki/loader.js +++ b/src/redakcja/static/js/wiki/loader.js @@ -115,7 +115,18 @@ $(function() e.returnValue = "Na stronie mogą być nie zapisane zmiany."; return "Na stronie mogą być nie zapisane zmiany."; }; - }; + + + + }; + + $('body').mousemove(function(e) { + CurrentDocument.active = true; + }); + $('body').keydown(function(e) { + CurrentDocument.active = true; + }); + console.log("Fetching document's text"); @@ -145,7 +156,7 @@ $(function() $('#header').addClass('out-of-date'); clearInterval(revTimer); }}); - }, 300000); + }, 60 * 1000); }, failure: function() { $('#loading-overlay').fadeOut(); diff --git a/src/redakcja/static/js/wiki/wikiapi.js b/src/redakcja/static/js/wiki/wikiapi.js index b9d36bea..b53bf06d 100644 --- a/src/redakcja/static/js/wiki/wikiapi.js +++ b/src/redakcja/static/js/wiki/wikiapi.js @@ -86,6 +86,7 @@ this.galleryImages = []; this.text = null; this.has_local_changes = false; + this.active = true; this._lock = -1; this._context_lock = -1; this._lock_count = 0; @@ -178,9 +179,14 @@ WikiDocument.prototype.checkRevision = function(params) { /* this doesn't modify anything, so no locks */ var self = this; + let active = self.active; + self.active = false; $.ajax({ method: "GET", url: reverse("ajax_document_rev", self.id), + data: { + 'a': active, + }, dataType: 'text', success: function(data) { if (data == '') { diff --git a/src/team/__init__.py b/src/team/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/team/admin.py b/src/team/admin.py new file mode 100644 index 00000000..cff63219 --- /dev/null +++ b/src/team/admin.py @@ -0,0 +1,13 @@ +from django.contrib import admin +from . import models + + +@admin.register(models.Profile) +class ProfileAdmin(admin.ModelAdmin): + list_display = ['user', 'presence'] + + +@admin.register(models.Presence) +class ProfileAdmin(admin.ModelAdmin): + list_display = ['user', 'timestamp', 'active'] + diff --git a/src/team/apps.py b/src/team/apps.py new file mode 100644 index 00000000..dbb33193 --- /dev/null +++ b/src/team/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TeamConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'team' diff --git a/src/team/migrations/0001_initial.py b/src/team/migrations/0001_initial.py new file mode 100644 index 00000000..4e2f1c49 --- /dev/null +++ b/src/team/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 4.0.6 on 2023-05-22 13:06 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('documents', '0008_book_legimi_id'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('presence', models.BooleanField()), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Presence', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now_add=True, db_index=True)), + ('active', models.BooleanField()), + ('chunk', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='documents.chunk')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/src/team/migrations/__init__.py b/src/team/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/team/models.py b/src/team/models.py new file mode 100644 index 00000000..05372c46 --- /dev/null +++ b/src/team/models.py @@ -0,0 +1,26 @@ +from django.conf import settings +from django.db import models +from django.utils.timezone import now + + +class Profile(models.Model): + user = models.OneToOneField(settings.AUTH_USER_MODEL, models.CASCADE) + presence = models.BooleanField() + + +class Presence(models.Model): + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE) + chunk = models.ForeignKey('documents.Chunk', models.SET_NULL, blank=True, null=True) + timestamp = models.DateTimeField(auto_now_add=True, db_index=True) + active = models.BooleanField() + + @classmethod + def report(cls, user, chunk, active): + if user.is_anonymous or not hasattr(user, 'profile') or not user.profile.presence: + return + cls.objects.create( + user=user, + chunk=chunk, + timestamp=now(), + active=active + ) diff --git a/src/team/tests.py b/src/team/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/src/team/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/src/team/views.py b/src/team/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/src/team/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/src/wiki/views.py b/src/wiki/views.py index cf67abbd..543a473c 100644 --- a/src/wiki/views.py +++ b/src/wiki/views.py @@ -7,6 +7,7 @@ import logging from time import mktime from urllib.parse import quote +from django.apps import apps from django.conf import settings from django.urls import reverse from django import http @@ -275,6 +276,8 @@ def revision(request, chunk_id): doc = get_object_or_404(Chunk, pk=chunk_id) if not doc.book.accessible(request): return HttpResponseForbidden("Not authorized.") + Presence = apps.get_model('team', 'Presence') + Presence.report(request.user, doc, request.GET.get('a') == 'true') return http.HttpResponse(str(doc.revision()))