[damned-lies] Add timezone support



commit 5181fdee3c92e21b086181b1ad28ec8f1a541f29
Author: Claude Paroz <claude 2xlibre net>
Date:   Tue Dec 7 17:43:30 2021 +0100

    Add timezone support

 common/tests.py                 |  8 +++---
 damnedlies/settings.py          |  2 ++
 people/models.py                |  7 ++---
 people/tests.py                 | 13 ++++-----
 stats/fixtures/sample_data.json | 58 ++++++++++++++++++++---------------------
 stats/models.py                 | 12 ++++-----
 teams/models.py                 |  6 ++---
 teams/tests.py                  | 12 +++++----
 vertimus/models.py              |  7 ++---
 9 files changed, 66 insertions(+), 59 deletions(-)
---
diff --git a/common/tests.py b/common/tests.py
index d7cb211c..2b1b98f3 100644
--- a/common/tests.py
+++ b/common/tests.py
@@ -1,5 +1,5 @@
 import operator
-from datetime import datetime, timedelta
+from datetime import timedelta
 from pathlib import Path
 from unittest import TestCase, skipUnless
 from unittest.mock import MagicMock, patch
@@ -8,7 +8,7 @@ from django.conf import settings
 from django.core.management import call_command
 from django.test import TestCase as DjangoTestCase
 from django.urls import reverse
-from django.utils import translation
+from django.utils import timezone, translation
 
 from people.models import Person
 from teams.models import Team, Role
@@ -55,13 +55,13 @@ class CommonTest(DjangoTestCase):
         # Unactivated person
         Person.objects.create(
             first_name='John', last_name='Reviewer',
-            username='jr', date_joined=datetime.now() - timedelta(days=11),
+            username='jr', date_joined=timezone.now() - timedelta(days=11),
             activation_key='non-activated-key'
         )
 
         inactive = Person.objects.create(
             first_name='John', last_name='Translator',
-            username='jt', last_login=datetime.now() - timedelta(days=30 * 6 + 1),
+            username='jt', last_login=timezone.now() - timedelta(days=30 * 6 + 1),
         )
 
         t1 = Team.objects.create(name='fr', description='French')
diff --git a/damnedlies/settings.py b/damnedlies/settings.py
index 9c98940e..1d261546 100644
--- a/damnedlies/settings.py
+++ b/damnedlies/settings.py
@@ -58,6 +58,8 @@ USE_I18N = True
 USE_L10N = True
 LOCALE_PATHS = [BASE_DIR / 'locale']
 
+USE_TZ = True
+
 # Absolute path to the directory that holds media.
 MEDIA_ROOT = BASE_DIR / 'media'
 
diff --git a/people/models.py b/people/models.py
index afa5bb37..e814e70a 100644
--- a/people/models.py
+++ b/people/models.py
@@ -1,12 +1,13 @@
 import binascii
-import datetime
 import os
 import re
+from datetime import timedelta
 
 from django.contrib.auth.models import User, UserManager
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import models
 from django.urls import reverse
+from django.utils import timezone
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
 from django.utils.translation import gettext_lazy as _
@@ -54,7 +55,7 @@ class Person(User):
     def clean_unactivated_accounts(cls):
         accounts = cls.objects.filter(
             activation_key__isnull=False,
-            date_joined__lt=(datetime.datetime.now() - datetime.timedelta(days=10))
+            date_joined__lt=(timezone.now() - timedelta(days=10))
         ).exclude(activation_key='')
         for account in accounts:
             account.delete()
@@ -72,7 +73,7 @@ class Person(User):
         ).annotate(
             num_states=models.Count('state')
         ).filter(
-            last_login__lt=(datetime.datetime.now() - datetime.timedelta(days=730))
+            last_login__lt=(timezone.now() - timedelta(days=730))
         ).exclude(
             role__role='coordinator'
         ).exclude(
diff --git a/people/tests.py b/people/tests.py
index 19ca6eac..39b205f9 100644
--- a/people/tests.py
+++ b/people/tests.py
@@ -1,4 +1,4 @@
-import datetime
+from datetime import timedelta
 from unittest import mock, skipUnless
 
 from django.contrib import auth
@@ -7,6 +7,7 @@ from django.core import mail
 from django.core.exceptions import ValidationError
 from django.test import TestCase, Client
 from django.urls import reverse
+from django.utils import timezone
 from django.utils.safestring import SafeData
 from django.utils.translation import gettext as _
 
@@ -173,14 +174,14 @@ class PeopleTestCase(TestCase):
         lang = Language.objects.create(name='French', locale='fr', team=team)
 
         # Create Users
-        p1 = self._create_person(seq='1', last_login=datetime.datetime.now() - datetime.timedelta(days=700))
-        p2 = self._create_person(seq='2', last_login=datetime.datetime.now() - datetime.timedelta(days=800))
+        p1 = self._create_person(seq='1', last_login=timezone.now() - timedelta(days=700))
+        p2 = self._create_person(seq='2', last_login=timezone.now() - timedelta(days=800))
         Role.objects.create(team=team, person=p2, role='coordinator')
-        p3 = self._create_person(seq='3', last_login=datetime.datetime.now() - datetime.timedelta(days=800))
+        p3 = self._create_person(seq='3', last_login=timezone.now() - timedelta(days=800))
         module.maintainers.add(p3)
-        p4 = self._create_person(seq='4', last_login=datetime.datetime.now() - datetime.timedelta(days=800))
+        p4 = self._create_person(seq='4', last_login=timezone.now() - timedelta(days=800))
         StateTranslating.objects.create(branch=branch, domain=domain, language=lang, person=p4)
-        self._create_person(seq='5', last_login=datetime.datetime.now() - datetime.timedelta(days=800))
+        self._create_person(seq='5', last_login=timezone.now() - timedelta(days=800))
         # Test only p5 should be deleted
         self.assertEqual(Person.objects.all().count(), 5)
         Person.clean_obsolete_accounts()
diff --git a/stats/fixtures/sample_data.json b/stats/fixtures/sample_data.json
index e273a2b2..1e87ac8c 100644
--- a/stats/fixtures/sample_data.json
+++ b/stats/fixtures/sample_data.json
@@ -7,12 +7,12 @@
   "is_active": true,
   "is_superuser": false,
   "is_staff": false,
-  "last_login": "2015-09-09T18:27:04",
+  "last_login": "2015-09-09T18:27:04Z",
   "groups": [],
   "user_permissions": [],
   "password": "!XmjxDUfBch5HinrLIWk7MUjJnVBJyHkjTi4FmXVi",
   "email": "bob example org",
-  "date_joined": "2015-09-09T18:27:04"
+  "date_joined": "2015-09-09T18:27:04Z"
  },
  "model": "auth.user",
  "pk": 2
@@ -25,12 +25,12 @@
   "is_active": true,
   "is_superuser": false,
   "is_staff": false,
-  "last_login": "2015-09-09T18:27:04",
+  "last_login": "2015-09-09T18:27:04Z",
   "groups": [],
   "user_permissions": [],
   "password": "!JHtSuqoDng9UMWR9s0Mm0kt9G5kZeigdAcwmt1yJ",
   "email": "coord example org",
-  "date_joined": "2015-09-09T18:27:04"
+  "date_joined": "2015-09-09T18:27:04Z"
  },
  "model": "auth.user",
  "pk": 3
@@ -43,12 +43,12 @@
   "is_active": true,
   "is_superuser": false,
   "is_staff": false,
-  "last_login": "2015-09-09T18:27:04",
+  "last_login": "2015-09-09T18:27:04Z",
   "groups": [],
   "user_permissions": [],
   "password": "!QBaPicJyWyy0eIVwoyzfKjGJp9QznzSA70j84WSq",
   "email": "alessio example org",
-  "date_joined": "2015-09-09T18:27:04"
+  "date_joined": "2015-09-09T18:27:04Z"
  },
  "model": "auth.user",
  "pk": 4
@@ -579,7 +579,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 47,
@@ -594,7 +594,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -609,7 +609,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 7,
@@ -624,7 +624,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 20,
@@ -641,7 +641,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -656,7 +656,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -671,7 +671,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 136,
@@ -686,7 +686,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 128,
@@ -701,7 +701,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -716,7 +716,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 6,
@@ -731,7 +731,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 28,
@@ -746,7 +746,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 259,
@@ -761,7 +761,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 259,
@@ -776,7 +776,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -791,7 +791,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 149,
@@ -806,7 +806,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -821,7 +821,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -836,7 +836,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 259,
@@ -851,7 +851,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 259,
@@ -866,7 +866,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
@@ -881,7 +881,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 626,
@@ -896,7 +896,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 2,
@@ -911,7 +911,7 @@
 },
 {
  "fields": {
-  "updated": "2015-09-09T18:27:04",
+  "updated": "2015-09-09T18:27:04Z",
   "untranslated_words": 0,
   "fuzzy_words": 0,
   "untranslated": 0,
diff --git a/stats/models.py b/stats/models.py
index c92668b7..102d3ff3 100644
--- a/stats/models.py
+++ b/stats/models.py
@@ -17,14 +17,14 @@ from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.management import call_command
 from django.core.validators import RegexValidator
+from django.db import models
+from django.db.models.functions import Coalesce
 from django.templatetags.static import static
 from django.urls import reverse
+from django.utils import dateformat, timezone
 from django.utils.encoding import force_str
 from django.utils.functional import cached_property
 from django.utils.translation import ngettext, gettext as _, gettext_noop
-from django.utils import dateformat
-from django.db import models
-from django.db.models.functions import Coalesce
 
 from common.utils import is_site_admin, run_shell_command
 from stats import repos, signals, utils
@@ -203,7 +203,7 @@ class ModuleLock:
                 self.dirpath.mkdir()
                 break
             except FileExistsError:
-                if (datetime.now() - datetime.fromtimestamp(self.dirpath.stat().st_ctime)).days > 1:
+                if (timezone.now() - datetime.fromtimestamp(self.dirpath.stat().st_ctime)).days > 1:
                     # After more than one day, something was blocked, force release the lock.
                     self.dirpath.rmdir()
                 else:
@@ -1667,7 +1667,7 @@ class Statistics(models.Model):
         self.full_po.fuzzy_words = int(stats['fuzzy_words'])
         self.full_po.untranslated_words = int(stats['untranslated_words'])
         self.full_po.figures = fig_stats
-        self.full_po.updated = datetime.now()
+        self.full_po.updated = timezone.now()
         self.full_po.save()
 
         if self.domain.dtype == "ui":
@@ -1710,7 +1710,7 @@ class Statistics(models.Model):
                     self.part_po.translated_words = part_stats['translated_words']
                     self.part_po.fuzzy_words = part_stats['fuzzy_words']
                     self.part_po.untranslated_words = part_stats['untranslated_words']
-                    self.part_po.updated = datetime.now()
+                    self.part_po.updated = timezone.now()
                     self.part_po.save()
             else:
                 part_po_equals_full_po()
diff --git a/teams/models.py b/teams/models.py
index 188925b9..0faff942 100644
--- a/teams/models.py
+++ b/teams/models.py
@@ -1,9 +1,9 @@
-from datetime import datetime, timedelta
+from datetime import timedelta
 
 from django.conf import settings
 from django.db import models
 from django.urls import reverse
-from django.utils import translation
+from django.utils import timezone, translation
 from django.utils.translation import gettext_lazy, gettext as _
 
 from common.utils import send_mail
@@ -244,7 +244,7 @@ class Role(models.Model):
     @classmethod
     def inactivate_unused_roles(cls):
         """ Inactivate the roles when login older than 180 days  """
-        last_login = datetime.now() - timedelta(days=30 * 6)
+        last_login = timezone.now() - timedelta(days=30 * 6)
         cls.objects.filter(
             person__last_login__lt=last_login, is_active=True
         ).update(is_active=False)
diff --git a/teams/tests.py b/teams/tests.py
index c1e6fc1e..f244bda1 100644
--- a/teams/tests.py
+++ b/teams/tests.py
@@ -1,9 +1,10 @@
-from datetime import datetime, timedelta
+from datetime import timedelta
 
 from django.conf import settings
 from django.core import mail
 from django.test import TestCase
 from django.urls import reverse
+from django.utils import timezone
 from django.utils.translation import gettext_lazy
 
 from people.models import Person
@@ -36,7 +37,7 @@ class TeamsAndRolesMixin:
         cls.pc = Person.objects.create(
             first_name='John', last_name='Committer',
             email='jc alinsudesonpleingre fr', username='jc',
-            last_login=datetime.now() - timedelta(days=30 * 6 - 1)
+            last_login=timezone.now() - timedelta(days=30 * 6 - 1)
         )
 
         cls.pcoo = Person(
@@ -290,13 +291,14 @@ class RoleTest(TeamsAndRolesMixin, TestCase):
     def setUp(self):
         super().setUp()
 
-        self.pt.last_login = datetime.now() - timedelta(days=10)  # active person
+        self.pt.last_login = timezone.now() - timedelta(days=10)  # active person
         self.pt.save()
 
-        self.pr.last_login = datetime.now() - timedelta(days=30 * 6 + 1)  # inactive person
+        self.pr.last_login = timezone.now() - timedelta(days=30 * 6 + 1)  # inactive person
         self.pr.save()
 
-        self.pc.last_login = datetime.now() - timedelta(days=30 * 6 - 1)  # active person, but in limit date
+        # active person, but in limit date
+        self.pc.last_login = timezone.now() - timedelta(days=30 * 6 - 1)
         self.pc.save()
 
         self.role = Role.objects.get(team=self.t, person=self.pt)
diff --git a/vertimus/models.py b/vertimus/models.py
index fbd4b03a..b6cdb00f 100644
--- a/vertimus/models.py
+++ b/vertimus/models.py
@@ -1,7 +1,7 @@
 import os
 import shutil
 import sys
-from datetime import datetime, timedelta
+from datetime import timedelta
 
 from django.conf import settings
 from django.db import models
@@ -9,6 +9,7 @@ from django.db.models import Max, Q
 from django.db.models.signals import post_save, pre_delete
 from django.dispatch import receiver
 from django.urls import reverse
+from django.utils import timezone
 from django.utils.translation import (
     override, gettext, gettext_noop, gettext_lazy as _, to_language
 )
@@ -465,7 +466,7 @@ class Action(ActionAbstract):
 
     def save(self, *args, **kwargs):
         if not self.id and not self.created:
-            self.created = datetime.today()
+            self.created = timezone.now()
         super().save(*args, **kwargs)
 
     def update_state(self):
@@ -607,7 +608,7 @@ class ActionArchived(ActionAbstract):
         ).annotate(
             max_created=Max('created')
         ).filter(
-            max_created__lt=datetime.now() - timedelta(days=days)
+            max_created__lt=timezone.now() - timedelta(days=days)
         ):
             # Call each action delete() so as file is also deleted
             for act in ActionArchived.objects.filter(sequence=action['sequence']):


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]