def fixPersonRoles(context, userId):
     # Remove all other Owners of this Person object. Note that the creator will have an implicit
     # owner role. The User Preferences Editor role allows us to allow the user defined by the Person
     # to manage their own password and user preferences, but prevent the creator of the Person object
     # from modifying those fields.
     for owner in context.users_with_local_role('Owner'):
         roles = list(context.get_local_roles_for_userid(owner))
         roles.remove('Owner')
         if roles:
             context.manage_setLocalRoles(owner, roles)
         else:
             context.manage_delLocalRoles([owner])
             
     # Grant 'Owner' and 'User Preferences Editor' to the user defined by this object:
     roles = list(context.get_local_roles_for_userid(userId))
     roles.extend(['Owner', 'User Preferences Editor'])
     # eliminate duplicated roles
     roles = list(set(roles))
     context.manage_setLocalRoles(userId, roles)
     
     # Grant 'Owner' only to any users listed as 'assistants':
     for assistant in context.getReferences(relationship="people_assistants"):
         pid = assistant.id
         user = userFolder.getUserById(pid)
         if user is None:
             raise KeyError, _(u"User %s cannot be found.") % pid
         roles = list(context.get_local_roles_for_userid(pid))
         roles.append('Owner')
         context.manage_setLocalRoles(pid, roles)
        def fixPersonRoles(context, userId):
            # Remove all other Owners of this Person object. Note that the creator will have an implicit
            # owner role. The User Preferences Editor role allows us to allow the user defined by the Person
            # to manage their own password and user preferences, but prevent the creator of the Person object
            # from modifying those fields.
            for owner in context.users_with_local_role('Owner'):
                roles = list(context.get_local_roles_for_userid(owner))
                roles.remove('Owner')
                if roles:
                    context.manage_setLocalRoles(owner, roles)
                else:
                    context.manage_delLocalRoles([owner])

            # Grant 'Owner' and 'User Preferences Editor' to the user defined by this object:
            roles = list(context.get_local_roles_for_userid(userId))
            roles.extend(['Owner', u'Reviewer', 'User Preferences Editor'])
            # eliminate duplicated roles
            roles = list(set(roles))
            context.manage_setLocalRoles(userId, roles)

            # Grant 'Owner' only to any users listed as 'assistants':
            for assistant in context.getReferences(
                    relationship="people_assistants"):
                pid = assistant.id
                user = userFolder.getUserById(pid)
                if user is None:
                    raise KeyError, _(u"User %s cannot be found.") % pid
                roles = list(context.get_local_roles_for_userid(pid))
                roles.append('Owner')
                context.manage_setLocalRoles(pid, roles)
 def validate_id(self, value):
     """Ensure the id is unique, also among groups globally."""
     if value != self.getId():
         parent = aq_parent(aq_inner(self))
         if value in parent.objectIds():
             return _(u"An object with id '%s' already exists in this folder") % value
     
         groups = getToolByName(self, 'portal_groups')
         if groups.getGroupById(value) is not None:
             return _(u"A group with id '%s' already exists in the portal") % value
示例#4
0
    def validate_id(self, value):
        """Ensure the id is unique, also among groups globally."""
        if value != self.getId():
            parent = aq_parent(aq_inner(self))
            if value in parent.objectIds():
                return _("An object with id '%s' already exists in this folder"
                         ) % value

            groups = getToolByName(self, 'portal_groups')
            if groups.getGroupById(value) is not None:
                return _("A group with id '%s' already exists in the portal"
                         ) % value
    def post_validate(self, REQUEST, errors):
        form = REQUEST.form
        if 'password' in form or 'confirmPassword' in form:
            password = form.get('password', None)
            confirm = form.get('confirmPassword', None)

            annotations = IAnnotations(self)
            passwordDigest = annotations.get(config.PASSWORD_KEY, None)

            if not passwordDigest:
                if not password and not confirm:
                    errors['password'] = _(u'An initial password must be set')
                    return
            if password or confirm:
                if password != confirm:
                    errors['password'] = errors['confirmPassword'] = _(u'Passwords do not match')
 def validate_officePhone(self, value=None):
     """ Make sure the phone number fits the regex defined in the configuration. """
     if value:
         fsd_tool = getToolByName(self, TOOLNAME)
         regexString = fsd_tool.getPhoneNumberRegex()
         if regexString and not re.match(regexString, value):
             return _(u"Please provide the phone number in the format %s") % fsd_tool.getPhoneNumberDescription()
 def post_validate(self, REQUEST, errors):
     form = REQUEST.form
     if form.has_key('password') or form.has_key('confirmPassword'):
         password = form.get('password', None)
         confirm = form.get('confirmPassword', None)
         
         annotations = IAnnotations(self)
         passwordDigest = annotations.get(PASSWORD_KEY, None)
         
         if not passwordDigest:
             if not password and not confirm:
                 errors['password'] = _(u'An initial password must be set')
                 return
         if password or confirm:
             if password != confirm:
                 errors['password'] = errors['confirmPassword'] = _(u'Passwords do not match')
 def validate_officePhone(self, value=None):
     """ Make sure the phone number fits the regex defined in the configuration. """
     if value:
         fsd_tool = getToolByName(self, config.TOOLNAME)
         regexString = fsd_tool.getPhoneNumberRegex()
         if regexString and not re.match(regexString, value):
             return _(u"Please provide the phone number in the format %s") % (
                 fsd_tool.getPhoneNumberDescription())
 def validate_id(self, value):
     """
     """
     # Ensure the ID is unique in this folder:
     if value != self.getId():
         parent = aq_parent(aq_inner(self))
         if value in parent.objectIds():
             return _(u"An object with ID '%s' already exists in this folder") % value
     
     # Make sure the ID fits the regex defined in the configuration:
     fsd_tool = getToolByName(self, TOOLNAME)
     regexString = fsd_tool.getIdRegex()
     if not re.match(regexString, value):
         return fsd_tool.getIdRegexErrorMessage()
    def validate_id(self, value):
        """
        """
        # Ensure the ID is unique in this folder:
        if value != self.getId():
            parent = aq_parent(aq_inner(self))
            if value in parent.objectIds():
                return _(u"An object with ID '%s' already exists in this folder") % value

        # Make sure the ID fits the regex defined in the configuration:
        fsd_tool = getToolByName(self, config.TOOLNAME)
        regexString = fsd_tool.getIdRegex()
        if not re.match(regexString, value):
            return fsd_tool.getIdRegexErrorMessage()
__author__ = """WebLion <*****@*****.**>"""
__docformat__ = 'plaintext'

from AccessControl import ClassSecurityInfo
from Products.Archetypes.atapi import *
from Products.FacultyStaffDirectory.config import *
from Products.FacultyStaffDirectory.interfaces.departmentalmembership import IDepartmentalMembership
from zope.interface import implements
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((

    StringField(
        name='position',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_position", default=u"Position"),
            i18n_domain='FacultyStaffDirectory',
        )
    ),

    StringField(
        name='title',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_title", default=u"Title"),
            i18n_domain='FacultyStaffDirectory',
            visible={'edit': 'invisible', 'view': 'invisible' },
        )
    ),
    BooleanField(
        name='primary_department',
        widget=BooleanWidget(
from AccessControl import ClassSecurityInfo
from Products.Archetypes.atapi import *
from Products.FacultyStaffDirectory.config import *

from Products.FacultyStaffDirectory.interfaces.specialtyinformation import ISpecialtyInformation
from zope.interface import implements
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((

    TextField(
        name='researchTopic',
        allowable_content_types=('text/plain', 'text/structured', 'text/html',),
        widget=RichWidget(
            label=_(u"FacultyStaffDirectory_label_researchTopic", default=u"Research Topic"),
            i18n_domain='FacultyStaffDirectory',
            allow_file_upload=False,
            rows=5,
        ),
        default_output_type='text/x-html-safe'
    ),

    StringField(
        name='title',
        default="Research Topic",
        widget=StringWidget(
            visible={'edit': 'invisible', 'view': 'visible'},
            label=_(u"FacultyStaffDirectory_label_title", default=u"Title"),
            i18n_domain='FacultyStaffDirectory',
        ),
from AccessControl import ClassSecurityInfo
from Products.Archetypes.atapi import *
from Products.ATContentTypes.content.base import ATCTContent
from Products.ATContentTypes.content.schemata import ATContentTypeSchema, finalizeATCTSchema
from Products.FacultyStaffDirectory.config import *
from Products.FacultyStaffDirectory.interfaces.committeemembership import ICommitteeMembership
from zope.interface import implements
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = ATContentTypeSchema.copy() + Schema((

    StringField(
        name='position',
        widget=StringWidget(
            label=_("FacultyStaffDirectory_label_position", default="Position"),
            i18n_domain='FacultyStaffDirectory',
        )
    ),

    StringField(
        name='title',
        default="Position",
        widget=StringWidget(
            visible={'edit':'invisible', 'view':'visible'},
            label=_("FacultyStaffDirectory_label_title", default="Title"),
            i18n_domain='FacultyStaffDirectory',
        ),
        accessor="Title"
    ),
from Products.Relations.field import RelationField
from Products.FacultyStaffDirectory.config import *
from zope.interface import implements
from Products.CMFCore.utils import getToolByName
from Products.membrane.at.interfaces import IPropertiesProvider
from Products.FacultyStaffDirectory.interfaces.committee import ICommittee
from Acquisition import aq_inner, aq_parent
from Products.FacultyStaffDirectory.permissions import ASSIGN_COMMITTIES_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((

    RelationField(
        name='members',
        widget=ReferenceBrowserWidget(
            label=_(u"FacultyStaffDirectory_label_members", default=u"Members"),
            i18n_domain='FacultyStaffDirectory',
            allow_browse=0,
            allow_search=1,
            show_results_without_query=1,
            base_query="_search_people_in_this_fsd",
            startup_directory_method="_get_parent_fsd_path",
        ),
        write_permission = ASSIGN_COMMITTIES_TO_PEOPLE,
        allowed_types=('FSDPerson',),
        multiValued=True,
        relationship='CommitteeMembership'
    ),
),
)
示例#15
0
        """Constructor
        
        validator - a validator (or ValidatorChain) to run against each item in
        the sequence. For reasonable results, make sure your chain cites the bad
        input in its error message. Otherwise, the user won't know what the
        error message applies to.
        """
        self.name = name
        self.title = kw.get('title', name)
        self.description = description
        self.validator = validator

    def __call__(self, values, *args, **kwargs):
        errors = [self.validator(v) for v in values]
        errors = [x for x in errors
                  if x not in (True, 1)]  # Filter out non-errors.
        if errors:
            return '\n\n'.join(errors)
        else:
            # Not sure why this needs to be True, but returning 1 (like
            # RegexValidator) throws an Unsubscriptable Object exception. [Ed:
            # It's because that's what the IValidator interface proclaims. The
            # stock validators are just nonconformant.]
            return True


classImplements(SequenceValidator, IValidator)

# Change some error messages to improve grammar
validation.validatorFor('isURL').errmsg = _(u'is not a valid URL.'),
         },
         pattern_options={
             'baseCriteria': [{
                 'i': 'portal_type',
                 'o': 'plone.app.querystring.operation.string.is',
                 'v': 'FSDPerson',
             }],
             'basePath':
             '',
             "contextPath":
             None,
             'selectableTypes': [
                 'FSDPerson',
             ],
             'placeholder':
             _(u'Begin typing a name'),
         },
     ),
     write_permission=ASSIGN_SPECIALTIES_TO_PEOPLE,
     allowed_types=('FSDPerson', ),
     multiValued=True,
     relationship=
     'SpecialtyInformation'  # weird relationship name is ArchGenXML's fault
 ),
 atapi.ImageField(
     name='overviewImage',
     schemata='Overview',
     widget=atapi.ImageWidget(
         label=_(
             u"FacultyStaffDirectory_label_overview_image",
             default=u"Overview image (used for specialty overview view)"
from Products.CMFPlone.interfaces import IPloneSiteRoot
from Products.FacultyStaffDirectory import FSDMessageFactory as _

try:
    from Products.Archetypes.Widget import TinyMCEWidget
except ImportError:
    TinyMCEWidget = atapi.RichWidget


schema = ATContentTypeSchema.copy() + atapi.Schema((

    atapi.TextField(
        name='text',
        allowable_content_types=config.ALLOWABLE_CONTENT_TYPES,
        widget=TinyMCEWidget(
            label=_("FacultyStaffDirectory_label_text", default="Body Text"),
            i18n_domain='FacultyStaffDirectory',
        ),
        default_output_type="text/x-html-safe",
        searchable=True,
        validators=('isTidyHtmlWithCleanup',)
    ),

),
)

# + on Schemas does only a shallow copy
PersonGrouping_schema = atapi.OrderedBaseFolderSchema.copy() + schema.copy()


class PersonGrouping(atapi.OrderedBaseFolder, ATCTContent):
示例#18
0
from Products.Archetypes.atapi import *
from archetypes.referencebrowserwidget.widget import ReferenceBrowserWidget
from Products.CMFCore.permissions import View
from Products.FacultyStaffDirectory.PersonGrouping import PersonGrouping
from Products.Relations.field import RelationField
from Products.FacultyStaffDirectory.config import *
from Products.CMFCore.utils import getToolByName
from Products.FacultyStaffDirectory.interfaces.department import IDepartment
from zope.interface import implements
from Products.FacultyStaffDirectory.permissions import ASSIGN_DEPARTMENTS_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema(
    (RelationField(name='members',
                   widget=ReferenceBrowserWidget(
                       label=_("FacultyStaffDirectory_label_members",
                               default="Members"),
                       i18n_domain='FacultyStaffDirectory',
                       allow_browse=0,
                       allow_search=1,
                       show_results_without_query=1,
                       base_query="_search_people_in_this_fsd",
                       startup_directory_method="_get_parent_fsd_path",
                   ),
                   write_permission=ASSIGN_DEPARTMENTS_TO_PEOPLE,
                   allowed_types=('FSDPerson', ),
                   multiValued=1,
                   relationship='departments_members'), ), )

Department_schema = getattr(PersonGrouping, 'schema', Schema(
    ())).copy() + schema.copy()
from Products.Archetypes.atapi import *
from Products.FacultyStaffDirectory.config import *
from Products.CMFCore.permissions import View
from Products.ATContentTypes.content.base import ATCTContent
from Products.ATContentTypes.content.schemata import ATContentTypeSchema, finalizeATCTSchema
from Products.FacultyStaffDirectory.interfaces.course import ICourse
from zope.interface import implements
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = ATContentTypeSchema.copy() + Schema((

    StringField(
        name='abbreviation',
        widget=StringWidget(
            size="5",
            label=_(u"FacultyStaffDirectory_label_abbreviation", default=u"Abbreviation"),
            i18n_domain='FacultyStaffDirectory',
        ),
        searchable=True
    ),

    StringField(
        name='number',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_number", default=u"Number"),
            i18n_domain='FacultyStaffDirectory',
        ),
        searchable=True
    ),

    TextField(
from Products.FacultyStaffDirectory import FSDMessageFactory as _

try:
    from Products.Archetypes.Widget import TinyMCEWidget
except ImportError:
    TinyMCEWidget = atapi.RichWidget

schema = atapi.Schema((
    atapi.TextField(name='researchTopic',
                    allowable_content_types=(
                        'text/plain',
                        'text/structured',
                        'text/html',
                    ),
                    widget=TinyMCEWidget(
                        label=_("FacultyStaffDirectory_label_researchTopic",
                                default="Research Topic"),
                        i18n_domain='FacultyStaffDirectory',
                        allow_file_upload=False,
                        rows=5,
                    ),
                    default_output_type='text/x-html-safe'),
    atapi.StringField(name='title',
                      default="Research Topic",
                      widget=atapi.StringWidget(
                          visible={
                              'edit': 'invisible',
                              'view': 'visible'
                          },
                          label=_("FacultyStaffDirectory_label_title",
                                  default="Title"),
                          i18n_domain='FacultyStaffDirectory',
from Products.membrane.at.interfaces import IPropertiesProvider
from Products.membrane.utils import getFilteredValidRolesForPortal
from Acquisition import aq_inner, aq_parent
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = ATContentTypeSchema.copy() + Schema((
    LinesField('roles_',
        accessor='getRoles',
        mutator='setRoles',
        edit_accessor='getRawRoles',
        vocabulary='getRoleSet',
        default = ['Member'], 
        multiValued=1,
        write_permission=ManageUsers,
        widget=MultiSelectionWidget(
            label=_(u"FacultyStaffDirectory_label_FacultyStaffDirectoryRoles", default=u"Roles"),
            description=_(u"FacultyStaffDirectory_description_FacultyStaffDirectoryRoles", default=u"The roles all people in this directory will be granted site-wide"),
            i18n_domain="FacultyStaffDirectory",
            ),
        ),
    IntegerField('personClassificationViewThumbnailWidth',
        accessor='getClassificationViewThumbnailWidth',
        mutator='setClassificationViewThumbnailWidth',
        schemata='Display',
        default=100,
        write_permission=ManageUsers,
        widget=IntegerWidget(
            label=_(u"FacultyStaffDirectory_label_personClassificationViewThumbnailWidth", default=u"Width for thumbnails in classification view"),
            description=_(u"FacultyStaffDirectory_description_personClassificationViewThumbnailWidth", default=u"Show all person thumbnails with a fixed width (in pixels) within the classification view"),
            i18n_domain="FacultyStaffDirectory",
            ),
from Products.ATContentTypes.content.base import ATCTContent
from Products.ATContentTypes.content.schemata import ATContentTypeSchema, finalizeATCTSchema
from Products.FacultyStaffDirectory.interfaces.course import ICourse
from zope.interface import implements
from Products.FacultyStaffDirectory import FSDMessageFactory as _

try:
    from Products.Archetypes.Widget import TinyMCEWidget
except ImportError:
    TinyMCEWidget = atapi.RichWidget

schema = ATContentTypeSchema.copy() + atapi.Schema((
    atapi.StringField(name='abbreviation',
                      widget=atapi.StringWidget(
                          size="5",
                          label=_("FacultyStaffDirectory_label_abbreviation",
                                  default="Abbreviation"),
                          i18n_domain='FacultyStaffDirectory',
                      ),
                      searchable=True),
    atapi.StringField(name='number',
                      widget=atapi.StringWidget(
                          label=_("FacultyStaffDirectory_label_number",
                                  default="Number"),
                          i18n_domain='FacultyStaffDirectory',
                      ),
                      searchable=True),
    atapi.TextField(name='description',
                    allowable_content_types=config.ALLOWABLE_CONTENT_TYPES,
                    widget=TinyMCEWidget(
                        label=_("FacultyStaffDirectory_label_description",
                                default="Description"),
def modifyPersonOwnership(event):
    """Let people own their own objects and modify their own user preferences.
    
    Stolen from Plone and CMF core, but made less picky about where users are 
    found. (and from borg, thanks, optilude!)
    """
    context = event.context

    # Only run this if FSDPerson is an active membrane type.
    fsd_tool = getToolByName(context, 'facultystaffdirectory_tool')
    if 'FSDPerson' in fsd_tool.getEnableMembraneTypes():

        catalog = getToolByName(context, 'portal_catalog')
        userId = IMembraneUserObject(context).getUserId()
        userFolder = getToolByName(context, 'acl_users')
        
        user = None
        while userFolder is not None:
            user = userFolder.getUserById(userId)
            if user is not None:
                break
            container = aq_parent(aq_inner(userFolder))
            parent = aq_parent(aq_inner(container))
            userFolder = getattr(parent, 'acl_users', None)
        
        if user is None:
            raise KeyError, _(u"User %s cannot be found.") % userId
        
        context.changeOwnership(user, False)

        def fixPersonRoles(context, userId):
            # Remove all other Owners of this Person object. Note that the creator will have an implicit
            # owner role. The User Preferences Editor role allows us to allow the user defined by the Person
            # to manage their own password and user preferences, but prevent the creator of the Person object
            # from modifying those fields.
            for owner in context.users_with_local_role('Owner'):
                roles = list(context.get_local_roles_for_userid(owner))
                roles.remove('Owner')
                if roles:
                    context.manage_setLocalRoles(owner, roles)
                else:
                    context.manage_delLocalRoles([owner])
                    
            # Grant 'Owner' and 'User Preferences Editor' to the user defined by this object:
            roles = list(context.get_local_roles_for_userid(userId))
            roles.extend(['Owner', 'User Preferences Editor'])
            # eliminate duplicated roles
            roles = list(set(roles))
            context.manage_setLocalRoles(userId, roles)
            
            # Grant 'Owner' only to any users listed as 'assistants':
            for assistant in context.getReferences(relationship="people_assistants"):
                pid = assistant.id
                user = userFolder.getUserById(pid)
                if user is None:
                    raise KeyError, _(u"User %s cannot be found.") % pid
                roles = list(context.get_local_roles_for_userid(pid))
                roles.append('Owner')
                context.manage_setLocalRoles(pid, roles)

        fixPersonRoles(context, user.getId())
        catalog.reindexObject(context)
from Products.ATContentTypes.content.base import ATCTContent
from Products.ATContentTypes.content.schemata import ATContentTypeSchema
from Products.FacultyStaffDirectory.config import *
from Products.FacultyStaffDirectory.interfaces.facultystaffdirectory import IFacultyStaffDirectory
from Products.CMFCore.permissions import View, ModifyPortalContent
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.interfaces import IPloneSiteRoot
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema =  ATContentTypeSchema.copy() + Schema((

    TextField(
        name='text',
        allowable_content_types=ALLOWABLE_CONTENT_TYPES,
        widget=RichWidget(
            label=_(u"FacultyStaffDirectory_label_text", default=u"Body Text"),
            i18n_domain='FacultyStaffDirectory',
        ),
        default_output_type="text/x-html-safe",
        searchable=True,
        validators=('isTidyHtmlWithCleanup',)
    ),

),
)

PersonGrouping_schema = OrderedBaseFolderSchema.copy() + schema.copy()  # + on Schemas does only a shallow copy

class PersonGrouping(OrderedBaseFolder, ATCTContent):
    """"""
    security = ClassSecurityInfo()
__author__ = """WebLion <*****@*****.**>"""
__docformat__ = 'plaintext'

from AccessControl import ClassSecurityInfo
from Products.Archetypes.atapi import *
from Products.FacultyStaffDirectory.config import *
from Products.FacultyStaffDirectory.interfaces.departmentalmembership import IDepartmentalMembership
from zope.interface import implements
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((

    StringField(
        name='position',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_position", default=u"Position"),
            i18n_domain='FacultyStaffDirectory',
        )
    ),

    StringField(
        name='title',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_title", default=u"Title"),
            i18n_domain='FacultyStaffDirectory',
            visible={'edit': 'invisible', 'view': 'invisible' },
        )
    ),
),
)
def modifyPersonOwnership(event):
    """Let people own their own objects and modify their own user preferences.
    
    Stolen from Plone and CMF core, but made less picky about where users are 
    found. (and from borg, thanks, optilude!)
    """
    context = event.context

    # Only run this if FSDPerson is an active membrane type.
    fsd_tool = getToolByName(context, 'facultystaffdirectory_tool')
    if 'FSDPerson' in fsd_tool.getEnableMembraneTypes():

        catalog = getToolByName(context, 'portal_catalog')
        userId = IMembraneUserObject(context).getUserId()
        userFolder = getToolByName(context, 'acl_users')

        user = None
        while userFolder is not None:
            user = userFolder.getUserById(userId)
            if user is not None:
                break
            container = aq_parent(aq_inner(userFolder))
            parent = aq_parent(aq_inner(container))
            userFolder = getattr(parent, 'acl_users', None)

        if user is None:
            raise KeyError, _(u"User %s cannot be found.") % userId

        context.changeOwnership(user, False)

        def fixPersonRoles(context, userId):
            # Remove all other Owners of this Person object. Note that the creator will have an implicit
            # owner role. The User Preferences Editor role allows us to allow the user defined by the Person
            # to manage their own password and user preferences, but prevent the creator of the Person object
            # from modifying those fields.
            for owner in context.users_with_local_role('Owner'):
                roles = list(context.get_local_roles_for_userid(owner))
                roles.remove('Owner')
                if roles:
                    context.manage_setLocalRoles(owner, roles)
                else:
                    context.manage_delLocalRoles([owner])

            # Grant 'Owner' and 'User Preferences Editor' to the user defined by this object:
            roles = list(context.get_local_roles_for_userid(userId))
            roles.extend(['Owner', u'Reviewer', 'User Preferences Editor'])
            # eliminate duplicated roles
            roles = list(set(roles))
            context.manage_setLocalRoles(userId, roles)

            # Grant 'Owner' only to any users listed as 'assistants':
            for assistant in context.getReferences(
                    relationship="people_assistants"):
                pid = assistant.id
                user = userFolder.getUserById(pid)
                if user is None:
                    raise KeyError, _(u"User %s cannot be found.") % pid
                roles = list(context.get_local_roles_for_userid(pid))
                roles.append('Owner')
                context.manage_setLocalRoles(pid, roles)

        fixPersonRoles(context, user.getId())
        catalog.reindexObject(context)
from zope.interface import implements, classImplements

try:
    from Products.Archetypes.Widget import TinyMCEWidget
except ImportError:
    TinyMCEWidget = atapi.RichWidget


logger = logging.getLogger('FacultyStaffDirectory')

schema = ATContentTypeSchema.copy() + atapi.Schema((

    atapi.StringField(
        name='firstName',
        widget=atapi.StringWidget(
            label=_(u"FacultyStaffDirectory_label_firstName", default=u"First Name"),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=True,
        schemata="Basic Information",
        searchable=True
    ),

    atapi.StringField(
        name='middleName',
        widget=atapi.StringWidget(
            label=_(u"FacultyStaffDirectory_label_middleName", default=u"Middle Name"),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=False,
        schemata="Basic Information",
from archetypes.referencebrowserwidget.widget import ReferenceBrowserWidget
from Products.CMFCore.permissions import View, ManageProperties, ModifyPortalContent
from Products.CMFCore.utils import getToolByName
from zope.interface import implements
from Products.CMFCore.permissions import ManageUsers
from Products.membrane.at.interfaces import IPropertiesProvider
from Products.FacultyStaffDirectory.interfaces.classification import IClassification
from Acquisition import aq_inner, aq_parent
from Products.FacultyStaffDirectory.permissions import ASSIGN_CLASSIFICATIONS_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _
from DateTime import DateTime

schema = Schema(
    (RelationField(name='people',
                   widget=ReferenceBrowserWidget(
                       label=_(u"FacultyStaffDirectory_label_people",
                               default=u"People"),
                       i18n_domain='FacultyStaffDirectory',
                       allow_browse=0,
                       allow_search=1,
                       show_results_without_query=1,
                       base_query="_search_people_in_this_fsd",
                       startup_directory_method="_get_parent_fsd_path",
                   ),
                   write_permission=ASSIGN_CLASSIFICATIONS_TO_PEOPLE,
                   allowed_types=('FSDPerson', ),
                   multiValued=1,
                   relationship='classifications_people'), ), )

Classification_schema = getattr(PersonGrouping, 'schema', Schema(
    ())).copy() + schema.copy()
from Products.FacultyStaffDirectory.interfaces.person import IPerson
from Products.FacultyStaffDirectory.interfaces.person import IPersonModifiedEvent
from Products.FacultyStaffDirectory.interfaces.facultystaffdirectory import IFacultyStaffDirectory
from Products.FacultyStaffDirectory.permissions import ASSIGN_CLASSIFICATIONS_TO_PEOPLE, ASSIGN_DEPARTMENTS_TO_PEOPLE, ASSIGN_COMMITTIES_TO_PEOPLE, ASSIGN_SPECIALTIES_TO_PEOPLE, CHANGE_PERSON_IDS
from Products.FacultyStaffDirectory.validators import SequenceValidator

from Products.FacultyStaffDirectory import FSDMessageFactory as _

logger = logging.getLogger('FacultyStaffDirectory')

schema = ATContentTypeSchema.copy() + Schema((
    
    StringField(
        name='firstName',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_firstName", default=u"First Name"),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=True,
        schemata="Basic Information",
        searchable=True
    ),
    
    StringField(
        name='middleName',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_middleName", default=u"Middle Name"),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=False,
        schemata="Basic Information",
from Products.CMFCore.utils import getToolByName

from Products.FacultyStaffDirectory.interfaces.specialty import ISpecialty
from Products.FacultyStaffDirectory.permissions import ASSIGN_SPECIALTIES_TO_PEOPLE

from zope.interface import implements
#from zope.i18nmessageid import MessageFactory
#_ = MessageFactory('FacultyStaffDirectory')
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((

    RelationField(
        name='people',
        widget=ReferenceBrowserWidget(
            label=_(u"FacultyStaffDirectory_label_people", default=u"People"),
            i18n_domain='FacultyStaffDirectory',
            allow_browse=0,
            allow_search=1,
            show_results_without_query=1,
            base_query="_search_people_in_this_fsd",
            startup_directory_method="_get_parent_fsd_path",   
        ),
        write_permission=ASSIGN_SPECIALTIES_TO_PEOPLE,
        allowed_types=('FSDPerson',),
        multiValued=True,
        relationship='SpecialtyInformation'  # weird relationship name is ArchGenXML's fault
    ),

    ImageField(
        name='overviewImage',
class Person(atapi.OrderedBaseFolder, ATCTContent):
    """A person in the Faculty/Staff directory"""
    meta_type = portal_type = "FSDPerson"
    security = ClassSecurityInfo()
    # zope3 interfaces
    implements(IPerson,
               IUserAuthProvider,
               IPropertiesProvider,
               IGroupsProvider,
               IGroupAwareRolesProvider,
               IAttributeAnnotatable,
               IUserChanger)

    # moved schema setting after finalizeATCTSchema, so the order of the fieldsets
    # is preserved. Also after updateActions is called since it seems to overwrite the schema
    # changes.
    # Move the description field, but not in Plone 2.5 since it's already in the metadata tab.
    # Although,
    # decription and relateditems are occasionally showing up in the "default" schemata. Move them
    # to "metadata" just to be safe.
    if 'categorization' in Person_schema.getSchemataNames():
        Person_schema.changeSchemataForField('description', 'settings')
    else:
        Person_schema.changeSchemataForField('description', 'metadata')
        Person_schema.changeSchemataForField('relatedItems', 'metadata')

    # reorder the fields to move the dates into the employment information schemata along with the
    # termination details field and rename the effective and expiration dates.
    Person_schema['effectiveDate'].schemata = 'Employment Information'
    Person_schema['effectiveDate'].widget.label = _(u"label_edit_hire_date", default=u"Hire Date")
    Person_schema['effectiveDate'].widget.description = _(
        u"description_edit_hire_date",
        default=u"The date when the person will be hired. If no date is selected the person "
                u"will be considered hired immediately.")
    Person_schema['expirationDate'].schemata = 'Employment Information'
    Person_schema['expirationDate'].widget.label = _(u"label_edit_termination_date",
                                                     default=u"Termination Date")
    Person_schema['expirationDate'].widget.description = _(
        u"description_edit_termination_date",
        default=u"The date when the person leaves the organization. This will automatically make "
                u"the person invisible for others at the given date.")
    Person_schema.moveField('effectiveDate', after='specialties')
    Person_schema.moveField('expirationDate', after='effectiveDate')
    Person_schema.moveField('terminationDetails', after='expirationDate')

    _at_rename_after_creation = True
    schema = Person_schema
    # Methods
    security.declareProtected(View, 'at_post_create_script')
    def at_post_create_script(self):
        """Notify that the Person has been modified.
        """
        notify(PersonModifiedEvent(self))

    security.declareProtected(View, 'at_post_edit_script')
    def at_post_edit_script(self):
        """Notify that the Person has been modified.
        """
        notify(PersonModifiedEvent(self))

    def __call__(self, *args, **kwargs):
        return self.getId()

    security.declareProtected(View, 'vcard_view')
    def vcard_view(self, REQUEST, RESPONSE):
        """vCard 3.0 output
        """
        RESPONSE.setHeader('Content-Type', 'text/x-vcard')
        RESPONSE.setHeader('Content-Disposition', 'attachment; filename="%s.vcf"' % self.getId())
        out = StringIO()

        # Get the fields using the accessors, so they're properly Unicode encoded.
        out.write("BEGIN:VCARD\nVERSION:3.0\n")
        out.write("FN:%s\n" % self.Title())
        out.write("N:%s;%s\n" % (self.getLastName(), self.getFirstName()))
        out.write(foldLine("TITLE:%s\n" % '\\n'.join(self.getJobTitles())))
        out.write(foldLine("ADR;TYPE=dom,postal,parcel,work:;;%s;%s;%s;%s\n" % (
            self.getOfficeAddress().replace('\r\n', '\\n'),
            self.getOfficeCity(),
            self.getOfficeState(),
            self.getOfficePostalCode())))
        out.write("TEL;WORK:%s\n" % self.getOfficePhone())
        out.write("EMAIL;TYPE=internet:%s\n" % self.getEmail())

        # Add the Person page to the list of URLs
        urls = list(self.getWebsites())
        urls.append(self.absolute_url())
        for url in urls:
            out.write(foldLine("URL:%s\n" % url))
        if self.getImage():
            encData = self.image_thumb.data.encode('base-64')
            # indent the data block:
            indentedData = '\n  '.join(encData.strip().split('\n'))
            out.write("PHOTO;ENCODING=BASE64;TYPE=JPEG:\n  %s\n" % indentedData)
        out.write("REV:%s\n" % DateTime(self.ModificationDate()).ISO8601())
        out.write("PRODID:WebLion Faculty/Staff Directory\nEND:VCARD")
        return n2rn(out.getvalue())

    security.declareProtected(View, 'getSortableName')
    def getSortableName(self):
        """
        Return a tuple of the person's name. For sorting purposes
        Return them as lowercase so that names like 'von Whatever' sort properly
        """
        return (self.lastName.lower(), self.firstName.lower())

    security.declareProtected(View, 'Title')
    def Title(self):
        """
        Return the Title as firstName middleName(when available) lastName, suffix(when available)
        """
        try:
            # Get the fields using the accessors, so they're properly Unicode encoded.
            # We also can't use the %s method of string concatentation for the same reason.
            # Is there another way to manage this?
            fn = self.getFirstName()
            ln = self.getLastName()
        except AttributeError:
            # YTF doesn't this display on the New Person page?
            # Couldn't call superclass's Title() for some unknown reason
            return u"new person"

        if self.getMiddleName():
            mn = " " + self.getMiddleName() + " "
        else:
            mn = " "

        t = fn + mn + ln
        if self.getSuffix():
            t = t + ", " + self.getSuffix()

        return t

    security.declarePrivate('_classificationReferences')
    def _classificationReferences(self):
        """Return a list of Classifications this Person can be referenced to."""
        return [(c.UID, safe_unicode(c.Title))
                for c in self.aq_parent.getFolderContents({'portal_type': 'FSDClassification'})]

    security.declarePrivate('_availableEditors')
    def _availableEditors(self):
        """ Return a list of the available WYSIWYG editors for the site. """
        try:
            props = getToolByName(self, 'portal_properties')
            editors = [
                ('', 'Use site default')
            ] + [(e, e) for e in props['site_properties'].available_editors]
        except (AttributeError, KeyError):
            # plone 5
            editors = [('tinymce', 'TinyMCE')]
        return editors

    security.declarePrivate('_availableLanguages')
    def _availableLanguages(self):
        """ Return a list of the available languages for the site. """
        props = getToolByName(self, 'portal_properties')
        return props.availableLanguages()

    security.declarePrivate('_skinSelections')
    def _skinSelections(self):
        """ Return a list of the available skins for the site. """
        skins = getToolByName(self, 'portal_skins')
        return skins.getSkinSelections()

    security.declareProtected(View, 'getCourses')
    def getCourses(self):
        """Return a listing of Courses contained by this Person."""
        portal_catalog = getToolByName(self, 'portal_catalog')
        return portal_catalog(
            path='/'.join(self.getPhysicalPath()),
            portal_type='FSDCourse',
            depth=1, sort_on="getObjPositionInParent")

    security.declareProtected(View, 'getClassificationNames')
    def getClassificationNames(self):
        """ Returns a list of the titles of the classifications attached to this person.
            Mainly used for pretty-looking metadata in SmartFolder tables.
        """
        cList = [(getObjPositionInParent(c)() + 1, c.Title()) for c in self.getClassifications()]
        cList.sort()
        return [c[-1] for c in cList]

    security.declareProtected(View, 'getSpecialtyTree')
    def getSpecialtyTree(self):
        """Return a tree-shaped dict of catalog brains of this person's specialties.
           The topmost level of the tree consists of SpecialtiesFolders; the remainder,
           of Specialties.

            The format of the dict is a superset of what buildFolderTree() returns (see its
            docstring for details). Consequently you can use a recursive macro similar
            to portlet_navtree_macro to render the results.

            Even if a person is mapped to a specialty but not to a superspecialty of it,
            the superspecialty will be returned. However, it will lack a 'reference' key,
            where explicitly mapped specialties will have one set to the reference from
            the Person to the Specialty. (All SpecialtiesFolders also lack 'reference' keys.)
            Thus, the template author can decide whether to consider people to implicitly
            belong to superspecialties of their explicitly mapped specialties, simply by
            deciding how to present the results.
        """
        def buildSpecialtiesFolderTree():
            """Return a buildFolderTree-style tree representing every SpecialtiesFolder and its descendents.

            More specifically, do a buildFolderTree for each SpecialtiesFolder, then merge the
            results into one big tree.
            """
            portal_catalog = getToolByName(self, 'portal_catalog')
            tree = {'children': []}
            for specialtiesFolder in portal_catalog(portal_type='FSDSpecialtiesFolder'):
                subtree = buildFolderTree(
                    self, query={'path': {'query': specialtiesFolder.getPath()},
                                 'portal_type': 'FSDSpecialty'})
                subtree['currentItem'] = False
                subtree['currentParent'] = False
                subtree['item'] = specialtiesFolder
                subtree['depth'] = 0
                # Let's see if that drives the stylesheets crazy. Otherwise,
                # I'm going to have to increment the 'depth' keys in the whole rest of the tree.
                tree['children'].append(subtree)
            return tree

        # Walk the tree, killing everything not in reffedUids, except for the ancestors of
        # reffed things.
        refs = getToolByName(self, 'reference_catalog').getReferences(
            self, relationship='people_specialties')
        reffedUids = dict([(ref.targetUID, ref) for ref in refs])
        def pruneUnreffed(tree):
            """
            Prune all subtrees from `tree` where no descendent is in `reffedUids`.
            Return whether `tree` itself should be pruned off. While we're at it,
            add 'reference' keys."""
            keptChildren = []
            for child in tree['children']:
                if not pruneUnreffed(child):  # If that child shouldn't be completely pruned away,
                    keptChildren.append(child)  # keep it.
            tree['children'] = keptChildren

            if 'item' in tree:  # 'item' is not in the root node.
                try:
                    ref = reffedUids.get(tree['item'].UID)
                except TypeError:
                    # Catch the 'unhashable type' error we're getting in rare cases
                    # (seems to be mostly on uninstall/reinstall when catalog reindexing goes awry).
                    ref = reffedUids.get(tree['item'].getObject().UID())
                if ref:
                    tree['reference'] = ref
                    # I don't care if you pruned all my children off. I myself am reffed,
                    # so I'm staying.
                    return False
            # My children are the only thing keeping me here.
            # Prune me if there aren't any. (Sounds so dramatic, doesn't it?)
            return not keptChildren

        tree = buildSpecialtiesFolderTree()
        pruneUnreffed(tree)
        return tree

    security.declareProtected(View, 'getSpecialties')
    def getSpecialties(self):
        """Return an iterable of tuples representing the specialties explicitly attached to this
           person. The first item of the tuple is a catalog brain of a specialty; the second, the
           reference pointing from the Person to the Specialty.

            Results are ordered by the position of the specialties in their containers
            (SpecialtiesFolders or other Specialties) and by the order of SpecialtiesFolders
            themselves if there is more than one.

            To get a Specialties object from a result, call result.getTargetObject(). To get a
            SpecialtyInformation object, call result.getContentObject().
        """
        items = []
        def depthFirst(tree):
            """
            Append, in depth-first pre order, a tuple of ('item' value, 'reference' value)
            from `tree` for every node that has a 'reference' value."""
            if 'reference' in tree:
                # There's always an 'item' key where there's a 'reference' key.
                # How can you have a reference if there's no item to reference?
                items.append((tree['item'], tree['reference']))
            for child in tree['children']:
                depthFirst(child)
        depthFirst(self.getSpecialtyTree())
        return items

    security.declareProtected(View, 'getSpecialtyNames')
    def getSpecialtyNames(self):
        """Return a list of the titles of the specialties explicitly attached to this person.

        Results are ordered as in getSpecialties().

        Mainly used for pretty-looking metadata in SmartFolder tables.
        """
        return [x.Title for x, _ in self.getSpecialties()]

    security.declareProtected(View, 'getResearchTopics')
    def getResearchTopics(self):
        """Return a list of the research topics of the specialties explicitly attached to this person.

        Results are ordered as in getSpecialties(). Specialties whose references have no content
        object (which doesn't happen) or where the content object has an empty research topic are
        omitted.

        Mainly used for pretty-looking metadata in SmartFolder tables.
        """
        topics = []
        for _, ref in self.getSpecialties():  # noqa
            # TODO: probably slow: wakes up all those SpecialtyInformation objects
            refContent = ref.getContentObject()
            # This is usually true, because reference-dwelling objects are always created when
            # the reference is created. However, it's false sometimes; run testSpecialties for
            # an example.
            if refContent:
                researchTopic = refContent.getResearchTopic()
                if researchTopic:
                    topics.append(researchTopic)
        return topics

    security.declareProtected(View, 'getDepartmentNames')
    def getDepartmentNames(self):
        """ Returns a list of the titles of the departments attached to this person.
            Mainly used for pretty-looking metadata in SmartFolder tables. Returns an
            alphabetically-sorted list since Departments can be located anywhere within the site,
            which makes using any other sort order somewhat problematic.
        """
        dList = [d.Title() for d in self.getDepartments()]
        dList.sort()
        return dList

    security.declareProtected(View, 'getCommitteeNames')
    def getCommitteeNames(self):
        """ Returns a list of the titles of the committees attached to this person.
            Mainly used for pretty-looking metadata in SmartFolder tables. Returns an
            alphabetically-sorted list since Committees can be located throughout the site,
            which makes using any other sort order somewhat problematic.
        """
        dList = [d.Title() for d in self.getCommittees()]
        dList.sort()
        return dList

    security.declareProtected(ModifyPortalContent, 'pre_edit_setup')
    def pre_edit_setup(self):
        """ Some schema tweaking that needs to happen before viewing the edit page.
        """

        fsd_tool = getToolByName(self, config.TOOLNAME)
        if (fsd_tool.getPhoneNumberRegex()):
            self.schema['officePhone'].widget.description = u"Example: %s" % (
                fsd_tool.getPhoneNumberDescription())
        if (fsd_tool.getIdLabel()):
            self.schema['id'].widget.label = u"%s" % fsd_tool.getIdLabel()

        # Make sure the default for the editor field is the same as the site defaut.
        # No idea why this isn't being handled properly.
        memberProps = getToolByName(self, 'portal_memberdata')
        self.schema['userpref_wysiwyg_editor'].default = memberProps.wysiwyg_editor

        return self.base_edit()

    security.declareProtected(View, 'tag')
    def tag(self, **kwargs):
        """Pass along the 'tag' method to the Person's image."""
        return self.getWrappedField('image').tag(self, **kwargs)

    security.declareProtected(View, 'getImageOfSize')
    def getImageOfSize(self, height, width, **kwargs):
        """Return the person's image sized to the given dimensions."""
        return self.getWrappedField('image').tag(self, width=width, height=height, **kwargs)

    security.declareProtected(View, 'getScaledImageByWidth')
    def getScaledImageByWidth(self, preferredWidth, **kwargs):
        """
        Return the person's image sized to the given width and a height scaled according to
        the original image ratio. Fail nicely, returning no image tag. This seems to occur
        when TIFF images are used."""
        if not (self.image.height or self.image.width):
            logger.error("There was an error resizing the image for person %s" % self)
            return ''
        hwratio = float(self.image.height)/float(self.image.width)
        calcHeight = int(preferredWidth * hwratio)
        return self.getImageOfSize(calcHeight, preferredWidth, **kwargs)

    security.declareProtected(ModifyPortalContent, 'setImage')
    def setImage(self, value, **kwargs):
        field = self.getField('image')

        # If the image exists in portal memberdata's portraits folder, delete it
        md = getToolByName(self, 'portal_memberdata')
        if self.id in md.portraits:
            md.portraits._delObject(self.id)

        # Assign the image to the field
        field.set(self, value)

        # If there is an image value (not the empty string that seems to get sent on
        # object creation)
        # and it's not a delete command, create a member portrait
        if value and value != 'DELETE_IMAGE':
            # Add the new portrait
            # md.portraits._setObject(id=self.id, object=self.getImage())
            raw_image = StringIO()
            raw_image.write(str(self.getRawImage().data))
            raw_image.seek(0)
            md.portraits._setObject(id=self.id, object=Image(id=self.id, file=raw_image, title=''))
            raw_image.close()

    security.declareProtected(SetOwnPassword, 'setPassword')
    def setPassword(self, value):
        """"""
        if value:
            annotations = IAnnotations(self)
            annotations[config.PASSWORD_KEY] = sha(value).digest()

    security.declareProtected(SetOwnPassword, 'setConfirmPassword')
    def setConfirmPassword(self, value):
        """"""
        # Do nothing - this value is used for verification only
        pass

    security.declarePrivate('validate_id')
    def validate_id(self, value):
        """
        """
        # Ensure the ID is unique in this folder:
        if value != self.getId():
            parent = aq_parent(aq_inner(self))
            if value in parent.objectIds():
                return _(u"An object with ID '%s' already exists in this folder") % value

        # Make sure the ID fits the regex defined in the configuration:
        fsd_tool = getToolByName(self, config.TOOLNAME)
        regexString = fsd_tool.getIdRegex()
        if not re.match(regexString, value):
            return fsd_tool.getIdRegexErrorMessage()

    security.declarePrivate('validate_officePhone')
    def validate_officePhone(self, value=None):
        """ Make sure the phone number fits the regex defined in the configuration. """
        if value:
            fsd_tool = getToolByName(self, config.TOOLNAME)
            regexString = fsd_tool.getPhoneNumberRegex()
            if regexString and not re.match(regexString, value):
                return _(u"Please provide the phone number in the format %s") % (
                    fsd_tool.getPhoneNumberDescription())

    def spamProtectFSD(self, email):
        """
        Implement a different email obfuscating approach than the standard Plone spam
        protection.  Dots, @ etc. will be replaced with a string representation. """
        email = email.replace('.', ' [ DOT ] ')
        email = email.replace('@', ' [ AT ] ')
        email = email.replace('-', ' [ DASH ] ')
        email = email.replace('_', ' [ UNDERSCORE ] ')
        return email

    security.declarePrivate('post_validate')
    def post_validate(self, REQUEST, errors):
        form = REQUEST.form
        if 'password' in form or 'confirmPassword' in form:
            password = form.get('password', None)
            confirm = form.get('confirmPassword', None)

            annotations = IAnnotations(self)
            passwordDigest = annotations.get(config.PASSWORD_KEY, None)

            if not passwordDigest:
                if not password and not confirm:
                    errors['password'] = _(u'An initial password must be set')
                    return
            if password or confirm:
                if password != confirm:
                    errors['password'] = errors['confirmPassword'] = _(u'Passwords do not match')

    ###
    # Methods to limit the referenceBrowserWidget start directory and search results
    # security.declareProtected(ModifyPortalContent, '_get_parent_fsd_path')
    # def _get_parent_fsd_path(self):
    #     """ wrap the utility method so we can use it in the context of an AT Schema declaration
    #     """
    #     parent = aq_parent(aq_inner(self))
    #     if IFacultyStaffDirectory.providedBy(parent):
    #         # we should pretty much always expect this to be true.  People can't be added anywhere
    #         #   but inside an FSD, right at the FSD root, right?  Is this a safe assumption?
    #         return parent.absolute_url_path()
    #     else:
    #         return '/'

    security.declareProtected(ModifyPortalContent, '_get_parent_fsd_path')
    def _get_parent_fsd_path(self, relative=True):
        """ given an object of an FSD type, return the path to the parent FSD of that object
        """
        url_tool = getToolByName(self, 'portal_url')
        # Walk up the tree until you find an FSD
        parent = aq_parent(aq_inner(self))
        while not IPloneSiteRoot.providedBy(parent):
            if IFacultyStaffDirectory.providedBy(parent):
                if relative:
                    # get the path relative to the portal root
                    path = '/'.join(url_tool.getRelativeContentPath(parent))
                else:
                    # return the path starting with the portal root
                    path = '/'.join(parent.getPhysicalPath())
                return path
            else:
                parent = aq_parent(aq_inner(parent))

        return ""

    security.declareProtected(ModifyPortalContent, '_limit_rbw_search_params')
    def _limit_rbw_search_params(self, portal_type="FSDPerson", sort_on="sortable_title"):
        """ return a query dictionary to limit the search parameters for a reference browser
            widget query.  Use as basis for more specific versions below
        """
        path = self._get_parent_fsd_path(relative=False)
        return {'portal_type': portal_type,
                'sort_on': sort_on,
                'path': {'query': path}}

    security.declareProtected(ModifyPortalContent, '_search_people_in_this_fsd')
    def _search_people_in_this_fsd(self):
        """ search only parent FSD for only people
        """
        return self._limit_rbw_search_params(portal_type="FSDPerson")

    security.declareProtected(ModifyPortalContent, '_search_departments_in_this_fsd')
    def _search_departments_in_this_fsd(self):
        """ search only parent FSD for only departments
        """
        return self._limit_rbw_search_params(portal_type="FSDDepartment")

    security.declareProtected(ModifyPortalContent, '_search_committees_in_this_fsd')
    def _search_committees_in_this_fsd(self):
        """ search only parent FSD for only committees
        """
        return self._limit_rbw_search_params(portal_type="FSDCommittee")

    security.declareProtected(ModifyPortalContent, '_search_specialties_in_this_fsd')
    def _search_specialties_in_this_fsd(self):
        """ search only parent FSD for only specialties
        """
        return self._limit_rbw_search_params(portal_type="FSDSpecialty")
    def __init__(self, name, validator, description='', **kw):
        """Constructor
        
        validator - a validator (or ValidatorChain) to run against each item in
        the sequence. For reasonable results, make sure your chain cites the bad
        input in its error message. Otherwise, the user won't know what the
        error message applies to.
        """
        self.name = name
        self.title = kw.get('title', name)
        self.description = description
        self.validator = validator
    
    def __call__(self, values, *args, **kwargs):
        errors = [self.validator(v) for v in values]
        errors = [x for x in errors if x not in (True, 1)]  # Filter out non-errors.
        if errors:
            return '\n\n'.join(errors)
        else:
            # Not sure why this needs to be True, but returning 1 (like
            # RegexValidator) throws an Unsubscriptable Object exception. [Ed:
            # It's because that's what the IValidator interface proclaims. The
            # stock validators are just nonconformant.]
            return True

classImplements(SequenceValidator, IValidator)

# Change some error messages to improve grammar
validation.validatorFor('isURL').errmsg = _(u'is not a valid URL.'),

示例#33
0
from Products.membrane.utils import getFilteredValidRolesForPortal
from Acquisition import aq_inner, aq_parent
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = ATContentTypeSchema.copy() + Schema((
    LinesField(
        'roles_',
        accessor='getRoles',
        mutator='setRoles',
        edit_accessor='getRawRoles',
        vocabulary='getRoleSet',
        default=['Member'],
        multiValued=1,
        write_permission=ManageUsers,
        widget=MultiSelectionWidget(
            label=_("FacultyStaffDirectory_label_FacultyStaffDirectoryRoles",
                    default="Roles"),
            description=_(
                "FacultyStaffDirectory_description_FacultyStaffDirectoryRoles",
                default=
                "The roles all people in this directory will be granted site-wide"
            ),
            i18n_domain="FacultyStaffDirectory",
        ),
    ),
    IntegerField(
        'personClassificationViewThumbnailWidth',
        accessor='getClassificationViewThumbnailWidth',
        mutator='setClassificationViewThumbnailWidth',
        schemata='Display',
        default=100,
        write_permission=ManageUsers,
        },
        pattern_options={
            'baseCriteria': [{
                'i': 'portal_type',
                'o': 'plone.app.querystring.operation.string.is',
                'v': 'FSDPerson',
            }],
            'basePath':
            '',
            "contextPath":
            None,
            'selectableTypes': [
                'FSDPerson',
            ],
            'placeholder':
            _(u'Begin typing a name'),
        },
    ),
    write_permission=ASSIGN_COMMITTIES_TO_PEOPLE,
    allowed_types=('FSDPerson', ),
    multiValued=True,
    relationship='CommitteeMembership'), ), )

Committee_schema = getattr(PersonGrouping, 'schema', Schema(
    ())).copy() + schema.copy()


class Committee(PersonGrouping):
    """
    """
    security = ClassSecurityInfo()
from Products.FacultyStaffDirectory.interfaces.person import IPerson
from Products.FacultyStaffDirectory.interfaces.person import IPersonModifiedEvent
from Products.FacultyStaffDirectory.interfaces.facultystaffdirectory import IFacultyStaffDirectory
from Products.FacultyStaffDirectory.permissions import ASSIGN_CLASSIFICATIONS_TO_PEOPLE, ASSIGN_DEPARTMENTS_TO_PEOPLE, ASSIGN_LABS_TO_PEOPLE,ASSIGN_COMMITTIES_TO_PEOPLE, ASSIGN_SPECIALTIES_TO_PEOPLE, CHANGE_PERSON_IDS
from Products.FacultyStaffDirectory.validators import SequenceValidator

from Products.FacultyStaffDirectory import FSDMessageFactory as _

logger = logging.getLogger('FacultyStaffDirectory')

schema = ATContentTypeSchema.copy() + Schema((
    
    StringField(
        name='firstName',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_firstName", default=u"First Name"),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=True,
        schemata="Basic Information",
        searchable=True
    ),
    
    StringField(
        name='middleName',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_middleName", default=u"Middle Name"),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=False,
        schemata="Basic Information",
from Products.CMFCore.utils import getToolByName

from Products.FacultyStaffDirectory.interfaces.specialty import ISpecialty
from Products.FacultyStaffDirectory.permissions import ASSIGN_SPECIALTIES_TO_PEOPLE

from zope.interface import implements
#from zope.i18nmessageid import MessageFactory
#_ = MessageFactory('FacultyStaffDirectory')
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema(
    (
        RelationField(
            name='people',
            widget=ReferenceBrowserWidget(
                label=_(u"FacultyStaffDirectory_label_people",
                        default=u"People"),
                i18n_domain='FacultyStaffDirectory',
                allow_browse=0,
                allow_search=1,
                show_results_without_query=1,
                base_query="_search_people_in_this_fsd",
                startup_directory_method="_get_parent_fsd_path",
            ),
            write_permission=ASSIGN_SPECIALTIES_TO_PEOPLE,
            allowed_types=('FSDPerson', ),
            multiValued=True,
            relationship=
            'SpecialtyInformation'  # weird relationship name is ArchGenXML's fault
        ),
        ImageField(
            name='overviewImage',
from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
from Products.CMFCore.permissions import View
from Products.FacultyStaffDirectory.PersonGrouping import PersonGrouping
from Products.Relations.field import RelationField
from Products.FacultyStaffDirectory.config import *
from Products.CMFCore.utils import getToolByName
from Products.FacultyStaffDirectory.interfaces.lab import ILab
from zope.interface import implements
from Products.FacultyStaffDirectory.permissions import ASSIGN_LABS_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((
    StringField(
        name="lab_short_name",
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_labshort", default=u"Lab Short Name"),
            description=_(u"FacultyStaffDirectory_description_labshort", default=u""),
            i18n_domain='FacultyStaffDirectory',
            ),
            required=False,
            allow_search=1,
            
        ),
    StringField(
        name='dept_url',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_labUrl", default=u"Primary Lab URL"),
            description=_(u"FacultyStaffDirectory_description_laburl", default=u""),
            i18n_domain='FacultyStaffDirectory',
        ),
        validators = ('isURL')
示例#38
0
            show_indexes = False,
            force_close_on_insert = True,
            label = u"Members",
            label_msgid = "FacultyStaffDirectory_label_members",
            i18n_domain = "FacultyStaffDirectory",
            visible = {'edit' : 'visible', 'view' : 'visible' },
            pattern_options={
                'baseCriteria': [{
                    'i': 'portal_type',
                    'o': 'plone.app.querystring.operation.string.is',
                    'v': 'FSDPerson',
                }],
                'basePath': '',
                "contextPath": None,
                'selectableTypes': ['FSDPerson', ],
                'placeholder': _(u'Begin typing a name'),
            },
        ),
        write_permission=ASSIGN_DEPARTMENTS_TO_PEOPLE,
        allowed_types=('FSDPerson',),
        multiValued=1,
        relationship='departments_members'
    ),
),
)

Department_schema = getattr(PersonGrouping, 'schema', Schema(())).copy() + schema.copy()

class Department(PersonGrouping):
    """
    """
示例#39
0
from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
from Products.CMFCore.permissions import View
from Products.FacultyStaffDirectory.PersonGrouping import PersonGrouping
from Products.Relations.field import RelationField
from Products.FacultyStaffDirectory.config import *
from Products.CMFCore.utils import getToolByName
from Products.FacultyStaffDirectory.interfaces.lab import ILab
from zope.interface import implements
from Products.FacultyStaffDirectory.permissions import ASSIGN_LABS_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((
    StringField(
        name="lab_short_name",
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_labshort",
                    default=u"Lab Short Name"),
            description=_(u"FacultyStaffDirectory_description_labshort",
                          default=u""),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=False,
        allow_search=1,
    ),
    StringField(name='dept_url',
                widget=StringWidget(
                    label=_(u"FacultyStaffDirectory_label_labUrl",
                            default=u"Primary Lab URL"),
                    description=_(u"FacultyStaffDirectory_description_laburl",
                                  default=u""),
                    i18n_domain='FacultyStaffDirectory',
                ),
from Products.CMFCore.permissions import View
from Products.FacultyStaffDirectory.PersonGrouping import PersonGrouping
from Products.Relations.field import RelationField
from Products.FacultyStaffDirectory.config import *
from Products.CMFCore.utils import getToolByName
from Products.FacultyStaffDirectory.interfaces.department import IDepartment
from zope.interface import implements
from Products.FacultyStaffDirectory.permissions import ASSIGN_DEPARTMENTS_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((
   
    StringField(
        name="dept_short_name",
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_deptshort", default=u"Department Short Name"),
            description=_(u"FacultyStaffDirectory_description_officePhone", default=u""),
            i18n_domain='FacultyStaffDirectory',
            ),
            required=False,
            allow_search=1,
            
        ),
    StringField(
        name='dept_url',
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_deptUrl", default=u"Primary Department URL"),
            description=_(u"FacultyStaffDirectory_description_depturl", default=u""),
            i18n_domain='FacultyStaffDirectory',
        ),
        validators = ('isURL')
示例#41
0
from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
from Products.CMFCore.permissions import View
from Products.FacultyStaffDirectory.PersonGrouping import PersonGrouping
from Products.Relations.field import RelationField
from Products.FacultyStaffDirectory.config import *
from Products.CMFCore.utils import getToolByName
from Products.FacultyStaffDirectory.interfaces.department import IDepartment
from zope.interface import implements
from Products.FacultyStaffDirectory.permissions import ASSIGN_DEPARTMENTS_TO_PEOPLE
from Products.FacultyStaffDirectory import FSDMessageFactory as _

schema = Schema((
    StringField(
        name="dept_short_name",
        widget=StringWidget(
            label=_(u"FacultyStaffDirectory_label_deptshort",
                    default=u"Department Short Name"),
            description=_(u"FacultyStaffDirectory_description_officePhone",
                          default=u""),
            i18n_domain='FacultyStaffDirectory',
        ),
        required=False,
        allow_search=1,
    ),
    StringField(name='dept_url',
                widget=StringWidget(
                    label=_(u"FacultyStaffDirectory_label_deptUrl",
                            default=u"Primary Department URL"),
                    description=_(u"FacultyStaffDirectory_description_depturl",
                                  default=u""),
                    i18n_domain='FacultyStaffDirectory',
                ),