From 0ac40527cdf485161086efb6526c391a7cc8c7e2 Mon Sep 17 00:00:00 2001 From: Dennis Sluijk Date: Tue, 21 Mar 2017 16:50:16 +0100 Subject: [PATCH] [10.0][ADD][web_chatter_paste] (#548) * Initial commit * Initial commit * [ADD] Tests * [FIX] Dependencies * [REM] Controller tests * [FIX] Removed unnecessary incompatibility warning * [FIX] Hyperlink to issues * [ADD] Tests * [FIX] Tests * [?] Testing test problem * [?] Testing test problem * [?] Testing test problem * [ADD] web_chatter_paste Initial commit Initial commit [ADD] Tests [FIX] Dependencies [REM] Controller tests [FIX] Removed unnecessary incompatibility warning [FIX] Hyperlink to issues [ADD] Tests [FIX] Tests [?] Testing test problem [?] Testing test problem [?] Testing test problem * Testing problem * Testing problem * Testing problem * [ADD] Mock for http.request * [FIX] Use patch to mock --- web_chatter_paste/README.rst | 67 +++++++++++ web_chatter_paste/__init__.py | 5 + web_chatter_paste/__manifest__.py | 24 ++++ web_chatter_paste/controllers/__init__.py | 5 + web_chatter_paste/controllers/main.py | 33 ++++++ .../static/src/js/web_chatter_paste.js | 110 ++++++++++++++++++ web_chatter_paste/templates/assets.xml | 12 ++ web_chatter_paste/tests/__init__.py | 5 + .../tests/test_web_chatter_paste.py | 43 +++++++ 9 files changed, 304 insertions(+) create mode 100644 web_chatter_paste/README.rst create mode 100644 web_chatter_paste/__init__.py create mode 100644 web_chatter_paste/__manifest__.py create mode 100644 web_chatter_paste/controllers/__init__.py create mode 100644 web_chatter_paste/controllers/main.py create mode 100644 web_chatter_paste/static/src/js/web_chatter_paste.js create mode 100644 web_chatter_paste/templates/assets.xml create mode 100644 web_chatter_paste/tests/__init__.py create mode 100644 web_chatter_paste/tests/test_web_chatter_paste.py diff --git a/web_chatter_paste/README.rst b/web_chatter_paste/README.rst new file mode 100644 index 00000000..77eafa8c --- /dev/null +++ b/web_chatter_paste/README.rst @@ -0,0 +1,67 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +============= +Chatter Paste +============= + +Paste images and drop files (while composing a message) into the chatter and upload them directly as attachment. + +Configuration +============= + +No configuration is needed. + +Usage +===== + +To paste an image: + +#. Copy an image (e.g. a screenshot); +#. paste the image into the chatter's composer. + +To drop a file: + +#. Drag any file (multiple) from your file system; +#. drop them into the chatter's composer. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/162/10.0 + +Known issues / Roadmap +====================== + +* Dropping files only works in Chrome. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Dennis Sluijk + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/web_chatter_paste/__init__.py b/web_chatter_paste/__init__.py new file mode 100644 index 00000000..cdd51248 --- /dev/null +++ b/web_chatter_paste/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Onestein () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import controllers diff --git a/web_chatter_paste/__manifest__.py b/web_chatter_paste/__manifest__.py new file mode 100644 index 00000000..98c014d9 --- /dev/null +++ b/web_chatter_paste/__manifest__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Onestein () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'Chatter Paste', + 'summary': """ + Paste images and drop files into the chatter and upload them directly + """, + 'version': '10.0.1.0.0', + 'category': 'Web', + 'author': 'Onestein,Odoo Community Association (OCA)', + 'website': 'http://www.onestein.eu', + 'license': 'AGPL-3', + 'depends': [ + 'base', + 'web' + ], + 'data': [ + 'templates/assets.xml' + ], + 'installable': True, + 'application': False, +} diff --git a/web_chatter_paste/controllers/__init__.py b/web_chatter_paste/controllers/__init__.py new file mode 100644 index 00000000..12c570cc --- /dev/null +++ b/web_chatter_paste/controllers/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Onestein () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import main diff --git a/web_chatter_paste/controllers/main.py b/web_chatter_paste/controllers/main.py new file mode 100644 index 00000000..65b57611 --- /dev/null +++ b/web_chatter_paste/controllers/main.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Onestein () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import http +from json import dumps + + +class ChatterPasteController(http.Controller): + + @http.route('/web_chatter_paste/upload_attachment', type='http', + auth="user") + def upload_attachment(self, callback, model, id, filename, mimetype, + content): + request = http.request + model_obj = request.env['ir.attachment'] + out = """""" + attachment = model_obj.create({ + 'name': filename, + 'datas': content, + 'datas_fname': filename, + 'res_model': model, + 'res_id': int(id) + }) + args = { + 'filename': filename, + 'mimetype': mimetype, + 'id': attachment.id + } + return out % (dumps(callback), dumps(args)) diff --git a/web_chatter_paste/static/src/js/web_chatter_paste.js b/web_chatter_paste/static/src/js/web_chatter_paste.js new file mode 100644 index 00000000..be13f53c --- /dev/null +++ b/web_chatter_paste/static/src/js/web_chatter_paste.js @@ -0,0 +1,110 @@ +/* Copyright 2017 Onestein +* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + +odoo.define('web_chatter_paste', function (require) { +"use strict"; + var core = require('web.core'), + composer = require('mail.composer'); + + composer.BasicComposer.include({ + start: function() { + var self = this; + var res = this._super.apply(this, arguments); + this.$('.o_composer_text_field').bind('drop', function(e) { + e.stopPropagation(); + e.preventDefault(); + var files = e.originalEvent.dataTransfer.files; + var i = 0; + + var next = function() { + $(window).off(self.fileupload_id, next); + i++; + upload(); + } + + var upload = function() { + if (files.length <= i) return; + var reader = new FileReader(); + reader.onload = function() { + $(window).on(self.fileupload_id, next); + self.add_as_attachment(reader.result, files[i].name); + } + reader.readAsDataURL(files[i]); + } + upload(); + }); + this.$('.o_composer_text_field').bind('paste', function(e) { + if (!e.originalEvent.clipboardData.items) return; + var items = e.originalEvent.clipboardData.items; + for (var i = 0; i < items.length; i++) { + var item = items[i]; + if (item.type != 'image/png') continue; + var reader = new FileReader(); + reader.onload = function() { + self.add_as_attachment(reader.result, _.uniqueId('pasted_file') + '.png'); + } + reader.readAsDataURL(item.getAsFile()); + } + }); + return res; + }, + add_as_attachment: function(data, filename, cb) { + //Fetch mimetype and base64 + var mimetype = data.substring(5, data.indexOf(';')); + var base64_data = data.substr(data.indexOf(',') + 1, data.length); + + //Change and submit form + this.prepare_form(); + this.$('form.o_form_binary_form input.filename').val(filename); + this.$('form.o_form_binary_form input.content').val(base64_data); + this.$('form.o_form_binary_form input.mimetype').val(mimetype); + + this.$('form.o_form_binary_form').submit(); + this.reverse_form(); + + var attachments = this.get('attachment_ids'); + this.$attachment_button.prop('disabled', true); + attachments.push({ + 'id': 0, + 'name': _.uniqueId('attachment_name'), + 'filename': filename, + 'url': filename, + 'upload': true, + 'mimetype': '', + }); + }, + prepare_form: function() { + //Change action + this.$('form.o_form_binary_form').attr('action', '/web_chatter_paste/upload_attachment'); + + //Remove ufile + this.$('form.o_form_binary_form input.o_form_input_file').remove(); + + //Add hidden input content + var $content = $(''); + this.$('form.o_form_binary_form').append($content); + + //Add hidden input filename + var $filename = $(''); + this.$('form.o_form_binary_form').append($filename); + + //Add hidden input filename + var $mimetype = $(''); + this.$('form.o_form_binary_form').append($mimetype); + }, + reverse_form: function() { + //Change action + this.$('form.o_form_binary_form').attr('action', '/web/binary/upload_attachment'); + + //Remove new input + this.$('form.o_form_binary_form input.content').remove(); + this.$('form.o_form_binary_form input.filename').remove(); + this.$('form.o_form_binary_form input.mimetype').remove(); + + //Restore old input + var $ufile = $(''); + this.$('form.o_form_binary_form').append($ufile); + + } + }); +}); diff --git a/web_chatter_paste/templates/assets.xml b/web_chatter_paste/templates/assets.xml new file mode 100644 index 00000000..d0040869 --- /dev/null +++ b/web_chatter_paste/templates/assets.xml @@ -0,0 +1,12 @@ + + + + +