This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
collective.contact.core/src/collective/contact/core/browser/addcontact.py

355 lines
14 KiB
Python

from AccessControl import getSecurityManager
from Products.CMFCore.utils import getToolByName
from Products.statusmessages.interfaces import IStatusMessage
from five import grok
from plone.dexterity.browser.add import DefaultAddForm
from plone.dexterity.events import AddCancelledEvent
from plone.dexterity.i18n import MessageFactory as DMF
from plone.dexterity.interfaces import IDexterityFTI
from plone.dexterity.utils import addContentToContainer
from plone.supermodel import model
from z3c.form import field, form, button
from z3c.form.contentprovider import ContentProviders
from z3c.form.interfaces import IFieldsAndContentProvidersForm, HIDDEN_MODE
from zope.component import getUtility
from zope.contentprovider.interfaces import IContentProvider
from zope.event import notify
from zope.interface import implements
from zope.publisher.browser import BrowserView
from collective.contact.widget.schema import ContactChoice
from collective.contact.widget.source import ContactSourceBinder
from collective.contact.widget.interfaces import IContactWidgetSettings
from collective.contact.core import _
from collective.contact.core.content.person import IPerson
class ContactWidgetSettings(grok.GlobalUtility):
grok.implements(IContactWidgetSettings)
def add_contact_infos(self, widget):
source = widget.bound_source
criteria = source.selectable_filter.criteria
addlink_enabled = widget.field.addlink
portal_types = criteria.get('portal_type', [])
catalog = getToolByName(widget.context, 'portal_catalog')
results = catalog.unrestrictedSearchResults(portal_type='directory')
actions = []
if len(results) == 0:
addlink_enabled = False
else:
directory = results[0].getObject()
sm = getSecurityManager()
if not sm.checkPermission("Add portal content", directory):
addlink_enabled = False
close_on_click = True
if addlink_enabled:
directory_url = directory.absolute_url()
if len(portal_types) == 1:
portal_type = portal_types[0]
if portal_type == 'held_position' and not IPerson.providedBy(widget.context):
url = "%s/@@add-contact" % directory_url
type_name = _(u"Contact")
label = _(u"Create ${name}", mapping={'name': type_name})
action = {'url': url, 'label': label,
'klass': 'addnew',
'formselector' : '#oform',
'closeselector': '[name="oform.buttons.cancel"]'}
actions.append(action)
close_on_click = False
else:
url = '%s/++add++%s' % (directory_url, portal_type)
fti = getUtility(IDexterityFTI, name=portal_type)
type_name = fti.Title()
label = _(u"Create ${name}", mapping={'name': type_name})
action = {'url': url, 'label': label}
actions.append(action)
else:
if len(portal_types) == 2 and \
'organization' in portal_types and \
'position' in portal_types:
url = "%s/@@add-organization" % directory_url
type_name = _(u"organization/position")
else:
url = "%s/@@add-contact" % directory_url
type_name = _(u"Contact")
close_on_click = False
label = _(u"Create ${name}", mapping={'name': type_name})
action = {'url': url, 'label': label,
'klass': 'addnew',
'formselector' : '#oform',
'closeselector': '[name="oform.buttons.cancel"]'}
actions.append(action)
return {'actions': actions,
'close_on_click': close_on_click,
'formatItem': """function(row, idx, count, value) {
return '<img src="' + portal_url + '/' + row[2] + '_icon.png'
+'" /> ' + row[1] }"""
}
class MasterSelectAddContactProvider(BrowserView):
implements(IContentProvider)
def __init__(self, context, request, view):
super(MasterSelectAddContactProvider, self).__init__(context, request)
self.__parent__ = view
def update(self):
pass
def render(self):
# If we fill organization and person, show position and held position fields
return """<script type="text/javascript">
$(document).ready(function() {
var o = $('#oform');
o.find('div[id$=held_position-position]').hide();
var position_fields = '#formfield-oform-widgets-position,div[id*=held_position]';
if (!(o.find('input[name="oform.widgets.person"]').length >= 1 &&
o.find('input[name="oform.widgets.organization"]').length >= 1)) {
o.find(position_fields).hide();
}
function serialize_form(form) {
viewArr = form.serializeArray(),
view = {};
for (var i in viewArr) {
view[viewArr[i].name] = viewArr[i].value;
}
return view;
}
function get_selected_organization(form) {
var view = serialize_form(form);
var token = view['oform.widgets.organization'];
var title = form.find('#oform-widgets-organization-input-fields input[value="'+token+'"]').siblings('.label').find('a').first().text();
var path = '/' + token.split('/').slice(2).join('/');
return {token: token, title: title, path: path};
}
o.find('#oform-widgets-organization-input-fields').delegate('input', 'change', function(e){
var form = $(this).closest('form');
var orga = get_selected_organization(form);
var add_organization_url, addneworga, add_text;
addneworga = o.find('#oform-widgets-organization-autocomplete .addnew');
if (!addneworga.data('pbo').original_src) {
addneworga.data('pbo').original_src = addneworga.data('pbo').src;
addneworga.data('pbo').original_text = addneworga.text();
}
if (orga.token == '--NOVALUE--') {
o.find(position_fields).hide();
add_organization_url = addneworga.data('pbo').original_src;
add_text = addneworga.data('pbo').original_text;
} else {
// update add new orga link to add sub orga
add_organization_url = portal_url + orga.path + '/++add++organization';
add_text = addneworga.data('pbo').original_text + ' dans ' + orga.title;
}
addneworga.data('pbo').src = add_organization_url;
addneworga.text(add_text);
// update position autocomplete field
o.find('#formfield-oform-widgets-position > .fieldErrorBox').text('Recherchez ou ajoutez une fonction dans "' + orga.title + '".');
o.find("#oform-widgets-position-widgets-query")
.setOptions({extraParams: {path: orga.token}}).flushCache();
// update add new position url
var add_position_url = portal_url + orga.path + '/++add++position';
o.find('#oform-widgets-position-autocomplete .addnew').data('pbo').src = add_position_url;
// show position and held position fields if orga and person are selected
if ((!o.find('#formfield-oform-widgets-person').length || o.find('input[name="oform.widgets.person"]').length >= 1) &&
o.find('input[name="oform.widgets.organization"]').length >= 1 &&
orga.token != '--NOVALUE--') {
o.find(position_fields).show('slow');
o.find('div[id$=held_position-position]').hide();
}
});
o.find('#oform-widgets-person-input-fields').delegate('input', 'change', function(e){
if (o.find('input[name="oform.widgets.person"]').length >= 1 &&
o.find('input[name="oform.widgets.organization"]').length >= 1) {
o.find(position_fields).show('slow');
o.find('div[id$=held_position-position]').hide();
}
});
o.find('#oform-widgets-position-widgets-query').setOptions({minChars: 0});
o.find('#oform-widgets-position-widgets-query').focus(function(e){
$(this).trigger('click');
});
// If organization was pre filled, we need to trigger the change event.
o.find('#oform-widgets-organization-input-fields input').trigger('change');
});
</script>
"""
class IAddContact(model.Schema):
organization = ContactChoice(
title=_(u"Organization"),
required=False,
source=ContactSourceBinder(portal_type="organization"))
person = ContactChoice(
title=_(u"Person"),
required=False,
source=ContactSourceBinder(portal_type="person"))
position = ContactChoice(
title=_(u"Position"),
required=False,
source=ContactSourceBinder(portal_type="position"))
class AddContact(DefaultAddForm, form.AddForm):
implements(IFieldsAndContentProvidersForm)
contentProviders = ContentProviders(['organization-ms'])
# contentProviders['organization-ms'] = MasterSelectAddContactProvider
contentProviders['organization-ms'].position = -1
label = _(u"Create ${name}", mapping={'name': _(u"Contact")})
description = u""
schema = IAddContact
portal_type = 'held_position'
prefix = 'oform'
@property
def additionalSchemata(self):
fti = getUtility(IDexterityFTI, name=self.portal_type)
schema = fti.lookupSchema()
# save the schema name to be able to remove a field afterwards
self._schema_name = schema.__name__
return (schema,)
def updateFieldsFromSchemata(self):
super(AddContact, self).updateFieldsFromSchemata()
# IHeldPosition and IAddContact have both a field named position
# hide the one from IHeldPosition
# TODO: there is no hidden template for autocomplete widget,
# we hide it in javascript for now.
self.fields[self._schema_name + '.position'].mode = HIDDEN_MODE
def updateWidgets(self):
super(AddContact, self).updateWidgets()
for widget in self.widgets.values():
if getattr(widget, 'required', False):
# This is really a hack to not have required field errors
# but have the visual required nevertheless.
# We need to revert this after updateActions
# because this change impact the held position form
widget.field.required = False
def update(self):
super(AddContact, self).update()
# revert required field changes
for widget in self.widgets.values():
if getattr(widget, 'required', False):
widget.field.required = True
@button.buttonAndHandler(_('Add'), name='save')
def handleAdd(self, action):
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return
obj = self.createAndAdd(data)
if obj is not None:
# mark only as finished if we get the new object
self._finishedAdd = True
IStatusMessage(self.request).addStatusMessage(DMF(u"Item created"),
"info")
@button.buttonAndHandler(DMF(u'Cancel'), name='cancel')
def handleCancel(self, action):
IStatusMessage(self.request).addStatusMessage(DMF(u"Add New Item operation cancelled"),
"info")
self.request.response.redirect(self.nextURL())
notify(AddCancelledEvent(self.context))
def createAndAdd(self, data):
if data['person'] is None and data['organization'] is None:
return
elif data['organization'] is not None and data['person'] is None:
self.request.response.redirect(data['organization'].absolute_url())
self._finishedAdd = True
return
elif data['person'] is not None and data['organization'] is None:
self.request.response.redirect(data['person'].absolute_url())
self._finishedAdd = True
return
else:
return super(AddContact, self).createAndAdd(data)
def create(self, data):
self._container = data.pop('person')
position = data.pop('position')
orga = data.pop('organization')
if position is None:
position = orga
data[self._schema_name + '.position'] = position
return super(AddContact, self).create(data)
def add(self, obj):
container = self._container
fti = getUtility(IDexterityFTI, name=self.portal_type)
new_object = addContentToContainer(container, obj)
if fti.immediate_view:
self.immediate_view = "%s/%s/%s" % (container.absolute_url(),
new_object.id,
fti.immediate_view,)
else:
self.immediate_view = "%s/%s" % (container.absolute_url(),
new_object.id)
class AddContactFromOrganization(AddContact):
def updateWidgets(self):
if 'oform.widgets.organization' not in self.request.form:
self.request.form['oform.widgets.organization'] = '/'.join(
self.context.getPhysicalPath())
super(AddContactFromOrganization, self).updateWidgets()
class AddOrganization(form.AddForm):
implements(IFieldsAndContentProvidersForm)
contentProviders = ContentProviders(['organization-ms'])
contentProviders['organization-ms'].position = 2
label = _(u"Create ${name}", mapping={'name': _(u"organization/position")})
description = u""
prefix = 'oform'
fields = field.Fields(IAddContact).select('organization', 'position')
def updateWidgets(self):
super(AddOrganization, self).updateWidgets()
self.widgets['organization'].label = _(
'help_add_organization_or_position_organization',
"Please fill the organization first "
"and then eventually select position")
@button.buttonAndHandler(_('Add'), name='save')
def handleAdd(self, action):
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return
self._finishedAdd = True
if data['position'] is not None:
self.request.response.redirect(data['position'].absolute_url())
return
elif data['organization'] is not None:
self.request.response.redirect(data['organization'].absolute_url())
return
@button.buttonAndHandler(DMF(u'Cancel'), name='cancel')
def handleCancel(self, action):
pass