Merge branch 'feat/tzaware' into dev/main-for-tzaware-merge

This commit is contained in:
Jennifer Richards 2022-10-28 14:40:04 -03:00
commit 0caf946e48
No known key found for this signature in database
GPG key ID: 26801E4DC0928410
192 changed files with 2987 additions and 1422 deletions

View file

@ -144,6 +144,8 @@ jobs:
run: |
echo "Running checks..."
./ietf/manage.py check
./ietf/manage.py migrate || true
echo "USE_TZ = True" >> ./ietf/settings_local.py
./ietf/manage.py migrate
echo "Validating migrations..."
if ! ( ietf/manage.py makemigrations --dry-run --check --verbosity 3 ) ; then

View file

@ -16,6 +16,7 @@ from django.conf import settings
from django.core.validators import validate_email, ValidationError
from ietf.utils.draft import PlaintextDraft
from ietf.submit.utils import update_authors
from ietf.utils.timezone import date_today
import debug # pyflakes:ignore
@ -66,9 +67,9 @@ for name in sorted(names):
print name, rev, "Can't parse", p,":",e
continue
if draft.errors and draft.errors.keys()!=['draftname',]:
print "Errors - could not process", name, rev, datetime.datetime.fromtimestamp(p.stat().st_mtime), draft.errors, draft.get_title().encode('utf8')
print "Errors - could not process", name, rev, datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc), draft.errors, draft.get_title().encode('utf8')
else:
time = datetime.datetime.fromtimestamp(p.stat().st_mtime)
time = datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc)
if not doc:
doc = Document.objects.create(name=name,
time=time,
@ -140,7 +141,7 @@ for name in sorted(names):
doc = doc,
rev = rev,
by = system,
desc = "Revision added from id-archive on %s by %s"%(datetime.date.today(),sys.argv[0]),
desc = "Revision added from id-archive on %s by %s"%(date_today(),sys.argv[0]),
time=time,
)
events.append(e)

View file

@ -162,7 +162,7 @@ def get_first_commit(path):
else:
pass
except OSError:
rev, who, when = None, None, datetime.datetime.now()
rev, who, when = None, None, datetime.datetime.now(datetime.timezone.utc)
return { path: { 'rev': rev, 'who': who, 'date': when.strftime('%Y-%m-%d %H:%M:%S'), }, }

View file

@ -9,7 +9,31 @@ chmod +x ./app-create-dirs.sh
./app-create-dirs.sh
echo "Running Datatracker checks..."
./ietf/manage.py check
echo "Running Datatracker migrations..."
./ietf/manage.py migrate
# Migrate, adjusting to what the current state of the underlying database might be:
WORKSPACEDIR=.
if ietf/manage.py showmigrations | grep "\[ \] 0003_pause_to_change_use_tz"; then
if grep "USE_TZ" $WORKSPACEDIR/ietf/settings_local.py; then
cat $WORKSPACEDIR/ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = False/' > /tmp/settings_local.py && mv /tmp/settings_local.py $WORKSPACEDIR/ietf/settings_local.py
else
echo "USE_TZ = False" >> $WORKSPACEDIR/ietf/settings_local.py
fi
echo "Running Datatracker migrations with USE_TZ = False..."
# This is expected to exit non-zero at the pause
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local || true
cat $WORKSPACEDIR/ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = True/' > /tmp/settings_local.py && mv /tmp/settings_local.py $WORKSPACEDIR/ietf/settings_local.py
echo "Running Datatracker migrations with USE_TZ = True..."
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local
else
if grep "USE_TZ" $WORKSPACEDIR/ietf/settings_local.py; then
cat $WORKSPACEDIR/ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = True/' > /tmp/settings_local.py && mv /tmp/settings_local.py $WORKSPACEDIR/ietf/settings_local.py
else
echo "USE_TZ = True" >> $WORKSPACEDIR/ietf/settings_local.py
echo "Running Datatracker migrations..."
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local
fi
fi
echo "Starting Datatracker..."
./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local

View file

@ -12,5 +12,24 @@ yarn legacy:build
echo "Creating data directories..."
chmod +x ./docker/scripts/app-create-dirs.sh
./docker/scripts/app-create-dirs.sh
./ietf/manage.py check
./ietf/manage.py migrate
if ./ietf/manage.py showmigrations | grep "\[ \] 0003_pause_to_change_use_tz"; then
if grep "USE_TZ" ./ietf/settings_local.py; then
cat ./ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = False/' > /tmp/settings_local.py && mv /tmp/settings_local.py ./ietf/settings_local.py
else
echo "USE_TZ = False" >> ./ietf/settings_local.py
fi
# This is expected to exit non-zero at the pause
/usr/local/bin/python ./ietf/manage.py migrate || true
cat ./ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = True/' > /tmp/settings_local.py && mv /tmp/settings_local.py ./ietf/settings_local.py
/usr/local/bin/python ./ietf/manage.py migrate
else
if grep "USE_TZ" ./ietf/settings_local.py; then
cat ./ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = True/' > /tmp/settings_local.py && mv /tmp/settings_local.py ./ietf/settings_local.py
else
echo "USE_TZ = True" >> ./ietf/settings_local.py
/usr/local/bin/python ./ietf/manage.py migrate
fi
fi

View file

@ -100,7 +100,28 @@ echo "Starting memcached..."
echo "Running initial checks..."
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py check --settings=settings_local
# /usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local
# Migrate, adjusting to what the current state of the underlying database might be:
if ietf/manage.py showmigrations | grep "\[ \] 0003_pause_to_change_use_tz"; then
if grep "USE_TZ" $WORKSPACEDIR/ietf/settings_local.py; then
cat $WORKSPACEDIR/ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = False/' > /tmp/settings_local.py && mv /tmp/settings_local.py $WORKSPACEDIR/ietf/settings_local.py
else
echo "USE_TZ = False" >> $WORKSPACEDIR/ietf/settings_local.py
fi
# This is expected to exit non-zero at the pause
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local || true
cat $WORKSPACEDIR/ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = True/' > /tmp/settings_local.py && mv /tmp/settings_local.py $WORKSPACEDIR/ietf/settings_local.py
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local
else
if grep "USE_TZ" $WORKSPACEDIR/ietf/settings_local.py; then
cat $WORKSPACEDIR/ietf/settings_local.py | sed 's/USE_TZ.*$/USE_TZ = True/' > /tmp/settings_local.py && mv /tmp/settings_local.py $WORKSPACEDIR/ietf/settings_local.py
else
echo "USE_TZ = True" >> $WORKSPACEDIR/ietf/settings_local.py
/usr/local/bin/python $WORKSPACEDIR/ietf/manage.py migrate --settings=settings_local
fi
fi
echo "-----------------------------------------------------------------"
echo "Done!"

View file

@ -3,7 +3,6 @@
import os
import datetime
import collections
import io
@ -14,6 +13,7 @@ import debug # pyflakes:ignore
from django.core.management.base import AppCommand
from django.db import models
from django.template import Template, Context
from django.utils import timezone
from tastypie.resources import ModelResource
@ -89,7 +89,7 @@ class Command(AppCommand):
info = dict(
app=app.name,
app_label=app.label,
date=datetime.datetime.now()
date=timezone.now()
)
new_models = {}
for model, rclass_name in missing_resources:

View file

@ -32,6 +32,7 @@ from ietf.person.models import User
from ietf.person.models import PersonalApiKey
from ietf.stats.models import MeetingRegistration
from ietf.utils.mail import outbox, get_payload_text
from ietf.utils.models import DumpInfo
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
OMITTED_APPS = (
@ -508,10 +509,17 @@ class CustomApiTests(TestCase):
self.assertEqual(set(missing_fields), set(drop_fields))
def test_api_version(self):
DumpInfo.objects.create(date=timezone.datetime(2022,8,31,7,10,1,tzinfo=timezone.utc), host='testapi.example.com',tz='UTC')
url = urlreverse('ietf.api.views.version')
r = self.client.get(url)
data = r.json()
self.assertEqual(data['version'], ietf.__version__+ietf.__patch__)
self.assertEqual(data['dumptime'], "2022-08-31 07:10:01 +0000")
DumpInfo.objects.update(tz='PST8PDT')
r = self.client.get(url)
data = r.json()
self.assertEqual(data['dumptime'], "2022-08-31 07:10:01 -0700")
def test_api_appauth(self):
url = urlreverse('ietf.api.views.app_auth')

View file

@ -203,8 +203,13 @@ def api_new_meeting_registration(request):
def version(request):
dumpdate = None
dumpinfo = DumpInfo.objects.order_by('-date').first()
dumptime = pytz.timezone(dumpinfo.tz).localize(dumpinfo.date).strftime('%Y-%m-%d %H:%M:%S %z') if dumpinfo else None
if dumpinfo:
dumpdate = dumpinfo.date
if dumpinfo.tz != "UTC":
dumpdate = pytz.timezone(dumpinfo.tz).localize(dumpinfo.date.replace(tzinfo=None))
dumptime = dumpdate.strftime('%Y-%m-%d %H:%M:%S %z') if dumpinfo else None
return HttpResponse(
json.dumps({
'version': ietf.__version__+ietf.__patch__,

View file

@ -28,7 +28,7 @@ def warn(string):
# ------------------------------------------------------------------------------
import re
from datetime import datetime as Datetime
import datetime
import django
django.setup()
@ -44,7 +44,7 @@ system_entity = Person.objects.get(name="(System)")
charterdir = Path(settings.CHARTER_PATH)
for file in charterdir.files("charter-ietf-*.txt"):
fname = file.name
ftime = Datetime.fromtimestamp(file.mtime)
ftime = datetime.datetime.fromtimestamp(file.mtime, datetime.timezone.utc)
match = re.search("^(?P<name>[a-z0-9-]+)-(?P<rev>\d\d-\d\d)\.txt$", fname)
if match:
name = match.group("name")

View file

@ -18,6 +18,7 @@ django.setup()
from django.conf import settings
from optparse import OptionParser
from zoneinfo import ZoneInfo
parser = OptionParser()
parser.add_option("-f", "--from", dest="start",
@ -38,13 +39,16 @@ CLOCK_SKEW_COMPENSATION = 5 # seconds
MAX_INTERVAL_ACCEPTED_BY_IANA = datetime.timedelta(hours=23)
local_tzinfo = ZoneInfo(settings.TIME_ZONE)
start = datetime.datetime.now() - datetime.timedelta(hours=23) + datetime.timedelta(seconds=CLOCK_SKEW_COMPENSATION)
if options.start:
start = datetime.datetime.strptime(options.start, "%Y-%m-%d %H:%M:%S")
start = start.replace(tzinfo=local_tzinfo).astimezone(datetime.timezone.utc)
end = start + datetime.timedelta(hours=23)
if options.end:
end = datetime.datetime.strptime(options.end, "%Y-%m-%d %H:%M:%S")
end = datetime.datetime.strptime(options.end, "%Y-%m-%d %H:%M:%S").replace(tzinfo=local_tzinfo)
end = end.astimezone(datetime.timezone.utc)
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_USER)
@ -52,7 +56,13 @@ syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_USER)
from ietf.sync.iana import fetch_changes_json, parse_changes_json, update_history_with_changes
syslog.syslog("Updating history log with new changes from IANA from %s, period %s - %s" % (settings.IANA_SYNC_CHANGES_URL, start, end))
syslog.syslog(
"Updating history log with new changes from IANA from %s, period %s - %s" % (
settings.IANA_SYNC_CHANGES_URL,
start.astimezone(local_tzinfo),
end.astimezone(local_tzinfo),
)
)
t = start
while t < end:

View file

@ -29,6 +29,7 @@ from django.core.mail import mail_admins
from ietf.doc.utils import rebuild_reference_relations
from ietf.utils.log import log
from ietf.utils.pipe import pipe
from ietf.utils.timezone import date_today
import ietf.sync.rfceditor
@ -39,7 +40,7 @@ parser.add_option("-d", dest="skip_date",
options, args = parser.parse_args()
skip_date = datetime.date.today() - datetime.timedelta(days=365)
skip_date = date_today() - datetime.timedelta(days=365)
if options.skip_date:
skip_date = datetime.datetime.strptime(options.skip_date, "%Y-%m-%d").date()

View file

@ -26,8 +26,9 @@ from ietf.review.utils import (
send_unavailability_period_ending_reminder, send_reminder_all_open_reviews,
send_review_reminder_overdue_assignment, send_reminder_unconfirmed_assignments)
from ietf.utils.log import log
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
today = datetime.date.today()
today = date_today(DEADLINE_TZINFO)
for assignment in review_assignments_needing_reviewer_reminder(today):
email_reviewer_reminder(assignment)

View file

@ -3,7 +3,7 @@
# This script requires that the proper virtual python environment has been
# invoked before start
import datetime, os, sys
import os, sys
import syslog
# boilerplate
@ -16,6 +16,7 @@ syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_USER)
import django
django.setup()
from django.utils import timezone
from ietf.utils.mail import log_smtp_exception, send_error_email
from smtplib import SMTPException
@ -32,7 +33,7 @@ from ietf.message.models import SendQueue
mode = sys.argv[1]
now = datetime.datetime.now()
now = timezone.now()
needs_sending = SendQueue.objects.filter(sent_at=None).select_related("message")
if mode == "specific":

View file

@ -10,6 +10,7 @@ import uuid
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import get_object_or_404, render
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from django.utils.html import strip_tags
import debug # pyflakes:ignore
@ -218,7 +219,7 @@ def feed(request, username=None, acronym=None, group_type=None):
significant = request.GET.get('significant', '') == '1'
documents = docs_tracked_by_community_list(clist).values_list('pk', flat=True)
since = datetime.datetime.now() - datetime.timedelta(days=14)
since = timezone.now() - datetime.timedelta(days=14)
events = DocEvent.objects.filter(
doc__id__in=documents,
@ -243,7 +244,7 @@ def feed(request, username=None, acronym=None, group_type=None):
'title': title,
'subtitle': subtitle,
'id': feed_id.urn,
'updated': datetime.datetime.now(),
'updated': timezone.now(),
}, content_type='text/xml')

View file

@ -4,6 +4,7 @@
from django.conf import settings
from django.utils import timezone
import datetime, os, shutil, glob, re
from pathlib import Path
@ -17,6 +18,7 @@ from ietf.person.models import Person
from ietf.meeting.models import Meeting
from ietf.doc.utils import add_state_change_event, update_action_holders
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO
nonexpirable_states: Optional[List[State]] = None
@ -52,17 +54,17 @@ def expirable_drafts(queryset=None):
def get_soon_to_expire_drafts(days_of_warning):
start_date = datetime.date.today() - datetime.timedelta(1)
start_date = datetime_today(DEADLINE_TZINFO) - datetime.timedelta(1)
end_date = start_date + datetime.timedelta(days_of_warning)
return expirable_drafts().filter(expires__gte=start_date, expires__lt=end_date)
def get_expired_drafts():
return expirable_drafts().filter(expires__lt=datetime.date.today() + datetime.timedelta(1))
return expirable_drafts().filter(expires__lt=datetime_today(DEADLINE_TZINFO) + datetime.timedelta(1))
def in_draft_expire_freeze(when=None):
if when == None:
when = datetime.datetime.now()
when = timezone.now()
meeting = Meeting.objects.filter(type='ietf', date__gte=when-datetime.timedelta(days=7)).order_by('date').first()
@ -84,7 +86,7 @@ def send_expire_warning_for_draft(doc):
(doc.get_state_slug("draft") != "active")):
return # don't warn about dead or inactive documents
expiration = doc.expires.date()
expiration = doc.expires.astimezone(DEADLINE_TZINFO).date()
(to,cc) = gather_address_lists('doc_expires_soon',doc=doc)
@ -171,7 +173,7 @@ def expire_draft(doc):
def clean_up_draft_files():
"""Move unidentified and old files out of the Internet Draft directory."""
cut_off = datetime.date.today()
cut_off = date_today(DEADLINE_TZINFO)
pattern = os.path.join(settings.INTERNET_DRAFT_PATH, "draft-*.*")
filename_re = re.compile(r'^(.*)-(\d\d)$')
@ -214,7 +216,9 @@ def clean_up_draft_files():
if state in ("rfc","repl"):
move_file_to("")
elif state in ("expired", "auth-rm", "ietf-rm") and doc.expires and doc.expires.date() < cut_off:
elif (state in ("expired", "auth-rm", "ietf-rm")
and doc.expires
and doc.expires.astimezone(DEADLINE_TZINFO).date() < cut_off):
move_file_to("")
except Document.DoesNotExist:

View file

@ -10,6 +10,7 @@ import datetime
from typing import Optional # pyflakes:ignore
from django.conf import settings
from django.utils import timezone
from ietf.doc.models import ( Document, DocEvent, NewRevisionDocEvent, DocAlias, State, DocumentAuthor,
StateDocEvent, BallotPositionDocEvent, BallotDocEvent, BallotType, IRSGBallotDocEvent, TelechatDocEvent,
@ -18,6 +19,7 @@ from ietf.group.models import Group
from ietf.person.factories import PersonFactory
from ietf.group.factories import RoleFactory
from ietf.utils.text import xslugify
from ietf.utils.timezone import date_today
def draft_name_generator(type_id,group,n):
@ -38,7 +40,7 @@ class BaseDocumentFactory(factory.django.DjangoModelFactory):
rev = '00'
std_level_id = None # type: Optional[str]
intended_std_level_id = None
time = datetime.datetime.now()
time = timezone.now()
expires = factory.LazyAttribute(lambda o: o.time+datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE))
pages = factory.fuzzy.FuzzyInteger(2,400)
@ -320,7 +322,7 @@ class ConflictReviewFactory(BaseDocumentFactory):
# This is very skeletal. It is enough for the tests that use it now, but when it's needed, it will need to be improved with, at least, a group generator that backs the object with a review team.
class ReviewFactory(BaseDocumentFactory):
type_id = 'review'
name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,datetime.date.today().isoformat()))
name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,date_today().isoformat()))
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='review')
class DocAliasFactory(factory.django.DjangoModelFactory):
@ -357,7 +359,8 @@ class TelechatDocEventFactory(DocEventFactory):
class Meta:
model = TelechatDocEvent
telechat_date = datetime.datetime.today()+datetime.timedelta(days=14)
# note: this is evaluated at import time and not updated - all events will have the same telechat_date
telechat_date = timezone.now()+datetime.timedelta(days=14)
type = 'scheduled_for_telechat'
class NewRevisionDocEventFactory(DocEventFactory):
@ -410,7 +413,7 @@ class IRSGBallotDocEventFactory(BallotDocEventFactory):
class Meta:
model = IRSGBallotDocEvent
duedate = datetime.datetime.now() + datetime.timedelta(days=14)
duedate = timezone.now() + datetime.timedelta(days=14)
ballot_type = factory.SubFactory(BallotTypeFactory, slug='irsg-approve')
class BallotPositionDocEventFactory(DocEventFactory):

View file

@ -10,11 +10,13 @@ from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
from django.urls import reverse as urlreverse
from django.template.defaultfilters import truncatewords, truncatewords_html, date as datefilter
from django.template.defaultfilters import linebreaks # type: ignore
from django.utils import timezone
from django.utils.html import strip_tags
from ietf.doc.models import Document, State, LastCallDocEvent, DocEvent
from ietf.doc.utils import augment_events_with_revision
from ietf.doc.templatetags.ietf_filters import format_textarea
from ietf.utils.timezone import RPC_TZINFO
def strip_control_characters(s):
@ -133,9 +135,16 @@ class RfcFeed(Feed):
def items(self):
if self.year:
rfc_events = DocEvent.objects.filter(type='published_rfc',time__year=self.year).order_by('-time')
# Find published RFCs based on their official publication year
start_of_year = datetime.datetime(int(self.year), 1, 1, tzinfo=RPC_TZINFO)
start_of_next_year = datetime.datetime(int(self.year) + 1, 1, 1, tzinfo=RPC_TZINFO)
rfc_events = DocEvent.objects.filter(
type='published_rfc',
time__gte=start_of_year,
time__lt=start_of_next_year,
).order_by('-time')
else:
cutoff = datetime.datetime.now() - datetime.timedelta(days=8)
cutoff = timezone.now() - datetime.timedelta(days=8)
rfc_events = DocEvent.objects.filter(type='published_rfc',time__gte=cutoff).order_by('-time')
results = [(e.doc, e.time) for e in rfc_events]
for doc,time in results:

View file

@ -15,6 +15,7 @@ from ietf.person.fields import SearchablePersonField, SearchablePersonsField
from ietf.person.models import Email, Person
from ietf.name.models import ExtResourceName
from ietf.utils.timezone import date_today
from ietf.utils.validators import validate_external_resource_value
class TelechatForm(forms.Form):
@ -34,7 +35,7 @@ class TelechatForm(forms.Form):
for d in dates:
self.page_count[d] = telechat_page_count(date=d).for_approval
choice_display[d] = '%s (%s pages)' % (d.strftime("%Y-%m-%d"),self.page_count[d])
if d-datetime.date.today() < datetime.timedelta(days=13):
if d - date_today() < datetime.timedelta(days=13):
choice_display[d] += ' : WARNING - this may not leave enough time for directorate reviews!'
self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, choice_display[d]) for d in dates]

View file

@ -1,7 +1,5 @@
# helpers for handling last calls on Internet Drafts
import datetime
from django.db.models import Q
from ietf.doc.models import Document, State, DocEvent, LastCallDocEvent, WriteupDocEvent
@ -10,6 +8,8 @@ from ietf.person.models import Person
from ietf.doc.utils import add_state_change_event, update_action_holders
from ietf.doc.mails import generate_ballot_writeup, generate_approval_mail, generate_last_call_announcement
from ietf.doc.mails import send_last_call_request, email_last_call_expired, email_last_call_expired_with_downref
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
def request_last_call(request, doc):
if not doc.latest_event(type="changed_ballot_writeup_text"):
@ -33,11 +33,10 @@ def request_last_call(request, doc):
e.save()
def get_expired_last_calls():
today = datetime.date.today()
for d in Document.objects.filter(Q(states__type="draft-iesg", states__slug="lc")
| Q(states__type="statchg", states__slug="in-lc")):
e = d.latest_event(LastCallDocEvent, type="sent_last_call")
if e and e.expires.date() <= today:
if e and e.expires.astimezone(DEADLINE_TZINFO).date() <= date_today(DEADLINE_TZINFO):
yield d
def expire_last_call(doc):

View file

@ -10,6 +10,7 @@ from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
from django.urls import reverse as urlreverse
from django.utils import timezone
from django.utils.encoding import force_text
import debug # pyflakes:ignore
@ -24,6 +25,7 @@ from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
from ietf.group.models import Role
from ietf.doc.models import Document
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
def email_state_changed(request, doc, text, mailtrigger_id=None):
@ -191,7 +193,7 @@ def generate_ballot_rfceditornote(request, doc):
return e
def generate_last_call_announcement(request, doc):
expiration_date = datetime.date.today() + datetime.timedelta(days=14)
expiration_date = date_today(DEADLINE_TZINFO) + datetime.timedelta(days=14)
if doc.group.type_id in ("individ", "area"):
group = "an individual submitter"
expiration_date += datetime.timedelta(days=14)
@ -418,7 +420,7 @@ def generate_issue_ballot_mail(request, doc, ballot):
e = doc.latest_event(LastCallDocEvent, type="sent_last_call")
last_call_expires = e.expires if e else None
last_call_has_expired = last_call_expires and last_call_expires < datetime.datetime.now()
last_call_has_expired = last_call_expires and last_call_expires < timezone.now()
return render_to_string("doc/mail/issue_iesg_ballot_mail.txt",
dict(doc=doc,
@ -437,7 +439,7 @@ def _send_irsg_ballot_email(request, doc, ballot, subject, template):
(to, cc) = gather_address_lists('irsg_ballot_issued', doc=doc)
sender = 'IESG Secretary <iesg-secretary@ietf.org>'
ballot_expired = ballot.duedate < datetime.datetime.now()
ballot_expired = ballot.duedate < timezone.now()
active_ballot = doc.active_ballot()
if active_ballot is None:
needed_bps = ''

View file

@ -16,6 +16,7 @@ from tempfile import mkstemp
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import timezone
import debug # pyflakes:ignore
@ -101,7 +102,7 @@ class Command(BaseCommand):
'that have seen activity in the last %s years.' % (DEFAULT_YEARS))
def handle(self, *args, **options):
show_since = datetime.datetime.now() - datetime.timedelta(DEFAULT_YEARS*365)
show_since = timezone.now() - datetime.timedelta(DEFAULT_YEARS*365)
date = time.strftime("%Y-%m-%d_%H:%M:%S")
signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date)

View file

@ -10,6 +10,7 @@ import sys
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import timezone
import debug # pyflakes:ignore
@ -68,7 +69,7 @@ class Command(BaseCommand):
if process_all:
doc_events = NewRevisionDocEvent.objects.filter(type='new_revision', doc__type_id='draft')
else:
start = datetime.datetime.now() - datetime.timedelta(days=days)
start = timezone.now() - datetime.timedelta(days=days)
doc_events = NewRevisionDocEvent.objects.filter(type='new_revision', doc__type_id='draft', time__gte=start)
doc_events = doc_events.order_by('time')

View file

@ -0,0 +1,39 @@
# Generated by Django 2.2.28 on 2022-07-12 11:24
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('doc', '0045_docstates_chatlogs_polls'),
]
operations = [
migrations.AlterField(
model_name='deletedevent',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name='docevent',
name='time',
field=models.DateTimeField(db_index=True, default=django.utils.timezone.now, help_text='When the event happened'),
),
migrations.AlterField(
model_name='dochistory',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name='document',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name='documentactionholder',
name='time_added',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View file

@ -0,0 +1,61 @@
# Generated by Django 2.2.28 on 2022-08-31 20:26
import datetime
import json
from zoneinfo import ZoneInfo
from django.db import migrations
TZ_BEFORE = ZoneInfo('PST8PDT')
def forward(apps, schema_editor):
DeletedEvent = apps.get_model('doc', 'DeletedEvent')
for deleted_event in DeletedEvent.objects.all():
fields = json.loads(deleted_event.json)
replacements = {}
for k, v in fields.items():
if isinstance(v, str):
try:
dt = datetime.datetime.strptime(v, '%Y-%m-%d %H:%M:%S')
except:
pass
else:
replacements[k] = dt.replace(tzinfo=TZ_BEFORE).astimezone(datetime.timezone.utc).isoformat()
if len(replacements) > 0:
fields.update(replacements)
deleted_event.json = json.dumps(fields)
deleted_event.save()
def reverse(apps, schema_editor):
DeletedEvent = apps.get_model('doc', 'DeletedEvent')
for deleted_event in DeletedEvent.objects.all():
fields = json.loads(deleted_event.json)
replacements = {}
for k, v in fields.items():
if isinstance(v, str) and 'T' in v:
try:
dt = datetime.datetime.fromisoformat(v)
except:
pass
else:
replacements[k] = dt.astimezone(TZ_BEFORE).replace(tzinfo=None).strftime('%Y-%m-%d %H:%M:%S')
if len(replacements) > 0:
fields.update(replacements)
deleted_event.json = json.dumps(fields)
deleted_event.save()
class Migration(migrations.Migration):
dependencies = [
('doc', '0046_use_timezone_now_for_doc_models'),
('utils', '0003_pause_to_change_use_tz'),
]
operations = [
migrations.RunPython(forward, reverse),
]

View file

@ -18,6 +18,7 @@ from django.core.validators import URLValidator, RegexValidator
from django.urls import reverse as urlreverse
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.html import mark_safe # type:ignore
@ -35,6 +36,7 @@ from ietf.utils.decorators import memoize
from ietf.utils.validators import validate_no_control_chars
from ietf.utils.mail import formataddr
from ietf.utils.models import ForeignKey
from ietf.utils.timezone import date_today, RPC_TZINFO, DEADLINE_TZINFO
if TYPE_CHECKING:
# importing other than for type checking causes errors due to cyclic imports
from ietf.meeting.models import ProceedingsMaterial, Session
@ -85,7 +87,7 @@ IESG_SUBSTATE_TAGS = ('ad-f-up', 'need-rev', 'extpty')
class DocumentInfo(models.Model):
"""Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement"""
time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True
time = models.DateTimeField(default=timezone.now) # should probably have auto_now=True
type = ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ...
title = models.CharField(max_length=255, validators=[validate_no_control_chars, ])
@ -349,7 +351,7 @@ class DocumentInfo(models.Model):
elif iesg_state.slug == "lc":
e = self.latest_event(LastCallDocEvent, type="sent_last_call")
if e:
return iesg_state_summary + " (ends %s)" % e.expires.date().isoformat()
return iesg_state_summary + " (ends %s)" % e.expires.astimezone(DEADLINE_TZINFO).date().isoformat()
return iesg_state_summary
else:
@ -682,7 +684,7 @@ class DocumentActionHolder(models.Model):
"""Action holder for a document"""
document = ForeignKey('Document')
person = ForeignKey(Person)
time_added = models.DateTimeField(default=datetime.datetime.now)
time_added = models.DateTimeField(default=timezone.now)
CLEAR_ACTION_HOLDERS_STATES = ['approved', 'ann', 'rfcqueue', 'pub', 'dead'] # draft-iesg state slugs
GROUP_ROLES_OF_INTEREST = ['chair', 'techadv', 'editor', 'secr']
@ -829,16 +831,20 @@ class Document(DocumentInfo):
def telechat_date(self, e=None):
if not e:
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
return e.telechat_date if e and e.telechat_date and e.telechat_date >= datetime.date.today() else None
return e.telechat_date if e and e.telechat_date and e.telechat_date >= date_today(settings.TIME_ZONE) else None
def past_telechat_date(self):
"Return the latest telechat date if it isn't in the future; else None"
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
return e.telechat_date if e and e.telechat_date and e.telechat_date < datetime.date.today() else None
return e.telechat_date if e and e.telechat_date and e.telechat_date < date_today(settings.TIME_ZONE) else None
def previous_telechat_date(self):
"Return the most recent telechat date in the past, if any (even if there's another in the future)"
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat", telechat_date__lt=datetime.datetime.now())
e = self.latest_event(
TelechatDocEvent,
type="scheduled_for_telechat",
telechat_date__lt=date_today(settings.TIME_ZONE),
)
return e.telechat_date if e else None
def request_closed_time(self, review_req):
@ -904,14 +910,21 @@ class Document(DocumentInfo):
def future_presentations(self):
""" returns related SessionPresentation objects for meetings that
have not yet ended. This implementation allows for 2 week meetings """
candidate_presentations = self.sessionpresentation_set.filter(session__meeting__date__gte=datetime.date.today()-datetime.timedelta(days=15))
return sorted([pres for pres in candidate_presentations if pres.session.meeting.end_date()>=datetime.date.today()], key=lambda x:x.session.meeting.date)
candidate_presentations = self.sessionpresentation_set.filter(
session__meeting__date__gte=date_today() - datetime.timedelta(days=15)
)
return sorted(
[pres for pres in candidate_presentations
if pres.session.meeting.end_date() >= date_today()],
key=lambda x:x.session.meeting.date,
)
def last_presented(self):
""" returns related SessionPresentation objects for the most recent meeting in the past"""
# Assumes no two meetings have the same start date - if the assumption is violated, one will be chosen arbitrariy
candidate_presentations = self.sessionpresentation_set.filter(session__meeting__date__lte=datetime.date.today())
candidate_meetings = set([p.session.meeting for p in candidate_presentations if p.session.meeting.end_date()<datetime.date.today()])
today = date_today()
candidate_presentations = self.sessionpresentation_set.filter(session__meeting__date__lte=today)
candidate_meetings = set([p.session.meeting for p in candidate_presentations if p.session.meeting.end_date()<today])
if candidate_meetings:
mtg = sorted(list(candidate_meetings),key=lambda x:x.date,reverse=True)[0]
return self.sessionpresentation_set.filter(session__meeting=mtg)
@ -924,13 +937,18 @@ class Document(DocumentInfo):
return s
def pub_date(self):
"""This is the rfc publication date (datetime) for RFCs,
and the new-revision datetime for other documents."""
"""Get the publication date for this document
This is the rfc publication date for RFCs, and the new-revision date for other documents.
"""
if self.get_state_slug() == "rfc":
# As of Sept 2022, in ietf.sync.rfceditor.update_docs_from_rfc_index() `published_rfc` events are
# created with a timestamp whose date *in the PST8PDT timezone* is the official publication date
# assigned by the RFC editor.
event = self.latest_event(type='published_rfc')
else:
event = self.latest_event(type='new_revision')
return event.time
return event.time.astimezone(RPC_TZINFO).date() if event else None
def is_dochistory(self):
return False
@ -955,7 +973,7 @@ class Document(DocumentInfo):
elif rev_events.exists():
time = rev_events.first().time
else:
time = datetime.datetime.fromtimestamp(0)
time = datetime.datetime.fromtimestamp(0, datetime.timezone.utc)
dh = DocHistory(name=self.name, rev=rev, doc=self, time=time, type=self.type, title=self.title,
stream=self.stream, group=self.group)
@ -1208,7 +1226,7 @@ EVENT_TYPES = [
class DocEvent(models.Model):
"""An occurrence for a document, used for tracking who, when and what."""
time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened", db_index=True)
time = models.DateTimeField(default=timezone.now, help_text="When the event happened", db_index=True)
type = models.CharField(max_length=50, choices=EVENT_TYPES)
by = ForeignKey(Person)
doc = ForeignKey(Document)
@ -1388,7 +1406,7 @@ class DeletedEvent(models.Model):
content_type = ForeignKey(ContentType)
json = models.TextField(help_text="Deleted object in JSON format, with attribute names chosen to be suitable for passing into the relevant create method.")
by = ForeignKey(Person)
time = models.DateTimeField(default=datetime.datetime.now)
time = models.DateTimeField(default=timezone.now)
def __str__(self):
return u"%s by %s %s" % (self.content_type, self.by, self.time)

View file

@ -38,6 +38,7 @@ import debug # pyflakes:ignore
from django import template
from django.urls import reverse as urlreverse
from django.db.models import Q
from django.utils import timezone
from django.utils.safestring import mark_safe
from ietf.ietfauth.utils import user_is_person, has_role
@ -173,17 +174,17 @@ def state_age_colored(doc):
if iesg_state in ["dead", "watching", "pub", "idexists"]:
return ""
try:
state_date = (
state_datetime = (
doc.docevent_set.filter(
Q(type="started_iesg_process")
| Q(type="changed_state", statedocevent__state_type="draft-iesg")
)
.order_by("-time")[0]
.time.date()
.time
)
except IndexError:
state_date = datetime.date(1990, 1, 1)
days = (datetime.date.today() - state_date).days
state_datetime = datetime.datetime(1990, 1, 1, tzinfo=datetime.timezone.utc)
days = (timezone.now() - state_datetime).days
# loosely based on
# https://trac.ietf.org/trac/iesg/wiki/PublishPath
if iesg_state == "lc":

View file

@ -18,6 +18,7 @@ from django.urls import reverse as urlreverse
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.urls import NoReverseMatch
from django.utils import timezone
import debug # pyflakes:ignore
@ -318,7 +319,7 @@ def timesince_days(date):
"""Returns the number of days since 'date' (relative to now)"""
if date.__class__ is not datetime.datetime:
date = datetime.datetime(date.year, date.month, date.day)
delta = datetime.datetime.now() - date
delta = timezone.now() - date
return delta.days
@register.filter
@ -501,6 +502,36 @@ def ics_esc(text):
text = re.sub(r"([\n,;\\])", r"\\\1", text)
return text
@register.simple_tag
def ics_date_time(dt, tzname):
"""Render a datetime as an iCalendar date-time
dt a datetime, localized to the timezone to be displayed
tzname is the name for this timezone
Caller must arrange for a VTIMEZONE for the tzname to be included in the iCalendar file.
Output includes a ':'. Use like:
DTSTART{% ics_date_time timestamp 'America/Los_Angeles' %}
to get
DTSTART;TZID=America/Los_Angeles:20221021T111200
>>> ics_date_time(datetime.datetime(2022,1,2,3,4,5), 'utc')
':20220102T030405Z'
>>> ics_date_time(datetime.datetime(2022,1,2,3,4,5), 'UTC')
':20220102T030405Z'
>>> ics_date_time(datetime.datetime(2022,1,2,3,4,5), 'America/Los_Angeles')
';TZID=America/Los_Angeles:20220102T030405'
"""
timestamp = dt.strftime('%Y%m%dT%H%M%S')
if tzname.lower() == 'utc':
return f':{timestamp}Z'
else:
return f';TZID={ics_esc(tzname)}:{timestamp}'
@register.filter
def consensus(doc):
"""Returns document consensus Yes/No/Unknown."""
@ -637,19 +668,19 @@ def action_holder_badge(action_holder):
>>> action_holder_badge(DocumentActionHolderFactory())
''
>>> action_holder_badge(DocumentActionHolderFactory(time_added=datetime.datetime.now() - datetime.timedelta(days=15)))
>>> action_holder_badge(DocumentActionHolderFactory(time_added=timezone.now() - datetime.timedelta(days=15)))
''
>>> action_holder_badge(DocumentActionHolderFactory(time_added=datetime.datetime.now() - datetime.timedelta(days=16)))
>>> action_holder_badge(DocumentActionHolderFactory(time_added=timezone.now() - datetime.timedelta(days=16)))
'<span class="badge rounded-pill bg-danger" title="In state for 16 days; goal is &lt;15 days."><i class="bi bi-clock-fill"></i> 16</span>'
>>> action_holder_badge(DocumentActionHolderFactory(time_added=datetime.datetime.now() - datetime.timedelta(days=30)))
>>> action_holder_badge(DocumentActionHolderFactory(time_added=timezone.now() - datetime.timedelta(days=30)))
'<span class="badge rounded-pill bg-danger" title="In state for 30 days; goal is &lt;15 days."><i class="bi bi-clock-fill"></i> 30</span>'
>>> settings.DOC_ACTION_HOLDER_AGE_LIMIT_DAYS = old_limit
"""
age_limit = settings.DOC_ACTION_HOLDER_AGE_LIMIT_DAYS
age = (datetime.datetime.now() - action_holder.time_added).days
age = (timezone.now() - action_holder.time_added).days
if age > age_limit:
return mark_safe(
'<span class="badge rounded-pill bg-danger" title="In state for %d day%s; goal is &lt;%d days."><i class="bi bi-clock-fill"></i> %d</span>'

View file

@ -18,6 +18,7 @@ from pyquery import PyQuery
from urllib.parse import urlparse, parse_qs
from tempfile import NamedTemporaryFile
from collections import defaultdict
from zoneinfo import ZoneInfo
from django.core.management import call_command
from django.urls import reverse as urlreverse
@ -25,6 +26,7 @@ from django.conf import settings
from django.forms import Form
from django.utils.html import escape
from django.test import override_settings
from django.utils import timezone
from django.utils.text import slugify
from tastypie.test import ResourceTestCaseMixin
@ -56,6 +58,8 @@ from ietf.utils.mail import outbox, empty_outbox
from ietf.utils.test_utils import login_testing_unauthorized, unicontent, reload_db_objects
from ietf.utils.test_utils import TestCase
from ietf.utils.text import normalize_text
from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO, RPC_TZINFO
class SearchTests(TestCase):
def test_search(self):
@ -385,13 +389,13 @@ class SearchTests(TestCase):
# Three drafts to show with various warnings
drafts = WgDraftFactory.create_batch(3,states=[('draft','active'),('draft-iesg','ad-eval')])
for index, draft in enumerate(drafts):
StateDocEventFactory(doc=draft, state=('draft-iesg','ad-eval'), time=datetime.datetime.now()-datetime.timedelta(days=[1,15,29][index]))
StateDocEventFactory(doc=draft, state=('draft-iesg','ad-eval'), time=timezone.now()-datetime.timedelta(days=[1,15,29][index]))
draft.action_holders.set([PersonFactory()])
# And one draft that should not show (with the default of 7 days to view)
old = WgDraftFactory()
old.docevent_set.filter(newrevisiondocevent__isnull=False).update(time=datetime.datetime.now()-datetime.timedelta(days=8))
StateDocEventFactory(doc=old, time=datetime.datetime.now()-datetime.timedelta(days=8))
old.docevent_set.filter(newrevisiondocevent__isnull=False).update(time=timezone.now()-datetime.timedelta(days=8))
StateDocEventFactory(doc=old, time=timezone.now()-datetime.timedelta(days=8))
url = urlreverse('ietf.doc.views_search.recent_drafts')
r = self.client.get(url)
@ -764,7 +768,7 @@ Man Expires September 22, 2015 [Page 3]
replacement = WgDraftFactory(
name="draft-ietf-replacement",
time=datetime.datetime.now(),
time=timezone.now(),
title="Replacement Draft",
stream_id=draft.stream_id, group_id=draft.group_id, abstract=draft.abstract,stream=draft.stream, rev=draft.rev,
pages=draft.pages, intended_std_level_id=draft.intended_std_level_id,
@ -1427,6 +1431,8 @@ Man Expires September 22, 2015 [Page 3]
def test_draft_group_link(self):
"""Link to group 'about' page should have correct format"""
event_datetime = datetime.datetime(2010, 10, 10, tzinfo=RPC_TZINFO)
for group_type_id in ['wg', 'rg', 'ag']:
group = GroupFactory(type_id=group_type_id)
draft = WgDraftFactory(name='draft-document-%s' % group_type_id, group=group)
@ -1435,7 +1441,7 @@ Man Expires September 22, 2015 [Page 3]
self.assert_correct_wg_group_link(r, group)
rfc = WgRfcFactory(name='draft-rfc-document-%s' % group_type_id, group=group)
DocEventFactory.create(doc=rfc, type='published_rfc', time = '2010-10-10')
DocEventFactory.create(doc=rfc, type='published_rfc', time=event_datetime)
# get the rfc name to avoid a redirect
rfc_name = rfc.docalias.filter(name__startswith='rfc').first().name
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=rfc_name)))
@ -1450,7 +1456,7 @@ Man Expires September 22, 2015 [Page 3]
self.assert_correct_non_wg_group_link(r, group)
rfc = WgRfcFactory(name='draft-rfc-document-%s' % group_type_id, group=group)
DocEventFactory.create(doc=rfc, type='published_rfc', time = '2010-10-10')
DocEventFactory.create(doc=rfc, type='published_rfc', time=event_datetime)
# get the rfc name to avoid a redirect
rfc_name = rfc.docalias.filter(name__startswith='rfc').first().name
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=rfc_name)))
@ -1586,7 +1592,7 @@ class DocTestCase(TestCase):
name = "session-72-mars-1",
meeting = Meeting.objects.get(number='72'),
group = Group.objects.get(acronym='mars'),
modified = datetime.datetime.now(),
modified = timezone.now(),
add_to_schedule=False,
)
SchedulingEvent.objects.create(
@ -1616,7 +1622,7 @@ class DocTestCase(TestCase):
type="changed_ballot_position",
pos_id="yes",
comment="Looks fine to me",
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
balloter=Person.objects.get(user__username="ad"),
by=Person.objects.get(name="(System)"))
@ -1650,7 +1656,7 @@ class DocTestCase(TestCase):
type="changed_ballot_position",
pos_id="noobj",
comment="Still looks okay to me",
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
balloter=Person.objects.get(user__username="ad"),
by=Person.objects.get(name="(System)"))
@ -1672,7 +1678,7 @@ class DocTestCase(TestCase):
type="changed_ballot_position",
pos_id="yes",
comment="Looks fine to me",
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
balloter=Person.objects.get(user__username="ad"),
by=Person.objects.get(name="(System)"))
@ -1842,7 +1848,7 @@ class DocTestCase(TestCase):
desc="Last call\x0b", # include a control character to be sure it does not break anything
type="sent_last_call",
by=Person.objects.get(user__username="secretary"),
expires=datetime.date.today() + datetime.timedelta(days=7))
expires=datetime_today(DEADLINE_TZINFO) + datetime.timedelta(days=7))
r = self.client.get("/feed/last-call/")
self.assertEqual(r.status_code, 200)
@ -1890,10 +1896,14 @@ class DocTestCase(TestCase):
#other_aliases = ['rfc6020',],
states = [('draft','rfc'),('draft-iesg','pub')],
std_level_id = 'ps',
time = datetime.datetime(2010,10,10),
time = datetime.datetime(2010, 10, 10, tzinfo=ZoneInfo(settings.TIME_ZONE)),
)
num = rfc.rfc_number()
DocEventFactory.create(doc=rfc, type='published_rfc', time = '2010-10-10')
DocEventFactory.create(
doc=rfc,
type='published_rfc',
time=datetime.datetime(2010, 10, 10, tzinfo=RPC_TZINFO),
)
#
url = urlreverse('ietf.doc.views_doc.document_bibtex', kwargs=dict(name=rfc.name))
r = self.client.get(url)
@ -1911,10 +1921,14 @@ class DocTestCase(TestCase):
stream_id = 'ise',
states = [('draft','rfc'),('draft-iesg','pub')],
std_level_id = 'inf',
time = datetime.datetime(1990,0o4,0o1),
time = datetime.datetime(1990, 4, 1, tzinfo=ZoneInfo(settings.TIME_ZONE)),
)
num = april1.rfc_number()
DocEventFactory.create(doc=april1, type='published_rfc', time = '1990-04-01')
DocEventFactory.create(
doc=april1,
type='published_rfc',
time=datetime.datetime(1990, 4, 1, tzinfo=RPC_TZINFO),
)
#
url = urlreverse('ietf.doc.views_doc.document_bibtex', kwargs=dict(name=april1.name))
r = self.client.get(url)
@ -2049,7 +2063,8 @@ class GenerateDraftAliasesTests(TestCase):
super().tearDown()
def testManagementCommand(self):
a_month_ago = datetime.datetime.now() - datetime.timedelta(30)
a_month_ago = (timezone.now() - datetime.timedelta(30)).astimezone(RPC_TZINFO)
a_month_ago = a_month_ago.replace(hour=0, minute=0, second=0, microsecond=0)
ad = RoleFactory(name_id='ad', group__type_id='area', group__state_id='active').person
shepherd = PersonFactory()
author1 = PersonFactory()
@ -2064,9 +2079,9 @@ class GenerateDraftAliasesTests(TestCase):
doc1 = IndividualDraftFactory(authors=[author1], shepherd=shepherd.email(), ad=ad)
doc2 = WgDraftFactory(name='draft-ietf-mars-test', group__acronym='mars', authors=[author2], ad=ad)
doc3 = WgRfcFactory.create(name='draft-ietf-mars-finished', group__acronym='mars', authors=[author3], ad=ad, std_level_id='ps', states=[('draft','rfc'),('draft-iesg','pub')], time=a_month_ago)
DocEventFactory.create(doc=doc3, type='published_rfc', time=a_month_ago.strftime("%Y-%m-%d"))
doc4 = WgRfcFactory.create(authors=[author4,author5], ad=ad, std_level_id='ps', states=[('draft','rfc'),('draft-iesg','pub')], time=datetime.datetime(2010,10,10))
DocEventFactory.create(doc=doc4, type='published_rfc', time = '2010-10-10')
DocEventFactory.create(doc=doc3, type='published_rfc', time=a_month_ago)
doc4 = WgRfcFactory.create(authors=[author4,author5], ad=ad, std_level_id='ps', states=[('draft','rfc'),('draft-iesg','pub')], time=datetime.datetime(2010,10,10, tzinfo=ZoneInfo(settings.TIME_ZONE)))
DocEventFactory.create(doc=doc4, type='published_rfc', time=datetime.datetime(2010, 10, 10, tzinfo=RPC_TZINFO))
doc5 = IndividualDraftFactory(authors=[author6])
args = [ ]
@ -2217,7 +2232,7 @@ class DocumentMeetingTests(TestCase):
self.other_chair = PersonFactory()
self.other_group.role_set.create(name_id='chair',person=self.other_chair,email=self.other_chair.email())
today = datetime.date.today()
today = date_today()
cut_days = settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_CORRECTION_DAYS
self.past_cutoff = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1+cut_days))
self.past = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=cut_days/2))

View file

@ -12,6 +12,7 @@ import debug # pyflakes:ignore
from django.test import RequestFactory
from django.utils.text import slugify
from django.urls import reverse as urlreverse
from django.utils import timezone
from ietf.doc.models import (Document, State, DocEvent,
BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, TelechatDocEvent)
@ -30,6 +31,7 @@ from ietf.person.utils import get_active_ads
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.text import unwrap
from ietf.utils.timezone import date_today
class EditPositionTests(TestCase):
@ -105,7 +107,7 @@ class EditPositionTests(TestCase):
draft = WgDraftFactory(ad=ad)
url = urlreverse('ietf.doc.views_ballot.api_set_position')
create_ballot_if_not_open(None, draft, ad, 'approve')
ad.user.last_login = datetime.datetime.now()
ad.user.last_login = timezone.now()
ad.user.save()
apikey = PersonalApiKey.objects.create(endpoint=url, person=ad)
@ -238,9 +240,9 @@ class EditPositionTests(TestCase):
doc=draft, rev=draft.rev, type="changed_ballot_position",
by=ad, balloter=ad, ballot=ballot, pos=BallotPositionName.objects.get(slug="discuss"),
discuss="This draft seems to be lacking a clearer title?",
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
comment="Test!",
comment_time=datetime.datetime.now())
comment_time=timezone.now())
url = urlreverse('ietf.doc.views_ballot.send_ballot_comment', kwargs=dict(name=draft.name,
ballot_id=ballot.pk))
@ -466,7 +468,7 @@ class BallotWriteupsTests(TestCase):
doc=draft,
rev=draft.rev,
desc='issued last call',
expires = datetime.datetime.now()+datetime.timedelta(days = 1 if case=='future' else -1)
expires = timezone.now()+datetime.timedelta(days = 1 if case=='future' else -1)
)
url = urlreverse('ietf.doc.views_ballot.ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
@ -791,7 +793,7 @@ class ApproveBallotTests(TestCase):
doc=draft,
rev=draft.rev,
desc='issued last call',
expires = datetime.datetime.now()-datetime.timedelta(days=14) )
expires = timezone.now()-datetime.timedelta(days=14) )
WriteupDocEvent.objects.create(
by=Person.objects.get(name='(System)'),
doc=draft,
@ -898,7 +900,7 @@ class MakeLastCallTests(TestCase):
mailbox_before = len(outbox)
last_call_sent_date = datetime.date.today()
last_call_sent_date = date_today()
expire_date = last_call_sent_date+datetime.timedelta(days=14)
r = self.client.post(url,
@ -1117,7 +1119,7 @@ class RegenerateLastCallTestCase(TestCase):
class BallotContentTests(TestCase):
def test_ballotpositiondocevent_any_email_sent(self):
now = datetime.datetime.now() # be sure event timestamps are at distinct times
now = timezone.now() # be sure event timestamps are at distinct times
bpde_with_null_send_email = BallotPositionDocEventFactory(
time=now - datetime.timedelta(minutes=30),
send_email=None,
@ -1219,7 +1221,7 @@ class BallotContentTests(TestCase):
balloter=balloters[0],
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=True,
)
BallotPositionDocEventFactory(
@ -1227,7 +1229,7 @@ class BallotContentTests(TestCase):
balloter=balloters[1],
pos_id='noobj',
comment='Commentary',
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
send_email=True,
)
@ -1237,7 +1239,7 @@ class BallotContentTests(TestCase):
balloter=balloters[2],
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=False,
)
BallotPositionDocEventFactory(
@ -1245,7 +1247,7 @@ class BallotContentTests(TestCase):
balloter=balloters[3],
pos_id='noobj',
comment='Commentary',
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
send_email=False,
)
@ -1255,7 +1257,7 @@ class BallotContentTests(TestCase):
balloter=balloters[4],
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now() - datetime.timedelta(days=1),
discuss_time=timezone.now() - datetime.timedelta(days=1),
send_email=True,
)
BallotPositionDocEventFactory(
@ -1263,7 +1265,7 @@ class BallotContentTests(TestCase):
balloter=balloters[4],
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=False,
)
BallotPositionDocEventFactory(
@ -1271,7 +1273,7 @@ class BallotContentTests(TestCase):
balloter=balloters[5],
pos_id='noobj',
comment='Commentary',
comment_time=datetime.datetime.now() - datetime.timedelta(days=1),
comment_time=timezone.now() - datetime.timedelta(days=1),
send_email=True,
)
BallotPositionDocEventFactory(
@ -1279,7 +1281,7 @@ class BallotContentTests(TestCase):
balloter=balloters[5],
pos_id='noobj',
comment='Commentary',
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
send_email=False,
)
@ -1296,7 +1298,7 @@ class BallotContentTests(TestCase):
balloter__plain='plain name1',
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=False,
).balloter
send_email_balloter = BallotPositionDocEventFactory(
@ -1304,7 +1306,7 @@ class BallotContentTests(TestCase):
balloter__plain='plain name2',
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=True,
).balloter
prev_send_email_balloter = BallotPositionDocEventFactory(
@ -1312,7 +1314,7 @@ class BallotContentTests(TestCase):
balloter__plain='plain name3',
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now() - datetime.timedelta(days=1),
discuss_time=timezone.now() - datetime.timedelta(days=1),
send_email=True,
).balloter
BallotPositionDocEventFactory(
@ -1320,7 +1322,7 @@ class BallotContentTests(TestCase):
balloter=prev_send_email_balloter,
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=False,
)
@ -1351,7 +1353,7 @@ class BallotContentTests(TestCase):
balloter=balloters[0],
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=None,
)
BallotPositionDocEventFactory(
@ -1359,7 +1361,7 @@ class BallotContentTests(TestCase):
balloter=balloters[1],
pos_id='noobj',
comment='Commentary',
comment_time=datetime.datetime.now(),
comment_time=timezone.now(),
send_email=None,
)
old_balloter = BallotPositionDocEventFactory(
@ -1367,7 +1369,7 @@ class BallotContentTests(TestCase):
balloter__plain='plain name', # ensure plain name is slugifiable
pos_id='discuss',
discuss='Discussion text',
discuss_time=datetime.datetime.now(),
discuss_time=timezone.now(),
send_email=None,
).balloter

View file

@ -14,6 +14,7 @@ from html import unescape
from django.conf import settings
from django.urls import reverse as urlreverse
from django.template.loader import render_to_string
from django.utils import timezone
from ietf.group.factories import RoleFactory
from ietf.doc.factories import BofreqFactory, NewRevisionDocEventFactory
@ -48,7 +49,7 @@ This test section has some text.
states = State.objects.filter(type_id='bofreq')
self.assertTrue(states.count()>0)
for i in range(3*len(states)):
BofreqFactory(states=[('bofreq',states[i%len(states)].slug)],newrevisiondocevent__time=datetime.datetime.today()-datetime.timedelta(days=randint(0,20)))
BofreqFactory(states=[('bofreq',states[i%len(states)].slug)],newrevisiondocevent__time=timezone.now()-datetime.timedelta(days=randint(0,20)))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)

View file

@ -26,6 +26,8 @@ from ietf.person.models import Person
from ietf.utils.test_utils import TestCase
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.timezone import datetime_today, date_today, DEADLINE_TZINFO
class ViewCharterTests(TestCase):
def test_view_revisions(self):
@ -402,7 +404,7 @@ class EditCharterTests(TestCase):
# Make it so that the charter has been through internal review, and passed its external review
# ballot on a previous telechat
last_week = datetime.date.today()-datetime.timedelta(days=7)
last_week = datetime_today(DEADLINE_TZINFO) - datetime.timedelta(days=7)
BallotDocEvent.objects.create(type='created_ballot',by=login,doc=charter, rev=charter.rev,
ballot_type=BallotType.objects.get(doc_type=charter.type,slug='r-extrev'),
time=last_week)
@ -746,7 +748,7 @@ class EditCharterTests(TestCase):
charter.set_state(State.objects.get(used=True, type="charter", slug="iesgrev"))
due_date = datetime.date.today() + datetime.timedelta(days=180)
due_date = date_today(DEADLINE_TZINFO) + datetime.timedelta(days=180)
m1 = GroupMilestone.objects.create(group=group,
state_id="active",
desc="Has been copied",
@ -826,7 +828,7 @@ class EditCharterTests(TestCase):
m = GroupMilestone.objects.create(group=charter.group,
state_id="active",
desc="Test milestone",
due=datetime.date.today(),
due=date_today(DEADLINE_TZINFO),
resolved="")
url = urlreverse('ietf.doc.views_charter.charter_with_milestones_txt', kwargs=dict(name=charter.name, rev=charter.rev))

View file

@ -13,6 +13,7 @@ from pyquery import PyQuery
from django.urls import reverse as urlreverse
from django.conf import settings
from django.utils import timezone
from django.utils.html import escape
import debug # pyflakes:ignore
@ -33,6 +34,7 @@ from ietf.iesg.models import TelechatDate
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import TestCase
from ietf.utils.timezone import date_today, datetime_from_date
class ChangeStateTests(TestCase):
@ -401,11 +403,11 @@ class EditInfoTests(TestCase):
# change to a telechat that should cause returning item to be auto-detected
# First, make it appear that the previous telechat has already passed
telechat_event.telechat_date = datetime.date.today()-datetime.timedelta(days=7)
telechat_event.telechat_date = date_today() - datetime.timedelta(days=7)
telechat_event.save()
ad = Person.objects.get(user__username="ad")
ballot = create_ballot_if_not_open(None, draft, ad, 'approve')
ballot.time = telechat_event.telechat_date
ballot.time = datetime_from_date(telechat_event.telechat_date)
ballot.save()
r = self.client.post(url, data)
@ -428,7 +430,7 @@ class EditInfoTests(TestCase):
self.assertTrue("Telechat update" in outbox[-1]['Subject'])
# Put it on an agenda that's very soon from now
next_week = datetime.date.today()+datetime.timedelta(days=7)
next_week = date_today() + datetime.timedelta(days=7)
td = TelechatDate.objects.active()[0]
td.date = next_week
td.save()
@ -618,7 +620,7 @@ class ResurrectTests(DraftFileMixin, TestCase):
self.assertEqual(draft.docevent_set.count(), events_before + 1)
self.assertEqual(draft.latest_event().type, "completed_resurrect")
self.assertEqual(draft.get_state_slug(), "active")
self.assertTrue(draft.expires >= datetime.datetime.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE - 1))
self.assertTrue(draft.expires >= timezone.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE - 1))
self.assertEqual(len(outbox), mailbox_before + 1)
self.assertTrue('Resurrection Completed' in outbox[-1]['Subject'])
self.assertTrue('iesg-secretary' in outbox[-1]['To'])
@ -638,7 +640,7 @@ class ExpireIDsTests(DraftFileMixin, TestCase):
meeting = Meeting.objects.create(number="123",
type=MeetingTypeName.objects.get(slug="ietf"),
date=datetime.date.today())
date=date_today())
second_cut_off = meeting.get_second_cut_off()
ietf_monday = meeting.get_ietf_monday()
@ -659,7 +661,7 @@ class ExpireIDsTests(DraftFileMixin, TestCase):
# hack into expirable state
draft.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
draft.expires = datetime.datetime.now() + datetime.timedelta(days=10)
draft.expires = timezone.now() + datetime.timedelta(days=10)
draft.save_with_history([DocEvent.objects.create(doc=draft, rev=draft.rev, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
self.assertEqual(len(list(get_soon_to_expire_drafts(14))), 1)
@ -698,7 +700,7 @@ class ExpireIDsTests(DraftFileMixin, TestCase):
# hack into expirable state
draft.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
draft.expires = datetime.datetime.now()
draft.expires = timezone.now()
draft.save_with_history([DocEvent.objects.create(doc=draft, rev=draft.rev, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
self.assertEqual(len(list(get_expired_drafts())), 1)
@ -741,7 +743,7 @@ class ExpireIDsTests(DraftFileMixin, TestCase):
draft.delete()
rgdraft = RgDraftFactory(expires=datetime.datetime.now())
rgdraft = RgDraftFactory(expires=timezone.now())
self.assertEqual(len(list(get_expired_drafts())), 1)
for slug in ('iesg-rev','irsgpoll'):
rgdraft.set_state(State.objects.get(type_id='draft-stream-irtf',slug=slug))
@ -791,7 +793,7 @@ class ExpireIDsTests(DraftFileMixin, TestCase):
# expire draft
draft.set_state(State.objects.get(used=True, type="draft", slug="expired"))
draft.expires = datetime.datetime.now() - datetime.timedelta(days=1)
draft.expires = timezone.now() - datetime.timedelta(days=1)
draft.save_with_history([DocEvent.objects.create(doc=draft, rev=draft.rev, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
e = DocEvent(doc=draft, rev=draft.rev, type= "expired_document", time=draft.expires,
@ -824,7 +826,7 @@ class ExpireLastCallTests(TestCase):
e = LastCallDocEvent(doc=draft, rev=draft.rev, type="sent_last_call", by=secretary)
e.text = "Last call sent"
e.expires = datetime.datetime.now() + datetime.timedelta(days=14)
e.expires = timezone.now() + datetime.timedelta(days=14)
e.save()
self.assertEqual(len(list(get_expired_last_calls())), 0)
@ -832,7 +834,7 @@ class ExpireLastCallTests(TestCase):
# test expired
e = LastCallDocEvent(doc=draft, rev=draft.rev, type="sent_last_call", by=secretary)
e.text = "Last call sent"
e.expires = datetime.datetime.now()
e.expires = timezone.now()
e.save()
drafts = list(get_expired_last_calls())
@ -866,7 +868,7 @@ class ExpireLastCallTests(TestCase):
e = LastCallDocEvent(doc=draft, rev=draft.rev, type="sent_last_call", by=secretary)
e.text = "Last call sent"
e.desc = "Blah, blah, blah.\n\nThis document makes the following downward references (downrefs):\n ** Downref: Normative reference to an Experimental RFC: RFC 4764"
e.expires = datetime.datetime.now()
e.expires = timezone.now()
e.save()
drafts = list(get_expired_last_calls())
@ -1730,7 +1732,7 @@ class ChangeStreamStateTests(TestCase):
self.assertEqual(draft.docevent_set.count() - events_before, 2)
reminder = DocReminder.objects.filter(event__doc=draft, type="stream-s")
self.assertEqual(len(reminder), 1)
due = datetime.datetime.now() + datetime.timedelta(weeks=10)
due = timezone.now() + datetime.timedelta(weeks=10)
self.assertTrue(due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1))
self.assertEqual(len(outbox), 1)
self.assertTrue("state changed" in outbox[0]["Subject"].lower())
@ -1775,7 +1777,7 @@ class ChangeStreamStateTests(TestCase):
self.assertEqual(draft.docevent_set.count() - events_before, 2)
reminder = DocReminder.objects.filter(event__doc=draft, type="stream-s")
self.assertEqual(len(reminder), 1)
due = datetime.datetime.now() + datetime.timedelta(weeks=10)
due = timezone.now() + datetime.timedelta(weeks=10)
self.assertTrue(due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1))
self.assertEqual(len(outbox), 1)
self.assertTrue("state changed" in outbox[0]["Subject"].lower())
@ -1826,7 +1828,7 @@ class ChangeReplacesTests(TestCase):
name="draft-test-base-b",
title="Base B",
group=mars_wg,
expires = datetime.datetime.now() - datetime.timedelta(days = 365 - settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
expires = timezone.now() - datetime.timedelta(days = 365 - settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
)
p = PersonFactory(name="baseb_author")
e = Email.objects.create(address="baseb_author@example.com", person=p, origin=p.user.username)

View file

@ -19,6 +19,7 @@ from ietf.doc.utils import create_ballot_if_not_open, close_ballot
from ietf.person.utils import get_active_irsg, get_active_ads
from ietf.group.factories import RoleFactory
from ietf.person.models import Person
from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO
class IssueIRSGBallotTests(TestCase):
@ -254,7 +255,7 @@ class IssueIRSGBallotTests(TestCase):
irsgmember = get_active_irsg()[0]
secr = RoleFactory(group__acronym='secretariat',name_id='secr')
wg_ballot = create_ballot_if_not_open(None, wg_draft, ad.person, 'approve')
due = datetime.date.today()+datetime.timedelta(days=14)
due = datetime_today(DEADLINE_TZINFO) + datetime.timedelta(days=14)
rg_ballot = create_ballot_if_not_open(None, rg_draft, secr.person, 'irsg-approve', due)
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=wg_draft.name, ballot_id=wg_ballot.pk))
@ -323,7 +324,7 @@ class BaseManipulationTests():
def test_issue_ballot(self):
draft = RgDraftFactory()
url = urlreverse('ietf.doc.views_ballot.issue_irsg_ballot',kwargs=dict(name=draft.name))
due = datetime.date.today()+datetime.timedelta(days=14)
due = date_today(DEADLINE_TZINFO)+datetime.timedelta(days=14)
empty_outbox()
login_testing_unauthorized(self, self.username , url)
@ -444,7 +445,7 @@ class IRSGMemberTests(TestCase):
def test_cant_issue_irsg_ballot(self):
draft = RgDraftFactory()
due = datetime.date.today()+datetime.timedelta(days=14)
due = datetime_today(DEADLINE_TZINFO) + datetime.timedelta(days=14)
url = urlreverse('ietf.doc.views_ballot.close_irsg_ballot', kwargs=dict(name=draft.name))
self.client.login(username = self.username, password = self.username+'+password')

View file

@ -4,7 +4,6 @@
import os
import shutil
import datetime
import io
from pathlib import Path
@ -14,6 +13,7 @@ import debug # pyflakes:ignore
from django.conf import settings
from django.urls import reverse as urlreverse
from django.utils import timezone
from ietf.doc.models import Document, State, DocAlias, NewRevisionDocEvent
from ietf.group.factories import RoleFactory
@ -155,7 +155,7 @@ class GroupMaterialTests(TestCase):
name = "session-42-mars-1",
meeting = Meeting.objects.get(number='42'),
group = Group.objects.get(acronym='mars'),
modified = datetime.datetime.now(),
modified = timezone.now(),
)
SchedulingEvent.objects.create(
session=session,

View file

@ -10,10 +10,10 @@ import email.mime.multipart, email.mime.text, email.utils
from mock import patch
from requests import Response
from django.apps import apps
from django.urls import reverse as urlreverse
from django.conf import settings
from django.utils import timezone
from pyquery import PyQuery
@ -38,6 +38,7 @@ from ietf.utils.mail import outbox, empty_outbox, parseaddr, on_behalf_of, get_p
from ietf.utils.test_utils import login_testing_unauthorized, reload_db_objects
from ietf.utils.test_utils import TestCase
from ietf.utils.text import strip_prefix, xslugify
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
from django.utils.html import escape
class ReviewTests(TestCase):
@ -67,7 +68,7 @@ class ReviewTests(TestCase):
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
RoleFactory(group=review_team3,person__user__username='reviewsecretary3',person__user__email='reviewsecretary3@example.com',name_id='secr')
req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
ReviewAssignmentFactory(review_request = req, reviewer = rev_role.person.email_set.first(), state_id='accepted')
url = urlreverse('ietf.doc.views_review.request_review', kwargs={ "name": doc.name })
@ -77,7 +78,7 @@ class ReviewTests(TestCase):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
deadline = datetime.date.today() + datetime.timedelta(days=10)
deadline = date_today() + datetime.timedelta(days=10)
empty_outbox()
@ -145,7 +146,7 @@ class ReviewTests(TestCase):
doc = WgDraftFactory(group__acronym='mars',rev='01')
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
ReviewAssignmentFactory(review_request=review_req, reviewer=rev_role.person.email_set.first(), state_id='accepted')
# move the review request to a doubly-replaced document to
@ -166,7 +167,7 @@ class ReviewTests(TestCase):
doc = WgDraftFactory(group__acronym='mars',rev='01', authors=[author])
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
ReviewAssignmentFactory(review_request = review_req, reviewer = rev_role.person.email_set.first(), state_id='accepted')
url = urlreverse('ietf.doc.views_review.review_request', kwargs={ "name": doc.name, "request_id": review_req.pk })
@ -195,7 +196,7 @@ class ReviewTests(TestCase):
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
RoleFactory(group=review_team,person__user__username='reviewsecretary2',person__user__email='reviewsecretary2@example.com',name_id='secr')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
ReviewAssignmentFactory(review_request=review_req, state_id='accepted', reviewer=rev_role.person.email_set.first())
close_url = urlreverse('ietf.doc.views_review.close_request', kwargs={ "name": doc.name, "request_id": review_req.pk })
@ -260,14 +261,14 @@ class ReviewTests(TestCase):
# previous review
req = ReviewRequestFactory(
time=datetime.datetime.now() - datetime.timedelta(days=100),
time=timezone.now() - datetime.timedelta(days=100),
requested_by=Person.objects.get(name="(System)"),
doc=doc,
type_id='early',
team=review_req.team,
state_id='assigned',
requested_rev="01",
deadline=datetime.date.today() - datetime.timedelta(days=80),
deadline=date_today() - datetime.timedelta(days=80),
)
ReviewAssignmentFactory(
review_request = req,
@ -372,7 +373,7 @@ class ReviewTests(TestCase):
doc = WgDraftFactory(group__acronym='mars',rev='01')
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
assignment = ReviewAssignmentFactory(review_request=review_req, state_id='assigned', reviewer=rev_role.person.email_set.first())
url = urlreverse('ietf.doc.views_review.review_request', kwargs={ "name": doc.name, "request_id": review_req.pk })
@ -395,7 +396,7 @@ class ReviewTests(TestCase):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
assignment = ReviewAssignmentFactory(review_request = review_req, reviewer=rev_role.person.email_set.first(), state_id='accepted')
reject_url = urlreverse('ietf.doc.views_review.reject_reviewer_assignment', kwargs={ "name": doc.name, "assignment_id": assignment.pk })
@ -495,7 +496,7 @@ class ReviewTests(TestCase):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
assignment = ReviewAssignmentFactory(review_request=review_req, reviewer=rev_role.person.email_set.first(), state_id='accepted')
# test URL construction
@ -525,7 +526,7 @@ class ReviewTests(TestCase):
messages = r.json()["messages"]
self.assertEqual(len(messages), 2)
today = datetime.date.today()
today = date_today()
self.assertEqual(messages[0]["url"], "https://www.example.com/testmessage")
self.assertTrue("John Doe" in messages[0]["content"])
@ -587,7 +588,7 @@ class ReviewTests(TestCase):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
assignment = ReviewAssignmentFactory(review_request=review_req, state_id='accepted', reviewer=rev_role.person.email_set.first())
for r in ReviewResultName.objects.filter(slug__in=("issues", "ready")):
review_req.team.reviewteamsettings.review_results.add(r)
@ -699,7 +700,7 @@ class ReviewTests(TestCase):
assignment = reload_db_objects(assignment)
self.assertEqual(assignment.state_id, "completed")
# Completed time should be close to now, but will not be exactly, so check within 10s margin
completed_time_diff = datetime.datetime.now() - assignment.completed_on
completed_time_diff = timezone.now() - assignment.completed_on
self.assertLess(completed_time_diff, datetime.timedelta(seconds=10))
with io.open(os.path.join(self.review_subdir, assignment.review.name + ".txt")) as f:
@ -733,15 +734,15 @@ class ReviewTests(TestCase):
# The secretary is allowed to set a custom completion date (#2590)
assignment = reload_db_objects(assignment)
self.assertEqual(assignment.state_id, "completed")
self.assertEqual(assignment.completed_on, datetime.datetime(2012, 12, 24, 12, 13, 14))
self.assertEqual(assignment.completed_on, datetime.datetime(2012, 12, 24, 12, 13, 14, tzinfo=DEADLINE_TZINFO))
# There should be two events:
# - the event logging when the change when it was entered, i.e. very close to now.
# - the completion of the review, set to the provided date/time
events = ReviewAssignmentDocEvent.objects.filter(doc=assignment.review_request.doc).order_by('-time')
event0_time_diff = datetime.datetime.now() - events[0].time
event0_time_diff = timezone.now() - events[0].time
self.assertLess(event0_time_diff, datetime.timedelta(seconds=10))
self.assertEqual(events[1].time, datetime.datetime(2012, 12, 24, 12, 13, 14))
self.assertEqual(events[1].time, datetime.datetime(2012, 12, 24, 12, 13, 14, tzinfo=DEADLINE_TZINFO))
with io.open(os.path.join(self.review_subdir, assignment.review.name + ".txt")) as f:
self.assertEqual(f.read(), "This is a review\nwith two lines")
@ -898,7 +899,7 @@ class ReviewTests(TestCase):
assignment.review_request.team.acronym,
assignment.review_request.type.slug,
xslugify(assignment.reviewer.person.ascii_parts()[3]),
datetime.date.today().isoformat(),
date_today().isoformat(),
]
review_name = "-".join(c for c in name_components if c).lower()
Document.objects.create(name=review_name,type_id='review',group=assignment.review_request.team)
@ -985,7 +986,7 @@ class ReviewTests(TestCase):
self.assertEqual(assignment.state_id, "completed")
# The revision event time should be the date the revision was submitted, i.e. not backdated
event1 = assignment.review_request.doc.latest_event(ReviewAssignmentDocEvent)
event_time_diff = datetime.datetime.now() - event1.time
event_time_diff = timezone.now() - event1.time
self.assertLess(event_time_diff, datetime.timedelta(seconds=10))
self.assertTrue('revised' in event1.desc.lower())
@ -1012,7 +1013,7 @@ class ReviewTests(TestCase):
assignment = reload_db_objects(assignment)
self.assertEqual(assignment.review.rev, "01")
event2 = assignment.review_request.doc.latest_event(ReviewAssignmentDocEvent)
event_time_diff = datetime.datetime.now() - event2.time
event_time_diff = timezone.now() - event2.time
self.assertLess(event_time_diff, datetime.timedelta(seconds=10))
# Ensure that a new event was created for the new revision (#2590)
self.assertNotEqual(event1.id, event2.id)
@ -1024,7 +1025,7 @@ class ReviewTests(TestCase):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='assigned',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
ReviewAssignmentFactory(review_request = review_req, reviewer = rev_role.person.email_set.first(), state_id='accepted')
url = urlreverse('ietf.doc.views_review.edit_comment', kwargs={ "name": doc.name, "request_id": review_req.pk })
@ -1046,7 +1047,7 @@ class ReviewTests(TestCase):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
RoleFactory(group=review_team,person__user__username='reviewsecretary',person__user__email='reviewsecretary@example.com',name_id='secr')
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='accepted',requested_by=rev_role.person,deadline=datetime.datetime.now()+datetime.timedelta(days=20))
review_req = ReviewRequestFactory(doc=doc,team=review_team,type_id='early',state_id='accepted',requested_by=rev_role.person,deadline=timezone.now()+datetime.timedelta(days=20))
ReviewAssignmentFactory(review_request = review_req, reviewer = rev_role.person.email_set.first(), state_id='accepted')
url = urlreverse('ietf.doc.views_review.edit_deadline', kwargs={ "name": doc.name, "request_id": review_req.pk })

View file

@ -16,6 +16,7 @@ from ietf.doc.models import State, DocumentActionHolder, DocumentAuthor, Documen
from ietf.doc.utils import (update_action_holders, add_state_change_event, update_documentauthors,
fuzzy_find_documents, rebuild_reference_relations)
from ietf.utils.draft import Draft, PlaintextDraft
from ietf.utils.timezone import date_today
from ietf.utils.xmldraft import XMLDraft
@ -143,12 +144,13 @@ class ActionHoldersTests(TestCase):
doc = self.doc_in_iesg_state('pub-req')
doc.action_holders.set([self.ad])
dah = doc.documentactionholder_set.get(person=self.ad)
dah.time_added = datetime.datetime(2020, 1, 1) # arbitrary date in the past
dah.time_added = datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc) # arbitrary date in the past
dah.save()
self.assertNotEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), datetime.date.today())
today = date_today()
self.assertNotEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), today)
self.update_doc_state(doc, State.objects.get(slug='ad-eval'))
self.assertEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), datetime.date.today())
self.assertEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), today)
def test_update_action_holders_add_tag_need_rev(self):
"""Adding need-rev tag adds authors as action holders"""

View file

@ -13,12 +13,14 @@ import textwrap
from collections import defaultdict, namedtuple
from urllib.parse import quote
from zoneinfo import ZoneInfo
from django.conf import settings
from django.contrib import messages
from django.forms import ValidationError
from django.http import Http404
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.html import escape
from django.urls import reverse as urlreverse
@ -39,6 +41,7 @@ from ietf.review.models import ReviewWish
from ietf.utils import draft, log
from ietf.utils.mail import send_mail
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.timezone import date_today, datetime_from_date, datetime_today, DEADLINE_TZINFO
from ietf.utils.xmldraft import XMLDraft
@ -637,11 +640,22 @@ def has_same_ballot(doc, date1, date2=None):
""" Test if the most recent ballot created before the end of date1
is the same as the most recent ballot created before the
end of date 2. """
datetime1 = datetime_from_date(date1, DEADLINE_TZINFO)
if date2 is None:
date2 = datetime.date.today()
ballot1 = doc.latest_event(BallotDocEvent,type='created_ballot',time__lt=date1+datetime.timedelta(days=1))
ballot2 = doc.latest_event(BallotDocEvent,type='created_ballot',time__lt=date2+datetime.timedelta(days=1))
return ballot1==ballot2
datetime2 = datetime_today(DEADLINE_TZINFO)
else:
datetime2 = datetime_from_date(date2, DEADLINE_TZINFO)
ballot1 = doc.latest_event(
BallotDocEvent,
type='created_ballot',
time__lt=datetime1 + datetime.timedelta(days=1),
)
ballot2 = doc.latest_event(
BallotDocEvent,
type='created_ballot',
time__lt=datetime2 + datetime.timedelta(days=1),
)
return ballot1 == ballot2
def make_notify_changed_event(request, doc, by, new_notify, time=None):
@ -687,7 +701,7 @@ def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None
and on_agenda
and prev_agenda
and new_telechat_date != prev_telechat
and prev_telechat < datetime.date.today()
and prev_telechat < date_today(DEADLINE_TZINFO)
and has_same_ballot(doc,prev.telechat_date)
):
returning = True
@ -718,7 +732,7 @@ def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None
e.save()
has_short_fuse = doc.type_id=='draft' and new_telechat_date and (( new_telechat_date - datetime.date.today() ) < datetime.timedelta(days=13))
has_short_fuse = doc.type_id=='draft' and new_telechat_date and (( new_telechat_date - date_today() ) < datetime.timedelta(days=13))
from ietf.doc.mails import email_update_telechat
@ -808,7 +822,7 @@ def set_replaces_for_document(request, doc, new_replaces, by, email_subject, com
cc.update(other_addrs.cc)
RelatedDocument.objects.filter(source=doc, target=d, relationship=relationship).delete()
if not RelatedDocument.objects.filter(target=d, relationship=relationship):
s = 'active' if d.document.expires > datetime.datetime.now() else 'expired'
s = 'active' if d.document.expires > timezone.now() else 'expired'
d.document.set_state(State.objects.get(type='draft', slug=s))
for d in new_replaces:
@ -956,6 +970,7 @@ def make_rev_history(doc):
history[url]['pages'] = d.history_set.filter(rev=e.newrevisiondocevent.rev).first().pages
if doc.type_id == "draft":
# e.time.date() agrees with RPC publication date when shown in the RPC_TZINFO time zone
e = doc.latest_event(type='published_rfc')
else:
e = doc.latest_event(type='iesg_approved')
@ -1119,7 +1134,7 @@ def build_doc_meta_block(doc, path):
lines[i] = line
return lines
#
now = datetime.datetime.now()
now = timezone.now()
draft_state = doc.get_state('draft')
block = ''
meta = {}
@ -1337,14 +1352,15 @@ def bibxml_for_draft(doc, rev=None):
latest_revision_event = doc.latest_event(NewRevisionDocEvent, type="new_revision")
latest_revision_rev = latest_revision_event.rev if latest_revision_event else None
best_events = NewRevisionDocEvent.objects.filter(doc__name=doc.name, rev=(rev or latest_revision_rev))
tzinfo = ZoneInfo(settings.TIME_ZONE)
if best_events.exists():
# There was a period where it was possible to get more than one NewRevisionDocEvent for a revision.
# A future data cleanup would allow this to be simplified
best_event = best_events.order_by('time').first()
log.assertion('doc.rev == best_event.rev')
doc.date = best_event.time.date()
doc.date = best_event.time.astimezone(tzinfo).date()
else:
doc.date = doc.time.date() # Even if this may be incoreect, what would be better?
doc.date = doc.time.astimezone(tzinfo).date() # Even if this may be incorrect, what would be better?
return render_to_string('doc/bibxml.xml', {'name':doc.name, 'doc': doc, 'doc_bibtype':'I-D'})

View file

@ -11,6 +11,7 @@ import shutil
from django.conf import settings
from django.urls import reverse as urlreverse
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.encoding import smart_text, force_text
import debug # pyflakes:ignore
@ -24,6 +25,8 @@ from ietf.utils.mail import parse_preformatted
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.log import log
from ietf.group.utils import save_group_in_history
from ietf.utils.timezone import date_today
def charter_name_for_group(group):
if group.type_id == "rg":
@ -73,7 +76,7 @@ def change_group_state_after_charter_approval(group, by):
save_group_in_history(group)
group.state = new_state
group.time = datetime.datetime.now()
group.time = timezone.now()
group.save()
# create an event for the group state change, too
@ -132,7 +135,7 @@ def historic_milestones_for_charter(charter, rev):
# revision (when approving a charter)
just_before_next_rev = e[0].time - datetime.timedelta(seconds=5)
else:
just_before_next_rev = datetime.datetime.now()
just_before_next_rev = timezone.now()
res = []
if hasattr(charter, 'chartered_group'):
@ -197,7 +200,7 @@ def derive_new_work_text(review_text,group):
return smart_text(m.as_string())
def default_review_text(group, charter, by):
now = datetime.datetime.now()
now = timezone.now()
addrs = gather_address_lists('charter_external_review',group=group).as_strings(compact=False)
e1 = WriteupDocEvent(doc=charter, rev=charter.rev, by=by)
@ -215,7 +218,7 @@ def default_review_text(group, charter, by):
parent_ads=group.parent.role_set.filter(name='ad'),
techadv=group.role_set.filter(name="techadv"),
milestones=group.groupmilestone_set.filter(state="charter"),
review_date=(datetime.date.today() + datetime.timedelta(weeks=1)).isoformat(),
review_date=(date_today() + datetime.timedelta(weeks=1)).isoformat(),
review_type="new" if group.state_id in ["proposed","bof"] else "recharter",
to=addrs.to,
cc=addrs.cc,

View file

@ -5,11 +5,17 @@ import re
import datetime
import debug # pyflakes:ignore
from zoneinfo import ZoneInfo
from django.conf import settings
from ietf.doc.models import Document, DocAlias, RelatedDocument, DocEvent, TelechatDocEvent, BallotDocEvent
from ietf.doc.expire import expirable_drafts
from ietf.doc.utils import augment_docs_and_user_with_user_info
from ietf.meeting.models import SessionPresentation, Meeting, Session
from ietf.review.utils import review_assignments_to_list_for_docs
from ietf.utils.timezone import date_today
def wrap_value(v):
return lambda: v
@ -30,8 +36,9 @@ def fill_in_telechat_date(docs, doc_dict=None, doc_ids=None):
seen.add(e.doc_id)
def fill_in_document_sessions(docs, doc_dict, doc_ids):
beg_date = datetime.date.today()-datetime.timedelta(days=7)
end_date = datetime.date.today()+datetime.timedelta(days=30)
today = date_today()
beg_date = today-datetime.timedelta(days=7)
end_date = today+datetime.timedelta(days=30)
meetings = Meeting.objects.filter(date__gte=beg_date, date__lte=end_date).prefetch_related('session_set')
# get sessions
sessions = Session.objects.filter(meeting_id__in=[ m.id for m in meetings ])
@ -204,7 +211,7 @@ def prepare_document_table(request, docs, query=None, max_results=200):
if sort_key == "title":
res.append(d.title)
elif sort_key == "date":
res.append(str(d.latest_revision_date))
res.append(str(d.latest_revision_date.astimezone(ZoneInfo(settings.TIME_ZONE))))
elif sort_key == "status":
if rfc_num != None:
res.append(num(rfc_num))

View file

@ -40,6 +40,8 @@ from ietf.person.models import Person
from ietf.utils.mail import send_mail_text, send_mail_preformatted
from ietf.utils.decorators import require_api_key
from ietf.utils.response import permission_denied
from ietf.utils.timezone import date_today, datetime_from_date, DEADLINE_TZINFO
BALLOT_CHOICES = (("yes", "Yes"),
("noobj", "No Objection"),
@ -1055,9 +1057,11 @@ def make_last_call(request, name):
e.desc = "The following Last Call announcement was sent out (ends %s):<br><br>" % expiration_date
e.desc += announcement
if form.cleaned_data['last_call_sent_date'] != e.time.date():
e.time = datetime.datetime.combine(form.cleaned_data['last_call_sent_date'], e.time.time())
e.expires = expiration_date
e_production_time = e.time.astimezone(DEADLINE_TZINFO)
if form.cleaned_data['last_call_sent_date'] != e_production_time.date():
lcsd = form.cleaned_data['last_call_sent_date']
e.time = e_production_time.replace(year=lcsd.year, month=lcsd.month, day=lcsd.day) # preserves tzinfo
e.expires = datetime_from_date(expiration_date, DEADLINE_TZINFO)
e.save()
events.append(e)
@ -1080,7 +1084,7 @@ def make_last_call(request, name):
return HttpResponseRedirect(doc.get_absolute_url())
else:
initial = {}
initial["last_call_sent_date"] = datetime.date.today()
initial["last_call_sent_date"] = date_today()
if doc.type.slug == 'draft':
# This logic is repeated in the code that edits last call text - why?
expire_days = 14
@ -1091,7 +1095,7 @@ def make_last_call(request, name):
expire_days=28
templ = 'doc/status_change/make_last_call.html'
initial["last_call_expiration_date"] = datetime.date.today() + datetime.timedelta(days=expire_days)
initial["last_call_expiration_date"] = date_today() + datetime.timedelta(days=expire_days)
form = MakeLastCallForm(initial=initial)
@ -1108,7 +1112,7 @@ def issue_irsg_ballot(request, name):
raise Http404
by = request.user.person
fillerdate = datetime.date.today() + datetime.timedelta(weeks=2)
fillerdate = date_today(DEADLINE_TZINFO) + datetime.timedelta(weeks=2)
if request.method == 'POST':
button = request.POST.get("irsg_button")
@ -1117,7 +1121,7 @@ def issue_irsg_ballot(request, name):
e = IRSGBallotDocEvent(doc=doc, rev=doc.rev, by=request.user.person)
if (duedate == None or duedate==""):
duedate = str(fillerdate)
e.duedate = datetime.datetime.strptime(duedate, '%Y-%m-%d')
e.duedate = datetime_from_date(datetime.datetime.strptime(duedate, '%Y-%m-%d'), DEADLINE_TZINFO)
e.type = "created_ballot"
e.desc = "Created IRSG Ballot"
ballot_type = BallotType.objects.get(doc_type=doc.type, slug="irsg-approve")
@ -1188,7 +1192,10 @@ def irsg_ballot_status(request):
ballot = doc.active_ballot()
if ballot:
doc.ballot = ballot
doc.duedate=datetime.datetime.strftime(ballot.irsgballotdocevent.duedate, '%Y-%m-%d')
doc.duedate=datetime.datetime.strftime(
ballot.irsgballotdocevent.duedate.astimezone(DEADLINE_TZINFO),
'%Y-%m-%d',
)
docs.append(doc)

View file

@ -16,6 +16,7 @@ from django.utils.safestring import mark_safe
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.html import escape
@ -77,7 +78,7 @@ def change_state(request, name, option=None):
chartering_type = get_chartering_type(charter)
initial_review = charter.latest_event(InitialReviewDocEvent, type="initial_review")
if charter.get_state_slug() != "infrev" or (initial_review and initial_review.expires < datetime.datetime.now()) or chartering_type == "rechartering":
if charter.get_state_slug() != "infrev" or (initial_review and initial_review.expires < timezone.now()) or chartering_type == "rechartering":
initial_review = None
by = request.user.person
@ -183,7 +184,7 @@ def change_state(request, name, option=None):
if charter_state.slug == "infrev" and clean["initial_time"] and clean["initial_time"] != 0:
e = InitialReviewDocEvent(type="initial_review", by=by, doc=charter, rev=charter.rev)
e.expires = datetime.datetime.now() + datetime.timedelta(weeks=clean["initial_time"])
e.expires = timezone.now() + datetime.timedelta(weeks=clean["initial_time"])
e.desc = "Initial review time expires %s" % e.expires.strftime("%Y-%m-%d")
e.save()
@ -506,7 +507,7 @@ def review_announcement_text(request, name):
existing_new_work.type = "changed_new_work_text"
existing_new_work.desc = "%s review text was changed" % group.type.name
existing_new_work.text = derive_new_work_text(existing.text,group)
existing_new_work.time = datetime.datetime.now()
existing_new_work.time = timezone.now()
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=escape(existing.text),new_work_text=escape(existing_new_work.text)))
@ -514,7 +515,7 @@ def review_announcement_text(request, name):
form = ReviewAnnouncementTextForm(request.POST)
if "save_text" in request.POST and form.is_valid():
now = datetime.datetime.now()
now = timezone.now()
events = []
t = form.cleaned_data['announcement_text']

View file

@ -34,7 +34,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import datetime
import glob
import io
import json
@ -85,6 +84,7 @@ from ietf.utils import markup_txt, log, markdown
from ietf.utils.draft import PlaintextDraft
from ietf.utils.response import permission_denied
from ietf.utils.text import maybe_split
from ietf.utils.timezone import date_today
def render_document_top(request, doc, tab, name):
@ -186,7 +186,7 @@ def document_main(request, name, rev=None):
telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
if telechat and (not telechat.telechat_date or telechat.telechat_date < datetime.date.today()):
if telechat and (not telechat.telechat_date or telechat.telechat_date < date_today(settings.TIME_ZONE)):
telechat = None
@ -990,7 +990,7 @@ def document_bibtex(request, name, rev=None):
latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision")
replaced_by = [d.name for d in doc.related_that("replaces")]
published = doc.latest_event(type="published_rfc")
published = doc.latest_event(type="published_rfc") is not None
rfc = latest_revision.doc if latest_revision and latest_revision.doc.get_state_slug() == "rfc" else None
if rev != None and rev != doc.rev:
@ -1408,11 +1408,12 @@ def telechat_date(request, name):
warnings = []
if e and e.telechat_date and doc.type.slug != 'charter':
if e.telechat_date==datetime.date.today():
today = date_today(settings.TIME_ZONE)
if e.telechat_date == today:
warnings.append( "This document is currently scheduled for today's telechat. "
+"Please set the returning item bit carefully.")
elif e.telechat_date<datetime.date.today() and has_same_ballot(doc,e.telechat_date):
elif e.telechat_date < today and has_same_ballot(doc,e.telechat_date):
initial_returning_item = True
warnings.append( "This document appears to have been on a previous telechat with the same ballot, "
+"so the returning item bit has been set. Clear it if that is not appropriate.")

View file

@ -19,6 +19,7 @@ from django.shortcuts import render, get_object_or_404, redirect
from django.template.loader import render_to_string
from django.forms.utils import ErrorList
from django.template.defaultfilters import pluralize
from django.utils import timezone
import debug # pyflakes:ignore
@ -52,6 +53,8 @@ from ietf.utils.mail import send_mail, send_mail_message, on_behalf_of
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.utils import log
from ietf.utils.response import permission_denied
from ietf.utils.timezone import datetime_today, DEADLINE_TZINFO
class ChangeStateForm(forms.Form):
state = forms.ModelChoiceField(State.objects.filter(used=True, type="draft-iesg"), empty_label=None, required=True)
@ -857,7 +860,7 @@ def resurrect(request, name):
events.append(e)
doc.set_state(State.objects.get(used=True, type="draft", slug="active"))
doc.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
doc.expires = timezone.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
doc.save_with_history(events)
restore_draft_file(request, doc)
@ -1480,7 +1483,7 @@ def adopt_draft(request, name):
due_date = None
if form.cleaned_data["weeks"] != None:
due_date = datetime.date.today() + datetime.timedelta(weeks=form.cleaned_data["weeks"])
due_date = datetime_today(DEADLINE_TZINFO) + datetime.timedelta(weeks=form.cleaned_data["weeks"])
update_reminder(doc, "stream-s", e, due_date)
@ -1671,7 +1674,7 @@ def change_stream_state(request, name, state_type):
due_date = None
if form.cleaned_data["weeks"] != None:
due_date = datetime.date.today() + datetime.timedelta(weeks=form.cleaned_data["weeks"])
due_date = datetime_today(DEADLINE_TZINFO) + datetime.timedelta(weeks=form.cleaned_data["weeks"])
update_reminder(doc, "stream-s", e, due_date)

View file

@ -10,7 +10,9 @@ import datetime
import requests
import email.utils
from django.utils import timezone
from django.utils.http import is_safe_url
from simple_history.utils import update_change_reason
import debug # pyflakes:ignore
@ -52,6 +54,8 @@ from ietf.utils.mail import send_mail_message
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.fields import MultiEmailField
from ietf.utils.response import permission_denied
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
def clean_doc_revision(doc, rev):
if rev:
@ -92,7 +96,7 @@ class RequestReviewForm(forms.ModelForm):
def clean_deadline(self):
v = self.cleaned_data.get('deadline')
if v < datetime.date.today():
if v < date_today(DEADLINE_TZINFO):
raise forms.ValidationError("Select today or a date in the future.")
return v
@ -117,7 +121,7 @@ def request_review(request, name):
if not can_request_review_of_doc(request.user, doc):
permission_denied(request, "You do not have permission to perform this action")
now = datetime.datetime.now()
now = timezone.now()
lc_ends = None
e = doc.latest_event(LastCallDocEvent, type="sent_last_call")
@ -348,7 +352,7 @@ class RejectReviewerAssignmentForm(forms.Form):
def reject_reviewer_assignment(request, name, assignment_id):
doc = get_object_or_404(Document, name=name)
review_assignment = get_object_or_404(ReviewAssignment, pk=assignment_id, state__in=["assigned", "accepted"])
review_request_past_deadline = review_assignment.review_request.deadline < datetime.date.today()
review_request_past_deadline = review_assignment.review_request.deadline < date_today(DEADLINE_TZINFO)
if not review_assignment.reviewer:
return redirect(review_request, name=review_assignment.review_request.doc.name, request_id=review_assignment.review_request.pk)
@ -364,7 +368,7 @@ def reject_reviewer_assignment(request, name, assignment_id):
if form.is_valid():
# reject the assignment
review_assignment.state = ReviewAssignmentStateName.objects.get(slug="rejected")
review_assignment.completed_on = datetime.datetime.now()
review_assignment.completed_on = timezone.now()
review_assignment.save()
descr = "Assignment of request for {} review by {} to {} was rejected".format(
@ -531,7 +535,7 @@ class CompleteReviewForm(forms.Form):
review_url = forms.URLField(label="Link to message", required=False)
review_file = forms.FileField(label="Text file to upload", required=False)
review_content = forms.CharField(widget=forms.Textarea, required=False, strip=False)
completion_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={ "autoclose": "1" }, initial=datetime.date.today, help_text="Date of announcement of the results of this review")
completion_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={ "autoclose": "1" }, initial=date_today, help_text="Date of announcement of the results of this review")
completion_time = forms.TimeField(widget=forms.HiddenInput, initial=datetime.time.min)
cc = MultiEmailField(required=False, help_text="Email addresses to send to in addition to the review team list")
email_ad = forms.BooleanField(label="Send extra email to the responsible AD suggesting early attention", required=False)
@ -704,7 +708,7 @@ def complete_review(request, name, assignment_id=None, acronym=None):
team.acronym,
request_type.slug,
xslugify(reviewer.person.ascii_parts()[3]),
datetime.date.today().isoformat(),
date_today().isoformat(),
]
review_name = "-".join(c for c in name_components if c).lower()
if not Document.objects.filter(name=review_name).exists():
@ -723,7 +727,7 @@ def complete_review(request, name, assignment_id=None, acronym=None):
type=form.cleaned_data['review_type'],
doc=doc,
team=team,
deadline=datetime.date.today(),
deadline=date_today(DEADLINE_TZINFO),
requested_by=Person.objects.get(user=request.user),
requested_rev=form.cleaned_data['reviewed_rev'],
)
@ -731,13 +735,13 @@ def complete_review(request, name, assignment_id=None, acronym=None):
review_request=review_request,
state_id='assigned',
reviewer=form.cleaned_data['reviewer'].role_email('reviewer', group=team),
assigned_on=datetime.datetime.now(),
assigned_on=timezone.now(),
review = review,
)
review.rev = "00" if not review.rev else "{:02}".format(int(review.rev) + 1)
review.title = "{} Review of {}-{}".format(assignment.review_request.type.name, assignment.review_request.doc.name, form.cleaned_data["reviewed_rev"])
review.time = datetime.datetime.now()
review.time = timezone.now()
if review_submission == "link":
review.external_url = form.cleaned_data['review_url']
@ -764,9 +768,13 @@ def complete_review(request, name, assignment_id=None, acronym=None):
with io.open(filename, 'w', encoding='utf-8') as destination:
destination.write(content)
completion_datetime = datetime.datetime.now()
completion_datetime = timezone.now()
if "completion_date" in form.cleaned_data:
completion_datetime = datetime.datetime.combine(form.cleaned_data["completion_date"], form.cleaned_data.get("completion_time") or datetime.time.min)
completion_datetime = datetime.datetime.combine(
form.cleaned_data["completion_date"],
form.cleaned_data.get("completion_time") or datetime.time.min,
tzinfo=DEADLINE_TZINFO,
)
# complete assignment
assignment.state = form.cleaned_data["state"]
@ -778,7 +786,7 @@ def complete_review(request, name, assignment_id=None, acronym=None):
need_to_email_review = review_submission != "link" and assignment.review_request.team.list_email and not revising_review
submitted_on_different_date = completion_datetime.date() != datetime.date.today()
submitted_on_different_date = completion_datetime.date() != date_today(DEADLINE_TZINFO)
desc = "Request for {} review by {} {}: {}. Reviewer: {}.".format(
assignment.review_request.type.name,
assignment.review_request.team.acronym.upper(),
@ -799,7 +807,7 @@ def complete_review(request, name, assignment_id=None, acronym=None):
close_event.by = request.user.person
close_event.desc = desc
close_event.state = assignment.state
close_event.time = datetime.datetime.now()
close_event.time = timezone.now()
close_event.save()
# If the completion date is different, record when the initial review was made too.
@ -894,8 +902,13 @@ def complete_review(request, name, assignment_id=None, acronym=None):
}
try:
initial['review_content'] = render_to_string('/group/%s/review/content_templates/%s.txt' % (assignment.review_request.team.acronym,
request_type.slug), {'assignment':assignment, 'today':datetime.date.today()})
initial['review_content'] = render_to_string(
f'/group/{assignment.review_request.team.acronym}/review/content_templates/{request_type.slug}.txt',
{
'assignment': assignment,
'today': date_today(settings.TIME_ZONE),
},
)
except (TemplateDoesNotExist, AttributeError):
pass
@ -984,7 +997,7 @@ class EditReviewRequestDeadlineForm(forms.ModelForm):
def clean_deadline(self):
v = self.cleaned_data.get('deadline')
if v < datetime.date.today():
if v < date_today(DEADLINE_TZINFO):
raise forms.ValidationError("Select today or a date in the future.")
return v

View file

@ -453,7 +453,7 @@ def ad_dashboard_sort_key(doc):
ageseconds = 0
changetime= doc.latest_event(type='changed_document')
if changetime:
ad = (datetime.datetime.now()-doc.latest_event(type='changed_document').time)
ad = (timezone.now()-doc.latest_event(type='changed_document').time)
ageseconds = (ad.microseconds + (ad.seconds + ad.days * 24 * 3600) * 10**6) / 10**6
return "1%d%s%s%010d" % (state[0].order,seed,doc.type.slug,ageseconds)
@ -761,7 +761,7 @@ def recent_drafts(request, days=7):
cache_key = f'recentdraftsview{days}'
cached_val = slowcache.get(cache_key)
if not cached_val:
since = datetime.datetime.now()-datetime.timedelta(days=days)
since = timezone.now()-datetime.timedelta(days=days)
state = State.objects.get(type='draft', slug='active')
events = NewRevisionDocEvent.objects.filter(time__gt=since)
names = [ e.doc.name for e in events ]

View file

@ -19,6 +19,8 @@ from ietf.doc.utils import get_search_cache_key
from ietf.doc.views_search import SearchForm, retrieve_search_results
from ietf.name.models import DocTypeName
from ietf.person.models import Person
from ietf.utils.timezone import date_today
epochday = datetime.datetime.utcfromtimestamp(0).date().toordinal()
@ -47,7 +49,7 @@ def model_to_timeline_data(model, field='time', **kwargs):
# This is needed for sqlite, when we're running tests:
if type(obj_list[0]['date']) != datetime.date:
obj_list = [ {'date': dt(e['date']), 'count': e['count']} for e in obj_list ]
today = datetime.date.today()
today = date_today()
if not obj_list[-1]['date'] == today:
obj_list += [ {'date': today, 'count': 0} ]
data = [ ((e['date'].toordinal()-epochday)*1000*60*60*24, e['count']) for e in obj_list ]

View file

@ -35,6 +35,7 @@ from ietf.name.models import DocRelationshipName, StdLevelName
from ietf.person.models import Person
from ietf.utils.mail import send_mail_preformatted
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
class ChangeStateForm(forms.Form):
@ -638,7 +639,7 @@ def generate_last_call_text(request, doc):
# and when groups are set, vary the expiration time accordingly
requester = "an individual participant"
expiration_date = datetime.date.today() + datetime.timedelta(days=28)
expiration_date = date_today(DEADLINE_TZINFO) + datetime.timedelta(days=28)
cc = []
new_text = render_to_string("doc/status_change/last_call_announcement.txt",

View file

@ -5,6 +5,8 @@ import factory
from typing import List # pyflakes:ignore
from django.utils import timezone
from ietf.group.models import Group, Role, GroupEvent, GroupMilestone, \
GroupHistory, RoleHistory
from ietf.review.factories import ReviewTeamSettingsFactory
@ -66,7 +68,7 @@ class BaseGroupMilestoneFactory(factory.django.DjangoModelFactory):
class DatedGroupMilestoneFactory(BaseGroupMilestoneFactory):
group = factory.SubFactory(GroupFactory, uses_milestone_dates=True)
due = datetime.datetime.today()+datetime.timedelta(days=180)
due = timezone.now()+datetime.timedelta(days=180)
class DatelessGroupMilestoneFactory(BaseGroupMilestoneFactory):
group = factory.SubFactory(GroupFactory, uses_milestone_dates=False)

View file

@ -3,7 +3,6 @@
# Stdlib imports
import datetime
import re
import debug # pyflakes:ignore
@ -27,6 +26,7 @@ from ietf.utils import log
from ietf.utils.textupload import get_cleaned_text_file_content
#from ietf.utils.ordereddict import insert_after_in_ordered_dict
from ietf.utils.fields import DatepickerDateField, MultiEmailField
from ietf.utils.timezone import date_today
from ietf.utils.validators import validate_external_resource_value
# --- Constants --------------------------------------------------------
@ -364,7 +364,7 @@ class AddUnavailablePeriodForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddUnavailablePeriodForm, self).__init__(*args, **kwargs)
self.fields["start_date"] = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label=self.fields["start_date"].label, help_text=self.fields["start_date"].help_text, required=self.fields["start_date"].required, initial=datetime.date.today())
self.fields["start_date"] = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label=self.fields["start_date"].label, help_text=self.fields["start_date"].help_text, required=self.fields["start_date"].required, initial=date_today())
self.fields["end_date"] = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label=self.fields["end_date"].label, help_text=self.fields["end_date"].help_text, required=self.fields["end_date"].required)
self.fields['availability'].widget = forms.RadioSelect(choices=UnavailablePeriod.LONG_AVAILABILITY_CHOICES)

View file

@ -15,6 +15,7 @@ from tempfile import mkstemp
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import timezone
import debug # pyflakes:ignore
@ -39,7 +40,7 @@ class Command(BaseCommand):
'have seen activity in the last %s years.' % (DEFAULT_YEARS))
def handle(self, *args, **options):
show_since = datetime.datetime.now() - datetime.timedelta(DEFAULT_YEARS*365)
show_since = timezone.now() - datetime.timedelta(DEFAULT_YEARS*365)
date = time.strftime("%Y-%m-%d_%H:%M:%S")
signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date)

View file

@ -0,0 +1,29 @@
# Generated by Django 2.2.28 on 2022-07-12 11:24
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('group', '0058_alter_has_default_chat'),
]
operations = [
migrations.AlterField(
model_name='group',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name='groupevent',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now, help_text='When the event happened'),
),
migrations.AlterField(
model_name='grouphistory',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View file

@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
import datetime
import email.utils
import jsonfield
import os
@ -13,6 +12,7 @@ from django.core.validators import RegexValidator
from django.db import models
from django.db.models.deletion import CASCADE, PROTECT
from django.dispatch import receiver
from django.utils import timezone
import debug # pyflakes:ignore
@ -27,7 +27,7 @@ from ietf.utils.validators import JSONForeignKeyListValidator
class GroupInfo(models.Model):
time = models.DateTimeField(default=datetime.datetime.now)
time = models.DateTimeField(default=timezone.now)
name = models.CharField(max_length=80)
state = ForeignKey(GroupStateName, null=True)
type = ForeignKey(GroupTypeName, null=True)
@ -180,11 +180,15 @@ class Group(GroupInfo):
return self.role_set.none()
def status_for_meeting(self,meeting):
end_date = meeting.end_date()+datetime.timedelta(days=1)
previous_meeting = meeting.previous_meeting()
status_events = self.groupevent_set.filter(type='status_update',time__lte=end_date).order_by('-time')
status_events = self.groupevent_set.filter(
type='status_update',
time__lt=meeting.end_datetime(),
).order_by('-time')
if previous_meeting:
status_events = status_events.filter(time__gte=previous_meeting.end_date()+datetime.timedelta(days=1))
status_events = status_events.filter(
time__gte=previous_meeting.end_datetime()
)
return status_events.first()
def get_description(self):
@ -353,7 +357,7 @@ GROUP_EVENT_CHOICES = [
class GroupEvent(models.Model):
"""An occurrence for a group, used for tracking who, when and what."""
group = ForeignKey(Group)
time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened")
time = models.DateTimeField(default=timezone.now, help_text="When the event happened")
type = models.CharField(max_length=50, choices=GROUP_EVENT_CHOICES)
by = ForeignKey(Person)
desc = models.TextField()

View file

@ -13,6 +13,7 @@ from django.conf import settings
from django.urls import reverse as urlreverse
from django.db.models import Q
from django.test import Client
from django.utils import timezone
import debug # pyflakes:ignore
@ -115,8 +116,8 @@ class GenerateGroupAliasesTests(TestCase):
super().tearDown()
def testManagementCommand(self):
a_month_ago = datetime.datetime.now() - datetime.timedelta(30)
a_decade_ago = datetime.datetime.now() - datetime.timedelta(3650)
a_month_ago = timezone.now() - datetime.timedelta(30)
a_decade_ago = timezone.now() - datetime.timedelta(3650)
role1 = RoleFactory(name_id='ad', group__type_id='area', group__acronym='myth', group__state_id='active')
area = role1.group
ad = role1.person

View file

@ -42,6 +42,8 @@ from ietf.person.factories import PersonFactory, EmailFactory
from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import login_testing_unauthorized, TestCase, unicontent, reload_db_objects
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
def group_urlreverse_list(group, viewname):
return [
@ -269,7 +271,7 @@ class GroupPagesTests(TestCase):
group=group,
state_id="active",
desc="Get Work Done",
due=datetime.date.today() + datetime.timedelta(days=100))
due=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=100))
milestone.docs.add(draft)
for url in [group.about_url(),] + group_urlreverse_list(group, 'ietf.group.views.group_about'):
@ -876,7 +878,7 @@ class GroupEditTests(TestCase):
self.assertEqual(r.status_code, 302)
review_assignment.state_id = 'accepted'
review_assignment.save()
review_req.deadline = datetime.date.today() - datetime.timedelta(days=1)
review_req.deadline = date_today(DEADLINE_TZINFO) - datetime.timedelta(days=1)
review_req.save()
r = self.client.post(url, post_data)
@ -1194,7 +1196,7 @@ class MilestoneTests(TestCase):
m1 = GroupMilestone.objects.create(id=1,
group=group,
desc="Test 1",
due=datetime.date.today(),
due=date_today(DEADLINE_TZINFO),
resolved="",
state_id="active")
m1.docs.set([draft])
@ -1202,7 +1204,7 @@ class MilestoneTests(TestCase):
m2 = GroupMilestone.objects.create(id=2,
group=group,
desc="Test 2",
due=datetime.date.today(),
due=date_today(DEADLINE_TZINFO),
resolved="",
state_id="charter")
m2.docs.set([draft])
@ -1246,7 +1248,7 @@ class MilestoneTests(TestCase):
events_before = group.groupevent_set.count()
doc_pks = pklist(Document.objects.filter(type="draft"))
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
due = self.last_day_of_month(date_today(DEADLINE_TZINFO) + datetime.timedelta(days=365))
# faulty post
r = self.client.post(url, { 'prefix': "m-1",
@ -1302,7 +1304,7 @@ class MilestoneTests(TestCase):
milestones_before = GroupMilestone.objects.filter(group=group).count()
events_before = group.groupevent_set.count()
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
due = self.last_day_of_month(date_today(DEADLINE_TZINFO) + datetime.timedelta(days=365))
# add
mailbox_before = len(outbox)
@ -1393,7 +1395,7 @@ class MilestoneTests(TestCase):
events_before = group.groupevent_set.count()
doc_pks = pklist(Document.objects.filter(type="draft"))
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
due = self.last_day_of_month(date_today(DEADLINE_TZINFO) + datetime.timedelta(days=365))
# faulty post
r = self.client.post(url, { 'prefix': "m1",
@ -1776,7 +1778,7 @@ class MeetingInfoTests(TestCase):
def setUp(self):
super().setUp()
self.group = GroupFactory.create(type_id='wg')
today = datetime.date.today()
today = date_today()
SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=14))
self.inprog = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1))
SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today+datetime.timedelta(days=90))
@ -1900,7 +1902,7 @@ class StatusUpdateTests(TestCase):
def test_view_status_update_for_meeting(self):
chair = RoleFactory(name_id='chair',group__type_id='wg')
GroupEventFactory(type='status_update',group=chair.group)
sess = SessionFactory.create(meeting__type_id='ietf',group=chair.group,meeting__date=datetime.datetime.today()-datetime.timedelta(days=1))
sess = SessionFactory.create(meeting__type_id='ietf',group=chair.group,meeting__date=date_today()-datetime.timedelta(days=1))
url = urlreverse('ietf.group.views.group_about_status_meeting',kwargs={'acronym':chair.group.acronym,'num':sess.meeting.number})
response = self.client.get(url)
self.assertEqual(response.status_code,200)

View file

@ -7,6 +7,7 @@ import debug # pyflakes:ignore
from ietf.doc.factories import WgDraftFactory
from ietf.group.factories import GroupFactory, RoleFactory, DatedGroupMilestoneFactory
from ietf.utils.jstest import IetfSeleniumTestCase, ifSeleniumEnabled, selenium_enabled
from ietf.utils.timezone import date_today
if selenium_enabled():
from selenium.common.exceptions import TimeoutException
@ -68,7 +69,7 @@ class MilestoneTests(IetfSeleniumTestCase):
draft = WgDraftFactory()
WgDraftFactory.create_batch(3) # some drafts to ignore
description = 'some description'
due_date = datetime.date.today() + datetime.timedelta(days=60)
due_date = date_today() + datetime.timedelta(days=60)
assert(len(draft.name) > 5)
draft_search_string = draft.name[-5:]

View file

@ -7,7 +7,9 @@ import debug # pyflakes:ignore
from pyquery import PyQuery
from django.conf import settings
from django.urls import reverse as urlreverse
from django.utils import timezone
from ietf.review.policies import get_reviewer_queue_policy
from ietf.utils.test_utils import login_testing_unauthorized, TestCase, reload_db_objects
@ -25,6 +27,7 @@ from ietf.person.factories import PersonFactory, EmailFactory
from ietf.doc.factories import DocumentFactory
from ietf.group.factories import RoleFactory, ReviewTeamFactory, GroupFactory
from ietf.review.factories import ReviewRequestFactory, ReviewerSettingsFactory, ReviewAssignmentFactory
from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO
from django.utils.html import escape
class ReviewTests(TestCase):
@ -131,7 +134,7 @@ class ReviewTests(TestCase):
doc.states.add(State.objects.get(type="draft-iesg", slug="lc", used=True))
LastCallDocEvent.objects.create(
doc=doc,
expires=datetime.datetime.now() + datetime.timedelta(days=365),
expires=timezone.now() + datetime.timedelta(days=365),
by=Person.objects.get(name="(System)"),
rev=doc.rev
)
@ -155,7 +158,7 @@ class ReviewTests(TestCase):
review_request__doc=review_req1.doc,
review_request__team=review_req1.team,
review_request__type_id="early",
review_request__deadline=datetime.date.today() + datetime.timedelta(days=30),
review_request__deadline=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=30),
review_request__state_id="assigned",
review_request__requested_by=Person.objects.get(user__username="reviewer"),
state_id = "accepted",
@ -165,7 +168,7 @@ class ReviewTests(TestCase):
UnavailablePeriod.objects.create(
team=review_req1.team,
person=reviewer,
start_date=datetime.date.today() - datetime.timedelta(days=10),
start_date=date_today() - datetime.timedelta(days=10),
availability="unavailable",
)
@ -210,7 +213,7 @@ class ReviewTests(TestCase):
review_request__doc=review_req2.doc,
review_request__team=review_req2.team,
review_request__type_id="lc",
review_request__deadline=datetime.date.today() - datetime.timedelta(days=30),
review_request__deadline=date_today(DEADLINE_TZINFO) - datetime.timedelta(days=30),
review_request__state_id="assigned",
review_request__requested_by=Person.objects.get(user__username="reviewer"),
state_id = "no-response",
@ -231,15 +234,15 @@ class ReviewTests(TestCase):
review_req3 = ReviewRequestFactory(state_id='completed', team=team)
ReviewAssignmentFactory(
review_request__doc=review_req3.doc,
review_request__time=datetime.date.today() - datetime.timedelta(days=30),
review_request__time=datetime_today() - datetime.timedelta(days=30),
review_request__team=review_req3.team,
review_request__type_id="telechat",
review_request__deadline=datetime.date.today() - datetime.timedelta(days=25),
review_request__deadline=date_today(DEADLINE_TZINFO) - datetime.timedelta(days=25),
review_request__state_id="completed",
review_request__requested_by=Person.objects.get(user__username="reviewer"),
state_id = "completed",
reviewer=reviewer.email_set.first(),
assigned_on=datetime.date.today() - datetime.timedelta(days=30)
assigned_on=datetime_today() - datetime.timedelta(days=30)
)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
@ -252,15 +255,15 @@ class ReviewTests(TestCase):
for i in range(10):
ReviewAssignmentFactory(
review_request__doc=reqs[i].doc,
review_request__time=datetime.date.today() - datetime.timedelta(days=i*30),
review_request__time=datetime_today() - datetime.timedelta(days=i*30),
review_request__team=reqs[i].team,
review_request__type_id="telechat",
review_request__deadline=datetime.date.today() - datetime.timedelta(days=i*20),
review_request__deadline=date_today(DEADLINE_TZINFO) - datetime.timedelta(days=i*20),
review_request__state_id="completed",
review_request__requested_by=Person.objects.get(user__username="reviewer"),
state_id = "completed",
reviewer=reviewer.email_set.first(),
assigned_on=datetime.date.today() - datetime.timedelta(days=i*30)
assigned_on=datetime_today() - datetime.timedelta(days=i*30)
)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
@ -304,28 +307,28 @@ class ReviewTests(TestCase):
review_req4 = ReviewRequestFactory(state_id='completed', team=team)
ReviewAssignmentFactory(
review_request__doc=review_req4.doc,
review_request__time=datetime.date.today() - datetime.timedelta(days=80),
review_request__time=datetime_today() - datetime.timedelta(days=80),
review_request__team=review_req4.team,
review_request__type_id="lc",
review_request__deadline=datetime.date.today() - datetime.timedelta(days=60),
review_request__deadline=date_today(DEADLINE_TZINFO) - datetime.timedelta(days=60),
review_request__state_id="assigned",
review_request__requested_by=Person.objects.get(user__username="reviewer"),
state_id = "accepted",
reviewer=reviewer.email_set.first(),
assigned_on=datetime.date.today() - datetime.timedelta(days=80)
assigned_on=datetime_today() - datetime.timedelta(days=80)
)
review_req5 = ReviewRequestFactory(state_id='completed', team=team)
ReviewAssignmentFactory(
review_request__doc=review_req5.doc,
review_request__time=datetime.date.today() - datetime.timedelta(days=120),
review_request__time=datetime_today() - datetime.timedelta(days=120),
review_request__team=review_req5.team,
review_request__type_id="lc",
review_request__deadline=datetime.date.today() - datetime.timedelta(days=100),
review_request__deadline=date_today(DEADLINE_TZINFO) - datetime.timedelta(days=100),
review_request__state_id="assigned",
review_request__requested_by=Person.objects.get(user__username="reviewer"),
state_id = "accepted",
reviewer=reviewer.email_set.first(),
assigned_on=datetime.date.today() - datetime.timedelta(days=120)
assigned_on=datetime_today() - datetime.timedelta(days=120)
)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
@ -429,7 +432,7 @@ class ReviewTests(TestCase):
doc.states.add(State.objects.get(type="draft-iesg", slug="lc", used=True))
LastCallDocEvent.objects.create(
doc=doc,
expires=datetime.datetime.now() + datetime.timedelta(days=365),
expires=timezone.now() + datetime.timedelta(days=365),
by=Person.objects.get(name="(System)"),
rev=doc.rev
)
@ -475,7 +478,7 @@ class ReviewTests(TestCase):
review_req1 = ReviewRequestFactory()
review_assignment_completed = ReviewAssignmentFactory(review_request=review_req1,reviewer=EmailFactory(person__user__username='marschairman'), state_id='completed', reviewed_rev=0)
ReviewAssignmentFactory(review_request=review_req1,reviewer=review_assignment_completed.reviewer)
TelechatDocEvent.objects.create(telechat_date=datetime.date.today(), type='scheduled_for_telechat', by=review_assignment_completed.reviewer.person, doc=review_req1.doc, rev=0)
TelechatDocEvent.objects.create(telechat_date=date_today(settings.TIME_ZONE), type='scheduled_for_telechat', by=review_assignment_completed.reviewer.person, doc=review_req1.doc, rev=0)
DBTemplateFactory.create(path='/group/defaults/email/open_assignments.txt',
type_id='django',
@ -555,7 +558,7 @@ class ReviewTests(TestCase):
# get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertEqual(r.context['period_form']['start_date'].initial, datetime.date.today())
self.assertEqual(r.context['period_form']['start_date'].initial, date_today())
# set settings
empty_outbox()
@ -596,7 +599,7 @@ class ReviewTests(TestCase):
self.assertEqual(settings.skip_next, 0)
# add unavailable period
start_date = datetime.date.today() + datetime.timedelta(days=10)
start_date = date_today() + datetime.timedelta(days=10)
empty_outbox()
r = self.client.post(url, {
"action": "add_period",

View file

@ -53,6 +53,7 @@ from django.http import HttpResponse, HttpResponseRedirect, Http404, JsonRespons
from django.shortcuts import render, redirect, get_object_or_404
from django.template.loader import render_to_string
from django.urls import reverse as urlreverse
from django.utils import timezone
from django.utils.html import escape
from django.views.decorators.cache import cache_page, cache_control
@ -118,6 +119,7 @@ from ietf.settings import MAILING_LIST_INFO_URL
from ietf.utils.response import permission_denied
from ietf.utils.text import strip_suffix
from ietf.utils import markdown
from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO
# --- Helpers ----------------------------------------------------------
@ -566,7 +568,7 @@ def all_status(request):
if e:
wg_reports.append(e)
wg_reports.sort(key=lambda x: (x.group.parent.acronym,datetime.datetime.now()-x.time))
wg_reports.sort(key=lambda x: (x.group.parent.acronym,timezone.now()-x.time))
rg_reports = []
for rg in rgs:
@ -808,7 +810,7 @@ def email_aliases(request, acronym=None, group_type=None):
def meetings(request, acronym=None, group_type=None):
group = get_group_or_404(acronym,group_type) if acronym else None
four_years_ago = datetime.datetime.now()-datetime.timedelta(days=4*365)
four_years_ago = timezone.now()-datetime.timedelta(days=4*365)
sessions = add_event_info_to_session_qs(
group.session_set.filter(
@ -972,7 +974,7 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
try:
group = Group.objects.get(acronym=clean["acronym"])
save_group_in_history(group)
group.time = datetime.datetime.now()
group.time = timezone.now()
group.save()
except Group.DoesNotExist:
group = Group.objects.create(name=clean["name"],
@ -1026,7 +1028,7 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
change_text=title + ' deleted: ' + ", ".join(x.name_and_email() for x in deleted)
personnel_change_text+=change_text+"\n"
today = datetime.date.today()
today = date_today()
for deleted_email in deleted:
# Verify the person doesn't have a separate reviewer role for the group with a different address
if not group.role_set.filter(name_id='reviewer',person=deleted_email.person).exists():
@ -1071,7 +1073,7 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
)
))
group.time = datetime.datetime.now()
group.time = timezone.now()
if changes and not new_group:
for attr, new, desc in changes:
@ -1387,7 +1389,7 @@ def review_requests(request, acronym, group_type=None):
unassigned_review_requests.sort(key=lambda r: r.doc.name)
open_review_assignments = list(ReviewAssignment.objects.filter(review_request__team=group, state_id__in=('assigned','accepted')).order_by('-assigned_on'))
today = datetime.date.today()
today = date_today(DEADLINE_TZINFO)
unavailable_periods = current_unavailable_periods_for_reviewers(group)
for a in open_review_assignments:
a.reviewer_unavailable = any(p.availability == "unavailable"
@ -1420,11 +1422,14 @@ def review_requests(request, acronym, group_type=None):
}[since]
closed_review_requests = closed_review_requests.filter(
Q(reviewrequestdocevent__type='closed_review_request', reviewrequestdocevent__time__gte=datetime.date.today() - date_limit)
| Q(reviewrequestdocevent__isnull=True, time__gte=datetime.date.today() - date_limit)
Q(reviewrequestdocevent__type='closed_review_request',
reviewrequestdocevent__time__gte=datetime_today(DEADLINE_TZINFO) - date_limit)
| Q(reviewrequestdocevent__isnull=True, time__gte=datetime_today(DEADLINE_TZINFO) - date_limit)
).distinct()
closed_review_assignments = closed_review_assignments.filter(completed_on__gte = datetime.date.today() - date_limit)
closed_review_assignments = closed_review_assignments.filter(
completed_on__gte = datetime_today(DEADLINE_TZINFO) - date_limit,
)
return render(request, 'group/review_requests.html',
construct_group_menu_context(request, group, "review requests", group_type, {
@ -1455,7 +1460,7 @@ def reviewer_overview(request, acronym, group_type=None):
unavailable_periods[p.person_id].append(p)
reviewer_roles = { r.person_id: r for r in Role.objects.filter(group=group, name="reviewer").select_related("email") }
today = datetime.date.today()
today = date_today()
max_closed_reqs = settings.GROUP_REVIEW_MAX_ITEMS_TO_SHOW_IN_REVIEWER_LIST
days_back = settings.GROUP_REVIEW_DAYS_TO_SHOW_IN_REVIEWER_LIST
@ -1509,7 +1514,7 @@ def reviewer_overview(request, acronym, group_type=None):
int(math.ceil(d.assignment_to_closure_days)) if d.assignment_to_closure_days is not None else None))
if d.state in ["completed", "completed_in_time", "completed_late"]:
if d.assigned_time is not None:
delta = datetime.datetime.now() - d.assigned_time
delta = timezone.now() - d.assigned_time
if d.assignment_to_closure_days is not None:
days = int(delta.days - d.assignment_to_closure_days)
if days_since > days: days_since = days
@ -1685,7 +1690,7 @@ def email_open_review_assignments(request, acronym, group_type=None):
r.section = 'Last calls:'
r.section_order='1'
e = r.review_request.doc.latest_event(LastCallDocEvent, type="sent_last_call")
r.lastcall_ends = e and e.expires.date().isoformat()
r.lastcall_ends = e and e.expires.astimezone(DEADLINE_TZINFO).date().isoformat()
r.earlier_review = ReviewAssignment.objects.filter(review_request__doc=r.review_request.doc,reviewer__in=r.reviewer.person.email_set.all(),state="completed")
if r.earlier_review:
earlier_reviews_formatted = ['-{} {} reviewed'.format(ra.reviewed_rev, ra.review_request.type.slug) for ra in r.earlier_review]
@ -1833,7 +1838,7 @@ def change_reviewer_settings(request, acronym, reviewer_email, group_type=None):
period.save()
update_change_reason(period, "Added unavailability period: {}".format(period))
today = datetime.date.today()
today = date_today()
in_the_past = period.end_date and period.end_date < today
@ -1874,7 +1879,7 @@ def change_reviewer_settings(request, acronym, reviewer_email, group_type=None):
period.delete()
update_change_reason(period, "Removed unavailability period: {}".format(period))
today = datetime.date.today()
today = date_today()
in_the_past = period.end_date and period.end_date < today

View file

@ -7,10 +7,10 @@
import datetime
import os
import pytz
from django.conf import settings
from django.template.loader import render_to_string
from django.utils import timezone
import debug # pyflakes:ignore
@ -296,6 +296,6 @@ def id_index_txt(with_abstracts=False):
return render_to_string("idindex/id_index.txt", {
'groups': groups,
'time': datetime.datetime.now(pytz.UTC).strftime("%Y-%m-%d %H:%M:%S %Z"),
'time': timezone.now().astimezone(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z"),
'with_abstracts': with_abstracts,
})

View file

@ -7,6 +7,7 @@ import datetime
from pathlib import Path
from django.conf import settings
from django.utils import timezone
import debug # pyflakes:ignore
@ -120,7 +121,7 @@ class IndexTests(TestCase):
draft.set_state(State.objects.get(type="draft", slug="active"))
draft.set_state(State.objects.get(type="draft-iesg", slug="lc"))
e = LastCallDocEvent.objects.create(doc=draft, rev=draft.rev, type="sent_last_call", expires=datetime.datetime.now() + datetime.timedelta(days=14), by=draft.ad)
e = LastCallDocEvent.objects.create(doc=draft, rev=draft.rev, type="sent_last_call", expires=timezone.now() + datetime.timedelta(days=14), by=draft.ad)
t = get_fields(all_id2_txt())
self.assertEqual(t[11], e.expires.strftime("%Y-%m-%d"))

View file

@ -17,13 +17,14 @@ from ietf.doc.models import Document, LastCallDocEvent, ConsensusDocEvent
from ietf.doc.utils_search import fill_in_telechat_date
from ietf.iesg.models import TelechatDate, TelechatAgendaItem
from ietf.review.utils import review_assignments_to_list_for_docs
from ietf.utils.timezone import date_today
def get_agenda_date(date=None):
if not date:
try:
return TelechatDate.objects.active().order_by('date')[0].date
except IndexError:
return datetime.date.today()
return date_today()
else:
try:
return TelechatDate.objects.active().get(date=datetime.datetime.strptime(date, "%Y-%m-%d").date()).date

View file

@ -2,12 +2,13 @@
# -*- coding: utf-8 -*-
import datetime
from django.conf import settings
from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Atom1Feed
from ietf.doc.models import Document, TelechatDocEvent
from ietf.utils.timezone import date_today
class IESGAgendaFeed(Feed):
title = "Documents on Future IESG Telechat Agendas"
@ -16,7 +17,7 @@ class IESGAgendaFeed(Feed):
description_template = "iesg/feed_item_description.html"
def items(self):
docs = Document.objects.filter(docevent__telechatdocevent__telechat_date__gte=datetime.date.today()).distinct()
docs = Document.objects.filter(docevent__telechatdocevent__telechat_date__gte=date_today(settings.TIME_ZONE)).distinct()
for d in docs:
d.latest_telechat_event = d.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
docs = [d for d in docs if d.latest_telechat_event.telechat_date]

View file

@ -36,8 +36,12 @@
import datetime
from django.conf import settings
from django.db import models
from ietf.utils.timezone import date_today
class TelechatAgendaItem(models.Model):
TYPE_CHOICES = (
(1, "Any Other Business (WG News, New Proposals, etc.)"),
@ -72,11 +76,11 @@ def next_telechat_date():
dates = TelechatDate.objects.order_by("-date")
if dates:
return dates[0].date + datetime.timedelta(days=14)
return datetime.date.today()
return date_today(settings.TIME_ZONE)
class TelechatDateManager(models.Manager):
def active(self):
return self.get_queryset().filter(date__gte=datetime.date.today())
return self.get_queryset().filter(date__gte=date_today(settings.TIME_ZONE))
class TelechatDate(models.Model):
objects = TelechatDateManager()

View file

@ -28,6 +28,7 @@ from ietf.name.models import StreamName
from ietf.person.models import Person
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
from ietf.iesg.factories import IESGMgmtItemFactory
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
class IESGTests(TestCase):
@ -58,7 +59,7 @@ class IESGTests(TestCase):
m = GroupMilestone.objects.create(group=draft.group,
state_id="review",
desc="Test milestone",
due=datetime.date.today())
due=date_today(DEADLINE_TZINFO))
url = urlreverse("ietf.iesg.views.milestones_needing_review")
login_testing_unauthorized(self, "ad", url)
@ -142,7 +143,7 @@ class IESGAgendaTests(TestCase):
mgmtitem = self.mgmt_items
# put on agenda
date = datetime.date.today() + datetime.timedelta(days=50)
date = date_today(settings.TIME_ZONE) + datetime.timedelta(days=50)
TelechatDate.objects.create(date=date)
telechat_event = TelechatDocEvent.objects.create(
type="scheduled_for_telechat",
@ -430,7 +431,7 @@ class IESGAgendaTests(TestCase):
self.assertNotIn(d.title, unicontent(r))
# Add the documents to a past telechat
by = Person.objects.get(name="Areað Irector")
date = datetime.date.today() - datetime.timedelta(days=14)
date = date_today(settings.TIME_ZONE) - datetime.timedelta(days=14)
approved = State.objects.get(type='draft-iesg', slug='approved')
iesg_eval = State.objects.get(type='draft-iesg', slug='iesg-eva')
for d in list(self.telechat_docs.values()):
@ -485,7 +486,7 @@ class IESGAgendaTests(TestCase):
def test_admin_change(self):
draft = Document.objects.get(name="draft-ietf-mars-test")
today = datetime.date.today()
today = date_today(settings.TIME_ZONE)
telechat_date = TelechatDate.objects.get(date=draft.telechat_date())
url = urlreverse('admin:iesg_telechatdate_change', args=(telechat_date.id,))
self.client.login(username="secretary", password="secretary+password")

View file

@ -63,6 +63,7 @@ from ietf.iesg.utils import telechat_page_count
from ietf.ietfauth.utils import has_role, role_required, user_is_person
from ietf.person.models import Person
from ietf.doc.utils_search import fill_in_document_table_attributes, fill_in_telechat_date
from ietf.utils.timezone import date_today, datetime_from_date
def review_decisions(request, year=None):
events = DocEvent.objects.filter(type__in=("iesg_disapproved", "iesg_approved"))
@ -73,9 +74,9 @@ def review_decisions(request, year=None):
year = int(year)
events = events.filter(time__year=year)
else:
d = datetime.date.today() - datetime.timedelta(days=185)
d = date_today() - datetime.timedelta(days=185)
d = datetime.date(d.year, d.month, 1)
events = events.filter(time__gte=d)
events = events.filter(time__gte=datetime_from_date(d))
events = events.select_related("doc", "doc__intended_std_level").order_by("-time", "-id")

View file

@ -8,6 +8,7 @@ from textwrap import dedent
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import timezone
import debug # pyflakes:ignore
@ -37,7 +38,7 @@ class Command(BaseCommand):
keys = PersonalApiKey.objects.filter(valid=True)
for key in keys:
earliest = datetime.datetime.now() - datetime.timedelta(days=days)
earliest = timezone.now() - datetime.timedelta(days=days)
events = PersonApiKeyEvent.objects.filter(key=key, time__gt=earliest)
count = events.count()
events = events[:32]

View file

@ -28,6 +28,7 @@ from django.urls import reverse as urlreverse
from django.contrib.auth.models import User
from django.conf import settings
from django.template.loader import render_to_string
from django.utils import timezone
import debug # pyflakes:ignore
@ -46,6 +47,8 @@ from ietf.stats.models import MeetingRegistration
from ietf.utils.decorators import skip_coverage
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.timezone import date_today
import ietf.ietfauth.views
@ -390,7 +393,7 @@ class IetfAuthTests(TestCase):
self.assertFalse(q('#volunteer-button'))
self.assertFalse(q('#volunteered'))
year = datetime.date.today().year
year = date_today().year
nomcom = NomComFactory(group__acronym=f'nomcom{year}',is_accepting_volunteers=True)
r = self.client.get(url)
self.assertEqual(r.status_code,200)
@ -505,7 +508,7 @@ class IetfAuthTests(TestCase):
UnavailablePeriod.objects.create(
team=review_req.team,
person=reviewer,
start_date=datetime.date.today() - datetime.timedelta(days=10),
start_date=date_today() - datetime.timedelta(days=10),
availability="unavailable",
)
@ -750,11 +753,11 @@ class IetfAuthTests(TestCase):
self.assertContains(r, 'Invalid apikey', status_code=403)
# too long since regular login
person.user.last_login = datetime.datetime.now() - datetime.timedelta(days=settings.UTILS_APIKEY_GUI_LOGIN_LIMIT_DAYS+1)
person.user.last_login = timezone.now() - datetime.timedelta(days=settings.UTILS_APIKEY_GUI_LOGIN_LIMIT_DAYS+1)
person.user.save()
r = self.client.post(key.endpoint, {'apikey':key.hash(), 'dummy':'dummy',})
self.assertContains(r, 'Too long since last regular login', status_code=400)
person.user.last_login = datetime.datetime.now()
person.user.last_login = timezone.now()
person.user.save()
# endpoint mismatch
@ -783,12 +786,12 @@ class IetfAuthTests(TestCase):
# apikey usage will be registered)
count = 2
# avoid usage across dates
if datetime.datetime.now().time() > datetime.time(hour=23, minute=59, second=58):
if timezone.now().time() > datetime.time(hour=23, minute=59, second=58):
time.sleep(2)
for i in range(count):
for key in person.apikeys.all():
self.client.post(key.endpoint, {'apikey':key.hash(), 'dummy': 'dummy', })
date = str(datetime.date.today())
date = str(date_today())
empty_outbox()
cmd = Command()
@ -905,7 +908,7 @@ class OpenIDConnectTests(TestCase):
# an additional email
EmailFactory(person=person)
email_list = person.email_set.all().values_list('address', flat=True)
meeting = MeetingFactory(type_id='ietf', date=datetime.date.today())
meeting = MeetingFactory(type_id='ietf', date=date_today())
MeetingRegistration.objects.create(
meeting=meeting, person=None, first_name=person.first_name(), last_name=person.last_name(),
email=email_list[0], ticket_type='full_week', reg_type='remote', affiliation='Some Company',

View file

@ -34,9 +34,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import datetime
import importlib
from datetime import date as Date, datetime as DateTime
# needed if we revert to higher barrier for account creation
#from datetime import datetime as DateTime, timedelta as TimeDelta, date as Date
from collections import defaultdict
@ -78,6 +78,7 @@ from ietf.doc.fields import SearchableDocumentField
from ietf.utils.decorators import person_required
from ietf.utils.mail import send_mail
from ietf.utils.validators import validate_external_resource_value
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
# These are needed if we revert to the higher bar for account creation
@ -223,7 +224,7 @@ def profile(request):
emails = Email.objects.filter(person=person).exclude(address__startswith='unknown-email-').order_by('-active','-time')
new_email_forms = []
nc = NomCom.objects.filter(group__acronym__icontains=Date.today().year).first()
nc = NomCom.objects.filter(group__acronym__icontains=date_today().year).first()
if nc and nc.volunteer_set.filter(person=person).exists():
volunteer_status = 'volunteered'
elif nc and nc.is_accepting_volunteers:
@ -455,7 +456,7 @@ def confirm_password_reset(request, auth):
password = data['password']
last_login = None
if data['last_login']:
last_login = DateTime.fromtimestamp(data['last_login'])
last_login = datetime.datetime.fromtimestamp(data['last_login'], datetime.timezone.utc)
except django.core.signing.BadSignature:
raise Http404("Invalid or expired auth")
@ -557,7 +558,7 @@ def review_overview(request):
reviewer__person__user=request.user,
state__in=["assigned", "accepted"],
)
today = Date.today()
today = date_today(DEADLINE_TZINFO)
for r in open_review_assignments:
r.due = max(0, (today - r.review_request.deadline).days)

View file

@ -5,6 +5,7 @@
import datetime
import factory
from django.utils import timezone
from ietf.ipr.models import (
IprDisclosureBase, HolderIprDisclosure, ThirdPartyIprDisclosure, NonDocSpecificIprDisclosure,
@ -13,7 +14,7 @@ from ietf.ipr.models import (
def _fake_patent_info():
return "Date: %s\nNotes: %s\nTitle: %s\nNumber: %s\nInventor: %s\n" % (
(datetime.datetime.today()-datetime.timedelta(days=365)).strftime("%Y-%m-%d"),
(timezone.now()-datetime.timedelta(days=365)).strftime("%Y-%m-%d"),
factory.Faker('paragraph'),
factory.Faker('sentence', nb_words=8),
'US9999999',

View file

@ -3,13 +3,14 @@
import base64
import email
import datetime
from dateutil.tz import tzoffset
import os
import pytz
import re
from email import message_from_bytes
from email.utils import parsedate_tz
from django.template.loader import render_to_string
from django.utils.encoding import force_text, force_bytes
@ -50,7 +51,7 @@ def parsedate_to_datetime(date):
http://python.readthedocs.org/en/latest/library/email.util.html
"""
try:
tuple = email.utils.parsedate_tz(date)
tuple = parsedate_tz(date)
if not tuple:
return None
tz = tuple[-1]
@ -62,10 +63,12 @@ def parsedate_to_datetime(date):
def utc_from_string(s):
date = parsedate_to_datetime(s)
if is_aware(date):
return date.astimezone(pytz.utc).replace(tzinfo=None)
if date is None:
return None
elif is_aware(date):
return date.astimezone(datetime.timezone.utc)
else:
return date
return date.replace(tzinfo=datetime.timezone.utc)
# ----------------------------------------------------------------
# Email Functions
@ -174,7 +177,7 @@ def process_response_email(msg):
a matching value in the reply_to field, associated to an IPR disclosure through
IprEvent. Create a Message object for the incoming message and associate it to
the original message via new IprEvent"""
message = email.message_from_bytes(force_bytes(msg))
message = message_from_bytes(force_bytes(msg))
to = message.get('To', '')
# exit if this isn't a response we're interested in (with plus addressing)

View file

@ -2,11 +2,10 @@
# -*- coding: utf-8 -*-
import datetime
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils import timezone
from ietf.doc.models import DocAlias, DocEvent
from ietf.name.models import DocRelationshipName,IprDisclosureStateName,IprLicenseTypeName,IprEventTypeName
@ -220,7 +219,7 @@ class IprEvent(models.Model):
"""Returns true if it's beyond the response_due date and no response has been
received"""
qs = IprEvent.objects.filter(disclosure=self.disclosure,in_reply_to=self.message)
if not qs and datetime.datetime.now().date() > self.response_due.date():
if not qs and timezone.now().date() > self.response_due.date():
return True
else:
return False

View file

@ -8,8 +8,9 @@ import datetime
from pyquery import PyQuery
from urllib.parse import quote, urlparse
from django.urls import reverse as urlreverse
from django.conf import settings
from django.urls import reverse as urlreverse
from django.utils import timezone
import debug # pyflakes:ignore
@ -27,6 +28,7 @@ from ietf.message.models import Message
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.text import text_to_dict
from ietf.utils.timezone import date_today
def make_data_from_content(content):
@ -572,7 +574,7 @@ I would like to revoke this declaration.
self.assertEqual(r.status_code,302)
self.assertEqual(len(outbox),len_before+2)
self.assertTrue('george@acme.com' in outbox[len_before]['To'])
self.assertIn('posted on '+datetime.date.today().strftime("%Y-%m-%d"), get_payload_text(outbox[len_before]).replace('\n',' '))
self.assertIn('posted on '+date_today().strftime("%Y-%m-%d"), get_payload_text(outbox[len_before]).replace('\n',' '))
self.assertTrue('draft-ietf-mars-test@ietf.org' in outbox[len_before+1]['To'])
self.assertTrue('mars-wg@ietf.org' in outbox[len_before+1]['Cc'])
self.assertIn('Secretariat on '+ipr.get_latest_event_submitted().time.strftime("%Y-%m-%d"), get_payload_text(outbox[len_before+1]).replace('\n',' '))
@ -600,7 +602,7 @@ I would like to revoke this declaration.
ipr = HolderIprDisclosureFactory()
url = urlreverse('ietf.ipr.views.email',kwargs={ "id": ipr.id })
self.client.login(username="secretary", password="secretary+password")
yesterday = datetime.date.today() - datetime.timedelta(1)
yesterday = date_today() - datetime.timedelta(1)
data = dict(
to='joe@test.com',
frm='ietf-ipr@ietf.org',
@ -640,7 +642,7 @@ I would like to revoke this declaration.
message_string.format(
to=addrs.to,
cc=addrs.cc,
date=datetime.datetime.now().ctime()
date=timezone.now().ctime()
)
)
self.assertIsNone(result)
@ -650,7 +652,7 @@ I would like to revoke this declaration.
From: joe@test.com
Date: {}
Subject: test
""".format(reply_to, datetime.datetime.now().ctime())
""".format(reply_to, timezone.now().ctime())
result = process_response_email(message_string)
self.assertIsInstance(result, Message)
@ -664,7 +666,7 @@ Subject: test
From: joe@test.com
Date: {}
Subject: test
""".format(reply_to, datetime.datetime.now().ctime())
""".format(reply_to, timezone.now().ctime())
message_bytes = message_string.encode('utf8') + b'\nInvalid stuff: \xfe\xff\n'
result = process_response_email(message_bytes)
self.assertIsInstance(result, Message)
@ -680,7 +682,7 @@ Subject: test
message_bytes = message_string.format(
to=addrs.to,
cc=addrs.cc,
date=datetime.datetime.now().ctime(),
date=timezone.now().ctime(),
).encode('utf8') + b'\nInvalid stuff: \xfe\xff\n'
result = process_response_email(message_bytes)
self.assertIsNone(result)

View file

@ -43,6 +43,7 @@ from ietf.utils.draft_search import normalize_draftname
from ietf.utils.mail import send_mail, send_mail_message
from ietf.utils.response import permission_denied
from ietf.utils.text import text_to_dict
from ietf.utils.timezone import datetime_from_date, datetime_today, DEADLINE_TZINFO
# ----------------------------------------------------------------
# Globals
@ -147,15 +148,14 @@ def ipr_rfc_number(disclosureDate, thirdPartyDisclosureFlag):
# made on 1993-07-23, which is more than a year after RFC 1310.
# RFC publication date comes from the RFC Editor announcement
# TODO: These times are tzinfo=pytz.utc, but disclosure times are offset-naive
ipr_rfc_pub_datetime = {
1310 : datetime.datetime(1992, 3, 13, 0, 0),
1802 : datetime.datetime(1994, 3, 23, 0, 0),
2026 : datetime.datetime(1996, 10, 29, 0, 0),
3668 : datetime.datetime(2004, 2, 18, 0, 0),
3979 : datetime.datetime(2005, 3, 2, 2, 23),
4879 : datetime.datetime(2007, 4, 10, 18, 21),
8179 : datetime.datetime(2017, 5, 31, 23, 1),
1310 : datetime.datetime(1992, 3, 13, 0, 0, tzinfo=datetime.timezone.utc),
1802 : datetime.datetime(1994, 3, 23, 0, 0, tzinfo=datetime.timezone.utc),
2026 : datetime.datetime(1996, 10, 29, 0, 0, tzinfo=datetime.timezone.utc),
3668 : datetime.datetime(2004, 2, 18, 0, 0, tzinfo=datetime.timezone.utc),
3979 : datetime.datetime(2005, 3, 2, 2, 23, tzinfo=datetime.timezone.utc),
4879 : datetime.datetime(2007, 4, 10, 18, 21, tzinfo=datetime.timezone.utc),
8179 : datetime.datetime(2017, 5, 31, 23, 1, tzinfo=datetime.timezone.utc),
}
if disclosureDate < ipr_rfc_pub_datetime[1310]:
@ -396,7 +396,7 @@ def email(request, id):
type_id = 'msgout',
by = request.user.person,
disclosure = ipr,
response_due = form.cleaned_data['response_due'],
response_due = datetime_from_date(form.cleaned_data['response_due'], DEADLINE_TZINFO),
message = msg,
)
@ -590,7 +590,7 @@ def notify(request, id, type):
type_id = form.cleaned_data['type'],
by = request.user.person,
disclosure = ipr,
response_due = datetime.datetime.now().date() + datetime.timedelta(days=30),
response_due = datetime_today(DEADLINE_TZINFO) + datetime.timedelta(days=30),
message = message,
)
messages.success(request,'Notifications sent')

View file

@ -3,7 +3,7 @@
import io
import datetime, os
import os
import operator
from typing import Union # pyflakes:ignore
@ -34,6 +34,7 @@ from ietf.person.models import Email
from ietf.person.fields import SearchableEmailField
from ietf.doc.models import Document, DocAlias
from ietf.utils.fields import DatepickerDateField
from ietf.utils.timezone import date_today, datetime_from_date, DEADLINE_TZINFO
from functools import reduce
'''
@ -185,9 +186,12 @@ class SearchLiaisonForm(forms.Form):
end_date = self.cleaned_data.get('end_date')
events = None
if start_date:
events = LiaisonStatementEvent.objects.filter(type='posted', time__gte=start_date)
events = LiaisonStatementEvent.objects.filter(
type='posted',
time__gte=datetime_from_date(start_date, DEADLINE_TZINFO),
)
if end_date:
events = events.filter(time__lte=end_date)
events = events.filter(time__lte=datetime_from_date(end_date, DEADLINE_TZINFO))
elif end_date:
events = LiaisonStatementEvent.objects.filter(type='posted', time__lte=end_date)
if events:
@ -222,7 +226,7 @@ class LiaisonModelForm(BetterModelForm):
to_groups.widget.attrs['data-minimum-input-length'] = 0
deadline = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Deadline', required=True)
related_to = SearchableLiaisonStatementsField(label='Related Liaison Statement', required=False)
submitted_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Submission date', required=True, initial=datetime.date.today())
submitted_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Submission date', required=True, initial=lambda: date_today(DEADLINE_TZINFO))
attachments = CustomModelMultipleChoiceField(queryset=Document.objects,label='Attachments', widget=ShowAttachmentsWidget, required=False)
attach_title = forms.CharField(label='Title', required=False)
attach_file = forms.FileField(label='File', required=False)
@ -538,7 +542,7 @@ class EditLiaisonForm(LiaisonModelForm):
super(EditLiaisonForm, self).save(*args,**kwargs)
if self.has_changed() and 'submitted_date' in self.changed_data:
event = self.instance.liaisonstatementevent_set.filter(type='submitted').first()
event.time = self.cleaned_data.get('submitted_date')
event.time = datetime_from_date(self.cleaned_data.get('submitted_date'), DEADLINE_TZINFO)
event.save()
return self.instance

View file

@ -2,14 +2,14 @@
# -*- coding: utf-8 -*-
import datetime
from django.conf import settings
from django.template.loader import render_to_string
from ietf.utils.mail import send_mail_text
from ietf.group.models import Role
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
def send_liaison_by_email(request, liaison):
subject = 'New Liaison Statement, "%s"' % (liaison.title)
@ -61,7 +61,7 @@ def possibly_send_deadline_reminder(liaison):
0: 'today'
}
days_to_go = (liaison.deadline - datetime.date.today()).days
days_to_go = (liaison.deadline - date_today(DEADLINE_TZINFO)).days
if not (days_to_go < 0 or days_to_go in list(PREVIOUS_DAYS.keys())):
return None # no reminder

View file

@ -8,13 +8,14 @@ from django.core.management.base import BaseCommand
from ietf.liaisons.models import LiaisonStatement
from ietf.liaisons.mails import possibly_send_deadline_reminder
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
class Command(BaseCommand):
help = ("Check liaison deadlines and send a reminder if we are close to a deadline")
def handle(self, *args, **options):
today = datetime.date.today()
today = date_today(DEADLINE_TZINFO)
cutoff = today - datetime.timedelta(14)
msgs = []

View file

@ -14,6 +14,8 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.urls import reverse as urlreverse
from django.db.models import Q
from django.utils import timezone
from io import StringIO
from pyquery import PyQuery
@ -29,6 +31,8 @@ from ietf.person.models import Person
from ietf.group.models import Group
from ietf.liaisons.mails import send_sdo_reminder, possibly_send_deadline_reminder
from ietf.liaisons.views import contacts_from_roles, contact_email_from_role
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
# -------------------------------------------------
# Helper Functions
@ -50,7 +54,7 @@ def get_liaison_post_data(type='incoming'):
to_contacts='to_contacts@example.com',
purpose="info",
title="title",
submitted_date=datetime.datetime.today().strftime("%Y-%m-%d"),
submitted_date=timezone.now().strftime("%Y-%m-%d"),
body="body",
send="1" )
@ -242,7 +246,7 @@ class ManagementCommandTests(TestCase):
def test_check_liaison_deadlines(self):
from django.core.management import call_command
LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1))
LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO)+datetime.timedelta(days=1))
out = io.StringIO()
mailbox_before = len(outbox)
@ -310,7 +314,7 @@ class LiaisonManagementTests(TestCase):
self.assertNotContains(r, 'Private comment')
def test_taken_care_of(self):
liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1))
liaison = LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO)+datetime.timedelta(days=1))
url = urlreverse('ietf.liaisons.views.liaison_detail', kwargs=dict(object_id=liaison.pk))
# normal get
@ -384,8 +388,8 @@ class LiaisonManagementTests(TestCase):
self.assertTrue(liaison.liaisonstatementevent_set.filter(type='posted'))
def test_edit_liaison(self):
liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1))
LiaisonStatementEventFactory(statement=liaison,type_id='submitted', time=datetime.datetime.now()-datetime.timedelta(days=1))
liaison = LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=1))
LiaisonStatementEventFactory(statement=liaison,type_id='submitted', time=timezone.now()-datetime.timedelta(days=1))
LiaisonStatementEventFactory(statement=liaison,type_id='posted')
from_group = liaison.from_groups.first()
to_group = liaison.to_groups.first()
@ -696,7 +700,7 @@ class LiaisonManagementTests(TestCase):
from_groups = [ str(g.pk) for g in Group.objects.filter(type="sdo") ]
to_group = Group.objects.get(acronym="mars")
submitter = Person.objects.get(user__username="marschairman")
today = datetime.date.today()
today = date_today()
related_liaison = liaison
r = self.client.post(url,
dict(from_groups=from_groups,
@ -775,7 +779,7 @@ class LiaisonManagementTests(TestCase):
from_group = Group.objects.get(acronym="mars")
to_group = Group.objects.filter(type="sdo")[0]
submitter = Person.objects.get(user__username="marschairman")
today = datetime.date.today()
today = date_today()
related_liaison = liaison
r = self.client.post(url,
dict(from_groups=str(from_group.pk),
@ -843,7 +847,7 @@ class LiaisonManagementTests(TestCase):
from_group = Group.objects.get(acronym="mars")
to_group = Group.objects.filter(type="sdo")[0]
submitter = Person.objects.get(user__username="marschairman")
today = datetime.date.today()
today = date_today()
r = self.client.post(url,
dict(from_groups=str(from_group.pk),
from_contact=submitter.email_address(),
@ -862,7 +866,7 @@ class LiaisonManagementTests(TestCase):
self.assertEqual(len(outbox), mailbox_before + 1)
def test_liaison_add_attachment(self):
liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1))
liaison = LiaisonStatementFactory(deadline=date_today()+datetime.timedelta(days=1))
LiaisonStatementEventFactory(statement=liaison,type_id='submitted')
self.assertEqual(liaison.attachments.count(),0)
@ -1021,7 +1025,7 @@ class LiaisonManagementTests(TestCase):
LiaisonStatementEventFactory(type_id='posted', statement__body="Has recently in its body",statement__from_groups=[GroupFactory(type_id='sdo',acronym='ulm'),])
# Statement 2
s2 = LiaisonStatementEventFactory(type_id='posted', statement__body="That word does not occur here", statement__title="Nor does it occur here")
s2.time=datetime.datetime(2010,1,1)
s2.time=datetime.datetime(2010, 1, 1, tzinfo=datetime.timezone.utc)
s2.save()
# test list only, no search filters
@ -1148,7 +1152,7 @@ class LiaisonManagementTests(TestCase):
self.assertTrue('ulm-liaiman@' in outbox[-1]['To'])
def test_send_liaison_deadline_reminder(self):
liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1))
liaison = LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=1))
mailbox_before = len(outbox)
possibly_send_deadline_reminder(liaison)

View file

@ -187,7 +187,9 @@ class TimeSlotFactory(factory.django.DjangoModelFactory):
@factory.lazy_attribute
def time(self):
return datetime.datetime.combine(self.meeting.date,datetime.time(11,0))
return self.meeting.tz().localize(
datetime.datetime.combine(self.meeting.date, datetime.time(11, 0))
)
@factory.lazy_attribute
def duration(self):

View file

@ -32,7 +32,7 @@
"comments": "",
"list_subscribe": "",
"state": "active",
"time": "2012-02-26T00:21:36",
"time": "2012-02-26T00:21:36Z",
"unused_tags": [],
"list_archive": "",
"type": "ietf",

View file

@ -17,6 +17,7 @@ from django.contrib.auth.models import AnonymousUser
from django.urls import reverse
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from django.utils import timezone
import debug # pyflakes:ignore
@ -42,7 +43,7 @@ def get_meeting(num=None,type_in=['ietf',],days=28):
if type_in:
meetings = meetings.filter(type__in=type_in)
if num == None:
meetings = meetings.filter(date__gte=datetime.datetime.today()-datetime.timedelta(days=days)).order_by('date')
meetings = meetings.filter(date__gte=timezone.now()-datetime.timedelta(days=days)).order_by('date')
else:
meetings = meetings.filter(number=num)
if meetings.exists():
@ -51,7 +52,7 @@ def get_meeting(num=None,type_in=['ietf',],days=28):
raise Http404("No such meeting found: %s" % num)
def get_current_ietf_meeting():
meetings = Meeting.objects.filter(type='ietf',date__gte=datetime.datetime.today()-datetime.timedelta(days=31)).order_by('date')
meetings = Meeting.objects.filter(type='ietf',date__gte=timezone.now()-datetime.timedelta(days=31)).order_by('date')
return meetings.first()
def get_current_ietf_meeting_num():
@ -118,7 +119,10 @@ def preprocess_assignments_for_agenda(assignments_queryset, meeting, extra_prefe
# assignments = list(assignments_queryset) # make sure we're set in stone
assignments = assignments_queryset
meeting_time = datetime.datetime.combine(meeting.date, datetime.time())
# meeting_time is meeting-local midnight at the start of the meeting date
meeting_time = meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time())
)
# replace groups with historic counterparts
groups = [ ]
@ -1149,11 +1153,15 @@ def sessions_post_cancel(request, sessions):
def update_interim_session_assignment(form):
"""Helper function to create / update timeslot assigned to interim session"""
time = datetime.datetime.combine(
form.cleaned_data['date'],
form.cleaned_data['time'])
"""Helper function to create / update timeslot assigned to interim session
form is an InterimSessionModelForm
"""
session = form.instance
meeting = session.meeting
time = meeting.tz().localize(
datetime.datetime.combine(form.cleaned_data['date'], form.cleaned_data['time'])
)
if session.official_timeslotassignment():
slot = session.official_timeslotassignment().timeslot
slot.time = time
@ -1161,14 +1169,14 @@ def update_interim_session_assignment(form):
slot.save()
else:
slot = TimeSlot.objects.create(
meeting=session.meeting,
meeting=meeting,
type_id='regular',
duration=session.requested_duration,
time=time)
SchedTimeSessAssignment.objects.create(
timeslot=slot,
session=session,
schedule=session.meeting.schedule)
schedule=meeting.schedule)
def populate_important_dates(meeting):
assert ImportantDate.objects.filter(meeting=meeting).exists() is False

View file

@ -48,7 +48,7 @@ import socket
import datetime
import pytz
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.db.models import Q
@ -75,10 +75,12 @@ class Command(BaseCommand):
def _meeting_datetime(self, day, *time_args):
"""Generate a datetime on a meeting day"""
return datetime.datetime.combine(
self.start_date,
datetime.time(*time_args)
) + datetime.timedelta(days=day)
return self.meeting_tz.localize(
datetime.datetime.combine(
self.start_date,
datetime.time(*time_args)
) + datetime.timedelta(days=day)
)
def handle(self, *args, **options):
if socket.gethostname().split('.')[0] in ['core3', 'ietfa', 'ietfb', 'ietfc', ]:
@ -87,10 +89,7 @@ class Command(BaseCommand):
opt_delete = options.get('delete', False)
opt_use_old_conflicts = options.get('old_conflicts', False)
self.start_date = options['start_date']
meeting_tz = options['tz']
if not opt_delete and (meeting_tz not in pytz.common_timezones):
self.stderr.write("Warning: {} is not a recognized time zone.".format(meeting_tz))
meeting_tzname = options['tz']
if opt_delete:
if Meeting.objects.filter(number='999').exists():
Meeting.objects.filter(number='999').delete()
@ -98,6 +97,11 @@ class Command(BaseCommand):
else:
self.stderr.write("Test meeting IETF 999 does not exist; nothing to do.\n")
else:
try:
self.meeting_tz = pytz.timezone(meeting_tzname)
except pytz.UnknownTimeZoneError:
raise CommandError("{} is not a recognized time zone.".format(meeting_tzname))
if Meeting.objects.filter(number='999').exists():
self.stderr.write("Test meeting IETF 999 already exists; nothing to do.\n")
else:
@ -111,7 +115,7 @@ class Command(BaseCommand):
type_id='IETF',
date=self._meeting_datetime(0).date(),
days=7,
time_zone=meeting_tz,
time_zone=meeting_tzname,
)
# Set enabled constraints
@ -177,6 +181,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1584, # grow
attendees=75,
agenda_note="",
@ -197,6 +202,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2166, # sidrops
attendees=62,
agenda_note="",
@ -221,6 +227,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1452, # dnsop
attendees=160,
agenda_note="",
@ -232,6 +239,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1452, # dnsop
attendees=160,
agenda_note="",
@ -260,6 +268,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1895, # dnssd
attendees=75,
agenda_note="Joint with HOMENET",
@ -271,6 +280,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1895, # dnssd
attendees=75,
agenda_note="",
@ -305,6 +315,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2216, # lsvr
attendees=100,
agenda_note="",
@ -331,6 +342,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2161, # quic
attendees=200,
agenda_note="",
@ -343,6 +355,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2161, # quic
attendees=200,
agenda_note="",
@ -399,6 +412,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1463, # tsvwg
attendees=100,
agenda_note="",
@ -410,6 +424,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1463, # tsvwg
attendees=100,
agenda_note="",
@ -449,6 +464,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1524, # ccamp
attendees=50,
agenda_note="",
@ -473,6 +489,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1763, # dispatch
attendees=80,
agenda_note="Joint with ARTAREA",
@ -514,6 +531,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1578, # v6ops
attendees=100,
agenda_note="",
@ -539,6 +557,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1899, # stir
attendees=60,
agenda_note="",
@ -576,6 +595,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1397, # pim
attendees=30,
agenda_note="",
@ -609,6 +629,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2211, # suit
attendees=80,
agenda_note="",
@ -646,6 +667,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2234, # coinrg
attendees=100,
agenda_note="",
@ -669,6 +691,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1883, # nwcrg
attendees=35,
agenda_note="",
@ -696,6 +719,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1620, # tcpm
attendees=60,
agenda_note="",
@ -721,6 +745,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1089, # ippm
attendees=60,
agenda_note="",
@ -757,6 +782,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2164, # lamps
attendees=45,
agenda_note="",
@ -792,6 +818,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1718, # httpbis
attendees=150,
agenda_note="",
@ -803,6 +830,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1718, # httpbis
attendees=150,
agenda_note="",
@ -826,6 +854,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1924, # taps
attendees=50,
agenda_note="",
@ -873,6 +902,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1958, # dprive
attendees=120,
agenda_note="",
@ -897,6 +927,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2194, # teep
attendees=50,
agenda_note="",
@ -908,6 +939,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2194, # teep
attendees=50,
agenda_note="",
@ -934,6 +966,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=42, # iccrg
attendees=100,
agenda_note="",
@ -959,6 +992,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2231, # rats
attendees=40,
agenda_note="",
@ -970,6 +1004,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2231, # rats
attendees=40,
agenda_note="",
@ -998,6 +1033,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2219, # secdispatch
attendees=200,
agenda_note="",
@ -1033,6 +1069,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1118, # mboned
attendees=30,
agenda_note="",
@ -1061,6 +1098,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1960, # bess
attendees=90,
agenda_note="",
@ -1072,6 +1110,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1960, # bess
attendees=90,
agenda_note="",
@ -1096,6 +1135,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1803, # homenet
attendees=60,
agenda_note="Joint with DNSSD",
@ -1131,6 +1171,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1995, # acme
attendees=70,
agenda_note="",
@ -1154,6 +1195,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2150, # babel
attendees=21,
agenda_note="",
@ -1178,6 +1220,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2215, # lsr
attendees=100,
agenda_note="",
@ -1189,6 +1232,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2215, # lsr
attendees=100,
agenda_note="",
@ -1212,6 +1256,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1575, # netconf
attendees=65,
agenda_note="",
@ -1238,6 +1283,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2145, # maprg
attendees=200,
agenda_note="",
@ -1277,6 +1323,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1897, # 6lo
attendees=55,
agenda_note="",
@ -1315,6 +1362,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1723, # 6man
attendees=120,
agenda_note="",
@ -1326,6 +1374,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1723, # 6man
attendees=120,
agenda_note="",
@ -1351,6 +1400,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1853, # irtfopen
attendees=150,
agenda_note="",
@ -1391,6 +1441,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2148, # lpwan
attendees=75,
agenda_note="",
@ -1421,6 +1472,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1903, # 6tisch
attendees=60,
agenda_note="",
@ -1451,6 +1503,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1751, # lisp
attendees=45,
agenda_note="",
@ -1486,6 +1539,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1764, # mptcp
attendees=50,
agenda_note="",
@ -1510,6 +1564,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1730, # roll
attendees=50,
agenda_note="",
@ -1521,6 +1576,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1730, # roll
attendees=50,
agenda_note="",
@ -1551,6 +1607,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1187, # saag
attendees=150,
agenda_note="",
@ -1596,6 +1653,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1140, # mpls
attendees=100,
agenda_note="",
@ -1630,6 +1688,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1630, # pce
attendees=75,
agenda_note="",
@ -1664,6 +1723,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1962, # detnet
attendees=100,
agenda_note="",
@ -1696,6 +1756,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1744, # alto
attendees=25,
agenda_note="",
@ -1716,6 +1777,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1968, # gaia
attendees=60,
agenda_note="",
@ -1732,6 +1794,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2233, # git
attendees=65,
agenda_note="",
@ -1779,6 +1842,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2227, # pearg
attendees=120,
agenda_note="",
@ -1809,6 +1873,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1326, # tls
attendees=120,
agenda_note="",
@ -1820,6 +1885,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1326, # tls
attendees=120,
agenda_note="",
@ -1854,6 +1920,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1679, # tsvarea
attendees=120,
agenda_note="",
@ -1888,6 +1955,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2169, # secevent
attendees=None,
agenda_note="",
@ -1900,6 +1968,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2209, # dinrg
attendees=90,
agenda_note="",
@ -1921,6 +1990,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1714, # opsawg
attendees=70,
agenda_note="Combined OpsAWG / OpsAREA",
@ -1946,6 +2016,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1812, # avtcore
attendees=30,
agenda_note="",
@ -1978,6 +2049,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1628, # bfd
attendees=50,
agenda_note="",
@ -2007,6 +2079,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1674, # emu
attendees=50,
agenda_note="",
@ -2045,6 +2118,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1988, # hrpc
attendees=100,
agenda_note="",
@ -2068,6 +2142,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2002, # cose
attendees=60,
agenda_note="",
@ -2095,6 +2170,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1996, # dots
attendees=50,
agenda_note="",
@ -2119,6 +2195,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1041, # idr
attendees=75,
agenda_note="",
@ -2130,6 +2207,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1041, # idr
attendees=75,
agenda_note="",
@ -2158,6 +2236,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=945, # bmwg
attendees=30,
agenda_note="",
@ -2185,6 +2264,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2202, # panrg
attendees=75,
agenda_note="",
@ -2219,6 +2299,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=38, # nmrg
attendees=80,
agenda_note="",
@ -2230,6 +2311,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=38, # nmrg
attendees=80,
agenda_note="",
@ -2252,6 +2334,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1665, # intarea
attendees=60,
agenda_note="",
@ -2279,6 +2362,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1817, # lwig
attendees=50,
agenda_note="",
@ -2312,6 +2396,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1619, # rtgwg
attendees=150,
agenda_note="",
@ -2323,6 +2408,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1619, # rtgwg
attendees=150,
agenda_note="",
@ -2344,6 +2430,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2214, # rift
attendees=70,
agenda_note="",
@ -2370,6 +2457,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1905, # spring
attendees=140,
agenda_note="",
@ -2381,6 +2469,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1905, # spring
attendees=140,
agenda_note="",
@ -2401,6 +2490,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=988, # dhc
attendees=25,
agenda_note="",
@ -2429,6 +2519,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1740, # ipsecme
attendees=50,
agenda_note="",
@ -2456,6 +2547,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2146, # regext
attendees=50,
agenda_note="",
@ -2480,6 +2572,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=31, # cfrg
attendees=150,
agenda_note="",
@ -2528,6 +2621,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1849, # icnrg
attendees=80,
agenda_note="",
@ -2555,6 +2649,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1847, # dmm
attendees=45,
agenda_note="",
@ -2574,6 +2669,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2176, # jmap
attendees=20,
agenda_note="",
@ -2608,6 +2704,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1953, # calext
attendees=15,
agenda_note="1330 - 1430",
@ -2631,6 +2728,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2175, # cbor
attendees=50,
agenda_note="",
@ -2675,6 +2773,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2242, # rum
attendees=20,
agenda_note="",
@ -2699,6 +2798,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2220, # mls
attendees=125,
agenda_note="",
@ -2728,6 +2828,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2205, # extra
attendees=15,
agenda_note="1430 - 1530",
@ -2747,6 +2848,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1132, # manet
attendees=20,
agenda_note="",
@ -2766,6 +2868,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1838, # rmcat
attendees=30,
agenda_note="",
@ -2794,6 +2897,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1956, # anima
attendees=80,
agenda_note="",
@ -2805,6 +2909,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1956, # anima
attendees=80,
agenda_note="",
@ -2841,6 +2946,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1642, # ntp
attendees=30,
agenda_note="",
@ -2866,6 +2972,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1748, # oauth
attendees=50,
agenda_note="",
@ -2877,6 +2984,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1748, # oauth
attendees=50,
agenda_note="",
@ -2904,6 +3012,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1869, # sacm
attendees=30,
agenda_note="",
@ -2935,6 +3044,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1964, # bier
attendees=30,
agenda_note="",
@ -2956,6 +3066,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1985, # teas
attendees=100,
agenda_note="",
@ -2983,6 +3094,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1638, # netmod
attendees=100,
agenda_note="",
@ -2994,6 +3106,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1638, # netmod
attendees=100,
agenda_note="",
@ -3015,6 +3128,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1789, # core
attendees=60,
agenda_note="",
@ -3027,6 +3141,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1789, # core
attendees=60,
agenda_note="",
@ -3075,6 +3190,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1991, # t2trg
attendees=90,
agenda_note="",
@ -3122,6 +3238,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1921, # ace
attendees=50,
agenda_note="",
@ -3156,6 +3273,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2254, # wpack
attendees=150,
agenda_note="",
@ -3178,6 +3296,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2260, # webtrans
attendees=100,
agenda_note="",
@ -3199,6 +3318,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2253, # abcd
attendees=200,
agenda_note="",
@ -3215,6 +3335,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2255, # tmrid
attendees=30,
agenda_note="",
@ -3235,6 +3356,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2248, # mops
attendees=100,
agenda_note="",
@ -3262,6 +3384,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2256, # raw
attendees=100,
agenda_note="",
@ -3284,6 +3407,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2257, # txauth
attendees=150,
agenda_note="",
@ -3322,6 +3446,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2252, # gendispatch
attendees=75,
agenda_note="",
@ -3356,6 +3481,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1966, # dtn
attendees=30,
agenda_note="",
@ -3376,6 +3502,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2249, # lake
attendees=100,
agenda_note="",
@ -3397,6 +3524,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2258, # mathmesh
attendees=100,
agenda_note="",
@ -3412,6 +3540,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=2228, # qirg
attendees=50,
agenda_note="",
@ -3433,6 +3562,7 @@ class Command(BaseCommand):
s = Session.objects.create(
meeting=m,
type_id="regular",
purpose_id="regular",
group_id=1840, # nvo3
attendees=50,
agenda_note="",

View file

@ -1,7 +1,5 @@
# Copyright The IETF Trust 2022, All Rights Reserved
# -*- coding: utf-8 -*-
import datetime
from textwrap import dedent
from django.conf import settings
@ -9,6 +7,7 @@ from django.core.management.base import BaseCommand, CommandError
from ietf.meeting.models import Session
from ietf.utils.meetecho import ConferenceManager, MeetechoAPIError
from ietf.utils.timezone import date_today
class Command(BaseCommand):
@ -85,7 +84,7 @@ class Command(BaseCommand):
for conf in confs:
conf_sessions[conf.id] = Session.objects.filter(
group__acronym=group,
meeting__date__gte=datetime.date.today(),
meeting__date__gte=date_today(),
remote_instructions__contains=conf.url,
)
return confs, conf_sessions

View file

@ -11,6 +11,8 @@ import debug # pyflakes:ignore
from ietf.name.models import ImportantDateName
from ietf.meeting.helpers import update_important_dates
from ietf.meeting.models import Meeting, ImportantDate
from ietf.utils.timezone import date_today
class Command(BaseCommand):
@ -29,7 +31,7 @@ class Command(BaseCommand):
if not meeting:
self.stderr.write("\nMeeting not found: %s\n" % (m, ))
continue
if meeting.date < datetime.date.today() + datetime.timedelta(days=max_offset):
if meeting.date < date_today(meeting.tz()) + datetime.timedelta(days=max_offset):
self.stderr.write("\nMeeting %s: Won't change dates for meetings in the past or close future\n" % (meeting, ))
continue
self.stdout.write('\n%s\n\n' % (meeting, ))

View file

@ -0,0 +1,19 @@
# Generated by Django 2.2.28 on 2022-07-12 11:24
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('meeting', '0055_pytz_2022_2_1'),
]
operations = [
migrations.AlterField(
model_name='schedulingevent',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now, help_text='When the event happened'),
),
]

View file

@ -0,0 +1,47 @@
# Generated by Django 2.2.28 on 2022-08-08 11:37
import datetime
from django.db import migrations
# date of last meeting with an empty time_zone before this migration
LAST_EMPTY_TZ = datetime.date(2022, 7, 1)
def forward(apps, schema_editor):
Meeting = apps.get_model('meeting', 'Meeting')
# Check that we will be able to identify the migrated meetings later
old_meetings_in_pst8pdt = Meeting.objects.filter(type_id='interim', time_zone='PST8PDT', date__lte=LAST_EMPTY_TZ)
assert old_meetings_in_pst8pdt.count() == 0, 'not expecting interim meetings in PST8PDT time_zone'
meetings_with_empty_tz = Meeting.objects.filter(time_zone='')
# check our expected conditions
for mtg in meetings_with_empty_tz:
assert mtg.type_id == 'interim', 'was not expecting non-interim meetings to be affected'
assert mtg.date <= LAST_EMPTY_TZ, 'affected meeting outside expected date range'
mtg.time_zone = 'PST8PDT'
# commit the changes
Meeting.objects.bulk_update(meetings_with_empty_tz, ['time_zone'])
def reverse(apps, schema_editor):
Meeting = apps.get_model('meeting', 'Meeting')
meetings_to_restore = Meeting.objects.filter(time_zone='PST8PDT', date__lte=LAST_EMPTY_TZ)
for mtg in meetings_to_restore:
mtg.time_zone = ''
# commit the changes
Meeting.objects.bulk_update(meetings_to_restore, ['time_zone'])
class Migration(migrations.Migration):
dependencies = [
('meeting', '0056_use_timezone_now_for_meeting_models'),
]
operations = [
migrations.RunPython(forward, reverse),
]

File diff suppressed because one or more lines are too long

View file

@ -24,6 +24,7 @@ from django.db.models import Max, Subquery, OuterRef, TextField, Value, Q
from django.db.models.functions import Coalesce
from django.conf import settings
from django.urls import reverse as urlreverse
from django.utils import timezone
from django.utils.text import slugify
from django.utils.safestring import mark_safe
@ -40,7 +41,7 @@ from ietf.person.models import Person
from ietf.utils.decorators import memoize
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
from ietf.utils.text import xslugify
from ietf.utils.timezone import date2datetime
from ietf.utils.timezone import datetime_from_date, date_today
from ietf.utils.models import ForeignKey
from ietf.utils.validators import (
MaxImageSizeValidator, WrappedValidator, validate_file_size, validate_mime_type,
@ -85,7 +86,7 @@ class Meeting(models.Model):
# We can't derive time-zone from country, as there are some that have
# more than one timezone, and the pytz module doesn't provide timezone
# lookup information for all relevant city/country combinations.
time_zone = models.CharField(blank=True, max_length=255, choices=timezones)
time_zone = models.CharField(max_length=255, choices=timezones, default='UTC')
idsubmit_cutoff_day_offset_00 = models.IntegerField(blank=True,
default=settings.IDSUBMIT_DEFAULT_CUTOFF_DAY_OFFSET_00,
help_text = "The number of days before the meeting start date when the submission of -00 drafts will be closed.")
@ -137,46 +138,52 @@ class Meeting(models.Model):
def end_date(self):
return self.get_meeting_date(self.days-1)
def start_datetime(self):
"""Start-of-day on meeting.date in meeting time zone"""
return datetime_from_date(self.date, self.tz())
def end_datetime(self):
"""Datetime of the first instant _after_ the meeting's last day in meeting time zone"""
return datetime_from_date(self.get_meeting_date(self.days), self.tz())
def get_00_cutoff(self):
start_date = datetime.datetime(year=self.date.year, month=self.date.month, day=self.date.day, tzinfo=pytz.utc)
"""Get the I-D submission 00 cutoff in UTC"""
importantdate = self.importantdate_set.filter(name_id='idcutoff').first()
if not importantdate:
importantdate = self.importantdate_set.filter(name_id='00cutoff').first()
if importantdate:
cutoff_date = importantdate.date
else:
cutoff_date = start_date + datetime.timedelta(days=ImportantDateName.objects.get(slug='idcutoff').default_offset_days)
cutoff_time = date2datetime(cutoff_date) + self.idsubmit_cutoff_time_utc
cutoff_date = self.date + datetime.timedelta(days=ImportantDateName.objects.get(slug='idcutoff').default_offset_days)
cutoff_time = datetime_from_date(cutoff_date, datetime.timezone.utc) + self.idsubmit_cutoff_time_utc
return cutoff_time
def get_01_cutoff(self):
start_date = datetime.datetime(year=self.date.year, month=self.date.month, day=self.date.day, tzinfo=pytz.utc)
"""Get the I-D submission 01 cutoff in UTC"""
importantdate = self.importantdate_set.filter(name_id='idcutoff').first()
if not importantdate:
importantdate = self.importantdate_set.filter(name_id='01cutoff').first()
if importantdate:
cutoff_date = importantdate.date
else:
cutoff_date = start_date + datetime.timedelta(days=ImportantDateName.objects.get(slug='idcutoff').default_offset_days)
cutoff_time = date2datetime(cutoff_date) + self.idsubmit_cutoff_time_utc
cutoff_date = self.date + datetime.timedelta(days=ImportantDateName.objects.get(slug='idcutoff').default_offset_days)
cutoff_time = datetime_from_date(cutoff_date, datetime.timezone.utc) + self.idsubmit_cutoff_time_utc
return cutoff_time
def get_reopen_time(self):
start_date = datetime.datetime(year=self.date.year, month=self.date.month, day=self.date.day)
local_tz = pytz.timezone(self.time_zone)
local_date = local_tz.localize(start_date)
"""Get the I-D submission reopening time in meeting-local time"""
cutoff = self.get_00_cutoff()
if cutoff.date() == start_date:
if cutoff.date() == self.date:
# no cutoff, so no local-time re-open
reopen_time = cutoff
else:
# reopen time is in local timezone. May need policy change?? XXX
reopen_time = local_date + self.idsubmit_cutoff_time_utc
reopen_time = datetime_from_date(self.date, self.tz()) + self.idsubmit_cutoff_time_utc
return reopen_time
@classmethod
def get_current_meeting(cls, type="ietf"):
return cls.objects.filter(type=type, date__gte=datetime.datetime.today()-datetime.timedelta(days=7) ).order_by('date').first()
return cls.objects.filter(type=type, date__gte=timezone.now()-datetime.timedelta(days=7) ).order_by('date').first()
def get_first_cut_off(self):
return self.get_00_cutoff()
@ -338,7 +345,7 @@ class Meeting(models.Model):
for ts in self.timeslot_set.all():
if ts.location_id is None:
continue
ymd = ts.time.date()
ymd = ts.local_start_time().date()
if ymd not in time_slices:
time_slices[ymd] = []
slots[ymd] = []
@ -346,15 +353,15 @@ class Meeting(models.Model):
if ymd in time_slices:
# only keep unique entries
if [ts.time, ts.time + ts.duration, ts.duration.seconds] not in time_slices[ymd]:
time_slices[ymd].append([ts.time, ts.time + ts.duration, ts.duration.seconds])
if [ts.local_start_time(), ts.local_end_time(), ts.duration.seconds] not in time_slices[ymd]:
time_slices[ymd].append([ts.local_start_time(), ts.local_end_time(), ts.duration.seconds])
slots[ymd].append(ts)
days.sort()
for ymd in time_slices:
# Make sure these sort the same way
time_slices[ymd].sort()
slots[ymd].sort(key=lambda x: (x.time, x.duration))
slots[ymd].sort(key=lambda x: (x.local_start_time(), x.duration))
return days,time_slices,slots
# this functions makes a list of timeslices and rooms, and
@ -370,20 +377,24 @@ class Meeting(models.Model):
# SchedTimeSessAssignment.objects.create(schedule = sched,
# timeslot = ts)
def tz(self):
if not hasattr(self, '_cached_tz'):
self._cached_tz = pytz.timezone(self.time_zone)
return self._cached_tz
def vtimezone(self):
if self.time_zone:
try:
tzfn = os.path.join(settings.TZDATA_ICS_PATH, self.time_zone + ".ics")
if os.path.exists(tzfn):
with io.open(tzfn) as tzf:
icstext = tzf.read()
vtimezone = re.search("(?sm)(\nBEGIN:VTIMEZONE.*\nEND:VTIMEZONE\n)", icstext).group(1).strip()
if vtimezone:
vtimezone += "\n"
return vtimezone
except IOError:
pass
return ''
try:
tzfn = os.path.join(settings.TZDATA_ICS_PATH, self.time_zone + ".ics")
if os.path.exists(tzfn):
with io.open(tzfn) as tzf:
icstext = tzf.read()
vtimezone = re.search("(?sm)(\nBEGIN:VTIMEZONE.*\nEND:VTIMEZONE\n)", icstext).group(1).strip()
if vtimezone:
vtimezone += "\n"
return vtimezone
except IOError:
pass
return None
def set_official_schedule(self, schedule):
if self.schedule != schedule:
@ -391,16 +402,14 @@ class Meeting(models.Model):
self.save()
def updated(self):
min_time = datetime.datetime(1970, 1, 1, 0, 0, 0) # should be Meeting.modified, but we don't have that
# should be Meeting.modified, but we don't have that
min_time = pytz.utc.localize(datetime.datetime(1970, 1, 1, 0, 0, 0))
timeslots_updated = self.timeslot_set.aggregate(Max('modified'))["modified__max"] or min_time
sessions_updated = self.session_set.aggregate(Max('modified'))["modified__max"] or min_time
assignments_updated = min_time
if self.schedule:
assignments_updated = SchedTimeSessAssignment.objects.filter(schedule__in=[self.schedule, self.schedule.base if self.schedule else None]).aggregate(Max('modified'))["modified__max"] or min_time
ts = max(timeslots_updated, sessions_updated, assignments_updated)
tz = pytz.timezone(settings.PRODUCTION_TIMEZONE)
ts = tz.localize(ts)
return ts
return max(timeslots_updated, sessions_updated, assignments_updated)
@memoize
def previous_meeting(self):
@ -621,41 +630,22 @@ class TimeSlot(models.Model):
return self._cached_html_location
def tz(self):
if not hasattr(self, '_cached_tz'):
if self.meeting.time_zone:
self._cached_tz = pytz.timezone(self.meeting.time_zone)
else:
self._cached_tz = None
return self._cached_tz
return self.meeting.tz()
def tzname(self):
if self.tz():
return self.tz().tzname(self.time)
else:
return ""
return self.tz().tzname(self.time)
def utc_start_time(self):
if self.tz():
local_start_time = self.tz().localize(self.time)
return local_start_time.astimezone(pytz.utc)
else:
return None
return self.time.astimezone(pytz.utc) # USE_TZ is True, so time is aware
def utc_end_time(self):
utc_start = self.utc_start_time()
# Add duration after converting start time, otherwise errors creep in around DST change
return None if utc_start is None else utc_start + self.duration
return self.time.astimezone(pytz.utc) + self.duration # USE_TZ is True, so time is aware
def local_start_time(self):
if self.tz():
return self.tz().localize(self.time)
else:
return None
return self.time.astimezone(self.tz())
def local_end_time(self):
local_start = self.local_start_time()
# Add duration after converting start time, otherwise errors creep in around DST change
return None if local_start is None else local_start + self.duration
return (self.time.astimezone(pytz.utc) + self.duration).astimezone(self.tz())
@property
def js_identifier(self):
@ -753,7 +743,7 @@ class Schedule(models.Model):
@property
def is_official_record(self):
return (self.is_official and
self.meeting.end_date() <= datetime.date.today() )
self.meeting.end_date() <= date_today() )
# returns a dictionary {group -> [schedtimesessassignment+]}
# and it has [] if the session is not placed.
@ -1180,7 +1170,7 @@ class Session(models.Model):
return can_manage_materials(user,self.group)
def is_material_submission_cutoff(self):
return datetime.date.today() > self.meeting.get_submission_correction_date()
return date_today(datetime.timezone.utc) > self.meeting.get_submission_correction_date()
def joint_with_groups_acronyms(self):
return [group.acronym for group in self.joint_with_groups.all()]
@ -1307,7 +1297,7 @@ class Session(models.Model):
class SchedulingEvent(models.Model):
session = ForeignKey(Session)
time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened")
time = models.DateTimeField(default=timezone.now, help_text="When the event happened")
status = ForeignKey(SessionStatusName)
by = ForeignKey(Person)

View file

@ -20,11 +20,15 @@ from ietf.name.models import RoomResourceName
from ietf.person.factories import PersonFactory
from ietf.person.models import Person
from ietf.utils.test_data import make_test_data
from ietf.utils.timezone import date_today
def make_interim_meeting(group,date,status='sched'):
def make_interim_meeting(group,date,status='sched',tz='UTC'):
system_person = Person.objects.get(name="(System)")
time = datetime.datetime.combine(date, datetime.time(9))
meeting = create_interim_meeting(group=group,date=date)
meeting = create_interim_meeting(group=group,date=date,timezone=tz)
time = meeting.tz().localize(
datetime.datetime.combine(date, datetime.time(9))
)
session = SessionFactory(meeting=meeting, group=group,
attendees=10,
requested_duration=datetime.timedelta(minutes=20),
@ -102,24 +106,37 @@ def make_meeting_test_data(meeting=None, create_interims=False):
# slots
session_date = meeting.date + datetime.timedelta(days=1)
tz = meeting.tz()
slot1 = TimeSlot.objects.create(meeting=meeting, type_id='regular', location=room,
duration=datetime.timedelta(minutes=60),
time=datetime.datetime.combine(session_date, datetime.time(9, 30)))
time=tz.localize(
datetime.datetime.combine(session_date, datetime.time(9, 30))
))
slot2 = TimeSlot.objects.create(meeting=meeting, type_id='regular', location=room,
duration=datetime.timedelta(minutes=60),
time=datetime.datetime.combine(session_date, datetime.time(10, 50)))
time=tz.localize(
datetime.datetime.combine(session_date, datetime.time(10, 50))
))
breakfast_slot = TimeSlot.objects.create(meeting=meeting, type_id="lead", location=breakfast_room,
duration=datetime.timedelta(minutes=90),
time=datetime.datetime.combine(session_date, datetime.time(7,0)))
time=tz.localize(
datetime.datetime.combine(session_date, datetime.time(7,0))
))
reg_slot = TimeSlot.objects.create(meeting=meeting, type_id="reg", location=reg_room,
duration=datetime.timedelta(minutes=480),
time=datetime.datetime.combine(session_date, datetime.time(9,0)))
time=tz.localize(
datetime.datetime.combine(session_date, datetime.time(9,0))
))
break_slot = TimeSlot.objects.create(meeting=meeting, type_id="break", location=break_room,
duration=datetime.timedelta(minutes=90),
time=datetime.datetime.combine(session_date, datetime.time(7,0)))
time=tz.localize(
datetime.datetime.combine(session_date, datetime.time(7,0))
))
plenary_slot = TimeSlot.objects.create(meeting=meeting, type_id="plenary", location=room,
duration=datetime.timedelta(minutes=60),
time=datetime.datetime.combine(session_date, datetime.time(11,0)))
time=tz.localize(
datetime.datetime.combine(session_date, datetime.time(11,0))
))
# mars WG
mars = Group.objects.get(acronym='mars')
mars_session = SessionFactory(meeting=meeting, group=mars,
@ -201,8 +218,8 @@ def make_meeting_test_data(meeting=None, create_interims=False):
mars_session.sessionpresentation_set.add(pres)
# Future Interim Meetings
date = datetime.date.today() + datetime.timedelta(days=365)
date2 = datetime.date.today() + datetime.timedelta(days=1000)
date = date_today() + datetime.timedelta(days=365)
date2 = date_today() + datetime.timedelta(days=1000)
ames = Group.objects.get(acronym="ames")
if create_interims:
@ -213,9 +230,9 @@ def make_meeting_test_data(meeting=None, create_interims=False):
return meeting
def make_interim_test_data():
date = datetime.date.today() + datetime.timedelta(days=365)
date2 = datetime.date.today() + datetime.timedelta(days=1000)
def make_interim_test_data(meeting_tz='UTC'):
date = date_today() + datetime.timedelta(days=365)
date2 = date_today() + datetime.timedelta(days=1000)
PersonFactory(user__username='plain')
area = GroupFactory(type_id='area')
ad = Person.objects.get(user__username='ad')
@ -225,10 +242,10 @@ def make_interim_test_data():
RoleFactory(group=mars,person__user__username='marschairman',name_id='chair')
RoleFactory(group=ames,person__user__username='ameschairman',name_id='chair')
make_interim_meeting(group=mars,date=date,status='sched')
make_interim_meeting(group=mars,date=date2,status='apprw')
make_interim_meeting(group=ames,date=date,status='canceled')
make_interim_meeting(group=ames,date=date2,status='apprw')
make_interim_meeting(group=mars,date=date,status='sched',tz=meeting_tz)
make_interim_meeting(group=mars,date=date2,status='apprw',tz=meeting_tz)
make_interim_meeting(group=ames,date=date,status='canceled',tz=meeting_tz)
make_interim_meeting(group=ames,date=date2,status='apprw',tz=meeting_tz)
return

View file

@ -18,6 +18,7 @@ from ietf.meeting.models import SchedTimeSessAssignment, Session
from ietf.meeting.test_data import make_meeting_test_data
from ietf.utils.meetecho import Conference
from ietf.utils.test_utils import TestCase
from ietf.utils.timezone import date_today
# override the legacy office hours setting to guarantee consistency with the tests
@ -623,12 +624,13 @@ class HelperTests(TestCase):
def test_get_ietf_meeting(self):
"""get_ietf_meeting() should only return IETF meetings"""
# put the IETF far in the past so it's not "current"
ietf = MeetingFactory(type_id='ietf', date=datetime.date.today() - datetime.timedelta(days=5 * 365))
today = date_today()
ietf = MeetingFactory(type_id='ietf', date=today- datetime.timedelta(days=5 * 365))
# put the interim meeting now so it will be picked up as "current" if there's a bug
interim = MeetingFactory(type_id='interim', date=datetime.date.today())
interim = MeetingFactory(type_id='interim', date=today)
self.assertEqual(get_ietf_meeting(ietf.number), ietf, 'Return IETF meeting by number')
self.assertIsNone(get_ietf_meeting(interim.number), 'Ignore non-IETF meetings')
self.assertIsNone(get_ietf_meeting(), 'Return None if there is no current IETF meeting')
ietf.date = datetime.date.today()
ietf.date = today
ietf.save()
self.assertEqual(get_ietf_meeting(), ietf, 'Return current meeting if there is one')

View file

@ -10,8 +10,8 @@ import re
from unittest import skipIf
import django
from django.utils import timezone
from django.utils.text import slugify
from django.utils.timezone import now
from django.db.models import F
import pytz
@ -34,7 +34,7 @@ from ietf.meeting.utils import add_event_info_to_session_qs
from ietf.utils.test_utils import assert_ical_response_is_valid
from ietf.utils.jstest import ( IetfSeleniumTestCase, ifSeleniumEnabled, selenium_enabled,
presence_of_element_child_by_css_selector )
from ietf.utils.timezone import timezone_not_near_midnight
from ietf.utils.timezone import datetime_today, datetime_from_date, date_today, timezone_not_near_midnight
if selenium_enabled():
from selenium.webdriver.common.action_chains import ActionChains
@ -269,14 +269,32 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
# modal_open.click()
self.assertTrue(self.driver.find_element(By.CSS_SELECTOR, "#timeslot-group-toggles-modal").is_displayed())
self.driver.find_element(By.CSS_SELECTOR, "#timeslot-group-toggles-modal [value=\"{}\"]".format("ts-group-{}-{}".format(slot2.time.strftime("%Y%m%d-%H%M"), int(slot2.duration.total_seconds() / 60)))).click()
self.driver.find_element(
By.CSS_SELECTOR,
"#timeslot-group-toggles-modal [value=\"{}\"]".format(
"ts-group-{}-{}".format(
slot2.time.astimezone(slot2.tz()).strftime("%Y%m%d-%H%M"),
int(slot2.duration.total_seconds() / 60),
),
),
).click()
self.driver.find_element(By.CSS_SELECTOR, "#timeslot-group-toggles-modal [data-bs-dismiss=\"modal\"]").click()
self.assertTrue(not self.driver.find_element(By.CSS_SELECTOR, "#timeslot-group-toggles-modal").is_displayed())
# swap days
self.driver.find_element(By.CSS_SELECTOR, ".day .swap-days[data-dayid=\"{}\"]".format(slot4.time.date().isoformat())).click()
self.driver.find_element(
By.CSS_SELECTOR,
".day .swap-days[data-dayid=\"{}\"]".format(
slot4.time.astimezone(slot4.tz()).date().isoformat(),
),
).click()
self.assertTrue(self.driver.find_element(By.CSS_SELECTOR, "#swap-days-modal").is_displayed())
self.driver.find_element(By.CSS_SELECTOR, "#swap-days-modal input[name=\"target_day\"][value=\"{}\"]".format(slot1.time.date().isoformat())).click()
self.driver.find_element(
By.CSS_SELECTOR,
"#swap-days-modal input[name=\"target_day\"][value=\"{}\"]".format(
slot1.time.astimezone(slot1.tz()).date().isoformat(),
),
).click()
self.driver.find_element(By.CSS_SELECTOR, "#swap-days-modal button[type=\"submit\"]").click()
self.assertTrue(self.driver.find_elements(By.CSS_SELECTOR, '#timeslot{} #session{}'.format(slot4.pk, s1.pk)),
@ -306,7 +324,7 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
room = RoomFactory(meeting=meeting)
# get current time in meeting time zone
right_now = now().astimezone(
right_now = timezone.now().astimezone(
pytz.timezone(meeting.time_zone)
)
if not settings.USE_TZ:
@ -395,14 +413,14 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
wait = WebDriverWait(self.driver, 2)
meeting = MeetingFactory(
type_id='ietf',
date=datetime.datetime.today() - datetime.timedelta(days=3),
date=date=timezone.now() - datetime.timedelta(days=3),
days=7,
time_zone=timezone_not_near_midnight(),
)
room = RoomFactory(meeting=meeting)
# get current time in meeting time zone
right_now = now().astimezone(
right_now = timezone.now().astimezone(
pytz.timezone(meeting.time_zone)
)
if not settings.USE_TZ:
@ -433,21 +451,24 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
past_swap_days_buttons = self.driver.find_elements(By.CSS_SELECTOR,
','.join(
'.swap-days[data-start="{}"]'.format(ts.time.date().isoformat()) for ts in past_timeslots
'.swap-days[data-start="{}"]'.format(ts.time.astimezone(ts.tz()).date().isoformat())
for ts in past_timeslots
)
)
self.assertEqual(len(past_swap_days_buttons), len(past_timeslots), 'Missing past swap days buttons')
future_swap_days_buttons = self.driver.find_elements(By.CSS_SELECTOR,
','.join(
'.swap-days[data-start="{}"]'.format(ts.time.date().isoformat()) for ts in future_timeslots
'.swap-days[data-start="{}"]'.format(ts.time.astimezone(ts.tz()).date().isoformat())
for ts in future_timeslots
)
)
self.assertEqual(len(future_swap_days_buttons), len(future_timeslots), 'Missing future swap days buttons')
now_swap_days_buttons = self.driver.find_elements(By.CSS_SELECTOR,
','.join(
'.swap-days[data-start="{}"]'.format(ts.time.date().isoformat()) for ts in now_timeslots
'.swap-days[data-start="{}"]'.format(ts.time.astimezone(ts.tz()).date().isoformat())
for ts in now_timeslots
)
)
# only one "now" button because both sessions are on the same day
@ -498,7 +519,8 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
self.assertFalse(
any(radio.is_enabled()
for radio in modal.find_elements(By.CSS_SELECTOR, ','.join(
'input[name="target_day"][value="{}"]'.format(ts.time.date().isoformat()) for ts in past_timeslots)
'input[name="target_day"][value="{}"]'.format(ts.time.astimezone(ts.tz()).date().isoformat())
for ts in past_timeslots)
)),
'Past day is enabled in swap-days modal for official schedule',
)
@ -507,14 +529,16 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
self.assertTrue(
all(radio.is_enabled()
for radio in modal.find_elements(By.CSS_SELECTOR, ','.join(
'input[name="target_day"][value="{}"]'.format(ts.time.date().isoformat()) for ts in enabled_timeslots)
'input[name="target_day"][value="{}"]'.format(ts.time.astimezone(ts.tz()).date().isoformat())
for ts in enabled_timeslots)
)),
'Future day is not enabled in swap-days modal for official schedule',
)
self.assertFalse(
any(radio.is_enabled()
for radio in modal.find_elements(By.CSS_SELECTOR, ','.join(
'input[name="target_day"][value="{}"]'.format(ts.time.date().isoformat()) for ts in now_timeslots)
'input[name="target_day"][value="{}"]'.format(ts.time.astimezone(ts.tz()).date().isoformat())
for ts in now_timeslots)
)),
'"Now" day is enabled in swap-days modal for official schedule',
)
@ -522,11 +546,11 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
def test_past_swap_timeslot_col_buttons(self):
"""Swap timeslot column buttons should be hidden for past items"""
wait = WebDriverWait(self.driver, 2)
meeting = MeetingFactory(type_id='ietf', date=datetime.datetime.today() - datetime.timedelta(days=3), days=7)
meeting = MeetingFactory(type_id='ietf', date=timezone.now() - datetime.timedelta(days=3), days=7)
room = RoomFactory(meeting=meeting)
# get current time in meeting time zone
right_now = now().astimezone(
right_now = timezone.now().astimezone(
pytz.timezone(meeting.time_zone)
)
if not settings.USE_TZ:
@ -812,7 +836,7 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
To test for recurrence of https://trac.ietf.org/trac/ietfdb/ticket/3327 need to have some constraints that
do not conflict. Testing with only violated constraints does not exercise the code adequately.
"""
meeting = MeetingFactory(type_id='ietf', date=datetime.date.today(), populate_schedule=False)
meeting = MeetingFactory(type_id='ietf', date=date_today(), populate_schedule=False)
TimeSlotFactory.create_batch(5, meeting=meeting)
schedule = ScheduleFactory(meeting=meeting)
sessions = SessionFactory.create_batch(5, meeting=meeting, add_to_schedule=False)
@ -934,7 +958,7 @@ class InterimTests(IetfSeleniumTestCase):
# Create a group with a plenary interim session for testing type filters
somegroup = GroupFactory(acronym='sg', name='Some Group')
sg_interim = make_interim_meeting(somegroup, datetime.date.today() + datetime.timedelta(days=20))
sg_interim = make_interim_meeting(somegroup, date_today() + datetime.timedelta(days=20))
sg_sess = sg_interim.session_set.first()
sg_slot = sg_sess.timeslotassignments.first().timeslot
sg_sess.purpose_id = 'plenary'
@ -966,7 +990,7 @@ class InterimTests(IetfSeleniumTestCase):
Session.objects.filter(
meeting__type_id='interim',
timeslotassignments__schedule=F('meeting__schedule'),
timeslotassignments__timeslot__time__gte=datetime.datetime.today()
timeslotassignments__timeslot__time__gte=timezone.now()
)
).filter(current_status__in=('sched','canceled'))
meetings = []
@ -979,7 +1003,7 @@ class InterimTests(IetfSeleniumTestCase):
def all_ietf_meetings(self):
meetings = Meeting.objects.filter(
type_id='ietf',
date__gte=datetime.datetime.today()-datetime.timedelta(days=7)
date__gte=timezone.now()-datetime.timedelta(days=7)
)
for m in meetings:
m.calendar_label = 'IETF %s' % m.number
@ -1109,7 +1133,7 @@ class InterimTests(IetfSeleniumTestCase):
expected_assignments = list(SchedTimeSessAssignment.objects.filter(
schedule__in=expected_schedules,
session__in=expected_interim_sessions,
timeslot__time__gte=datetime.date.today(),
timeslot__time__gte=datetime_today(),
))
# The UID formats should match those in the upcoming.ics template
expected_uids = [
@ -1425,7 +1449,7 @@ class ProceedingsMaterialTests(IetfSeleniumTestCase):
def setUp(self):
super().setUp()
self.wait = WebDriverWait(self.driver, 2)
self.meeting = MeetingFactory(type_id='ietf', number='123', date=datetime.date.today())
self.meeting = MeetingFactory(type_id='ietf', number='123', date=date_today())
def test_add_proceedings_material(self):
url = self.absreverse(
@ -1527,7 +1551,7 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
self.meeting: Meeting = MeetingFactory(
type_id='ietf',
number=120,
date=datetime.datetime.today() + datetime.timedelta(days=10),
date=date_today() + datetime.timedelta(days=10),
populate_schedule=False,
)
self.edit_timeslot_url = self.absreverse(
@ -1597,22 +1621,23 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
self.do_delete_timeslot_test(cancel=True)
def do_delete_time_interval_test(self, cancel=False):
delete_day = self.meeting.date.date()
delete_day = self.meeting.date
delete_time = datetime.time(hour=10)
other_day = self.meeting.get_meeting_date(1).date()
other_day = self.meeting.get_meeting_date(1)
other_time = datetime.time(hour=12)
duration = datetime.timedelta(minutes=60)
delete: [TimeSlot] = TimeSlotFactory.create_batch(
2,
meeting=self.meeting,
time=datetime.datetime.combine(delete_day, delete_time),
duration=duration)
time=datetime_from_date(delete_day, self.meeting.tz()).replace(hour=delete_time.hour),
duration=duration,
)
keep: [TimeSlot] = [
TimeSlotFactory(
meeting=self.meeting,
time=datetime.datetime.combine(day, time),
time=datetime_from_date(day, self.meeting.tz()).replace(hour=time.hour),
duration=duration
)
for (day, time) in (
@ -1629,7 +1654,9 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
'[data-col-id="{}T{}-{}"]'.format(
delete_day.isoformat(),
delete_time.strftime('%H:%M'),
(datetime.datetime.combine(delete_day, delete_time) + duration).strftime(
self.meeting.tz().localize(
datetime.datetime.combine(delete_day, delete_time) + duration
).strftime(
'%H:%M'
))
)
@ -1644,22 +1671,22 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
self.do_delete_time_interval_test(cancel=True)
def do_delete_day_test(self, cancel=False):
delete_day = self.meeting.date.date()
times = [datetime.time(hour=10), datetime.time(hour=12)]
other_days = [self.meeting.get_meeting_date(d).date() for d in range(1, 3)]
delete_day = self.meeting.date
hours = [10, 12]
other_days = [self.meeting.get_meeting_date(d) for d in range(1, 3)]
delete: [TimeSlot] = [
TimeSlotFactory(
meeting=self.meeting,
time=datetime.datetime.combine(delete_day, time),
) for time in times
time=datetime_from_date(delete_day, self.meeting.tz()).replace(hour=hour),
) for hour in hours
]
keep: [TimeSlot] = [
TimeSlotFactory(
meeting=self.meeting,
time=datetime.datetime.combine(day, time),
) for day in other_days for time in times
time=datetime_from_date(day, self.meeting.tz()).replace(hour=hour),
) for day in other_days for hour in hours
]
selector = (

View file

@ -3,6 +3,8 @@
"""Tests of models in the Meeting application"""
import datetime
from mock import patch
from ietf.meeting.factories import MeetingFactory, SessionFactory, AttendedFactory
from ietf.stats.factories import MeetingRegistrationFactory
from ietf.utils.test_utils import TestCase
@ -86,6 +88,22 @@ class MeetingTests(TestCase):
self.assertEqual(att.onsite, 1)
self.assertEqual(att.remote, 0)
def test_vtimezone(self):
# normal time zone that should have a zoneinfo file
meeting = MeetingFactory(type_id='ietf', time_zone='America/Los_Angeles', populate_schedule=False)
vtz = meeting.vtimezone()
self.assertIsNotNone(vtz)
self.assertGreater(len(vtz), 0)
# time zone that does not have a zoneinfo file should return None
meeting = MeetingFactory(type_id='ietf', time_zone='Fake/Time_Zone', populate_schedule=False)
vtz = meeting.vtimezone()
self.assertIsNone(vtz)
# ioerror trying to read zoneinfo should return None
meeting = MeetingFactory(type_id='ietf', time_zone='America/Los_Angeles', populate_schedule=False)
with patch('ietf.meeting.models.io.open', side_effect=IOError):
vtz = meeting.vtimezone()
self.assertIsNone(vtz)
class SessionTests(TestCase):
def test_chat_archive_url_with_jabber(self):

View file

@ -1,6 +1,7 @@
# Copyright The IETF Trust 2020, All Rights Reserved
import calendar
import datetime
import pytz
from io import StringIO
from django.core.management.base import CommandError
@ -36,9 +37,11 @@ class ScheduleGeneratorTest(TestCase):
t = TimeSlotFactory(
meeting=self.meeting,
location=room,
time=datetime.datetime.combine(
self.meeting.date + datetime.timedelta(days=day),
datetime.time(hour, 0),
time=self.meeting.tz().localize(
datetime.datetime.combine(
self.meeting.date + datetime.timedelta(days=day),
datetime.time(hour, 0),
)
),
duration=datetime.timedelta(minutes=60),
)
@ -306,8 +309,11 @@ class ScheduleGeneratorTest(TestCase):
add_to_schedule=False
)
# use a timeslot not on Sunday
meeting_date = pytz.utc.localize(
datetime.datetime.combine(self.meeting.get_meeting_date(1), datetime.time())
)
ts = self.meeting.timeslot_set.filter(
time__gt=self.meeting.date + datetime.timedelta(days=1),
time__gt=meeting_date,
location__capacity__lt=base_reg_session.attendees,
).order_by(
'time'

View file

@ -21,6 +21,7 @@ from urllib.parse import urlparse, urlsplit
from PIL import Image
from pathlib import Path
from tempfile import NamedTemporaryFile
from zoneinfo import ZoneInfo
from django.urls import reverse as urlreverse
from django.conf import settings
@ -29,8 +30,8 @@ from django.test import Client, override_settings
from django.db.models import F, Max
from django.http import QueryDict, FileResponse
from django.template import Context, Template
from django.utils import timezone
from django.utils.text import slugify
from django.utils.timezone import now
import debug # pyflakes:ignore
@ -51,6 +52,7 @@ from ietf.name.models import SessionStatusName, ImportantDateName, RoleName, Pro
from ietf.utils.decorators import skip_coverage
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
from ietf.utils.timezone import date_today, time_now
from ietf.person.factories import PersonFactory
from ietf.group.factories import GroupFactory, GroupEventFactory, RoleFactory
@ -154,7 +156,7 @@ class MeetingTests(BaseMeetingTestCase):
#
self.write_materials_files(meeting, session)
#
future_year = datetime.date.today().year+1
future_year = date_today().year+1
future_num = (future_year-1984)*3 # valid for the mid-year meeting
future_meeting = Meeting.objects.create(date=datetime.date(future_year, 7, 22), number=future_num, type_id='ietf',
city="Panama City", country="PA", time_zone='America/Panama')
@ -213,7 +215,10 @@ class MeetingTests(BaseMeetingTestCase):
)
# plain
time_interval = r"%s<span.*/span>-%s" % (slot.time.strftime("%H:%M").lstrip("0"), (slot.time + slot.duration).strftime("%H:%M").lstrip("0"))
time_interval = r"{}<span.*/span>-{}".format(
slot.time.astimezone(meeting.tz()).strftime("%H:%M").lstrip("0"),
slot.end_time().astimezone(meeting.tz()).strftime("%H:%M").lstrip("0"),
)
# text
# the rest of the results don't have as nicely formatted times
@ -351,7 +356,7 @@ class MeetingTests(BaseMeetingTestCase):
def test_interim_materials(self):
make_meeting_test_data()
group = Group.objects.get(acronym='mars')
date = datetime.datetime.today() - datetime.timedelta(days=10)
date = timezone.now() - datetime.timedelta(days=10)
meeting = make_interim_meeting(group=group, date=date, status='sched')
session = meeting.session_set.first()
@ -548,7 +553,12 @@ class MeetingTests(BaseMeetingTestCase):
a1 = s1.official_timeslotassignment()
t1 = a1.timeslot
# Create an extra session
t2 = TimeSlotFactory.create(meeting=meeting, time=datetime.datetime.combine(meeting.date, datetime.time(11, 30)))
t2 = TimeSlotFactory.create(
meeting=meeting,
time=meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time(11, 30))
)
)
s2 = SessionFactory.create(meeting=meeting, group=s1.group, add_to_schedule=False)
SchedTimeSessAssignment.objects.create(timeslot=t2, session=s2, schedule=meeting.schedule)
#
@ -558,16 +568,16 @@ class MeetingTests(BaseMeetingTestCase):
r,
expected_event_summaries=['mars - Martian Special Interest Group'],
expected_event_count=2)
self.assertContains(r, t1.time.strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t2.time.strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t1.local_start_time().strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t2.local_start_time().strftime('%Y%m%dT%H%M%S'))
#
url = urlreverse('ietf.meeting.views.agenda_ical', kwargs={'num':meeting.number, 'session_id':s1.id, })
r = self.client.get(url)
assert_ical_response_is_valid(self, r,
expected_event_summaries=['mars - Martian Special Interest Group'],
expected_event_count=1)
self.assertContains(r, t1.time.strftime('%Y%m%dT%H%M%S'))
self.assertNotContains(r, t2.time.strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t1.local_start_time().strftime('%Y%m%dT%H%M%S'))
self.assertNotContains(r, t2.local_start_time().strftime('%Y%m%dT%H%M%S'))
def test_parse_agenda_filter_params(self):
def _r(show=(), hide=(), showtypes=(), hidetypes=()):
@ -673,7 +683,7 @@ class MeetingTests(BaseMeetingTestCase):
url = urlreverse('ietf.meeting.views.current_materials')
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
MeetingFactory(type_id='ietf', date=datetime.date.today())
MeetingFactory(type_id='ietf', date=date_today())
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
@ -818,7 +828,9 @@ class EditMeetingScheduleTests(TestCase):
TimeSlotFactory(
meeting=meeting,
location=room,
time=datetime.datetime.combine(meeting.date, time),
time=meeting.tz().localize(
datetime.datetime.combine(meeting.date, time)
),
duration=datetime.timedelta(minutes=duration),
)
@ -889,7 +901,7 @@ class EditMeetingScheduleTests(TestCase):
# Meeting must be in the future so it can be edited
meeting = MeetingFactory(
type_id='ietf',
date=datetime.date.today() + datetime.timedelta(days=7),
date=date_today() + datetime.timedelta(days=7),
populate_schedule=False,
)
meeting.schedule = ScheduleFactory(meeting=meeting)
@ -902,7 +914,11 @@ class EditMeetingScheduleTests(TestCase):
]
# Set up different sets of timeslots
t0 = datetime.datetime.combine(meeting.date, datetime.time(11, 0))
# Work with t0 in UTC for arithmetic. This does not change the results but is cleaner if someone looks
# at intermediate results which may be misleading until passed through tz.normalize().
t0 = meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time(11, 0))
).astimezone(pytz.utc)
dur = datetime.timedelta(hours=2)
for room in room_groups[0]:
TimeSlotFactory(meeting=meeting, location=room, duration=dur, time=t0)
@ -997,7 +1013,7 @@ class EditMeetingScheduleTests(TestCase):
self.client.login(username=username, password=username + '+password')
# Swap group 0's first and last sessions, first in the past
right_now = self._right_now_in(meeting.time_zone)
right_now = self._right_now_in(meeting.tz())
for room in room_groups[0]:
ts = room.timeslot_set.last()
ts.time = right_now - datetime.timedelta(minutes=5)
@ -1179,12 +1195,18 @@ class EditMeetingScheduleTests(TestCase):
self.client.login(username=username, password=username + '+password')
# Swap group 0's first and last sessions, first in the past
right_now = self._right_now_in(meeting.time_zone)
yesterday = (right_now - datetime.timedelta(days=1)).date()
day_before = (right_now - datetime.timedelta(days=2)).date()
right_now = self._right_now_in(meeting.tz())
yesterday = right_now.date() - datetime.timedelta(days=1)
day_before = right_now.date() - datetime.timedelta(days=2)
for room in room_groups[0]:
ts = room.timeslot_set.last()
ts.time = datetime.datetime.combine(yesterday, ts.time.time())
# Calculation keeps local clock time, shifted to a different day.
ts.time = meeting.tz().localize(
datetime.datetime.combine(
yesterday,
ts.time.astimezone(meeting.tz()).time()
),
)
ts.save()
# timeslot_set is ordered by -time, so check that we know which is past/future
self.assertTrue(room_groups[0][0].timeslot_set.last().time < right_now)
@ -1218,7 +1240,12 @@ class EditMeetingScheduleTests(TestCase):
# now with both in the past
for room in room_groups[0]:
ts = room.timeslot_set.first()
ts.time = datetime.datetime.combine(day_before, ts.time.time())
ts.time = meeting.tz().localize(
datetime.datetime.combine(
day_before,
ts.time.astimezone(meeting.tz()).time(),
)
)
ts.save()
past_slots = room_groups[0][0].timeslot_set.filter(time__lt=right_now)
self.assertEqual(len(past_slots), 2, 'Need two timeslots in the past!')
@ -1241,20 +1268,18 @@ class EditMeetingScheduleTests(TestCase):
self.fail('Response was not valid JSON: {}'.format(err))
@staticmethod
def _right_now_in(tzname):
right_now = now().astimezone(pytz.timezone(tzname))
if not settings.USE_TZ:
right_now = right_now.replace(tzinfo=None)
def _right_now_in(tzinfo):
right_now = timezone.now().astimezone(tzinfo)
return right_now
def test_assign_session(self):
"""Allow assignment to future timeslots only for official schedule"""
meeting = MeetingFactory(
type_id='ietf',
date=(datetime.datetime.today() - datetime.timedelta(days=1)).date(),
date=(timezone.now() - datetime.timedelta(days=1)).date(),
days=3,
)
right_now = self._right_now_in(meeting.time_zone)
right_now = self._right_now_in(meeting.tz())
schedules = dict(
official=meeting.schedule,
@ -1311,10 +1336,10 @@ class EditMeetingScheduleTests(TestCase):
"""Do not allow assignment of past sessions for official schedule"""
meeting = MeetingFactory(
type_id='ietf',
date=(datetime.datetime.today() - datetime.timedelta(days=1)).date(),
date=(timezone.now() - datetime.timedelta(days=1)).date(),
days=3,
)
right_now = self._right_now_in(meeting.time_zone)
right_now = self._right_now_in(meeting.tz())
schedules = dict(
official=meeting.schedule,
@ -1446,10 +1471,10 @@ class EditMeetingScheduleTests(TestCase):
"""Allow unassignment only of future timeslots for official schedule"""
meeting = MeetingFactory(
type_id='ietf',
date=(datetime.datetime.today() - datetime.timedelta(days=1)).date(),
date=(timezone.now() - datetime.timedelta(days=1)).date(),
days=3,
)
right_now = self._right_now_in(meeting.time_zone)
right_now = self._right_now_in(meeting.tz())
schedules = dict(
official=meeting.schedule,
@ -1531,7 +1556,7 @@ class EditMeetingScheduleTests(TestCase):
"""Schedule editor should not crash when there are no timeslots"""
meeting = MeetingFactory(
type_id='ietf',
date=datetime.date.today() + datetime.timedelta(days=7),
date=date_today() + datetime.timedelta(days=7),
populate_schedule=False,
)
meeting.schedule = ScheduleFactory(meeting=meeting)
@ -1545,6 +1570,58 @@ class EditMeetingScheduleTests(TestCase):
self.assertContains(r, 'No timeslots exist')
self.assertContains(r, urlreverse('ietf.meeting.views.edit_timeslots', kwargs={'num': meeting.number}))
def test_editor_time_zone(self):
"""Agenda editor should show meeting time zone"""
time_zone = 'Etc/GMT+8'
meeting_tz = ZoneInfo(time_zone)
meeting = MeetingFactory(
type_id='ietf',
date=date_today(meeting_tz) + datetime.timedelta(days=7),
populate_schedule=False,
time_zone=time_zone,
)
meeting.schedule = ScheduleFactory(meeting=meeting)
meeting.save()
timeslot = TimeSlotFactory(meeting=meeting)
ts_start = timeslot.time.astimezone(meeting_tz)
ts_end = timeslot.end_time().astimezone(meeting_tz)
url = urlreverse('ietf.meeting.views.edit_meeting_schedule', kwargs={'num': meeting.number})
self.assertTrue(self.client.login(username='secretary', password='secretary+password'))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
pq = PyQuery(r.content)
day_header = pq('.day-flow .day-label')
self.assertIn(ts_start.strftime('%A'), day_header.text())
day_swap = day_header.find('.swap-days')
self.assertEqual(day_swap.attr('data-dayid'), ts_start.date().isoformat())
self.assertEqual(day_swap.attr('data-start'), ts_start.date().isoformat())
time_label = pq('.day-flow .time-header .time-label')
self.assertEqual(len(time_label), 1)
# strftime() does not seem to support hours without leading 0, so do this manually
time_label_string = f'{ts_start.hour:d}:{ts_start.minute:02d} - {ts_end.hour:d}:{ts_end.minute:02d}'
self.assertIn(time_label_string, time_label.text())
self.assertEqual(time_label.attr('data-start'), ts_start.astimezone(datetime.timezone.utc).isoformat())
self.assertEqual(time_label.attr('data-end'), ts_end.astimezone(datetime.timezone.utc).isoformat())
ts_swap = time_label.find('.swap-timeslot-col')
origin_label = ts_swap.attr('data-origin-label')
# testing the exact date in origin_label is hard because Django's date filter uses
# different month formats than Python's strftime, so just check a couple parts.
self.assertIn(ts_start.strftime('%A'), origin_label)
self.assertIn(f'{ts_start.hour:d}:{ts_start.minute:02d}-{ts_end.hour:d}:{ts_end.minute:02d}', origin_label)
timeslot_elt = pq(f'#timeslot{timeslot.pk}')
self.assertEqual(len(timeslot_elt), 1)
self.assertEqual(timeslot_elt.attr('data-start'), ts_start.astimezone(datetime.timezone.utc).isoformat())
self.assertEqual(timeslot_elt.attr('data-end'), ts_end.astimezone(datetime.timezone.utc).isoformat())
timeslot_label = pq(f'#timeslot{timeslot.pk} .time-label')
self.assertEqual(len(timeslot_label), 1)
self.assertIn(time_label_string, timeslot_label.text())
class EditTimeslotsTests(TestCase):
def login(self, username='secretary'):
@ -1570,7 +1647,7 @@ class EditTimeslotsTests(TestCase):
return MeetingFactory(
type_id='ietf',
number=number,
date=datetime.datetime.today() + datetime.timedelta(days=10),
date=date_today() + datetime.timedelta(days=10),
populate_schedule=False,
)
@ -1602,7 +1679,8 @@ class EditTimeslotsTests(TestCase):
meeting = self.create_bare_meeting(number=number)
RoomFactory.create_batch(8, meeting=meeting)
self.create_initial_schedule(meeting)
return meeting
# retrieve meeting from DB so it goes through Django's processing
return Meeting.objects.get(pk=meeting.pk)
def test_view_permissions(self):
"""Only the secretary should be able to edit timeslots"""
@ -1771,7 +1849,7 @@ class EditTimeslotsTests(TestCase):
meeting = self.create_meeting()
# add some timeslots
times = [datetime.time(hour=h) for h in (11, 14)]
days = [meeting.get_meeting_date(ii).date() for ii in range(meeting.days)]
days = [meeting.get_meeting_date(ii) for ii in range(meeting.days)]
timeslots = []
duration = datetime.timedelta(minutes=90)
@ -1781,7 +1859,7 @@ class EditTimeslotsTests(TestCase):
TimeSlotFactory(
meeting=meeting,
location=room,
time=datetime.datetime.combine(day, t),
time=meeting.tz().localize(datetime.datetime.combine(day, t)),
duration=duration,
)
for t in times
@ -1862,17 +1940,21 @@ class EditTimeslotsTests(TestCase):
TimeSlotFactory(
meeting=meeting,
location=meeting.room_set.first(),
time=datetime.datetime.combine(
meeting.get_meeting_date(day).date(),
datetime.time(hour=11)
time=meeting.tz().localize(
datetime.datetime.combine(
meeting.get_meeting_date(day),
datetime.time(hour=11),
)
),
)
TimeSlotFactory(
meeting=meeting,
location=meeting.room_set.first(),
time=datetime.datetime.combine(
meeting.get_meeting_date(day).date(),
datetime.time(hour=14)
time=meeting.tz().localize(
datetime.datetime.combine(
meeting.get_meeting_date(day),
datetime.time(hour=14),
)
),
)
@ -1971,10 +2053,8 @@ class EditTimeslotsTests(TestCase):
name_before = 'Name Classic (tm)'
type_before = 'regular'
time_before = datetime.datetime.combine(
meeting.date,
datetime.time(hour=10),
)
time_utc = pytz.utc.localize(datetime.datetime.combine(meeting.date, datetime.time(hour=10)))
time_before = time_utc.astimezone(meeting.tz())
duration_before = datetime.timedelta(minutes=60)
show_location_before = True
location_before = meeting.room_set.first()
@ -1991,7 +2071,7 @@ class EditTimeslotsTests(TestCase):
self.login()
name_after = 'New Name (tm)'
type_after = 'plenary'
time_after = time_before + datetime.timedelta(days=1, hours=2)
time_after = (time_utc + datetime.timedelta(days=1, hours=2)).astimezone(meeting.tz())
duration_after = duration_before * 2
show_location_after = False
location_after = meeting.room_set.last()
@ -2171,8 +2251,8 @@ class EditTimeslotsTests(TestCase):
ts = meeting.timeslot_set.exclude(pk__in=timeslots_before).first() # only 1
self.assertEqual(ts.name, post_data['name'])
self.assertEqual(ts.type_id, post_data['type'])
self.assertEqual(str(ts.time.date().toordinal()), post_data['days'])
self.assertEqual(ts.time.strftime('%H:%M'), post_data['time'])
self.assertEqual(str(ts.local_start_time().date().toordinal()), post_data['days'])
self.assertEqual(ts.local_start_time().strftime('%H:%M'), post_data['time'])
self.assertEqual(str(ts.duration), '{}:00'.format(post_data['duration'])) # add seconds
self.assertEqual(ts.show_location, post_data['show_location'])
self.assertEqual(str(ts.location.pk), post_data['locations'])
@ -2181,7 +2261,7 @@ class EditTimeslotsTests(TestCase):
"""Creating a single timeslot outside the official meeting days should work"""
meeting = self.create_meeting()
timeslots_before = set(ts.pk for ts in meeting.timeslot_set.all())
other_date = meeting.get_meeting_date(-7).date()
other_date = meeting.get_meeting_date(-7)
post_data = dict(
name='some name',
type='regular',
@ -2204,8 +2284,8 @@ class EditTimeslotsTests(TestCase):
ts = meeting.timeslot_set.exclude(pk__in=timeslots_before).first() # only 1
self.assertEqual(ts.name, post_data['name'])
self.assertEqual(ts.type_id, post_data['type'])
self.assertEqual(ts.time.date(), other_date)
self.assertEqual(ts.time.strftime('%H:%M'), post_data['time'])
self.assertEqual(ts.local_start_time().date(), other_date)
self.assertEqual(ts.local_start_time().strftime('%H:%M'), post_data['time'])
self.assertEqual(str(ts.duration), '{}:00'.format(post_data['duration'])) # add seconds
self.assertEqual(ts.show_location, post_data['show_location'])
self.assertEqual(str(ts.location.pk), post_data['locations'])
@ -2419,8 +2499,8 @@ class EditTimeslotsTests(TestCase):
"""Creating multiple timeslots should work"""
meeting = self.create_meeting()
timeslots_before = set(ts.pk for ts in meeting.timeslot_set.all())
days = [meeting.get_meeting_date(n).date() for n in range(meeting.days)]
other_date = meeting.get_meeting_date(-1).date() # date before start of meeting
days = [meeting.get_meeting_date(n) for n in range(meeting.days)]
other_date = meeting.get_meeting_date(-1) # date before start of meeting
self.assertNotIn(other_date, days)
locations = meeting.room_set.all()
post_data = dict(
@ -2450,10 +2530,10 @@ class EditTimeslotsTests(TestCase):
for ts in meeting.timeslot_set.exclude(pk__in=timeslots_before):
self.assertEqual(ts.name, post_data['name'])
self.assertEqual(ts.type_id, post_data['type'])
self.assertEqual(ts.time.strftime('%H:%M'), post_data['time'])
self.assertEqual(ts.local_start_time().strftime('%H:%M'), post_data['time'])
self.assertEqual(str(ts.duration), '{}:00'.format(post_data['duration'])) # add seconds
self.assertEqual(ts.show_location, post_data['show_location'])
self.assertIn(ts.time.date(), days)
self.assertIn(ts.local_start_time().date(), days)
self.assertIn(ts.location, locations)
self.assertIn((ts.time.date(), ts.location), day_locs,
'Duplicated day / location found')
@ -2593,7 +2673,7 @@ class ReorderSlidesTests(TestCase):
def test_add_slides_to_session(self):
for type_id in ('ietf','interim'):
chair_role = RoleFactory(name_id='chair')
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90), meeting__type_id=type_id)
session = SessionFactory(group=chair_role.group, meeting__date=date_today() - datetime.timedelta(days=90), meeting__type_id=type_id)
slides = DocumentFactory(type_id='slides')
url = urlreverse('ietf.meeting.views.ajax_add_slides_to_session', kwargs={'session_id':session.pk, 'num':session.meeting.number})
@ -2609,7 +2689,7 @@ class ReorderSlidesTests(TestCase):
self.assertEqual(r.status_code, 403)
self.assertIn('materials cutoff', unicontent(r))
session.meeting.date = datetime.date.today()
session.meeting.date = date_today()
session.meeting.save()
# Invalid order
@ -2696,7 +2776,7 @@ class ReorderSlidesTests(TestCase):
def test_remove_slides_from_session(self):
for type_id in ['ietf','interim']:
chair_role = RoleFactory(name_id='chair')
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90), meeting__type_id=type_id)
session = SessionFactory(group=chair_role.group, meeting__date=date_today()-datetime.timedelta(days=90), meeting__type_id=type_id)
slides = DocumentFactory(type_id='slides')
url = urlreverse('ietf.meeting.views.ajax_remove_slides_from_session', kwargs={'session_id':session.pk, 'num':session.meeting.number})
@ -2712,7 +2792,7 @@ class ReorderSlidesTests(TestCase):
self.assertEqual(r.status_code, 403)
self.assertIn('materials cutoff', unicontent(r))
session.meeting.date = datetime.date.today()
session.meeting.date = date_today()
session.meeting.save()
# Invalid order
@ -2807,7 +2887,7 @@ class ReorderSlidesTests(TestCase):
def test_reorder_slides_in_session(self):
chair_role = RoleFactory(name_id='chair')
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90))
session = SessionFactory(group=chair_role.group, meeting__date=date_today() - datetime.timedelta(days=90))
sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session)
for num, sp in enumerate(sp_list, start=1):
sp.order = num
@ -2817,7 +2897,7 @@ class ReorderSlidesTests(TestCase):
for type_id in ['ietf','interim']:
session.meeting.type_id = type_id
session.meeting.date = datetime.date.today()-datetime.timedelta(days=90)
session.meeting.date = date_today()-datetime.timedelta(days=90)
session.meeting.save()
# Not a valid user
@ -2832,7 +2912,7 @@ class ReorderSlidesTests(TestCase):
self.assertEqual(r.status_code, 403)
self.assertIn('materials cutoff', unicontent(r))
session.meeting.date = datetime.date.today()
session.meeting.date = date_today()
session.meeting.save()
# Bad index values
@ -2899,7 +2979,7 @@ class ReorderSlidesTests(TestCase):
def test_slide_order_reconditioning(self):
chair_role = RoleFactory(name_id='chair')
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90))
session = SessionFactory(group=chair_role.group, meeting__date=date_today() - datetime.timedelta(days=90))
sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session)
for num, sp in enumerate(sp_list, start=1):
sp.order = 2*num
@ -2918,7 +2998,7 @@ class EditTests(TestCase):
def test_official_record_schedule_is_read_only(self):
def _set_date_offset_and_retrieve_page(meeting, days_offset, client):
meeting.date = datetime.date.today() + datetime.timedelta(days=days_offset)
meeting.date = date_today() + datetime.timedelta(days=days_offset)
meeting.save()
client.login(username="secretary", password="secretary+password")
url = urlreverse("ietf.meeting.views.edit_meeting_schedule", kwargs=dict(num=meeting.number))
@ -3001,7 +3081,9 @@ class EditTests(TestCase):
room = Room.objects.get(meeting=meeting, session_types='regular')
base_timeslot = TimeSlot.objects.create(meeting=meeting, type_id='regular', location=room,
duration=datetime.timedelta(minutes=50),
time=datetime.datetime.combine(meeting.date + datetime.timedelta(days=2), datetime.time(9, 30)))
time=meeting.tz().localize(
datetime.datetime.combine(meeting.date + datetime.timedelta(days=2), datetime.time(9, 30))
))
timeslots = list(TimeSlot.objects.filter(meeting=meeting, type='regular').order_by('time'))
@ -3223,7 +3305,12 @@ class EditTests(TestCase):
self.assertIn("#scroll=1234", r['Location'])
test_timeslot = TimeSlot.objects.get(meeting=meeting, name="IETF Testing")
self.assertEqual(test_timeslot.time, datetime.datetime.combine(meeting.date, datetime.time(8, 30)))
self.assertEqual(
test_timeslot.time,
meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time(8, 30))
),
)
self.assertEqual(test_timeslot.duration, datetime.timedelta(hours=1, minutes=30))
self.assertEqual(test_timeslot.location_id, break_room.pk)
self.assertEqual(test_timeslot.show_location, True)
@ -3265,7 +3352,12 @@ class EditTests(TestCase):
})
self.assertNoFormPostErrors(r)
test_timeslot.refresh_from_db()
self.assertEqual(test_timeslot.time, datetime.datetime.combine(meeting.date, datetime.time(9, 30)))
self.assertEqual(
test_timeslot.time,
meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time(9, 30))
),
)
self.assertEqual(test_timeslot.duration, datetime.timedelta(hours=1))
self.assertEqual(test_timeslot.location_id, breakfast_room.pk)
self.assertEqual(test_timeslot.show_location, False)
@ -3710,7 +3802,7 @@ class SessionDetailsTests(TestCase):
def test_session_details(self):
group = GroupFactory.create(type_id='wg',state_id='active')
session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=datetime.date.today()+datetime.timedelta(days=90))
session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=date_today() + datetime.timedelta(days=90))
SessionPresentationFactory.create(session=session,document__type_id='draft',rev=None)
SessionPresentationFactory.create(session=session,document__type_id='minutes')
SessionPresentationFactory.create(session=session,document__type_id='slides')
@ -3729,7 +3821,7 @@ class SessionDetailsTests(TestCase):
session = SessionFactory.create(
meeting__type_id='ietf',
group=group,
meeting__date=datetime.date.today() + datetime.timedelta(days=90),
meeting__date=date_today() + datetime.timedelta(days=90),
)
session_details_url = urlreverse(
'ietf.meeting.views.session_details',
@ -3781,7 +3873,7 @@ class SessionDetailsTests(TestCase):
def test_session_details_past_interim(self):
group = GroupFactory.create(type_id='wg',state_id='active')
chair = RoleFactory(name_id='chair',group=group)
session = SessionFactory.create(meeting__type_id='interim',group=group, meeting__date=datetime.date.today()-datetime.timedelta(days=90))
session = SessionFactory.create(meeting__type_id='interim',group=group, meeting__date=date_today() - datetime.timedelta(days=90))
SessionPresentationFactory.create(session=session,document__type_id='draft',rev=None)
SessionPresentationFactory.create(session=session,document__type_id='minutes')
SessionPresentationFactory.create(session=session,document__type_id='slides')
@ -3800,7 +3892,7 @@ class SessionDetailsTests(TestCase):
group = GroupFactory.create(type_id='wg',state_id='active')
group_chair = PersonFactory.create()
group.role_set.create(name_id='chair',person = group_chair, email = group_chair.email())
session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=datetime.date.today()+datetime.timedelta(days=90))
session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=date_today() + datetime.timedelta(days=90))
SessionPresentationFactory.create(session=session,document__type_id='draft',rev=None)
old_draft = session.sessionpresentation_set.filter(document__type='draft').first().document
new_draft = DocumentFactory(type_id='draft')
@ -3966,7 +4058,7 @@ class InterimTests(TestCase):
def do_interim_skip_announcement_test(self, base_session=False, extra_session=False, canceled_session=False):
make_meeting_test_data()
group = Group.objects.get(acronym='irg')
date = datetime.date.today() + datetime.timedelta(days=30)
date = date_today() + datetime.timedelta(days=30)
meeting = make_interim_meeting(group=group, date=date, status='scheda')
session = meeting.session_set.first()
if base_session:
@ -4036,12 +4128,10 @@ class InterimTests(TestCase):
self.do_interim_skip_announcement_test(extra_session=True, canceled_session=True, base_session=True)
def do_interim_send_announcement_test(self, base_session=False, extra_session=False, canceled_session=False):
make_interim_test_data()
make_interim_test_data(meeting_tz='America/Los_Angeles')
session = Session.objects.with_current_status().filter(
meeting__type='interim', group__acronym='mars', current_status='apprw').first()
meeting = session.meeting
meeting.time_zone = 'America/Los_Angeles'
meeting.save()
if base_session:
base_session = SessionFactory(meeting=meeting, status_id='apprw', add_to_schedule=False)
@ -4247,7 +4337,7 @@ class InterimTests(TestCase):
self.do_interim_approve_by_secretariat_test(extra_session=True, canceled_session=True, base_session=True)
def test_past(self):
today = datetime.date.today()
today = date_today()
last_week = today - datetime.timedelta(days=7)
ietf = SessionFactory(meeting__type_id='ietf',meeting__date=last_week,group__state_id='active',group__parent=GroupFactory(state_id='active'))
SessionFactory(meeting__type_id='interim',meeting__date=last_week,status_id='canceled',group__state_id='active',group__parent=GroupFactory(state_id='active'))
@ -4266,7 +4356,7 @@ class InterimTests(TestCase):
if querystring is not None:
url += '?' + querystring
today = datetime.date.today()
today = date_today()
interims = dict(
mars=add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', meeting__date__gt=today, group__acronym='mars')).filter(current_status='sched').first().meeting,
ames=add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', meeting__date__gt=today, group__acronym='ames')).filter(current_status='canceled').first().meeting,
@ -4386,9 +4476,9 @@ class InterimTests(TestCase):
def do_interim_request_single_virtual(self, emails_expected):
make_meeting_test_data()
group = Group.objects.get(acronym='mars')
date = datetime.date.today() + datetime.timedelta(days=30)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
dt = datetime.datetime.combine(date, time)
date = date_today() + datetime.timedelta(days=30)
time = time_now().replace(microsecond=0,second=0)
dt = pytz.utc.localize(datetime.datetime.combine(date, time))
duration = datetime.timedelta(hours=3)
remote_instructions = 'Use webex'
agenda = 'Intro. Slides. Discuss.'
@ -4457,13 +4547,14 @@ class InterimTests(TestCase):
def test_interim_request_single_in_person(self):
make_meeting_test_data()
group = Group.objects.get(acronym='mars')
date = datetime.date.today() + datetime.timedelta(days=30)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
dt = datetime.datetime.combine(date, time)
date = date_today() + datetime.timedelta(days=30)
time = time_now().replace(microsecond=0,second=0)
time_zone = 'America/Los_Angeles'
tz = pytz.timezone(time_zone)
dt = tz.localize(datetime.datetime.combine(date, time))
duration = datetime.timedelta(hours=3)
city = 'San Francisco'
country = 'US'
time_zone = 'America/Los_Angeles'
remote_instructions = 'Use webex'
agenda = 'Intro. Slides. Discuss.'
agenda_note = 'On second level'
@ -4504,16 +4595,17 @@ class InterimTests(TestCase):
def test_interim_request_multi_day(self):
make_meeting_test_data()
date = datetime.date.today() + datetime.timedelta(days=30)
date = date_today() + datetime.timedelta(days=30)
date2 = date + datetime.timedelta(days=1)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
dt = datetime.datetime.combine(date, time)
dt2 = datetime.datetime.combine(date2, time)
time = time_now().replace(microsecond=0,second=0)
time_zone = 'America/Los_Angeles'
tz = pytz.timezone(time_zone)
dt = tz.localize(datetime.datetime.combine(date, time))
dt2 = tz.localize(datetime.datetime.combine(date2, time))
duration = datetime.timedelta(hours=3)
group = Group.objects.get(acronym='mars')
city = 'San Francisco'
country = 'US'
time_zone = 'America/Los_Angeles'
remote_instructions = 'Use webex'
agenda = 'Intro. Slides. Discuss.'
agenda_note = 'On second level'
@ -4570,9 +4662,9 @@ class InterimTests(TestCase):
def test_interim_request_multi_day_non_consecutive(self):
make_meeting_test_data()
date = datetime.date.today() + datetime.timedelta(days=30)
date = date_today() + datetime.timedelta(days=30)
date2 = date + datetime.timedelta(days=2)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
time = timezone.now().time().replace(microsecond=0,second=0)
group = Group.objects.get(acronym='mars')
city = 'San Francisco'
country = 'US'
@ -4607,7 +4699,7 @@ class InterimTests(TestCase):
def test_interim_request_multi_day_cancel(self):
"""All sessions of a multi-day interim request should be canceled"""
length_before = len(outbox)
date = datetime.date.today()+datetime.timedelta(days=15)
date = date_today() + datetime.timedelta(days=15)
# Set up an interim request with several sessions
num_sessions = 3
@ -4630,7 +4722,7 @@ class InterimTests(TestCase):
def test_interim_request_series(self):
make_meeting_test_data()
meeting_count_before = Meeting.objects.filter(type='interim').count()
date = datetime.date.today() + datetime.timedelta(days=30)
date = date_today() + datetime.timedelta(days=30)
if (date.month, date.day) == (12, 31):
# Avoid date and date2 in separate years
# (otherwise the test will fail if run on December 1st)
@ -4640,14 +4732,15 @@ class InterimTests(TestCase):
if date.year != date2.year:
date += datetime.timedelta(days=1)
date2 += datetime.timedelta(days=1)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
dt = datetime.datetime.combine(date, time)
dt2 = datetime.datetime.combine(date2, time)
time = time_now().replace(microsecond=0,second=0)
time_zone = 'America/Los_Angeles'
tz = pytz.timezone(time_zone)
dt = tz.localize(datetime.datetime.combine(date, time))
dt2 = tz.localize(datetime.datetime.combine(date2, time))
duration = datetime.timedelta(hours=3)
group = Group.objects.get(acronym='mars')
city = ''
country = ''
time_zone = 'America/Los_Angeles'
remote_instructions = 'Use webex'
agenda = 'Intro. Slides. Discuss.'
agenda_note = 'On second level'
@ -4789,14 +4882,14 @@ class InterimTests(TestCase):
self.assertFalse(can_manage_group(user=user,group=group))
def test_interim_request_details(self):
make_interim_test_data()
make_interim_test_data(meeting_tz='America/Chicago')
meeting = Session.objects.with_current_status().filter(
meeting__type='interim', group__acronym='mars', current_status='apprw').first().meeting
url = urlreverse('ietf.meeting.views.interim_request_details',kwargs={'number':meeting.number})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
start_time = meeting.session_set.first().official_timeslotassignment().timeslot.time.strftime('%H:%M')
start_time = meeting.session_set.first().official_timeslotassignment().timeslot.local_start_time().strftime('%H:%M')
utc_start_time = meeting.session_set.first().official_timeslotassignment().timeslot.utc_start_time().strftime('%H:%M')
self.assertIn(start_time, unicontent(r))
self.assertIn(utc_start_time, unicontent(r))
@ -4804,7 +4897,7 @@ class InterimTests(TestCase):
def test_interim_request_details_announcement(self):
'''Test access to Announce / Skip Announce features'''
make_meeting_test_data()
date = datetime.date.today() + datetime.timedelta(days=30)
date = date_today() + datetime.timedelta(days=30)
group = Group.objects.get(acronym='mars')
meeting = make_interim_meeting(group=group, date=date, status='scheda')
url = urlreverse('ietf.meeting.views.interim_request_details',kwargs={'number':meeting.number})
@ -5322,7 +5415,7 @@ class InterimTests(TestCase):
def test_send_interim_minutes_reminder(self):
make_meeting_test_data()
group = Group.objects.get(acronym='mars')
date = datetime.datetime.today() - datetime.timedelta(days=10)
date = timezone.now() - datetime.timedelta(days=10)
meeting = make_interim_meeting(group=group, date=date, status='sched')
length_before = len(outbox)
send_interim_minutes_reminder(meeting=meeting)
@ -5337,7 +5430,11 @@ class InterimTests(TestCase):
a1 = s1.official_timeslotassignment()
t1 = a1.timeslot
# Create an extra session
t2 = TimeSlotFactory.create(meeting=meeting, time=datetime.datetime.combine(meeting.date, datetime.time(11, 30)))
t2 = TimeSlotFactory.create(
meeting=meeting,
time=meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time(11, 30))
))
s2 = SessionFactory.create(meeting=meeting, group=s1.group, add_to_schedule=False)
SchedTimeSessAssignment.objects.create(timeslot=t2, session=s2, schedule=meeting.schedule)
#
@ -5347,8 +5444,8 @@ class InterimTests(TestCase):
self.assertContains(r, 'BEGIN:VEVENT')
self.assertEqual(r.content.count(b'UID'), 2)
self.assertContains(r, 'SUMMARY:mars - Martian Special Interest Group')
self.assertContains(r, t1.time.strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t2.time.strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t1.local_start_time().strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, t2.local_start_time().strftime('%Y%m%dT%H%M%S'))
self.assertContains(r, 'END:VEVENT')
#
url = urlreverse('ietf.meeting.views.agenda_ical', kwargs={'num':meeting.number, 'session_id':s1.id, })
@ -5539,7 +5636,7 @@ class MaterialsTests(TestCase):
def test_upload_bluesheets_interim_chair_access(self):
make_meeting_test_data()
mars = Group.objects.get(acronym='mars')
session=SessionFactory(meeting__type_id='interim',group=mars, meeting__date = datetime.date.today())
session=SessionFactory(meeting__type_id='interim',group=mars, meeting__date = date_today())
url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id})
self.client.login(username="marschairman", password="marschairman+password")
r = self.client.get(url)
@ -5782,7 +5879,7 @@ class MaterialsTests(TestCase):
for type_id in ['ietf','interim']:
session = SessionFactory(meeting__type_id=type_id)
chair = RoleFactory(group=session.group,name_id='chair').person
session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20))
newperson = PersonFactory()
session_overview_url = urlreverse('ietf.meeting.views.session_details',kwargs={'num':session.meeting.number,'acronym':session.group.acronym})
@ -5830,7 +5927,7 @@ class MaterialsTests(TestCase):
def test_disapprove_proposed_slides(self):
submission = SlideSubmissionFactory()
submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20))
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 1)
chair = RoleFactory(group=submission.session.group,name_id='chair').person
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
@ -5848,7 +5945,7 @@ class MaterialsTests(TestCase):
def test_approve_proposed_slides(self):
submission = SlideSubmissionFactory()
session = submission.session
session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20))
chair = RoleFactory(group=submission.session.group,name_id='chair').person
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
login_testing_unauthorized(self, chair.user.username, url)
@ -5873,7 +5970,7 @@ class MaterialsTests(TestCase):
submission = SlideSubmissionFactory(session__meeting__type_id='ietf')
session1 = submission.session
session2 = SessionFactory(group=submission.session.group, meeting=submission.session.meeting)
submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20))
chair = RoleFactory(group=submission.session.group,name_id='chair').person
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
login_testing_unauthorized(self, chair.user.username, url)
@ -5890,7 +5987,7 @@ class MaterialsTests(TestCase):
submission = SlideSubmissionFactory(session__meeting__type_id='ietf')
session1 = submission.session
session2 = SessionFactory(group=submission.session.group, meeting=submission.session.meeting)
submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20))
chair = RoleFactory(group=submission.session.group,name_id='chair').person
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
login_testing_unauthorized(self, chair.user.username, url)
@ -5904,7 +6001,7 @@ class MaterialsTests(TestCase):
def test_submit_and_approve_multiple_versions(self):
session = SessionFactory(meeting__type_id='ietf')
chair = RoleFactory(group=session.group,name_id='chair').person
session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
session.meeting.importantdate_set.create(name_id='revsub',date=date_today()+datetime.timedelta(days=20))
newperson = PersonFactory()
propose_url = urlreverse('ietf.meeting.views.propose_session_slides', kwargs={'session_id':session.pk, 'num': session.meeting.number})
@ -6285,8 +6382,8 @@ class HasMeetingsTests(TestCase):
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('#id_group option[value="%d"]'%group.pk))
date = datetime.date.today() + datetime.timedelta(days=30+meeting_count)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
date = date_today() + datetime.timedelta(days=30+meeting_count)
time = time_now().replace(microsecond=0,second=0)
remote_instructions = 'Use webex'
agenda = 'Intro. Slides. Discuss.'
agenda_note = 'On second level'
@ -6382,7 +6479,7 @@ class HasMeetingsTests(TestCase):
session = SessionFactory(
group__type_id = gf.type_id,
meeting__type_id='interim',
meeting__date = datetime.datetime.today()+datetime.timedelta(days=30),
meeting__date = timezone.now()+datetime.timedelta(days=30),
status_id='sched',
)
sessions.append(session)
@ -6398,7 +6495,7 @@ class HasMeetingsTests(TestCase):
sessions=[]
for gf in GroupFeatures.objects.filter(has_meetings=True):
group = GroupFactory(type_id=gf.type_id)
meeting_date = datetime.datetime.today() + datetime.timedelta(days=30)
meeting_date = timezone.now() + datetime.timedelta(days=30)
session = SessionFactory(
group=group,
meeting__type_id='interim',
@ -6419,7 +6516,7 @@ class HasMeetingsTests(TestCase):
sessions=[]
for gf in GroupFeatures.objects.filter(has_meetings=True):
group = GroupFactory(type_id=gf.type_id)
meeting_date = datetime.datetime.today() + datetime.timedelta(days=30)
meeting_date = timezone.now() + datetime.timedelta(days=30)
session = SessionFactory(
group=group,
meeting__type_id='interim',
@ -7145,7 +7242,7 @@ class ProceedingsTests(BaseMeetingTestCase):
def test_proceedings_no_agenda(self):
# Meeting number must be larger than the last special-cased proceedings (currently 96)
meeting = MeetingFactory(type_id='ietf',populate_schedule=False,date=datetime.date.today(), number='100')
meeting = MeetingFactory(type_id='ietf',populate_schedule=False,date=date_today(), number='100')
url = urlreverse('ietf.meeting.views.proceedings')
r = self.client.get(url)
self.assertRedirects(r, urlreverse('ietf.meeting.views.materials'))
@ -7254,7 +7351,7 @@ class ProceedingsTests(BaseMeetingTestCase):
"""Generate a meeting for proceedings material test"""
# meeting number 123 avoids various legacy cases that affect these tests
# (as of Aug 2021, anything above 96 is probably ok)
return MeetingFactory(type_id='ietf', number='123', date=datetime.date.today())
return MeetingFactory(type_id='ietf', number='123', date=date_today())
def _secretary_only_permission_test(self, url, include_post=True):
self.client.logout()

View file

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import datetime
import itertools
import pytz
import requests
import subprocess
@ -12,6 +13,7 @@ from urllib.error import HTTPError
from django.conf import settings
from django.contrib import messages
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.encoding import smart_text
import debug # pyflakes:ignore
@ -26,6 +28,7 @@ from ietf.person.models import Person
from ietf.secr.proceedings.proc_utils import import_audio_files
from ietf.utils.html import sanitize_document
from ietf.utils.log import log
from ietf.utils.timezone import date_today
def session_time_for_sorting(session, use_meeting_date):
@ -33,13 +36,17 @@ def session_time_for_sorting(session, use_meeting_date):
if official_timeslot:
return official_timeslot.time
elif use_meeting_date and session.meeting.date:
return datetime.datetime.combine(session.meeting.date, datetime.time.min)
return session.meeting.tz().localize(
datetime.datetime.combine(session.meeting.date, datetime.time.min)
)
else:
first_event = SchedulingEvent.objects.filter(session=session).order_by('time', 'id').first()
if first_event:
return first_event.time
else:
return datetime.datetime.min
# n.b. cannot interpret this in timezones west of UTC. That is not expected to be necessary,
# but could probably safely add a day to the minimum datetime to make that possible.
return pytz.utc.localize(datetime.datetime.min)
def session_requested_by(session):
first_event = SchedulingEvent.objects.filter(session=session).order_by('time', 'id').first()
@ -64,12 +71,12 @@ def group_sessions(sessions):
sessions = sorted(sessions,key=lambda s:s.time)
today = datetime.date.today()
future = []
in_progress = []
recent = []
past = []
for s in sessions:
today = date_today(s.meeting.tz())
if s.meeting.date > today:
future.append(s)
elif s.meeting.end_date() >= today:
@ -101,7 +108,7 @@ def get_upcoming_manageable_sessions(user):
# .filter(date__gte=today - F('days')), but unfortunately, it
# doesn't work correctly with Django 1.11 and MySQL/SQLite
today = datetime.date.today()
today = date_today()
candidate_sessions = add_event_info_to_session_qs(
Session.objects.filter(meeting__date__gte=today - datetime.timedelta(days=15))
@ -158,7 +165,12 @@ def create_proceedings_templates(meeting):
def finalize(meeting):
end_date = meeting.end_date()
end_time = datetime.datetime.combine(end_date, datetime.datetime.min.time())+datetime.timedelta(days=1)
end_time = meeting.tz().localize(
datetime.datetime.combine(
end_date,
datetime.time.min,
)
).astimezone(pytz.utc) + datetime.timedelta(days=1)
for session in meeting.session_set.all():
for sp in session.sessionpresentation_set.filter(document__type='draft',rev=None):
rev_before_end = [e for e in sp.document.docevent_set.filter(newrevisiondocevent__isnull=False).order_by('-time') if e.time <= end_time ]
@ -322,7 +334,9 @@ def preprocess_constraints_for_meeting_schedule_editor(meeting, sessions):
# synthesize AD constraints - we can treat them as a special kind of 'bethere'
responsible_ad_for_group = {}
session_groups = set(s.group for s in sessions if s.group and s.group.parent and s.group.parent.type_id == 'area')
meeting_time = datetime.datetime.combine(meeting.date, datetime.time(0, 0, 0))
meeting_time = meeting.tz().localize(
datetime.datetime.combine(meeting.date, datetime.time(0, 0, 0))
)
# dig up historic AD names
for group_id, history_time, pk in Person.objects.filter(rolehistory__name='ad', rolehistory__group__group__in=session_groups, rolehistory__group__time__lte=meeting_time).values_list('rolehistory__group__group', 'rolehistory__group__time', 'pk').order_by('rolehistory__group__time'):
@ -511,7 +525,7 @@ def swap_meeting_schedule_timeslot_assignments(schedule, source_timeslots, targe
if max_overlap > datetime.timedelta(minutes=5):
for a in lts_assignments:
a.timeslot = most_overlapping_rts
a.modified = datetime.datetime.now()
a.modified = timezone.now()
a.save()
swapped = True

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ import email
import datetime
from django.core.management.base import BaseCommand
from django.utils import timezone
import debug # pyflakes:ignore
@ -25,7 +26,7 @@ class Command(BaseCommand):
"""
def add_arguments(self, parser):
default_start = datetime.datetime.now() - datetime.timedelta(days=14)
default_start = timezone.now() - datetime.timedelta(days=14)
parser.add_argument(
'-t', '--start', '--from', type=str, default=default_start.strftime('%Y-%m-%d %H:%M'),
help='Limit the list to messages saved after the given time (default %(default)s).',

View file

@ -0,0 +1,24 @@
# Generated by Django 2.2.28 on 2022-07-12 11:24
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('message', '0011_auto_20201109_0439'),
]
operations = [
migrations.AlterField(
model_name='message',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name='sendqueue',
name='time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View file

@ -2,10 +2,10 @@
# -*- coding: utf-8 -*-
import datetime
import email.utils
from django.db import models
from django.utils import timezone
import debug # pyflakes:ignore
@ -17,7 +17,7 @@ from ietf.utils.models import ForeignKey
from ietf.utils.mail import get_email_addresses_from_text
class Message(models.Model):
time = models.DateTimeField(default=datetime.datetime.now)
time = models.DateTimeField(default=timezone.now)
by = ForeignKey(Person)
subject = models.CharField(max_length=255)
@ -62,7 +62,7 @@ class MessageAttachment(models.Model):
class SendQueue(models.Model):
time = models.DateTimeField(default=datetime.datetime.now)
time = models.DateTimeField(default=timezone.now)
by = ForeignKey(Person)
message = ForeignKey(Message)

View file

@ -5,6 +5,7 @@
import datetime
from django.urls import reverse as urlreverse
from django.utils import timezone
import debug # pyflakes:ignore
@ -14,10 +15,13 @@ from ietf.message.utils import send_scheduled_message_from_send_queue
from ietf.person.models import Person
from ietf.utils.mail import outbox, send_mail_text, send_mail_message, get_payload_text
from ietf.utils.test_utils import TestCase
from ietf.utils.timezone import date_today
class MessageTests(TestCase):
def test_message_view(self):
nomcom = GroupFactory(name="nomcom%s" % datetime.date.today().year, type_id="nomcom")
nomcom = GroupFactory(name="nomcom%s" % date_today().year, type_id="nomcom")
msg = Message.objects.create(
by=Person.objects.get(name="(System)"),
subject="This is a test",
@ -87,7 +91,7 @@ class SendScheduledAnnouncementsTests(TestCase):
q = SendQueue.objects.create(
by=Person.objects.get(name="(System)"),
message=msg,
send_at=datetime.datetime.now() + datetime.timedelta(hours=12)
send_at=timezone.now() + datetime.timedelta(hours=12)
)
mailbox_before = len(outbox)
@ -113,7 +117,7 @@ class SendScheduledAnnouncementsTests(TestCase):
q = SendQueue.objects.create(
by=Person.objects.get(name="(System)"),
message=msg,
send_at=datetime.datetime.now() + datetime.timedelta(hours=12)
send_at=timezone.now() + datetime.timedelta(hours=12)
)
mailbox_before = len(outbox)

View file

@ -2,8 +2,9 @@
# -*- coding: utf-8 -*-
import re, datetime, email
import re, email
from django.utils import timezone
from django.utils.encoding import force_str
from ietf.utils.mail import send_mail_text, send_mail_mime
@ -52,7 +53,7 @@ def send_scheduled_message_from_send_queue(queue_item):
send_mail_mime(None, message.to, message.frm, message.subject,
msg, cc=message.cc, bcc=message.bcc)
queue_item.sent_at = datetime.datetime.now()
queue_item.sent_at = timezone.now()
queue_item.save()
queue_item.message.sent = queue_item.sent_at

Some files were not shown because too many files have changed in this diff Show more