opt-in presence record
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 22 May 2023 13:32:31 +0000 (15:32 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 22 May 2023 13:32:31 +0000 (15:32 +0200)
12 files changed:
src/redakcja/settings/__init__.py
src/redakcja/static/js/wiki/loader.js
src/redakcja/static/js/wiki/wikiapi.js
src/team/__init__.py [new file with mode: 0644]
src/team/admin.py [new file with mode: 0644]
src/team/apps.py [new file with mode: 0644]
src/team/migrations/0001_initial.py [new file with mode: 0644]
src/team/migrations/__init__.py [new file with mode: 0644]
src/team/models.py [new file with mode: 0644]
src/team/tests.py [new file with mode: 0644]
src/team/views.py [new file with mode: 0644]
src/wiki/views.py

index ecebe40..95956d9 100644 (file)
@@ -106,6 +106,7 @@ INSTALLED_APPS = (
     'email_mangler',
     'wlxml.apps.WlxmlConfig',
     'alerts',
     'email_mangler',
     'wlxml.apps.WlxmlConfig',
     'alerts',
+    'team',
 )
 
 if DEBUG:
 )
 
 if DEBUG:
index 1573c76..7f7d1b1 100644 (file)
@@ -115,7 +115,18 @@ $(function()
                                e.returnValue = "Na stronie mogą być nie zapisane zmiany.";
                                return "Na stronie mogą być nie zapisane zmiany.";
                        };
                                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");
 
 
                console.log("Fetching document's text");
 
@@ -145,7 +156,7 @@ $(function()
                             $('#header').addClass('out-of-date');
                             clearInterval(revTimer);
                         }});
                             $('#header').addClass('out-of-date');
                             clearInterval(revTimer);
                         }});
-                    }, 300000);
+                    }, 60 * 1000);
                        },
                        failure: function() {
                                $('#loading-overlay').fadeOut();
                        },
                        failure: function() {
                                $('#loading-overlay').fadeOut();
index b9d36be..b53bf06 100644 (file)
@@ -86,6 +86,7 @@
                this.galleryImages = [];
                this.text = null;
                this.has_local_changes = false;
                this.galleryImages = [];
                this.text = null;
                this.has_local_changes = false;
+                this.active = true;
                this._lock = -1;
                this._context_lock = -1;
                this._lock_count = 0;
                this._lock = -1;
                this._context_lock = -1;
                this._lock_count = 0;
     WikiDocument.prototype.checkRevision = function(params) {
         /* this doesn't modify anything, so no locks */
         var self = this;
     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),
         $.ajax({
             method: "GET",
             url: reverse("ajax_document_rev", self.id),
+            data: {
+                'a': active,
+            },
             dataType: 'text',
             success: function(data) {
                 if (data == '') {
             dataType: 'text',
             success: function(data) {
                 if (data == '') {
diff --git a/src/team/__init__.py b/src/team/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/team/admin.py b/src/team/admin.py
new file mode 100644 (file)
index 0000000..cff6321
--- /dev/null
@@ -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 (file)
index 0000000..dbb3319
--- /dev/null
@@ -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 (file)
index 0000000..4e2f1c4
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/src/team/models.py b/src/team/models.py
new file mode 100644 (file)
index 0000000..05372c4
--- /dev/null
@@ -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 (file)
index 0000000..7ce503c
--- /dev/null
@@ -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 (file)
index 0000000..91ea44a
--- /dev/null
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
index cf67abb..543a473 100644 (file)
@@ -7,6 +7,7 @@ import logging
 from time import mktime
 from urllib.parse import quote
 
 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
 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.")
     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()))
 
 
     return http.HttpResponse(str(doc.revision()))