@@ -1,197 +1,67 @@
from opengever.base.browser.helper import get_css_class
from opengever.base.response import JSONResponse
from opengever.meeting import _
from opengever.meeting.service import meeting_service
from Products.Five.browser import BrowserView
from zExceptions import NotFound
from zExceptions import Unauthorized
from zope.interface import implements
from zope.interface import Interface
from zope.publisher.interfaces import IPublishTraverse
from zope.publisher.interfaces.browser import IBrowserView
import json
from opengever.base.browser.helper import get_css_class


class ScheduleSubmittedProposal(BrowserView):

implements(IBrowserView, IPublishTraverse)

@classmethod
def url_for(cls, context, meeting, proposal):
return '{}/{}'.format(
meeting.get_url(view='schedule_proposal'),
proposal.proposal_id)

def __init__(self, context, request):
super(ScheduleSubmittedProposal, self).__init__(context, request)
self.meeting = self.context.model
self.proposal_id = None

def publishTraverse(self, request, name):
# we only support exactly one id
if self.proposal_id:
raise NotFound
self.proposal_id = int(name)
return self

def extract_proposal(self):
return meeting_service().fetch_proposal(self.proposal_id)

def __call__(self):
if not self.meeting.is_editable():
raise Unauthorized("Editing is not allowed")

proposal = self.extract_proposal()
if proposal:
self.meeting.schedule_proposal(proposal)

return JSONResponse(self.request).info(
_('Scheduled Successfully')).proceed().dump()


class ScheduleText(ScheduleSubmittedProposal):

implements(IBrowserView)

@classmethod
def url_for(cls, context, meeting):
return meeting.get_url(view='schedule_text')

def nextURL(self):
return self.meeting.get_url()

def extract_title(self):
if self.request.method != 'POST':
return

if 'schedule-paragraph' not in self.request \
and 'schedule-text' not in self.request:
return
class IAgendaItemActions(Interface):

return self.request.get('title')

def extract_is_paragraph(self):
return 'schedule-paragraph' in self.request

def __call__(self):
if not self.meeting.is_editable():
raise Unauthorized("Editing is not allowed")

title = self.extract_title()
is_paragraph = self.extract_is_paragraph()
if title:
self.meeting.schedule_text(title, is_paragraph=is_paragraph)

return self.request.response.redirect(self.nextURL())


class UpdateAgendaItemOrder(BrowserView):

implements(IBrowserView, IPublishTraverse)

@classmethod
def url_for(cls, context, meeting):
return meeting.get_url(view='update_agenda_item_order')

def __init__(self, context, request):
super(UpdateAgendaItemOrder, self).__init__(context, request)
self.model = self.context.model

def __call__(self):
if not self.model.is_editable():
raise Unauthorized("Editing is not allowed")
def list():
"""Returns json list of all agendaitems for the current
context (meeting).
"""

self.model.reorder_agenda_items(json.loads(self.request.get('sortOrder')))
def edit():
"""Updates the title fo the current agendaitem, with the one given by
the request parameter `title`. The view expect that its called by
traversing over the agendaitem: `plone/meeting-3/14/edit` for example.
"""

return JSONResponse(self.request).info(_('agenda_item_order_updated',
default=u"Agenda Item order updated.")).dump()
def delete():
"""Remove or unschedule (proposal related) the current agendaitem.
The view expect that its called by traversing over the agendaitem:
`plone/meeting-3/14/delete` for example.
"""

def update_sortorder(self, json_data):
new_order = [int(item_id) for item_id in json_data['sortOrder']]
self.model.reorder_agenda_items(new_order)
def update_order():
"""Updates the order of the meetings agendaitems. The new sortOrder
is expected in the request parameter `sortOrder` and should be a list
of of agendaitem ids.
"""

numbers = dict((each.agenda_item_id, each.number) for each in
self.model.agenda_items)
def schedule_text():
"""Schedule the given Text(request parameter `title`) on the current
meeting.
"""

return JSONResponse(self.request).info(_('agenda_item_order_updated',
default=u"Agenda Item order updated.")).data(numbers=numbers).dump()
def schedule_paragraph():
"""Schedule the given Paragraph(request parameter `title`) on the current
meeting.
"""


class DeleteAgendaItem(BrowserView):
class AgendaItemsView(BrowserView):

implements(IBrowserView, IPublishTraverse)

@classmethod
def url_for(cls, context, meeting, agend_item):

return "{}/{}".format(
meeting.get_url('delete_agenda_item'),
agend_item.agenda_item_id)

def __init__(self, context, request):
super(DeleteAgendaItem, self).__init__(context, request)
self.model = self.context.model
self.item_id = None

def nextURL(self):
return self.model.get_url()

def publishTraverse(self, request, name):
if name in IAgendaItemActions.names():
return getattr(self, name)

# we only support exactly one id
if self.item_id:
if self.agenda_item_id:
raise NotFound
self.item_id = name
self.agenda_item_id = int(name)
return self

def __call__(self):
if not self.model.is_editable():
raise Unauthorized("Editing is not allowed")

if not self.item_id:
raise NotFound

try:
item_id = int(self.item_id)
except ValueError:
raise NotFound

agenda_item = meeting_service().fetch_agenda_item(item_id)
if not agenda_item:
raise NotFound

agenda_item.remove()

return JSONResponse(self.request).info("Successfully deleted").dump()


class UpdateAgendaItem(BrowserView):

@classmethod
def url_for(cls, context, meeting):
return meeting.get_url(view='update_agenda_item')

def __call__(self):
if not self.context.model.is_editable():
raise Unauthorized("Editing is not allowed")

title = self.request.get('title')
agenda_item_id = self.request.get('agenda_item_id')
if not title or not agenda_item_id:
return JSONResponse(self.request).error(_('agenda_item_update_empty_string',
default=u"Agenda Item title must not be empty.")).remain().dump()

agenda_item = meeting_service().fetch_agenda_item(agenda_item_id)
if not agenda_item:
raise NotFound

agenda_item.set_title(title)
return JSONResponse(self.request).info(_('agenda_item_updated',
default=u"Agenda Item updated.")).proceed().dump()


class AgendaItemsView(BrowserView):

implements(IBrowserView, IPublishTraverse)

def __init__(self, context, request):
super(AgendaItemsView, self).__init__(context, request)
self.meeting = self.context.model
@@ -201,7 +71,7 @@ def _serialize_submitted_documents(self, item):
if not item.has_proposal:
return []

return map(lambda document : {
return map(lambda document: {
'title': document.title,
'link': document.absolute_url(),
'css_class': get_css_class(document)},
@@ -218,34 +88,9 @@ def _serialize_submitted_excerpt(self, item):
'css_class': get_css_class(excerpt),
}

def publishTraverse(self, request, name):
if name == 'list':
return self.list

if name == 'edit':
return self.edit

if name == 'delete':
return self.delete

if name == 'update_order':
return self.update_order

if name == 'schedule_text':
return self.schedule_text

if name == 'schedule_paragraph':
return self.schedule_paragraph

# we only support exactly one id
if self.agenda_item_id:
raise NotFound
self.agenda_item_id = int(name)
return self

def list(self):
"""
Returns json list of all agendaitems for the current context (meeting).
"""Returns json list of all agendaitems for the current
context (meeting).
"""
meeting = self.context.model
agenda_items = []
@@ -262,7 +107,7 @@ def list(self):
return JSONResponse(self.request).data(items=agenda_items).dump()

def update_order(self):
"""Updat the order of the agendaitems. The new sortOrder is expected
"""Updates the order of the agendaitems. The new sortOrder is expected
in the request parameter `sortOrder`.
"""
if not self.context.model.is_editable():
@@ -59,47 +59,12 @@
permission="zope2.View"
/>

<browser:page
for="opengever.meeting.interfaces.IMeetingWrapper"
name="schedule_proposal"
class=".agendaitem.ScheduleSubmittedProposal"
permission="zope2.View"
/>

<browser:page
for="opengever.meeting.interfaces.IMeetingWrapper"
name="schedule_text"
class=".agendaitem.ScheduleText"
permission="zope2.View"
/>

<browser:page
for="opengever.meeting.interfaces.IMeetingWrapper"
name="update_agenda_item_order"
class=".agendaitem.UpdateAgendaItemOrder"
permission="zope2.View"
/>

<browser:page
for="opengever.meeting.interfaces.IMeetingWrapper"
name="delete_agenda_item"
class=".agendaitem.DeleteAgendaItem"
permission="zope2.View"
/>

<browser:page
for="opengever.meeting.interfaces.IMeetingWrapper"
name="update_agenda_item"
class=".agendaitem.UpdateAgendaItem"
permission="zope2.View"
/>

<browser:page
for="opengever.meeting.interfaces.IMeetingWrapper"
name="agenda_items"
class=".agendaitem.AgendaItemsView"
permission="zope2.View"
allowed_attributes="list edit delete update_order schedule_paragraph schedule_text"
allowed_interface=".agendaitem.IAgendaItemActions"
/>

<browser:page
@@ -6,11 +6,6 @@
from opengever.base.model import create_session
from opengever.base.oguid import Oguid
from opengever.meeting import _
from opengever.meeting.browser.meetings.agendaitem import DeleteAgendaItem
from opengever.meeting.browser.meetings.agendaitem import UpdateAgendaItem
from opengever.meeting.browser.meetings.agendaitem import ScheduleSubmittedProposal
from opengever.meeting.browser.meetings.agendaitem import ScheduleText
from opengever.meeting.browser.meetings.agendaitem import UpdateAgendaItemOrder
from opengever.meeting.browser.meetings.transitions import MeetingTransitionController
from opengever.meeting.browser.protocol import GenerateProtocol
from opengever.meeting.browser.protocol import UpdateProtocol
@@ -249,15 +244,6 @@ def transition_url(self, transition):
def unscheduled_proposals(self):
return self.context.get_unscheduled_proposals()

def url_schedule_proposal(self, proposal):
return ScheduleSubmittedProposal.url_for(self.context, self.model, proposal)

def url_schedule_text(self):
return ScheduleText.url_for(self.context, self.model)

def url_delete_agenda_item(self, agenda_item):
return DeleteAgendaItem.url_for(self.context, self.model, agenda_item)

def get_protocol_document(self):
if self.model.protocol_document:
return self.model.protocol_document.resolve_document()
@@ -289,11 +275,7 @@ def manually_generated_excerpts(self):

@property
def url_update_agenda_item_order(self):
return UpdateAgendaItemOrder.url_for(self.context, self.model)

@property
def url_update_agenda_item(self):
return UpdateAgendaItem.url_for(self.context, self.model)
return '{}/agenda_items/update_order'.format(self.context.absolute_url())

@property
def url_list_agenda_items(self):
@@ -107,7 +107,7 @@
<h2 class="label" i18n:translate="">Agenda Items</h2>
</div>
<div class="collapsible-content open">
<form method="post" tal:attributes="action view/url_schedule_text">
<form method="post">
<div class="input-group">
<label for="title">Freitext:</label>
<input id="title" type="text" />