Skip to content

Commit

Permalink
Merge pull request #7154 from jennifer-richards/the-neverending-api
Browse files Browse the repository at this point in the history
feat: send Meetecho slides updates in doc UI
  • Loading branch information
jennifer-richards authored Mar 8, 2024
2 parents 8370136 + 60058d4 commit bacd98b
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 11 deletions.
89 changes: 83 additions & 6 deletions ietf/doc/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2575,37 +2575,68 @@ def test_view_document_meetings(self):
self.assertFalse(q("#futuremeets a.btn:contains('Remove document')"))
self.assertFalse(q("#pastmeets a.btn:contains('Remove document')"))

def test_edit_document_session(self):
@override_settings(MEETECHO_API_CONFIG="fake settings")
@mock.patch("ietf.doc.views_doc.SlidesManager")
def test_edit_document_session(self, mock_slides_manager_cls):
doc = IndividualDraftFactory.create()
sp = doc.presentations.create(session=self.future,rev=None)

url = urlreverse('ietf.doc.views_doc.edit_sessionpresentation',kwargs=dict(name='no-such-doc',session_id=sp.session_id))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertFalse(mock_slides_manager_cls.called)

url = urlreverse('ietf.doc.views_doc.edit_sessionpresentation',kwargs=dict(name=doc.name,session_id=0))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertFalse(mock_slides_manager_cls.called)

url = urlreverse('ietf.doc.views_doc.edit_sessionpresentation',kwargs=dict(name=doc.name,session_id=sp.session_id))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertFalse(mock_slides_manager_cls.called)

self.client.login(username=self.other_chair.user.username,password='%s+password'%self.other_chair.user.username)
response = self.client.get(url)
self.assertEqual(response.status_code, 404)

self.assertFalse(mock_slides_manager_cls.called)

self.client.login(username=self.group_chair.user.username,password='%s+password'%self.group_chair.user.username)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
q = PyQuery(response.content)
self.assertEqual(2,len(q('select#id_version option')))
self.assertFalse(mock_slides_manager_cls.called)

# edit draft
self.assertEqual(1,doc.docevent_set.count())
response = self.client.post(url,{'version':'00','save':''})
self.assertEqual(response.status_code, 302)
self.assertEqual(doc.presentations.get(pk=sp.pk).rev,'00')
self.assertEqual(2,doc.docevent_set.count())
self.assertFalse(mock_slides_manager_cls.called)

# editing slides should call Meetecho API
slides = SessionPresentationFactory(
session=self.future,
document__type_id="slides",
document__rev="00",
rev=None,
order=1,
).document
url = urlreverse(
"ietf.doc.views_doc.edit_sessionpresentation",
kwargs={"name": slides.name, "session_id": self.future.pk},
)
response = self.client.post(url, {"version": "00", "save": ""})
self.assertEqual(response.status_code, 302)
self.assertEqual(mock_slides_manager_cls.call_count, 1)
self.assertEqual(mock_slides_manager_cls.call_args, mock.call(api_config="fake settings"))
self.assertEqual(mock_slides_manager_cls.return_value.send_update.call_count, 1)
self.assertEqual(
mock_slides_manager_cls.return_value.send_update.call_args,
mock.call(self.future),
)

def test_edit_document_session_after_proceedings_closed(self):
doc = IndividualDraftFactory.create()
Expand All @@ -2622,35 +2653,60 @@ def test_edit_document_session_after_proceedings_closed(self):
q=PyQuery(response.content)
self.assertEqual(1,len(q(".alert-warning:contains('may affect published proceedings')")))

def test_remove_document_session(self):
@override_settings(MEETECHO_API_CONFIG="fake settings")
@mock.patch("ietf.doc.views_doc.SlidesManager")
def test_remove_document_session(self, mock_slides_manager_cls):
doc = IndividualDraftFactory.create()
sp = doc.presentations.create(session=self.future,rev=None)

url = urlreverse('ietf.doc.views_doc.remove_sessionpresentation',kwargs=dict(name='no-such-doc',session_id=sp.session_id))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertFalse(mock_slides_manager_cls.called)

url = urlreverse('ietf.doc.views_doc.remove_sessionpresentation',kwargs=dict(name=doc.name,session_id=0))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertFalse(mock_slides_manager_cls.called)

url = urlreverse('ietf.doc.views_doc.remove_sessionpresentation',kwargs=dict(name=doc.name,session_id=sp.session_id))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertFalse(mock_slides_manager_cls.called)

self.client.login(username=self.other_chair.user.username,password='%s+password'%self.other_chair.user.username)
response = self.client.get(url)
self.assertEqual(response.status_code, 404)

self.assertFalse(mock_slides_manager_cls.called)

self.client.login(username=self.group_chair.user.username,password='%s+password'%self.group_chair.user.username)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertFalse(mock_slides_manager_cls.called)

# removing a draft
self.assertEqual(1,doc.docevent_set.count())
response = self.client.post(url,{'remove_session':''})
self.assertEqual(response.status_code, 302)
self.assertFalse(doc.presentations.filter(pk=sp.pk).exists())
self.assertEqual(2,doc.docevent_set.count())
self.assertFalse(mock_slides_manager_cls.called)

# removing slides should call Meetecho API
slides = SessionPresentationFactory(session=self.future, document__type_id="slides", order=1).document
url = urlreverse(
"ietf.doc.views_doc.remove_sessionpresentation",
kwargs={"name": slides.name, "session_id": self.future.pk},
)
response = self.client.post(url, {"remove_session": ""})
self.assertEqual(response.status_code, 302)
self.assertEqual(mock_slides_manager_cls.call_count, 1)
self.assertEqual(mock_slides_manager_cls.call_args, mock.call(api_config="fake settings"))
self.assertEqual(mock_slides_manager_cls.return_value.delete.call_count, 1)
self.assertEqual(
mock_slides_manager_cls.return_value.delete.call_args,
mock.call(self.future, slides),
)

def test_remove_document_session_after_proceedings_closed(self):
doc = IndividualDraftFactory.create()
Expand All @@ -2667,28 +2723,49 @@ def test_remove_document_session_after_proceedings_closed(self):
q=PyQuery(response.content)
self.assertEqual(1,len(q(".alert-warning:contains('may affect published proceedings')")))

def test_add_document_session(self):
@override_settings(MEETECHO_API_CONFIG="fake settings")
@mock.patch("ietf.doc.views_doc.SlidesManager")
def test_add_document_session(self, mock_slides_manager_cls):
doc = IndividualDraftFactory.create()

url = urlreverse('ietf.doc.views_doc.add_sessionpresentation',kwargs=dict(name=doc.name))
login_testing_unauthorized(self,self.group_chair.user.username,url)
response = self.client.get(url)
self.assertEqual(response.status_code,200)

self.assertFalse(mock_slides_manager_cls.called)

response = self.client.post(url,{'session':0,'version':'current'})
self.assertEqual(response.status_code,200)
q=PyQuery(response.content)
self.assertTrue(q('.form-select.is-invalid'))
self.assertFalse(mock_slides_manager_cls.called)

response = self.client.post(url,{'session':self.future.pk,'version':'bogus version'})
self.assertEqual(response.status_code,200)
q=PyQuery(response.content)
self.assertTrue(q('.form-select.is-invalid'))
self.assertFalse(mock_slides_manager_cls.called)

# adding a draft
self.assertEqual(1,doc.docevent_set.count())
response = self.client.post(url,{'session':self.future.pk,'version':'current'})
self.assertEqual(response.status_code,302)
self.assertEqual(2,doc.docevent_set.count())
self.assertEqual(doc.presentations.get(session__pk=self.future.pk).order, 0)
self.assertFalse(mock_slides_manager_cls.called)

# adding slides should set order / call Meetecho API
slides = DocumentFactory(type_id="slides")
url = urlreverse("ietf.doc.views_doc.add_sessionpresentation", kwargs=dict(name=slides.name))
response = self.client.post(url, {"session": self.future.pk, "version": "current"})
self.assertEqual(response.status_code,302)
self.assertEqual(slides.presentations.get(session__pk=self.future.pk).order, 1)
self.assertEqual(mock_slides_manager_cls.call_args, mock.call(api_config="fake settings"))
self.assertEqual(mock_slides_manager_cls.return_value.add.call_count, 1)
self.assertEqual(
mock_slides_manager_cls.return_value.add.call_args,
mock.call(self.future, slides, order=1),
)

def test_get_related_meeting(self):
"""Should be able to retrieve related meeting"""
Expand Down
51 changes: 48 additions & 3 deletions ietf/doc/tests_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@
import shutil
import io

from mock import call, patch
from pathlib import Path
from pyquery import PyQuery

import debug # pyflakes:ignore

from django.conf import settings
from django.test import override_settings
from django.urls import reverse as urlreverse
from django.utils import timezone

from ietf.doc.models import Document, State, NewRevisionDocEvent
from ietf.group.factories import RoleFactory
from ietf.group.models import Group
from ietf.meeting.factories import MeetingFactory, SessionFactory
from ietf.meeting.factories import MeetingFactory, SessionFactory, SessionPresentationFactory
from ietf.meeting.models import Meeting, SessionPresentation, SchedulingEvent
from ietf.name.models import SessionStatusName
from ietf.person.models import Person
Expand Down Expand Up @@ -135,19 +137,47 @@ def test_change_state(self):
doc = Document.objects.get(name=doc.name)
self.assertEqual(doc.get_state_slug(), "deleted")

def test_edit_title(self):
@override_settings(MEETECHO_API_CONFIG="fake settings")
@patch("ietf.doc.views_material.SlidesManager")
def test_edit_title(self, mock_slides_manager_cls):
doc = self.create_slides()

url = urlreverse('ietf.doc.views_material.edit_material', kwargs=dict(name=doc.name, action="title"))
login_testing_unauthorized(self, "secretary", url)
self.assertFalse(mock_slides_manager_cls.called)

# post
r = self.client.post(url, dict(title="New title"))
self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name=doc.name)
self.assertEqual(doc.title, "New title")
self.assertFalse(mock_slides_manager_cls.return_value.send_update.called)

def test_revise(self):
# assign to a session to see that it now sends updates to Meetecho
session = SessionPresentationFactory(session__group=doc.group, document=doc).session

# Grab the title on the slides when the API call was made (to be sure it's not before it was updated)
titles_sent = []
mock_slides_manager_cls.return_value.send_update.side_effect = lambda sess: titles_sent.extend(
list(sess.presentations.values_list("document__title", flat=True))
)

r = self.client.post(url, dict(title="Newer title"))
self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name=doc.name)
self.assertEqual(doc.title, "Newer title")
self.assertTrue(mock_slides_manager_cls.called)
self.assertEqual(mock_slides_manager_cls.call_args, call(api_config="fake settings"))
self.assertEqual(mock_slides_manager_cls.return_value.send_update.call_count, 1)
self.assertEqual(
mock_slides_manager_cls.return_value.send_update.call_args,
call(session),
)
self.assertEqual(titles_sent, ["Newer title"])

@override_settings(MEETECHO_API_CONFIG="fake settings")
@patch("ietf.doc.views_material.SlidesManager")
def test_revise(self, mock_slides_manager_cls):
doc = self.create_slides()

session = SessionFactory(
Expand All @@ -165,11 +195,18 @@ def test_revise(self):

url = urlreverse('ietf.doc.views_material.edit_material', kwargs=dict(name=doc.name, action="revise"))
login_testing_unauthorized(self, "secretary", url)
self.assertFalse(mock_slides_manager_cls.called)

content = "some text"
test_file = io.StringIO(content)
test_file.name = "unnamed.txt"

# Grab the title on the slides when the API call was made (to be sure it's not before it was updated)
titles_sent = []
mock_slides_manager_cls.return_value.send_update.side_effect = lambda sess: titles_sent.extend(
list(sess.presentations.values_list("document__title", flat=True))
)

# post
r = self.client.post(url, dict(title="New title",
abstract="New abstract",
Expand All @@ -180,6 +217,14 @@ def test_revise(self):
self.assertEqual(doc.rev, "02")
self.assertEqual(doc.title, "New title")
self.assertEqual(doc.get_state_slug(), "active")
self.assertTrue(mock_slides_manager_cls.called)
self.assertEqual(mock_slides_manager_cls.call_args, call(api_config="fake settings"))
self.assertEqual(mock_slides_manager_cls.return_value.send_update.call_count, 1)
self.assertEqual(
mock_slides_manager_cls.return_value.send_update.call_args,
call(session),
)
self.assertEqual(titles_sent, ["New title"])

with io.open(os.path.join(doc.get_file_path(), doc.name + "-" + doc.rev + ".txt")) as f:
self.assertEqual(f.read(), content)
Expand Down
27 changes: 25 additions & 2 deletions ietf/doc/views_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from urllib.parse import quote
from pathlib import Path

from django.db.models import Max
from django.http import HttpResponse, Http404
from django.shortcuts import render, get_object_or_404, redirect
from django.template.loader import render_to_string
Expand Down Expand Up @@ -75,13 +76,14 @@
from ietf.doc.forms import TelechatForm, NotifyForm, ActionHoldersForm, DocAuthorForm, DocAuthorChangeBasisForm
from ietf.doc.mails import email_comment, email_remind_action_holders
from ietf.mailtrigger.utils import gather_relevant_expansions
from ietf.meeting.models import Session
from ietf.meeting.models import Session, SessionPresentation
from ietf.meeting.utils import group_sessions, get_upcoming_manageable_sessions, sort_sessions, add_event_info_to_session_qs
from ietf.review.models import ReviewAssignment
from ietf.review.utils import can_request_review_of_doc, review_assignments_to_list_for_docs, review_requests_to_list_for_docs
from ietf.review.utils import no_review_from_teams_on_doc
from ietf.utils import markup_txt, log, markdown
from ietf.utils.draft import PlaintextDraft
from ietf.utils.meetecho import SlidesManager
from ietf.utils.response import permission_denied
from ietf.utils.text import maybe_split
from ietf.utils.timezone import date_today
Expand Down Expand Up @@ -2075,6 +2077,9 @@ def edit_sessionpresentation(request,name,session_id):
new_selection = form.cleaned_data['version']
if initial['version'] != new_selection:
doc.presentations.filter(pk=sp.pk).update(rev=None if new_selection=='current' else new_selection)
if doc.type_id == "slides" and hasattr(settings, "MEETECHO_API_CONFIG"):
sm = SlidesManager(api_config=settings.MEETECHO_API_CONFIG)
sm.send_update(sp.session)
c = DocEvent(type="added_comment", doc=doc, rev=doc.rev, by=request.user.person)
c.desc = "Revision for session %s changed to %s" % (sp.session,new_selection)
c.save()
Expand All @@ -2096,6 +2101,9 @@ def remove_sessionpresentation(request,name,session_id):

if request.method == 'POST':
doc.presentations.filter(pk=sp.pk).delete()
if doc.type_id == "slides" and hasattr(settings, "MEETECHO_API_CONFIG"):
sm = SlidesManager(api_config=settings.MEETECHO_API_CONFIG)
sm.delete(sp.session, doc)
c = DocEvent(type="added_comment", doc=doc, rev=doc.rev, by=request.user.person)
c.desc = "Removed from session: %s" % (sp.session)
c.save()
Expand Down Expand Up @@ -2132,7 +2140,22 @@ def add_sessionpresentation(request,name):
session_id = session_form.cleaned_data['session']
version = version_form.cleaned_data['version']
rev = None if version=='current' else version
doc.presentations.create(session_id=session_id,rev=rev)
if doc.type_id == "slides":
max_order = SessionPresentation.objects.filter(
document__type='slides',
session__pk=session_id,
).aggregate(Max('order'))['order__max'] or 0
order = max_order + 1
else:
order = 0
sp = doc.presentations.create(
session_id=session_id,
rev=rev,
order=order,
)
if doc.type_id == "slides" and hasattr(settings, "MEETECHO_API_CONFIG"):
sm = SlidesManager(api_config=settings.MEETECHO_API_CONFIG)
sm.add(sp.session, doc, order=sp.order)
c = DocEvent(type="added_comment", doc=doc, rev=doc.rev, by=request.user.person)
c.desc = "%s to session: %s" % ('Added -%s'%rev if rev else 'Added', Session.objects.get(pk=session_id))
c.save()
Expand Down
Loading

0 comments on commit bacd98b

Please sign in to comment.