mirror of https://github.com/OCA/web.git
[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 mockpull/589/head
parent
b5d7d1a9d4
commit
0ac40527cd
|
@ -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
|
||||
<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.
|
|
@ -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
|
|
@ -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,
|
||||
}
|
|
@ -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
|
|
@ -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))
|
|
@ -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);
|
||||
|
||||
}
|
||||
});
|
||||
});
|
|
@ -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>
|
|
@ -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
|
|
@ -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)
|
Loading…
Reference in New Issue