[IMP] shop: added openchatter on product shop
authorThibault Delavallée <tde@openerp.com>
Mon, 6 Jan 2014 13:57:27 +0000 (14:57 +0100)
committerThibault Delavallée <tde@openerp.com>
Mon, 6 Jan 2014 13:57:27 +0000 (14:57 +0100)
- product.template now inherits from mail.thread
- added opencahtter on product.template form view
- added discussion thread + attachments in product website view
- added file_type field on ir_attachment, that replaces the javascript thing
from mail.js
- added a controller to comment a product.template

bzr revid: tde@openerp.com-20140106135727-uf0zaxav28pdx4sv

addons/mail/__init__.py
addons/mail/ir_attachment.py [new file with mode: 0644]
addons/mail/mail_message.py
addons/mail/static/src/js/mail.js
addons/mail/static/src/xml/mail.xml
addons/product/product.py
addons/product/product_view.xml
addons/website_sale/controllers/main.py
addons/website_sale/models/product.py
addons/website_sale/views/website_sale.xml

index 26578e1..08a7a92 100644 (file)
@@ -19,6 +19,7 @@
 #
 ##############################################################################
 
+import ir_attachment
 import mail_message_subtype
 import mail_alias
 import mail_followers
diff --git a/addons/mail/ir_attachment.py b/addons/mail/ir_attachment.py
new file mode 100644 (file)
index 0000000..99c5a9e
--- /dev/null
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2014-TODAY OpenERP SA (http://www.openerp.com)
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, osv
+
+import os.path
+
+
+class IrAttachment(osv.Model):
+    """ Update partner to add a field about notification preferences """
+    _name = "ir.attachment"
+    _inherit = 'ir.attachment'
+
+    _fileext_to_type = {
+        '7z': 'archive',
+        'aac': 'audio',
+        'ace': 'archive',
+        'ai': 'vector',
+        'aiff': 'audio',
+        'apk': 'archive',
+        'app': 'binary',
+        'as': 'script',
+        'asf': 'video',
+        'ass': 'text',
+        'avi': 'video',
+        'bat': 'script',
+        'bin': 'binary',
+        'bmp': 'image',
+        'bzip2': 'archive',
+        'c': 'script',
+        'cab': 'archive',
+        'cc': 'script',
+        'ccd': 'disk',
+        'cdi': 'disk',
+        'cdr': 'vector',
+        'cer': 'certificate',
+        'cgm': 'vector',
+        'cmd': 'script',
+        'coffee': 'script',
+        'com': 'binary',
+        'cpp': 'script',
+        'crl': 'certificate',
+        'crt': 'certificate',
+        'cs': 'script',
+        'csr': 'certificate',
+        'css': 'html',
+        'csv': 'spreadsheet',
+        'cue': 'disk',
+        'd': 'script',
+        'dds': 'image',
+        'deb': 'archive',
+        'der': 'certificate',
+        'djvu': 'image',
+        'dmg': 'archive',
+        'dng': 'image',
+        'doc': 'document',
+        'docx': 'document',
+        'dvi': 'print',
+        'eot': 'font',
+        'eps': 'vector',
+        'exe': 'binary',
+        'exr': 'image',
+        'flac': 'audio',
+        'flv': 'video',
+        'gif': 'webimage',
+        'gz': 'archive',
+        'gzip': 'archive',
+        'h': 'script',
+        'htm': 'html',
+        'html': 'html',
+        'ico': 'image',
+        'icon': 'image',
+        'img': 'disk',
+        'iso': 'disk',
+        'jar': 'archive',
+        'java': 'script',
+        'jp2': 'image',
+        'jpe': 'webimage',
+        'jpeg': 'webimage',
+        'jpg': 'webimage',
+        'jpx': 'image',
+        'js': 'script',
+        'key': 'presentation',
+        'keynote': 'presentation',
+        'lisp': 'script',
+        'lz': 'archive',
+        'lzip': 'archive',
+        'm': 'script',
+        'm4a': 'audio',
+        'm4v': 'video',
+        'mds': 'disk',
+        'mdx': 'disk',
+        'mid': 'audio',
+        'midi': 'audio',
+        'mkv': 'video',
+        'mng': 'image',
+        'mp2': 'audio',
+        'mp3': 'audio',
+        'mp4': 'video',
+        'mpe': 'video',
+        'mpeg': 'video',
+        'mpg': 'video',
+        'nrg': 'disk',
+        'numbers': 'spreadsheet',
+        'odg': 'vector',
+        'odm': 'document',
+        'odp': 'presentation',
+        'ods': 'spreadsheet',
+        'odt': 'document',
+        'ogg': 'audio',
+        'ogm': 'video',
+        'otf': 'font',
+        'p12': 'certificate',
+        'pak': 'archive',
+        'pbm': 'image',
+        'pdf': 'print',
+        'pem': 'certificate',
+        'pfx': 'certificate',
+        'pgf': 'image',
+        'pgm': 'image',
+        'pk3': 'archive',
+        'pk4': 'archive',
+        'pl': 'script',
+        'png': 'webimage',
+        'pnm': 'image',
+        'ppm': 'image',
+        'pps': 'presentation',
+        'ppt': 'presentation',
+        'ps': 'print',
+        'psd': 'image',
+        'psp': 'image',
+        'py': 'script',
+        'r': 'script',
+        'ra': 'audio',
+        'rar': 'archive',
+        'rb': 'script',
+        'rpm': 'archive',
+        'rtf': 'text',
+        'sh': 'script',
+        'sub': 'disk',
+        'svg': 'vector',
+        'sxc': 'spreadsheet',
+        'sxd': 'vector',
+        'tar': 'archive',
+        'tga': 'image',
+        'tif': 'image',
+        'tiff': 'image',
+        'ttf': 'font',
+        'txt': 'text',
+        'vbs': 'script',
+        'vc': 'spreadsheet',
+        'vml': 'vector',
+        'wav': 'audio',
+        'webp': 'image',
+        'wma': 'audio',
+        'wmv': 'video',
+        'woff': 'font',
+        'xar': 'vector',
+        'xbm': 'image',
+        'xcf': 'image',
+        'xhtml': 'html',
+        'xls': 'spreadsheet',
+        'xlsx': 'spreadsheet',
+        'xml': 'html',
+        'zip': 'archive'
+    }
+
+    def get_attachment_type(self, cr, uid, ids, name, args, context=None):
+        result = {}
+        for attachment in self.browse(cr, uid, ids, context=context):
+            fileext = os.path.splitext(attachment.datas_fname)[1].lower()
+            if not fileext or not fileext[1:] in self._fileext_to_type:
+                return 'unknown'
+            result[attachment.id] = self._fileext_to_type[fileext[1:]]
+        return result
+
+    _columns = {
+        'file_type': fields.function(get_attachment_type, type='char', string='File Type'),
+    }
index 4d8d00e..40a51df 100644 (file)
@@ -351,8 +351,13 @@ class mail_message(osv.Model):
         partner_tree = dict((partner[0], partner) for partner in partners)
 
         # 2. Attachments as SUPERUSER, because could receive msg and attachments for doc uid cannot see
-        attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname', 'name'], context=context)
-        attachments_tree = dict((attachment['id'], {'id': attachment['id'], 'filename': attachment['datas_fname'], 'name': attachment['name']}) for attachment in attachments)
+        attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname', 'name', 'file_type'], context=context)
+        attachments_tree = dict((attachment['id'], {
+            'id': attachment['id'],
+            'filename': attachment['datas_fname'],
+            'name': attachment['name'],
+            'file_type': attachment['file_type'],
+        }) for attachment in attachments)
 
         # 3. Update message dictionaries
         for message_dict in messages:
index 4378d2f..d9fd252 100644 (file)
@@ -114,57 +114,6 @@ openerp.mail = function (session) {
             }
             return out;
         },
-
-        // returns the file type of a file based on its extension 
-        // As it only looks at the extension it is quite approximative. 
-        filetype: function(url){
-            var url = url && url.filename || url;
-            var tokens = typeof url == 'string' ? url.split('.') : [];
-            if(tokens.length <= 1){
-                return 'unknown';
-            }
-            var extension = tokens[tokens.length -1];
-            if(extension.length === 0){
-                return 'unknown';
-            }else{
-                extension = extension.toLowerCase();
-            }
-            var filetypes = {
-                'webimage':     ['png','jpg','jpeg','jpe','gif'], // those have browser preview
-                'image':        ['tif','tiff','tga',
-                                 'bmp','xcf','psd','ppm','pbm','pgm','pnm','mng',
-                                 'xbm','ico','icon','exr','webp','psp','pgf','xcf',
-                                 'jp2','jpx','dng','djvu','dds'],
-                'vector':       ['ai','svg','eps','vml','cdr','xar','cgm','odg','sxd'],
-                'print':        ['dvi','pdf','ps'],
-                'document':     ['doc','docx','odm','odt'],
-                'presentation': ['key','keynote','odp','pps','ppt'],
-                'font':         ['otf','ttf','woff','eot'],
-                'archive':      ['zip','7z','ace','apk','bzip2','cab','deb','dmg','gzip','jar',
-                                 'rar','tar','gz','pak','pk3','pk4','lzip','lz','rpm'],
-                'certificate':  ['cer','key','pfx','p12','pem','crl','der','crt','csr'],
-                'audio':        ['aiff','wav','mp3','ogg','flac','wma','mp2','aac',
-                                 'm4a','ra','mid','midi'],
-                'video':        ['asf','avi','flv','mkv','m4v','mpeg','mpg','mpe','wmv','mp4','ogm'],
-                'text':         ['txt','rtf','ass'],
-                'html':         ['html','xhtml','xml','htm','css'],
-                'disk':         ['iso','nrg','img','ccd','sub','cdi','cue','mds','mdx'],
-                'script':       ['py','js','c','cc','cpp','cs','h','java','bat','sh',
-                                 'd','rb','pl','as','cmd','coffee','m','r','vbs','lisp'],
-                'spreadsheet':  ['123','csv','ods','numbers','sxc','xls','vc','xlsx'],
-                'binary':       ['exe','com','bin','app'],
-            };
-            for(filetype in filetypes){
-                var ext_list = filetypes[filetype];
-                for(var i = 0, len = ext_list.length; i < len; i++){
-                    if(extension === ext_list[i]){
-                        return filetype;
-                    }
-                }
-            }
-            return 'unknown';
-        },
-
     };
 
 
@@ -304,7 +253,6 @@ openerp.mail = function (session) {
                 var attach = this.attachment_ids[l];
                 if (!attach.formating) {
                     attach.url = mail.ChatterUtils.get_attachment_url(this.session, this.id, attach.id);
-                    attach.filetype = mail.ChatterUtils.filetype(attach.filename || attach.name);
                     attach.name = mail.ChatterUtils.breakword(attach.name || attach.filename);
                     attach.formating = true;
                 }
index 31539e2..3a7a546 100644 (file)
         -->
     <t t-name="mail.thread.message.attachments">
         <t t-foreach='widget.attachment_ids' t-as='attachment'>
-            <t t-if="attachment.filetype !== 'webimage'">
+            <t t-if="attachment.file_type !== 'webimage'">
                 <div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}">
                     <a t-att-href='attachment.url' target="_blank">
-                        <img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.filetype + '.png'"></img>
+                        <img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.file_type + '.png'"></img>
                         <div class='oe_name'><t t-raw='attachment.name' /></div>
                     </a>
                     <div class='oe_delete oe_e' title="Delete this attachment" t-att-data-id="attachment.id">[</div>
                     </div>
                 </div>
             </t>
-            <t t-if="attachment.filetype === 'webimage'">
+            <t t-if="attachment.file_type === 'webimage'">
                 <div t-attf-class="oe_attachment oe_preview #{attachment.upload ? 'oe_uploading' : ''}">
                     <a t-att-href='attachment.url' target="_blank">
                         <img t-att-src="widget.attachments_resize_image(attachment.id, [100,80])"></img>
index e73486c..f82b13f 100644 (file)
@@ -361,6 +361,7 @@ class product_public_category(osv.osv):
 #----------------------------------------------------------
 class product_template(osv.osv):
     _name = "product.template"
+    _inherit = ['mail.thread']
     _description = "Product Template"
 
     def _get_image(self, cr, uid, ids, name, args, context=None):
@@ -650,7 +651,6 @@ class product_product(osv.osv):
     _table = "product_product"
     _inherits = {'product.template': 'product_tmpl_id'}
     _inherit = ['mail.thread']
-    _inherit = ['mail.thread']
     _order = 'default_code,name_template'
     _columns = {
         'qty_available': fields.function(_product_qty_available, type='float', string='Quantity On Hand'),
index 6e4d31b..1a75a6e 100644 (file)
                             </page>
                         </notebook>
                     </sheet>
+                    <div class="oe_chatter">
+                        <field name="message_follower_ids" widget="mail_followers"/>
+                        <field name="message_ids" widget="mail_thread"/>
+                    </div>
                 </form>
             </field>
         </record>
             <field name="view_id" ref="product_template_tree_view"/>
         </record>
 
+        <menuitem id="product_template_menu"
+            parent="base.menu_product" sequence="25"
+            action="product_template_action_tree"/>
+
     </data>
 </openerp>
index 2e19fe2..23872a1 100644 (file)
@@ -2,6 +2,7 @@
 import random
 import simplejson
 import urllib
+import werkzeug
 
 from openerp import SUPERUSER_ID
 from openerp.addons.web import http
@@ -285,6 +286,18 @@ class Ecommerce(http.Controller):
         }
         return request.website.render("website_sale.product", values)
 
+    @website.route(['/shop/product/<int:product_template_id>/comment'], type='http', auth="public")
+    def product_comment(self, product_template_id, **post):
+        cr, uid, context = request.cr, request.uid, request.context
+        if post.get('comment'):
+            request.registry['product.template'].message_post(
+                cr, uid, product_template_id,
+                body=post.get('comment'),
+                type='comment',
+                subtype='mt_comment',
+                context=dict(context, mail_create_nosubcribe=True))
+        return werkzeug.utils.redirect(request.httprequest.referrer + "#comments")
+
     @website.route(['/shop/add_product/', '/shop/category/<int:cat_id>/add_product/'], type='http', auth="user", multilang=True, methods=['POST'])
     def add_product(self, name="New Product", cat_id=0, **post):
         Product = request.registry.get('product.product')
index 7070f92..03798fb 100644 (file)
@@ -44,6 +44,15 @@ class product_template(osv.Model):
     _columns = {
         'website_published': fields.boolean('Available in the website'),
         'website_description': fields.html('Description for the website'),
+        # TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
+        'website_message_ids': fields.one2many(
+            'mail.message', 'res_id',
+            domain=lambda self: [
+                '&', ('model', '=', self._name), ('type', '=', 'comment')
+            ],
+            string='Website Messages',
+            help="Website communication history",
+        ),
         'suggested_product_id': fields.many2one('product.template', 'Suggested For Product'),
         'suggested_product_ids': fields.one2many('product.template', 'suggested_product_id', 'Suggested Products'),
         'website_size_x': fields.integer('Size X'),
index 629c615..3f040da 100644 (file)
             </div>
           </div>
         </section>
-        <div t-field="product.website_description" class="oe_structure" id="product_full_description"/>
+        <div t-field="product.website_description" class="oe_structure mt16" id="product_full_description"/>
       </div>
   </t>
 </template>
 
+<!-- Product option: related / recommended products -->
 <template id="recommended_products" inherit_id="website_sale.product" inherit_option_id="website_sale.product" name="Recommended Products">
   <xpath expr="//div[@id='product_full_description']" position="after">
       <div class="container mt32" t-if="product.recommended_products()">
   </xpath>
 </template>
 
+<!-- Product option: attributes -->
 <template id="product_attributes" inherit_option_id="website_sale.product" name="Product Attributes">
 <xpath expr="//p[@t-field='product.description_sale']" position="after">
   <hr t-if="product.website_attribute_ids"/>
 </xpath>
 </template>
 
+<!-- Product options: OpenChatter -->
+<template id="product_option_openchatter" inherit_option_id="website_sale.product" name="Discussion">
+    <xpath expr="//div[@t-field='product.website_description']" position="after">
+        <hr class="mb32"/>
+        <section class="container">
+            <div class="row col-md-10 col-md-offset-1">
+                <a id="comments"/>
+                <ul class="media-list" id="comments-list">
+                    <li t-foreach="product.website_message_ids" t-as="message" class="media">
+                        <div class="media-body">
+                            <img class="media-object pull-left" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(message.author_id.id)" style="width: 50px; margin-right: 10px;"/>
+                            <div class="media-body">
+                                <t t-call="website.publish_short">
+                                    <t t-set="object" t-value="message"/>
+                                </t>
+                                <h5 class="media-heading">
+                                    <span t-field="message.author_id"/> <small>on <span t-field="message.date"/></small>
+                                </h5>
+                                <div t-field="message.body"/>
+                                <div>
+                                    <div class="col-md-2" t-foreach='message.attachment_ids' t-as='attachment'>
+                                        <a t-att-href="'/mail/download_attachment?model=mail.message&amp;id='+str(message.id)+'&amp;method=download_attachment&amp;attachment_id='+str(attachment.id)" target="_blank">
+                                            <t t-if="attachment.file_type == 'webimage'">
+                                                <img t-att-src="'/web/binary/image?model=ir.attachment&amp;field=datas&amp;id=' + str(attachment.id) + '&amp;resize=100,80'"></img>
+                                            </t>
+                                            <t t-if="attachment.file_type != 'webimage'">
+                                                <img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.file_type + '.png'"></img>
+                                            </t>
+                                            <div class='oe_name'><t t-raw='attachment.name' /></div>
+                                        </a>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </li>
+                </ul>
+                <div class="css_editable_mode_hidden">
+                    <form id="comment" t-attf-action="/shop/product/#{product.id}/comment"
+                            method="POST">
+                        <img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(user_id.partner_id.id)" style="width: 50px; margin-right: 10px;"/>
+                        <div class="pull-left mb32" style="width: 75%%">
+                            <textarea rows="3" name="comment" class="form-control" placeholder="Write a comment..."></textarea>
+                            <button type="submit" class="btn btn-primary mt8">Post</button>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </section>
+    </xpath>
+</template>
+
 <!-- Page Shop my cart -->
 
 <template id="mycart" name="Your Cart">