Thibault Delavallée (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-server/trunk-user_img-tde into lp:openobject-server.

Requested reviews:
  OpenERP Core Team (openerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-user_img-tde/+merge/97184

User avatar
===========

This revision adds an avatar for users. This replaces the use of gravatar to 
emulate avatars, used in views like the tasks kanban view. Two fields have been 
added to the res.users model:
 - avatar, a binary field holding the image
 - avatar_mini, a binary field holding an automatically resized version of the 
avatar. Dimensions of the resized avatar are 180x150.
User avatar has to be used everywhere an image depicting users is likely to be 
used, by using the avatar_mini field.

An avatar field has been added to the users form view, as well as in 
Preferences. When creating a new user, a default avatar is chosen among 6 
possible default images.

-- 
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-user_img-tde/+merge/97184
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-server/trunk-user_img-tde.
=== added file 'doc/api/user_img_specs.rst'
--- doc/api/user_img_specs.rst	1970-01-01 00:00:00 +0000
+++ doc/api/user_img_specs.rst	2012-03-13 10:45:56 +0000
@@ -0,0 +1,9 @@
+User avatar
+===========
+
+This revision adds an avatar for users. This replaces the use of gravatar to emulate avatars, used in views like the tasks kanban view. Two fields have been added to the res.users model:
+ - avatar, a binary field holding the image
+ - avatar_mini, a binary field holding an automatically resized version of the avatar. Dimensions of the resized avatar are 180x150.
+User avatar has to be used everywhere an image depicting users is likely to be used, by using the avatar_mini field.
+
+An avatar field has been added to the users form view, as well as in Preferences. When creating a new user, a default avatar is chosen among 6 possible default images.

=== modified file 'doc/index.rst.inc'
--- doc/index.rst.inc	2012-03-05 14:07:38 +0000
+++ doc/index.rst.inc	2012-03-13 10:45:56 +0000
@@ -6,3 +6,11 @@
    :maxdepth: 1
 
    test-framework
+
+New feature merges
+++++++++++++++++++
+
+.. toctree::
+   :maxdepth: 1
+
+   api/user_img_specs

=== modified file 'openerp/addons/base/base_update.xml'
--- openerp/addons/base/base_update.xml	2012-02-08 13:50:10 +0000
+++ openerp/addons/base/base_update.xml	2012-03-13 10:45:56 +0000
@@ -84,12 +84,18 @@
                 <form string="Users">
                     <field name="name" readonly="1"/>
                     <newline/>
-                    <group colspan="2" col="2">
-                        <separator string="Preferences" colspan="2"/>
-                        <field name="view" readonly="0"/>
-                        <field name="context_lang" readonly="0"/>
-                        <field name="context_tz" readonly="0"/>
-                        <field name="menu_tips" readonly="0" groups="base.group_no_one"/>
+                    <group colspan="2" col="3">
+                        <group col="2" colspan="2">
+                            <separator string="Preferences" colspan="2"/>
+                            <field name="view" readonly="0"/>
+                            <field name="context_lang" readonly="0"/>
+                            <field name="context_tz" readonly="0"/>
+                            <field name="menu_tips" readonly="0" groups="base.group_no_one"/>
+                        </group>
+                        <group col="2" colspan="1">
+                            <separator string="Avatar" colspan="2"/>
+                            <field name="avatar" widget='image' nolabel="1" colspan="2"/>
+                        </group>
                     </group>
                     <group name="default_filters" colspan="2" col="2">
                         <separator string="Default Filters" colspan="2"/>
@@ -118,32 +124,36 @@
                     </group>
                     <notebook colspan="4">
                         <page string="User">
-                          <group colspan="4" col="6">
-                            <!-- Second nested group to avoid misalignment with email prefs groups
-                                 in simplified view -->
-                            <group colspan="6" col="6">
-                                <group col="2" colspan="2">
-                                    <separator string="Preferences" colspan="2"/>
-                                    <field name="context_lang"/>
-                                    <field name="context_tz"/>
-                                    <field name="menu_tips"/>
-                                </group>
-                                <group name="default_filters" colspan="2" col="2">
-                                    <separator string="Default Filters" colspan="2"/>
-                                    <field name="company_id" required="1" context="{'user_preference': 0}" groups="base.group_multi_company"/>
-                                </group>
-                                <group colspan="2" col="2" groups="base.group_extended">
-                                    <separator string="Action" colspan="2"/>
-                                    <field name="action_id"/>
-                                    <field domain="[('usage','=','menu')]" name="menu_id" required="True"/>
-                                </group>
-                            </group>
-                            <group colspan="6" col="2">
-                                <separator string="Email Preferences" colspan="2"/>
-                                <field name="user_email" widget="email"/>
-                                <field name="signature"/>
-                            </group>
-                          </group>
+                            <group colspan="4" col="7">
+                                <!-- Second nested group to avoid misalignment with email prefs groups
+                                    in simplified view -->
+                                <group colspan="7" col="7">
+                                    <group col="2" colspan="1">
+                                        <separator string="Avatar" colspan="2"/>
+                                        <field name="avatar_mini" widget='image' nolabel="1" colspan="2" on_change="onchange_avatar_mini(avatar_mini)"/>
+                                    </group>
+                                    <group col="3" colspan="2">
+                                        <separator string="Preferences" colspan="3"/>
+                                        <field name="context_lang"/>
+                                        <field name="context_tz"/>
+                                        <field name="menu_tips"/>
+                                    </group>
+                                    <group name="default_filters" colspan="2" col="2">
+                                        <separator string="Default Filters" colspan="2"/>
+                                        <field name="company_id" required="1" context="{'user_preference': 0}" groups="base.group_multi_company"/>
+                                    </group>
+                                    <group colspan="2" col="2" groups="base.group_extended">
+                                        <separator string="Action" colspan="2"/>
+                                        <field name="action_id"/>
+                                        <field domain="[('usage','=','menu')]" name="menu_id" required="True"/>
+                                    </group>
+                                </group>
+                                <group colspan="7" col="2">
+                                    <separator string="Email Preferences" colspan="2"/>
+                                    <field name="user_email" widget="email"/>
+                                    <field name="signature"/>
+                                </group>
+                            </group>
                         </page>
                         <page string="Access Rights">
                             <field nolabel="1" name="groups_id"/>

=== added directory 'openerp/addons/base/images'
=== added file 'openerp/addons/base/images/avatar0.jpg'
Binary files openerp/addons/base/images/avatar0.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar0.jpg	2012-03-13 10:45:56 +0000 differ
=== added file 'openerp/addons/base/images/avatar1.jpg'
Binary files openerp/addons/base/images/avatar1.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar1.jpg	2012-03-13 10:45:56 +0000 differ
=== added file 'openerp/addons/base/images/avatar2.jpg'
Binary files openerp/addons/base/images/avatar2.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar2.jpg	2012-03-13 10:45:56 +0000 differ
=== added file 'openerp/addons/base/images/avatar3.jpg'
Binary files openerp/addons/base/images/avatar3.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar3.jpg	2012-03-13 10:45:56 +0000 differ
=== added file 'openerp/addons/base/images/avatar4.jpg'
Binary files openerp/addons/base/images/avatar4.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar4.jpg	2012-03-13 10:45:56 +0000 differ
=== added file 'openerp/addons/base/images/avatar5.jpg'
Binary files openerp/addons/base/images/avatar5.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar5.jpg	2012-03-13 10:45:56 +0000 differ
=== added file 'openerp/addons/base/images/avatar6.jpg'
Binary files openerp/addons/base/images/avatar6.jpg	1970-01-01 00:00:00 +0000 and openerp/addons/base/images/avatar6.jpg	2012-03-13 10:45:56 +0000 differ
=== modified file 'openerp/addons/base/res/res_users.py'
--- openerp/addons/base/res/res_users.py	2012-02-13 18:32:07 +0000
+++ openerp/addons/base/res/res_users.py	2012-03-13 10:45:56 +0000
@@ -35,6 +35,12 @@
 import openerp
 import openerp.exceptions
 
+# for avatar resizing
+import io, StringIO
+from PIL import Image
+# for default avatar choice
+import random
+
 _logger = logging.getLogger(__name__)
 
 class groups(osv.osv):
@@ -200,7 +206,6 @@
             self.write(cr, uid, ids, {'groups_id': [(4, extended_group_id)]}, context=context)
         return True
 
-
     def _get_interface_type(self, cr, uid, ids, name, args, context=None):
         """Implementation of 'view' function field getter, returns the type of interface of the users.
         @param field_name: Name of the field
@@ -212,6 +217,29 @@
         extended_users = group_obj.read(cr, uid, extended_group_id, ['users'], context=context)['users']
         return dict(zip(ids, ['extended' if user in extended_users else 'simple' for user in ids]))
 
+    def onchange_avatar_mini(self, cr, uid, ids, value, context=None):
+        return {'value': {'avatar': value } }
+    
+    def _set_avatar_mini(self, cr, uid, id, name, value, args, context=None):
+        return self.write(cr, uid, [id], {'avatar': value}, context=context)
+    
+    def _avatar_resize(self, cr, uid, avatar, context=None):
+        image_stream = io.BytesIO(avatar.decode('base64'))
+        img = Image.open(image_stream)
+        img.thumbnail((180, 150), Image.ANTIALIAS)
+        img_stream = StringIO.StringIO()
+        img.save(img_stream, "JPEG")
+        return img_stream.getvalue().encode('base64')
+    
+    def _get_avatar_mini(self, cr, uid, ids, name, args, context=None):
+        result = {}
+        for user in self.browse(cr, uid, ids, context=context):
+            if not user.avatar:
+                result[user.id] = False
+            else:
+                result[user.id] = self._avatar_resize(cr, uid, user.avatar)
+        return result
+
     def _set_new_password(self, cr, uid, id, name, value, args, context=None):
         if value is False:
             # Do not update the password if no value is provided, ignore silently.
@@ -241,6 +269,11 @@
                                                             "otherwise leave empty. After a change of password, the user has to login again."),
         'user_email': fields.char('Email', size=64),
         'signature': fields.text('Signature', size=64),
+        'avatar': fields.binary('User Avatar'),
+        'avatar_mini': fields.function(_get_avatar_mini, fnct_inv=_set_avatar_mini, string='User Avatar Mini', type="binary",
+            store = {
+                'res.users': (lambda self, cr, uid, ids, c={}: ids, ['avatar'], 10),
+            }),
         'active': fields.boolean('Active'),
         'action_id': fields.many2one('ir.actions.actions', 'Home Action', help="If specified, this action will be opened at logon for this user, in addition to the standard menu."),
         'menu_id': fields.many2one('ir.actions.actions', 'Menu Action', help="If specified, the action will replace the standard menu for this user."),
@@ -352,9 +385,16 @@
             pass
         return result
 
+    def _get_avatar(self, cr, uid, context=None):
+        # default avatar file name: avatar0 -> avatar6, choose randomly
+        random.seed()
+        avatar_path = openerp.modules.get_module_resource('base', 'images', 'avatar%d.jpg' % random.randint(0, 6))
+        return self._avatar_resize(cr, uid, open(avatar_path, 'rb').read().encode('base64'))
+    
     _defaults = {
         'password' : '',
         'context_lang': 'en_US',
+        'avatar_mini': _get_avatar,
         'active' : True,
         'menu_id': _get_menu,
         'company_id': _get_company,

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to