Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions web_chatter_paste/README.rst
Original file line number Diff line number Diff line change
@@ -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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment outdated now?


Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/web/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 <d.sluijk@onestein.nl>

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.
5 changes: 5 additions & 0 deletions web_chatter_paste/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import controllers
24 changes: 24 additions & 0 deletions web_chatter_paste/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# 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,
}
5 changes: 5 additions & 0 deletions web_chatter_paste/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import main
33 changes: 33 additions & 0 deletions web_chatter_paste/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# 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 = """<script language="javascript" type="text/javascript">
var win = window.top.window;
win.jQuery(win).trigger(%s, %s);
</script>"""
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))
110 changes: 110 additions & 0 deletions web_chatter_paste/static/src/js/web_chatter_paste.js
Original file line number Diff line number Diff line change
@@ -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 = $('<input type="hidden" name="content" class="content" />');
this.$('form.o_form_binary_form').append($content);

//Add hidden input filename
var $filename = $('<input type="hidden" name="filename" class="filename" />');
this.$('form.o_form_binary_form').append($filename);

//Add hidden input filename
var $mimetype = $('<input type="hidden" name="mimetype" class="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 = $('<input class="o_form_input_file" name="ufile" type="file" />');
this.$('form.o_form_binary_form').append($ufile);

}
});
});
12 changes: 12 additions & 0 deletions web_chatter_paste/templates/assets.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2017 Onestein
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->

<odoo>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr=".">
<script type="text/javascript"
src="/web_chatter_paste/static/src/js/web_chatter_paste.js"/>
</xpath>
</template>
</odoo>
5 changes: 5 additions & 0 deletions web_chatter_paste/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import test_web_chatter_paste
43 changes: 43 additions & 0 deletions web_chatter_paste/tests/test_web_chatter_paste.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from mock import patch
from odoo import http
from odoo.tests.common import HttpCase
from odoo.addons.web_chatter_paste.controllers.main \
import ChatterPasteController


class TestWebChatterPaste(HttpCase):
def test_controller(self):
partner_id = self.ref('base.main_partner')
attachment_obj = self.env['ir.attachment']

attachment_count = attachment_obj.search_count([
('res_model', '=', 'res.partner'),
('res_id', '=', partner_id)
])

f = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6' \
'QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFN' \
'vZnR3YXJlAHBhaW50Lm5ldCA0LjAuOWwzfk4AAAAMSURBVBhXY/j//z8ABf4C/q' \
'c1gYQAAAAASUVORK5CYII='

with patch.object(http, 'request') as request:
request.env = self.env
controller = ChatterPasteController()
controller.upload_attachment(
'_',
'res.partner',
partner_id,
'test.png',
'image/png',
f
)

new_attachment_count = attachment_obj.search_count([
('res_model', '=', 'res.partner'),
('res_id', '=', partner_id)
])
self.assertEqual(attachment_count + 1, new_attachment_count)