Skip to content
Closed
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
4 changes: 2 additions & 2 deletions attachment_base_synchronize/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_attachment_metadata_user,ir.attachment.metadata.user,model_ir_attachment_metadata,,1,0,0,0
access_attachment_metadata_user,ir.attachment.metadata.user,model_ir_attachment_metadata,base.group_no_one,1,1,1,1
access_attachment_metadata_user_all,ir.attachment.metadata.user,model_ir_attachment_metadata,,1,0,0,0
access_attachment_metadata_user_conf,ir.attachment.metadata.user,model_ir_attachment_metadata,base.group_no_one,1,1,1,1
70 changes: 70 additions & 0 deletions external_file_location/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.. 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

======================
External File Location
======================

This module was written to extend the functionality of ir.attachment to support remote communication and allow you to import/export file to a remote server.
For now, FTP, SFTP and local filestore are handled by the module.

Installation
============

To install this module, you need to:

* fs python module at version 0.5.4 or under
* Paramiko python module

Usage
=====

To use this module, you need to:

* Add a location with your server infos
* Create a task with your file info and remote communication method
* A cron task will trigger each task

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/9.0

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

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/server-tools/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
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

Contributors
------------

* Valentin CHEMIERE <valentin.chemiere@akretion.com>
* Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
* Florian DA COSTA <florian.dacosta@akretion.com>
* Carlos ALMEIDA <carlos.almeida@tkobr.com>

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.
3 changes: 3 additions & 0 deletions external_file_location/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

from . import models
35 changes: 35 additions & 0 deletions external_file_location/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# coding: utf-8
# @ 2016 florian DA COSTA @ Akretion
# © 2016 @author Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
'name': 'External File Location',
'version': '10.0.1.0.0',
'author': 'Akretion,Odoo Community Association (OCA)',
'website': 'http://www.akretion.com/',
'license': 'AGPL-3',
'category': 'Generic Modules',
'depends': [
'attachment_base_synchronize',
],
'external_dependencies': {
'python': [
'fs',
'paramiko',
],
},
'data': [
'views/menu.xml',
'views/attachment_view.xml',
'views/location_view.xml',
'views/task_view.xml',
'data/cron.xml',
'security/ir.model.access.csv',
],
'demo': [
'demo/task_demo.xml',
],
'installable': True,
'application': False,
}
14 changes: 14 additions & 0 deletions external_file_location/data/cron.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record model="ir.cron" id="cronjob_run_exchange_tasks">
<field name='name'>Run file exchange tasks</field>
<field name='interval_number'>30</field>
<field name='interval_type'>minutes</field>
<field name="numbercall">-1</field>
<field name="active">True</field>
<field name="doall" eval="False"/>
<field name="model">external.file.task</field>
<field name="function">run_task_scheduler</field>
<field name="args">([[('method_type', '=', 'import')]])</field>
</record>
</odoo>
95 changes: 95 additions & 0 deletions external_file_location/demo/task_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="location_ftp" model="external.file.location">
<field name="name">TEST FTP</field>
<field name="protocol">ftp</field>
<field name="address">my-ftp-address</field>
<field name="login">my-ftp-user</field>
<field name="password">my-ftp-password</field>
<field name="port">21</field>
</record>

<record id="location_sftp" model="external.file.location">
<field name="name">TEST SFTP</field>
<field name="protocol">sftp</field>
<field name="address">my-sftp-address</field>
<field name="login">my-sftp-user</field>
<field name="password">my-sftp-password</field>
<field name="port">22</field>
</record>

<record id="location_filestore" model="external.file.location">
<field name="name">TEST File Store</field>
<field name="protocol">file_store</field>
<field name="filestore_rootpath">/</field>
</record>

<record id="ftp_import_task" model="external.file.task">
<field name="method_type">import</field>
<field name="location_id" eval="ref('external_file_location.location_ftp')"/>
<field name="filename">test-import-ftp.txt</field>
<field name="filepath">/home/user/test</field>
<field name="name">Import FTP Task</field>
</record>

<record id="ftp_export_task" model="external.file.task">
<field name="method_type">export</field>
<field name="location_id" eval="ref('external_file_location.location_ftp')"/>
<field name="filepath">/home/user/test</field>
<field name="name">Export FTP Task</field>
</record>

<record id="sftp_import_task" model="external.file.task">
<field name="method_type">import</field>
<field name="location_id" eval="ref('external_file_location.location_sftp')"/>
<field name="filename">test-import-sftp.txt</field>
<field name="filepath">/home/user/test</field>
<field name="name">Import SFTP Task</field>
</record>

<record id="sftp_export_task" model="external.file.task">
<field name="method_type">export</field>
<field name="location_id" eval="ref('external_file_location.location_sftp')"/>
<field name="filepath">/home/user/test</field>
<field name="name">Export SFTP Task</field>
</record>

<record id="filestore_import_task" model="external.file.task">
<field name="method_type">import</field>
<field name="location_id" eval="ref('external_file_location.location_filestore')"/>
<field name="filename">test-import-filestore.txt</field>
<field name="filepath">/home/user/test</field>
<field name="name">Import filestore Task</field>
</record>

<record id="filestore_export_task" model="external.file.task">
<field name="method_type">export</field>
<field name="location_id" eval="ref('external_file_location.location_filestore')"/>
<field name="filepath">/home/user/test</field>
<field name="name">Export filestore Task</field>
</record>

<record id="ir_attachment_export_file_sftp" model="ir.attachment.metadata">
<field name="name">Sftp text export file</field>
<field name="datas">dGVzdCBzZnRwIGZpbGUgZXhwb3J0</field>
<field name="datas_fname">sftp_test_export.txt</field>
<field name="task_id" eval="ref('external_file_location.sftp_export_task')"/>
<field name="file_type">export_external_location</field>
</record>

<record id="ir_attachment_export_file_ftp" model="ir.attachment.metadata">
<field name="name">ftp text export file</field>
<field name="datas">dGVzdCBmdHAgZmlsZSBleHBvcnQ=</field>
<field name="datas_fname">ftp_test_export.txt</field>
<field name="task_id" eval="ref('external_file_location.ftp_export_task')"/>
<field name="file_type">export_external_location</field>
</record>

<record id="ir_attachment_export_file_filestore" model="ir.attachment.metadata">
<field name="name">filestore text export file</field>
<field name="datas">dGVzdCBmaWxlc3RvcmUgZmlsZSBleHBvcnQ=</field>
<field name="datas_fname">filestore_test_export.txt</field>
<field name="task_id" eval="ref('external_file_location.filestore_export_task')"/>
<field name="file_type">export_external_location</field>
</record>
</odoo>
5 changes: 5 additions & 0 deletions external_file_location/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-

from . import task
from . import attachment
from . import location
33 changes: 33 additions & 0 deletions external_file_location/models/attachment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# coding: utf-8
# @ 2016 Florian DA COSTA @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models, fields, api
import base64
import os


class IrAttachmentMetadata(models.Model):
_inherit = 'ir.attachment.metadata'

task_id = fields.Many2one('external.file.task', string='Task')
location_id = fields.Many2one(
'external.file.location', string='Location',
related='task_id.location_id', store=True)
file_type = fields.Selection(
selection_add=[
('export_external_location',
'Export File (External location)')
])

@api.multi
def _run(self):
super(IrAttachmentMetadata, self)._run()
if self.file_type == 'export_external_location':
protocols = self.env['external.file.location']._get_classes()
location = self.location_id
cls = protocols.get(location.protocol)[1]
path = os.path.join(self.task_id.filepath, self.datas_fname)
with cls.connect(location) as conn:
datas = base64.decodestring(self.datas)
conn.setcontents(path, data=datas)
68 changes: 68 additions & 0 deletions external_file_location/models/location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# coding: utf-8
# @ 2015 Valentin CHEMIERE @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models, fields, api
from ..tasks.filestore import FileStoreTask
from ..tasks.ftp import FtpTask
from ..tasks.sftp import SftpTask


class Location(models.Model):
_name = 'external.file.location'
_description = 'Location'

name = fields.Char(string='Name', required=True)
protocol = fields.Selection(selection='_get_protocol', required=True)
address = fields.Char(
string='Address')
filestore_rootpath = fields.Char(
string='FileStore Root Path',
help="Server's root path")
port = fields.Integer()
login = fields.Char()
password = fields.Char()
task_ids = fields.One2many('external.file.task', 'location_id')
hide_login = fields.Boolean()
hide_password = fields.Boolean()
hide_port = fields.Boolean()
company_id = fields.Many2one(
'res.company', 'Company',
default=lambda self: self.env['res.company']._company_default_get(
'external.file.location'))

@api.model
def _get_classes(self):
"surcharge this method to add new protocols"
return {
'ftp': ('FTP', FtpTask),
'sftp': ('SFTP', SftpTask),
'file_store': ('File Store', FileStoreTask),
}

@api.model
def _get_protocol(self):
protocols = self._get_classes()
selection = []
for key, val in protocols.iteritems():
selection.append((key, val[0]))
return selection

@api.onchange('protocol')
def onchange_protocol(self):
protocols = self._get_classes()
if self.protocol:
cls = protocols.get(self.protocol)[1]
self.port = cls._default_port
if cls._hide_login:
self.hide_login = True
else:
self.hide_login = False
if cls._hide_password:
self.hide_password = True
else:
self.hide_password = False
if cls._hide_port:
self.hide_port = True
else:
self.hide_port = False
Loading