Added public profile
authorThierry Florac <thierry.florac@onf.fr>
Thu, 08 Oct 2015 09:28:33 +0200
changeset 50 a6d994c60822
parent 49 e4fc19ce77fa
child 51 550988fcf228
Added public profile
src/pyams_security/interfaces/profile.py
src/pyams_security/profile.py
src/pyams_security/zmi/profile.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_security/interfaces/profile.py	Thu Oct 08 09:28:33 2015 +0200
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+
+# import packages
+from pyams_file.schema import ThumbnailImageField
+from zope.interface import Interface
+
+from pyams_security import _
+
+
+PUBLIC_PROFILE_KEY = 'pyams_security.public_profile'
+
+
+class IPublicProfile(Interface):
+    """User public profile preferences"""
+
+    avatar = ThumbnailImageField(title=_("Profile's avatar"),
+                                 description=_("This picture will be associated to your user profile"),
+                                 required=False)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_security/profile.py	Thu Oct 08 09:28:33 2015 +0200
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_security.interfaces import IPrincipalInfo
+from pyams_security.interfaces.profile import PUBLIC_PROFILE_KEY, IPublicProfile
+from pyams_utils.interfaces.site import ISiteRoot
+from pyams_utils.interfaces.tales import ITALESExtension
+from zope.annotation.interfaces import IAnnotations, IAttributeAnnotatable
+from zope.traversing.interfaces import ITraversable
+
+# import packages
+from persistent import Persistent
+from pyams_file.property import FileProperty
+from pyams_utils.adapter import adapter_config, ContextRequestAdapter
+from pyams_utils.request import check_request
+from pyams_utils.traversing import get_parent
+from pyramid.threadlocal import get_current_registry, get_current_request
+from zope.container.contained import Contained
+from zope.lifecycleevent import ObjectCreatedEvent
+from zope.interface import implementer, Interface
+from zope.location import locate
+
+
+@implementer(IPublicProfile, IAttributeAnnotatable)
+class PublicProfile(Persistent, Contained):
+    """Public profile persistent class"""
+
+    avatar = FileProperty(IPublicProfile['avatar'])
+
+
+@adapter_config(context=Interface, provides=IPublicProfile)
+def PublicProfileFactory(context):
+    request = check_request()
+    return IPublicProfile(request.principal)
+
+
+@adapter_config(context=IPrincipalInfo, provides=IPublicProfile)
+def PrincipalPublicProfileFactory(principal):
+    """Principal public profile factory adapter"""
+    annotations = IAnnotations(principal)
+    profile = annotations.get(PUBLIC_PROFILE_KEY)
+    if profile is None:
+        profile = annotations[PUBLIC_PROFILE_KEY] = PublicProfile()
+        get_current_registry().notify(ObjectCreatedEvent(profile))
+        request = get_current_request()
+        if request is not None:
+            root = get_parent(request.context, ISiteRoot)
+            locate(profile, root, '++profile++')
+    return profile
+
+
+@adapter_config(name='profile', context=(Interface, Interface), provides=ITraversable)
+class ProfileTraverser(ContextRequestAdapter):
+    """++profile++ namespace traverser"""
+
+    def traverse(self, name, furtherpath=None):
+        return IPublicProfile(self.request)
+
+
+@adapter_config(name='public_profile', context=(Interface, Interface), provides=ITALESExtension)
+class PublicProfileExtension(ContextRequestAdapter):
+    """public_profile TALES extension"""
+
+    def render(self, request=None):
+        if request is None:
+            request = self.request
+        return IPublicProfile(request)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_security/zmi/profile.py	Thu Oct 08 09:28:33 2015 +0200
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_form.interfaces.form import IInnerTabForm
+from pyams_security.interfaces.profile import IPublicProfile
+from pyams_skin.interfaces.viewlet import IShortcutsViewletManager
+from pyams_skin.layer import IPyAMSLayer
+
+# import packages
+from pyams_form.form import InnerEditForm, AJAXEditForm
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_skin.viewlet.shortcuts import Shortcut
+from pyams_utils.adapter import adapter_config
+from pyams_zmi.form import AdminDialogEditForm
+from pyramid.view import view_config
+from z3c.form import field
+from zope.interface import Interface
+
+from pyams_security import _
+
+
+@viewlet_config(name='profile', layer=IPyAMSLayer, manager=IShortcutsViewletManager, weight=10)
+class UserProfileShortcut(Shortcut):
+    """User profile shortcut"""
+
+    label = _("User profile")
+    bg_color_class = 'bg-color-greenLight'
+    icon_class = 'fa-user'
+    url = 'user-profile.html'
+    modal_target = True
+    checked = 'selected'
+
+
+@pagelet_config(name='user-profile.html', layer=IPyAMSLayer)
+class UserProfileEditForm(AdminDialogEditForm):
+    """User profile edit form"""
+
+    legend = _("Edit user profile")
+    fields = field.Fields(Interface)
+
+    ajax_handler = 'user-profile.json'
+    edit_permission = None
+
+    dialog_class = 'modal-large'
+
+    @property
+    def title(self):
+        return self.request.principal.title
+
+
+@view_config(name='user-profile.json', request_type=IPyAMSLayer, renderer='json', xhr=True)
+class UserProfileAJAXEditForm(AJAXEditForm, UserProfileEditForm):
+    """User profile edit form, JSON renderer"""
+
+
+@adapter_config(name='public_profile',
+                context=(Interface, IPyAMSLayer, UserProfileEditForm),
+                provides=IInnerTabForm)
+class PublicProfileTabForm(InnerEditForm):
+    """Public profile tab form"""
+
+    tab_label = _("Public profile")
+    legend = None
+
+    fields = field.Fields(IPublicProfile)
+    edit_permission = None
+
+    label_css_class = 'control-label col-md-4'
+    input_css_class = 'col-md-8'
+
+    weight = 10
+
+    def getContent(self):
+        return IPublicProfile(self.request.principal)