Use correct UTC time when creating Meetecho conferences. Fixes #3565. Commit ready for merge.
- Legacy-Id: 19969
This commit is contained in:
parent
f0d40680fe
commit
82ea659ed4
|
@ -1099,7 +1099,7 @@ def create_interim_session_conferences(sessions):
|
||||||
confs = meetecho_manager.create(
|
confs = meetecho_manager.create(
|
||||||
group=session.group,
|
group=session.group,
|
||||||
description=str(session),
|
description=str(session),
|
||||||
start_time=ts.time,
|
start_time=ts.utc_start_time(),
|
||||||
duration=ts.duration,
|
duration=ts.duration,
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
|
|
@ -456,8 +456,8 @@ class InterimTests(TestCase):
|
||||||
def test_create_interim_session_conferences(self, mock):
|
def test_create_interim_session_conferences(self, mock):
|
||||||
mock_conf_mgr = mock.return_value # "instance" seen by the internals
|
mock_conf_mgr = mock.return_value # "instance" seen by the internals
|
||||||
sessions = [
|
sessions = [
|
||||||
SessionFactory(meeting__type_id='interim', remote_instructions='junk'),
|
SessionFactory(meeting__type_id='interim', meeting__time_zone='america/halifax', remote_instructions='junk'),
|
||||||
SessionFactory(meeting__type_id='interim', remote_instructions=''),
|
SessionFactory(meeting__type_id='interim', meeting__time_zone='asia/kuala_lumpur', remote_instructions=''),
|
||||||
]
|
]
|
||||||
timeslots = [
|
timeslots = [
|
||||||
session.official_timeslotassignment().timeslot for session in sessions
|
session.official_timeslotassignment().timeslot for session in sessions
|
||||||
|
@ -482,18 +482,18 @@ class InterimTests(TestCase):
|
||||||
mock_conf_mgr.create.return_value = [
|
mock_conf_mgr.create.return_value = [
|
||||||
Conference(
|
Conference(
|
||||||
manager=mock_conf_mgr, id=1, public_id='some-uuid', description='desc',
|
manager=mock_conf_mgr, id=1, public_id='some-uuid', description='desc',
|
||||||
start_time=timeslots[0].time, duration=timeslots[0].duration, url='fake-meetecho-url',
|
start_time=timeslots[0].utc_start_time(), duration=timeslots[0].duration, url='fake-meetecho-url',
|
||||||
deletion_token='please-delete-me',
|
deletion_token='please-delete-me',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
create_interim_session_conferences([sessions[0]])
|
create_interim_session_conferences([sessions[0]])
|
||||||
self.assertTrue(mock_conf_mgr.create.called)
|
self.assertTrue(mock_conf_mgr.create.called)
|
||||||
self.assertCountEqual(
|
self.assertEqual(
|
||||||
mock_conf_mgr.create.call_args[1],
|
mock_conf_mgr.create.call_args[1],
|
||||||
{
|
{
|
||||||
'group': sessions[0].group,
|
'group': sessions[0].group,
|
||||||
'description': str(sessions[0]),
|
'description': str(sessions[0]),
|
||||||
'start_time': timeslots[0].time,
|
'start_time': timeslots[0].utc_start_time(),
|
||||||
'duration': timeslots[0].duration,
|
'duration': timeslots[0].duration,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -507,30 +507,30 @@ class InterimTests(TestCase):
|
||||||
mock_conf_mgr.create.side_effect = [
|
mock_conf_mgr.create.side_effect = [
|
||||||
[Conference(
|
[Conference(
|
||||||
manager=mock_conf_mgr, id=1, public_id='some-uuid', description='desc',
|
manager=mock_conf_mgr, id=1, public_id='some-uuid', description='desc',
|
||||||
start_time=timeslots[0].time, duration=timeslots[0].duration, url='different-fake-meetecho-url',
|
start_time=timeslots[0].utc_start_time(), duration=timeslots[0].duration, url='different-fake-meetecho-url',
|
||||||
deletion_token='please-delete-me',
|
deletion_token='please-delete-me',
|
||||||
)],
|
)],
|
||||||
[Conference(
|
[Conference(
|
||||||
manager=mock_conf_mgr, id=2, public_id='another-uuid', description='desc',
|
manager=mock_conf_mgr, id=2, public_id='another-uuid', description='desc',
|
||||||
start_time=timeslots[1].time, duration=timeslots[1].duration, url='another-fake-meetecho-url',
|
start_time=timeslots[1].utc_start_time(), duration=timeslots[1].duration, url='another-fake-meetecho-url',
|
||||||
deletion_token='please-delete-me-too',
|
deletion_token='please-delete-me-too',
|
||||||
)],
|
)],
|
||||||
]
|
]
|
||||||
create_interim_session_conferences([sessions[0], sessions[1]])
|
create_interim_session_conferences([sessions[0], sessions[1]])
|
||||||
self.assertTrue(mock_conf_mgr.create.called)
|
self.assertTrue(mock_conf_mgr.create.called)
|
||||||
self.assertCountEqual(
|
self.assertEqual(
|
||||||
mock_conf_mgr.create.call_args_list,
|
mock_conf_mgr.create.call_args_list,
|
||||||
[
|
[
|
||||||
({
|
({
|
||||||
'group': sessions[0].group,
|
'group': sessions[0].group,
|
||||||
'description': str(sessions[0]),
|
'description': str(sessions[0]),
|
||||||
'start_time': timeslots[0].time,
|
'start_time': timeslots[0].utc_start_time(),
|
||||||
'duration': timeslots[0].duration,
|
'duration': timeslots[0].duration,
|
||||||
},),
|
},),
|
||||||
({
|
({
|
||||||
'group': sessions[1].group,
|
'group': sessions[1].group,
|
||||||
'description': str(sessions[1]),
|
'description': str(sessions[1]),
|
||||||
'start_time': timeslots[1].time,
|
'start_time': timeslots[1].utc_start_time(),
|
||||||
'duration': timeslots[1].duration,
|
'duration': timeslots[1].duration,
|
||||||
},),
|
},),
|
||||||
]
|
]
|
||||||
|
|
|
@ -15,11 +15,14 @@ import debug # pyflakes: ignore
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
|
from pytz import utc
|
||||||
from typing import Dict, Sequence, Union
|
from typing import Dict, Sequence, Union
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
|
||||||
class MeetechoAPI:
|
class MeetechoAPI:
|
||||||
|
timezone = utc
|
||||||
|
|
||||||
def __init__(self, api_base: str, client_id: str, client_secret: str, request_timeout=3.01):
|
def __init__(self, api_base: str, client_id: str, client_secret: str, request_timeout=3.01):
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
self.client_secret = client_secret
|
self.client_secret = client_secret
|
||||||
|
@ -57,10 +60,10 @@ class MeetechoAPI:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _deserialize_time(self, s: str) -> datetime:
|
def _deserialize_time(self, s: str) -> datetime:
|
||||||
return datetime.strptime(s, '%Y-%m-%d %H:%M:%S')
|
return self.timezone.localize(datetime.strptime(s, '%Y-%m-%d %H:%M:%S'))
|
||||||
|
|
||||||
def _serialize_time(self, dt: datetime) -> str:
|
def _serialize_time(self, dt: datetime) -> str:
|
||||||
return dt.strftime('%Y-%m-%d %H:%M:%S')
|
return dt.astimezone(self.timezone).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
def _deserialize_duration(self, minutes: int) -> timedelta:
|
def _deserialize_duration(self, minutes: int) -> timedelta:
|
||||||
return timedelta(minutes=minutes)
|
return timedelta(minutes=minutes)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
||||||
import requests
|
import requests
|
||||||
import requests_mock
|
import requests_mock
|
||||||
|
|
||||||
|
from pytz import timezone, utc
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ class APITests(TestCase):
|
||||||
api = MeetechoAPI(API_BASE, CLIENT_ID, CLIENT_SECRET)
|
api = MeetechoAPI(API_BASE, CLIENT_ID, CLIENT_SECRET)
|
||||||
api_response = api.schedule_meeting(
|
api_response = api.schedule_meeting(
|
||||||
wg_token='my-token',
|
wg_token='my-token',
|
||||||
start_time=datetime.datetime(2021, 9, 14, 10, 0, 0),
|
start_time=utc.localize(datetime.datetime(2021, 9, 14, 10, 0, 0)),
|
||||||
duration=datetime.timedelta(minutes=130),
|
duration=datetime.timedelta(minutes=130),
|
||||||
description='interim-2021-wgname-01',
|
description='interim-2021-wgname-01',
|
||||||
extrainfo='message for staff',
|
extrainfo='message for staff',
|
||||||
|
@ -117,23 +118,32 @@ class APITests(TestCase):
|
||||||
},
|
},
|
||||||
'Incorrect request content'
|
'Incorrect request content'
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
# same time in different time zones
|
||||||
api_response,
|
for start_time in [
|
||||||
{
|
utc.localize(datetime.datetime(2021, 9, 14, 10, 0, 0)),
|
||||||
'rooms': {
|
timezone('america/halifax').localize(datetime.datetime(2021, 9, 14, 7, 0, 0)),
|
||||||
'3d55bce0-535e-4ba8-bb8e-734911cf3c32': {
|
timezone('europe/kiev').localize(datetime.datetime(2021, 9, 14, 13, 0, 0)),
|
||||||
'room': {
|
timezone('pacific/easter').localize(datetime.datetime(2021, 9, 14, 5, 0, 0)),
|
||||||
'id': 18,
|
timezone('africa/porto-novo').localize(datetime.datetime(2021, 9, 14, 11, 0, 0)),
|
||||||
'start_time': datetime.datetime(2021, 9, 14, 10, 0, 0),
|
]:
|
||||||
'duration': datetime.timedelta(minutes=130),
|
self.assertEqual(
|
||||||
'description': 'interim-2021-wgname-01',
|
api_response,
|
||||||
|
{
|
||||||
|
'rooms': {
|
||||||
|
'3d55bce0-535e-4ba8-bb8e-734911cf3c32': {
|
||||||
|
'room': {
|
||||||
|
'id': 18,
|
||||||
|
'start_time': start_time,
|
||||||
|
'duration': datetime.timedelta(minutes=130),
|
||||||
|
'description': 'interim-2021-wgname-01',
|
||||||
|
},
|
||||||
|
'url': 'https://meetings.conf.meetecho.com/interim/?short=3d55bce0-535e-4ba8-bb8e-734911cf3c32',
|
||||||
|
'deletion_token': 'session-deletion-token',
|
||||||
},
|
},
|
||||||
'url': 'https://meetings.conf.meetecho.com/interim/?short=3d55bce0-535e-4ba8-bb8e-734911cf3c32',
|
}
|
||||||
'deletion_token': 'session-deletion-token',
|
},
|
||||||
},
|
f'Incorrect time conversion for {start_time.tzinfo.zone}',
|
||||||
}
|
)
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_fetch_meetings(self):
|
def test_fetch_meetings(self):
|
||||||
self.maxDiff = 2048
|
self.maxDiff = 2048
|
||||||
|
@ -181,7 +191,7 @@ class APITests(TestCase):
|
||||||
'3d55bce0-535e-4ba8-bb8e-734911cf3c32': {
|
'3d55bce0-535e-4ba8-bb8e-734911cf3c32': {
|
||||||
'room': {
|
'room': {
|
||||||
'id': 18,
|
'id': 18,
|
||||||
'start_time': datetime.datetime(2021, 9, 14, 10, 0, 0),
|
'start_time': utc.localize(datetime.datetime(2021, 9, 14, 10, 0, 0)),
|
||||||
'duration': datetime.timedelta(minutes=130),
|
'duration': datetime.timedelta(minutes=130),
|
||||||
'description': 'interim-2021-wgname-01',
|
'description': 'interim-2021-wgname-01',
|
||||||
},
|
},
|
||||||
|
@ -191,7 +201,7 @@ class APITests(TestCase):
|
||||||
'e68e96d4-d38f-475b-9073-ecab46ca96a5': {
|
'e68e96d4-d38f-475b-9073-ecab46ca96a5': {
|
||||||
'room': {
|
'room': {
|
||||||
'id': 23,
|
'id': 23,
|
||||||
'start_time': datetime.datetime(2021, 9, 15, 14, 30, 0),
|
'start_time': utc.localize(datetime.datetime(2021, 9, 15, 14, 30, 0)),
|
||||||
'duration': datetime.timedelta(minutes=30),
|
'duration': datetime.timedelta(minutes=30),
|
||||||
'description': 'interim-2021-wgname-02',
|
'description': 'interim-2021-wgname-02',
|
||||||
},
|
},
|
||||||
|
@ -239,7 +249,7 @@ class APITests(TestCase):
|
||||||
|
|
||||||
def test_time_serialization(self):
|
def test_time_serialization(self):
|
||||||
"""Time de/serialization should be consistent"""
|
"""Time de/serialization should be consistent"""
|
||||||
time = datetime.datetime.now().replace(microsecond=0) # cut off to 0 microseconds
|
time = datetime.datetime.now(utc).replace(microsecond=0) # cut off to 0 microseconds
|
||||||
api = MeetechoAPI(API_BASE, CLIENT_ID, CLIENT_SECRET)
|
api = MeetechoAPI(API_BASE, CLIENT_ID, CLIENT_SECRET)
|
||||||
self.assertEqual(api._deserialize_time(api._serialize_time(time)), time)
|
self.assertEqual(api._deserialize_time(api._serialize_time(time)), time)
|
||||||
|
|
||||||
|
@ -253,7 +263,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
'session-1-uuid': {
|
'session-1-uuid': {
|
||||||
'room': {
|
'room': {
|
||||||
'id': 1,
|
'id': 1,
|
||||||
'start_time': datetime.datetime(2022,2,4,1,2,3),
|
'start_time': utc.localize(datetime.datetime(2022,2,4,1,2,3)),
|
||||||
'duration': datetime.timedelta(minutes=45),
|
'duration': datetime.timedelta(minutes=45),
|
||||||
'description': 'some-description',
|
'description': 'some-description',
|
||||||
},
|
},
|
||||||
|
@ -263,7 +273,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
'session-2-uuid': {
|
'session-2-uuid': {
|
||||||
'room': {
|
'room': {
|
||||||
'id': 2,
|
'id': 2,
|
||||||
'start_time': datetime.datetime(2022,2,5,4,5,6),
|
'start_time': utc.localize(datetime.datetime(2022,2,5,4,5,6)),
|
||||||
'duration': datetime.timedelta(minutes=90),
|
'duration': datetime.timedelta(minutes=90),
|
||||||
'description': 'another-description',
|
'description': 'another-description',
|
||||||
},
|
},
|
||||||
|
@ -280,7 +290,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
id=1,
|
id=1,
|
||||||
public_id='session-1-uuid',
|
public_id='session-1-uuid',
|
||||||
description='some-description',
|
description='some-description',
|
||||||
start_time=datetime.datetime(2022,2,4,1,2,3),
|
start_time=utc.localize(datetime.datetime(2022, 2, 4, 1, 2, 3)),
|
||||||
duration=datetime.timedelta(minutes=45),
|
duration=datetime.timedelta(minutes=45),
|
||||||
url='https://example.com/some/url',
|
url='https://example.com/some/url',
|
||||||
deletion_token='delete-me',
|
deletion_token='delete-me',
|
||||||
|
@ -290,7 +300,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
id=2,
|
id=2,
|
||||||
public_id='session-2-uuid',
|
public_id='session-2-uuid',
|
||||||
description='another-description',
|
description='another-description',
|
||||||
start_time=datetime.datetime(2022,2,5,4,5,6),
|
start_time=utc.localize(datetime.datetime(2022, 2, 5, 4, 5, 6)),
|
||||||
duration=datetime.timedelta(minutes=90),
|
duration=datetime.timedelta(minutes=90),
|
||||||
url='https://example.com/another/url',
|
url='https://example.com/another/url',
|
||||||
deletion_token='delete-me-too',
|
deletion_token='delete-me-too',
|
||||||
|
@ -306,7 +316,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
'session-1-uuid': {
|
'session-1-uuid': {
|
||||||
'room': {
|
'room': {
|
||||||
'id': 1,
|
'id': 1,
|
||||||
'start_time': datetime.datetime(2022,2,4,1,2,3),
|
'start_time': utc.localize(datetime.datetime(2022,2,4,1,2,3)),
|
||||||
'duration': datetime.timedelta(minutes=45),
|
'duration': datetime.timedelta(minutes=45),
|
||||||
'description': 'some-description',
|
'description': 'some-description',
|
||||||
},
|
},
|
||||||
|
@ -325,7 +335,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
id=1,
|
id=1,
|
||||||
public_id='session-1-uuid',
|
public_id='session-1-uuid',
|
||||||
description='some-description',
|
description='some-description',
|
||||||
start_time=datetime.datetime(2022,2,4,1,2,3),
|
start_time=utc.localize(datetime.datetime(2022,2,4,1,2,3)),
|
||||||
duration=datetime.timedelta(minutes=45),
|
duration=datetime.timedelta(minutes=45),
|
||||||
url='https://example.com/some/url',
|
url='https://example.com/some/url',
|
||||||
deletion_token='delete-me',
|
deletion_token='delete-me',
|
||||||
|
@ -341,7 +351,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
'session-1-uuid': {
|
'session-1-uuid': {
|
||||||
'room': {
|
'room': {
|
||||||
'id': 1,
|
'id': 1,
|
||||||
'start_time': datetime.datetime(2022,2,4,1,2,3),
|
'start_time': utc.localize(datetime.datetime(2022,2,4,1,2,3)),
|
||||||
'duration': datetime.timedelta(minutes=45),
|
'duration': datetime.timedelta(minutes=45),
|
||||||
'description': 'some-description',
|
'description': 'some-description',
|
||||||
},
|
},
|
||||||
|
@ -359,7 +369,7 @@ class ConferenceManagerTests(TestCase):
|
||||||
id=1,
|
id=1,
|
||||||
public_id='session-1-uuid',
|
public_id='session-1-uuid',
|
||||||
description='some-description',
|
description='some-description',
|
||||||
start_time=datetime.datetime(2022,2,4,1,2,3),
|
start_time=utc.localize(datetime.datetime(2022,2,4,1,2,3)),
|
||||||
duration=datetime.timedelta(minutes=45),
|
duration=datetime.timedelta(minutes=45),
|
||||||
url='https://example.com/some/url',
|
url='https://example.com/some/url',
|
||||||
deletion_token='delete-me',
|
deletion_token='delete-me',
|
||||||
|
|
Loading…
Reference in a new issue