Browse Source
Port external_file_location to v9
Port external_file_location to v9
Add company_id on external location and external taskpull/516/head
Florian da Costa
8 years ago
26 changed files with 1364 additions and 747 deletions
-
47external_file_location/README.rst
-
12external_file_location/__openerp__.py
-
4external_file_location/data/cron.xml
-
99external_file_location/demo/task_demo.xml
-
347external_file_location/i18n/external_file_location.pot
-
347external_file_location/i18n/fr.po
-
30external_file_location/models/attachment.py
-
84external_file_location/models/helper.py
-
71external_file_location/models/location.py
-
235external_file_location/models/task.py
-
1external_file_location/tasks/__init__.py
-
196external_file_location/tasks/abstract_fs.py
-
28external_file_location/tasks/abstract_task.py
-
50external_file_location/tasks/filestore.py
-
55external_file_location/tasks/ftp.py
-
55external_file_location/tasks/sftp.py
-
2external_file_location/tests/__init__.py
-
32external_file_location/tests/common.py
-
19external_file_location/tests/mock_server.py
-
50external_file_location/tests/test_filestore.py
-
86external_file_location/tests/test_ftp.py
-
213external_file_location/tests/test_sftp.py
-
28external_file_location/views/attachment_view.xml
-
7external_file_location/views/location_view.xml
-
12external_file_location/views/task_view.xml
-
1requirements.txt
@ -0,0 +1,99 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<openerp> |
|||
<data> |
|||
|
|||
<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> |
|||
|
|||
|
|||
|
|||
</data> |
|||
</openerp> |
@ -0,0 +1,347 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * external_file_location |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 9.0c\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2016-08-10 16:51+0000\n" |
|||
"PO-Revision-Date: 2016-08-10 16:51+0000\n" |
|||
"Last-Translator: <>\n" |
|||
"Language-Team: \n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: \n" |
|||
"Plural-Forms: \n" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_needaction |
|||
msgid "Action Needed" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_after_import |
|||
msgid "Action after import a file" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_address |
|||
msgid "Address" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_after_import |
|||
msgid "After import" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_attachment_ids |
|||
msgid "Attachment" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_md5_check |
|||
msgid "Control file integrity after import with a md5 file" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_create_uid |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_create_uid |
|||
msgid "Created by" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_create_date |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_create_date |
|||
msgid "Created on" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
msgid "Data importation setting" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_last_post |
|||
msgid "Date of the last message posted on the record." |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model,name:external_file_location.model_external_file_location |
|||
msgid "Description" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_display_name |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_display_name |
|||
msgid "Display Name" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: selection:external.file.task,method_type:0 |
|||
msgid "Export" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model,name:external_file_location.model_external_file_task |
|||
msgid "External file task" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_tree |
|||
msgid "File Location" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.actions.act_window,name:external_file_location.action_location |
|||
#: model:ir.ui.menu,name:external_file_location.menu_ir_location |
|||
msgid "File Locations" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.menu,name:external_file_location.menu_file_exchange |
|||
msgid "File exchange" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_filename |
|||
msgid "File name which is imported.You can use file pattern like *.txtto import all txt files" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_file_type |
|||
msgid "File type" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_filestore_rootpath |
|||
msgid "FileStore Root Path" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_filename |
|||
msgid "Filename" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_filepath |
|||
msgid "Filepath" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_follower_ids |
|||
msgid "Followers" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_channel_ids |
|||
msgid "Followers (Channels)" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_partner_ids |
|||
msgid "Followers (Partners)" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_hide_login |
|||
msgid "Hide login" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_hide_password |
|||
msgid "Hide password" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_hide_port |
|||
msgid "Hide port" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_id |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_id |
|||
msgid "ID" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_unread |
|||
msgid "If checked new messages require your attention." |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_needaction |
|||
msgid "If checked, new messages require your attention." |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: selection:external.file.task,method_type:0 |
|||
msgid "Import" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_move_path |
|||
msgid "Imported File will be moved to this path" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_new_name |
|||
msgid "Imported File will be renamed to this nameName can use mako template where obj is an ir_attachement. template exemple : ${obj.name}-${obj.create_date}.csv" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_is_follower |
|||
msgid "Is Follower" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_last_post |
|||
msgid "Last Message Date" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location___last_update |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task___last_update |
|||
msgid "Last Modified on" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_write_uid |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_write_uid |
|||
msgid "Last Updated by" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_write_date |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_write_date |
|||
msgid "Last Updated on" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_location_id |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_location_id |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_form |
|||
msgid "Location" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_login |
|||
msgid "Login" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_md5_check |
|||
msgid "Md5 check" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_ids |
|||
msgid "Messages" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_method_type |
|||
msgid "Method type" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_move_path |
|||
msgid "Move path" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_name |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_name |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_form |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
msgid "Name" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_new_name |
|||
msgid "New name" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_needaction_counter |
|||
msgid "Number of Actions" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_needaction_counter |
|||
msgid "Number of messages which requires an action" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_unread_counter |
|||
msgid "Number of unread messages" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_password |
|||
msgid "Password" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_filepath |
|||
msgid "Path to imported/exported file" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_port |
|||
msgid "Port" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_protocol |
|||
msgid "Protocol" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
msgid "Run" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_location_filestore_rootpath |
|||
msgid "Server's root path" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_task_id |
|||
msgid "Task" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_task_ids |
|||
msgid "Task ids" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_form |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_tree |
|||
msgid "Tasks" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_file_type |
|||
msgid "The file type determines an import method to be used to parse and transform data before their import in ERP" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_unread |
|||
msgid "Unread Messages" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_unread_counter |
|||
msgid "Unread Messages Counter" |
|||
msgstr "" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model,name:external_file_location.model_ir_attachment_metadata |
|||
msgid "ir.attachment.metadata" |
|||
msgstr "" |
|||
|
@ -0,0 +1,347 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * external_file_location |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 9.0c\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2016-08-10 16:51+0000\n" |
|||
"PO-Revision-Date: 2016-08-10 16:51+0000\n" |
|||
"Last-Translator: <>\n" |
|||
"Language-Team: \n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: \n" |
|||
"Plural-Forms: \n" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_needaction |
|||
msgid "Action Needed" |
|||
msgstr "A besoin d'une action" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_after_import |
|||
msgid "Action after import a file" |
|||
msgstr "Action après l'import du fichier" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_address |
|||
msgid "Address" |
|||
msgstr "Addresse" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_after_import |
|||
msgid "After import" |
|||
msgstr "Après import" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_attachment_ids |
|||
msgid "Attachment" |
|||
msgstr "Pièce jointe" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_md5_check |
|||
msgid "Control file integrity after import with a md5 file" |
|||
msgstr "Contrôle l'intégrité du fichier après l'import avec un fichier md5" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_create_uid |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_create_uid |
|||
msgid "Created by" |
|||
msgstr "Créé par" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_create_date |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_create_date |
|||
msgid "Created on" |
|||
msgstr "Créé le" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
msgid "Data importation setting" |
|||
msgstr "Data importation setting" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_last_post |
|||
msgid "Date of the last message posted on the record." |
|||
msgstr "Date du dernier message publié sur cet enregistrement" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model,name:external_file_location.model_external_file_location |
|||
msgid "Description" |
|||
msgstr "Description" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_display_name |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_display_name |
|||
msgid "Display Name" |
|||
msgstr "Afficher le nom" |
|||
|
|||
#. module: external_file_location |
|||
#: selection:external.file.task,method_type:0 |
|||
msgid "Export" |
|||
msgstr "Export" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model,name:external_file_location.model_external_file_task |
|||
msgid "External file task" |
|||
msgstr "Tache" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_tree |
|||
msgid "File Location" |
|||
msgstr "Emplacement fichier" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.actions.act_window,name:external_file_location.action_location |
|||
#: model:ir.ui.menu,name:external_file_location.menu_ir_location |
|||
msgid "File Locations" |
|||
msgstr "Emplacements fichiers" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.menu,name:external_file_location.menu_file_exchange |
|||
msgid "File exchange" |
|||
msgstr "Echange de fichier" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_filename |
|||
msgid "File name which is imported.You can use file pattern like *.txtto import all txt files" |
|||
msgstr "Nom du fichier importé. Vous pouvez utiliser une expression comme *.txt pour importer tous les fichiers txt" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_file_type |
|||
msgid "File type" |
|||
msgstr "Type de fichier" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_filestore_rootpath |
|||
msgid "FileStore Root Path" |
|||
msgstr "Emplacement racine" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_filename |
|||
msgid "Filename" |
|||
msgstr "Nom du fichier" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_filepath |
|||
msgid "Filepath" |
|||
msgstr "Chemin" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_follower_ids |
|||
msgid "Followers" |
|||
msgstr "Abonnés" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_channel_ids |
|||
msgid "Followers (Channels)" |
|||
msgstr "Abonnés (Canaux)" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_partner_ids |
|||
msgid "Followers (Partners)" |
|||
msgstr "Abonnés (Partenaires)" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_hide_login |
|||
msgid "Hide login" |
|||
msgstr "Cacher le login" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_hide_password |
|||
msgid "Hide password" |
|||
msgstr "Cacher le mot de passe" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_hide_port |
|||
msgid "Hide port" |
|||
msgstr "Cacher le port" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_id |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_id |
|||
msgid "ID" |
|||
msgstr "Identifiant" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_unread |
|||
msgid "If checked new messages require your attention." |
|||
msgstr "Si coché, de nouveaux messages demandent votre attention." |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_needaction |
|||
msgid "If checked, new messages require your attention." |
|||
msgstr "si elle est cochée, de nouveaux messages requièrent votre attention." |
|||
|
|||
#. module: external_file_location |
|||
#: selection:external.file.task,method_type:0 |
|||
msgid "Import" |
|||
msgstr "Import" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_move_path |
|||
msgid "Imported File will be moved to this path" |
|||
msgstr "Le fichier importé sera déplacé dans cet emplacement" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_new_name |
|||
msgid "Imported File will be renamed to this nameName can use mako template where obj is an ir_attachement. template exemple : ${obj.name}-${obj.create_date}.csv" |
|||
msgstr "Imported File will be renamed to this nameName can use mako template where obj is an ir_attachement. template exemple : ${obj.name}-${obj.create_date}.csv" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_is_follower |
|||
msgid "Is Follower" |
|||
msgstr "Est un abonné" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_last_post |
|||
msgid "Last Message Date" |
|||
msgstr "Date du dernier message" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location___last_update |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task___last_update |
|||
msgid "Last Modified on" |
|||
msgstr "Dernière modification le" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_write_uid |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_write_uid |
|||
msgid "Last Updated by" |
|||
msgstr "Dernière mise à jour par" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_write_date |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_write_date |
|||
msgid "Last Updated on" |
|||
msgstr "Dernière mise à jour le" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_location_id |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_location_id |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_form |
|||
msgid "Location" |
|||
msgstr "Emplacement" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_login |
|||
msgid "Login" |
|||
msgstr "Identifiant" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_md5_check |
|||
msgid "Md5 check" |
|||
msgstr "Md5 check" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_ids |
|||
msgid "Messages" |
|||
msgstr "Messages" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_method_type |
|||
msgid "Method type" |
|||
msgstr "Type de méthode" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_move_path |
|||
msgid "Move path" |
|||
msgstr "chemin des archives" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_name |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_name |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_form |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
msgid "Name" |
|||
msgstr "Nom" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_task_new_name |
|||
msgid "New name" |
|||
msgstr "Nouveau nom" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_needaction_counter |
|||
msgid "Number of Actions" |
|||
msgstr "Nombre d'Actions" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_needaction_counter |
|||
msgid "Number of messages which requires an action" |
|||
msgstr "Nombre de messages demandant une action" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_ir_attachment_metadata_message_unread_counter |
|||
msgid "Number of unread messages" |
|||
msgstr "Nombre de messages non lus" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_password |
|||
msgid "Password" |
|||
msgstr "Mot de passe" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_filepath |
|||
msgid "Path to imported/exported file" |
|||
msgstr "Path to imported/exported file" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_port |
|||
msgid "Port" |
|||
msgstr "Port" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_protocol |
|||
msgid "Protocol" |
|||
msgstr "Protocole" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
msgid "Run" |
|||
msgstr "Run" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_location_filestore_rootpath |
|||
msgid "Server's root path" |
|||
msgstr "Chemin racine du serveur" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_task_id |
|||
msgid "Task" |
|||
msgstr "Tache" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_external_file_location_task_ids |
|||
msgid "Task ids" |
|||
msgstr "Task ids" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_location_form |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_form |
|||
#: model:ir.ui.view,arch_db:external_file_location.view_task_tree |
|||
msgid "Tasks" |
|||
msgstr "Taches" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,help:external_file_location.field_external_file_task_file_type |
|||
msgid "The file type determines an import method to be used to parse and transform data before their import in ERP" |
|||
msgstr "Le type de fichier détermine la méthode d'import utilisée pour parser le fichier et transformer les données avant l'import dans l'ERP" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_unread |
|||
msgid "Unread Messages" |
|||
msgstr "Messages non lus" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model.fields,field_description:external_file_location.field_ir_attachment_metadata_message_unread_counter |
|||
msgid "Unread Messages Counter" |
|||
msgstr "Compteur de messages non lus" |
|||
|
|||
#. module: external_file_location |
|||
#: model:ir.model,name:external_file_location.model_ir_attachment_metadata |
|||
msgid "ir.attachment.metadata" |
|||
msgstr "ir.attachment.metadata" |
|||
|
@ -1,21 +1,33 @@ |
|||
# coding: utf-8 |
|||
# @ 2015 Valentin CHEMIERE @ Akretion |
|||
# @ 2016 Florian DA COSTA @ Akretion |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from openerp import models, fields |
|||
from openerp import models, fields, api |
|||
import base64 |
|||
import os |
|||
|
|||
|
|||
class IrAttachmentMetadata(models.Model): |
|||
_inherit = 'ir.attachment.metadata' |
|||
|
|||
sync_date = fields.Datetime() |
|||
state = fields.Selection([ |
|||
('pending', 'Pending'), |
|||
('failed', 'Failed'), |
|||
('done', 'Done'), |
|||
], readonly=False, required=True, default='pending') |
|||
state_message = fields.Text() |
|||
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) |
@ -1,84 +0,0 @@ |
|||
# coding: utf-8 |
|||
# Author: Joel Grand-Guillaume |
|||
# Copyright 2011-2012 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
|
|||
def itersubclasses(cls, _seen=None): |
|||
""" |
|||
itersubclasses(cls) |
|||
Generator over all subclasses of a given class, in depth first order. |
|||
>>> list(itersubclasses(int)) == [bool] |
|||
True |
|||
>>> class A(object): pass |
|||
>>> class B(A): pass |
|||
>>> class C(A): pass |
|||
>>> class D(B,C): pass |
|||
>>> class E(D): pass |
|||
>>> |
|||
>>> for cls in itersubclasses(A): |
|||
... print(cls.__name__) |
|||
B |
|||
D |
|||
E |
|||
C |
|||
>>> # get ALL (new-style) classes currently defined |
|||
>>> [cls.__name__ for cls in itersubclasses(object)] #doctest: +ELLIPSIS |
|||
['type', ...'tuple', ...] |
|||
""" |
|||
if not isinstance(cls, type): |
|||
raise TypeError('itersubclasses must be called with ' |
|||
'new-style classes, not %.100r' % cls |
|||
) |
|||
if _seen is None: |
|||
_seen = set() |
|||
try: |
|||
subs = cls.__subclasses__() |
|||
except TypeError: # fails only when cls is type |
|||
subs = cls.__subclasses__(cls) |
|||
for sub in subs: |
|||
if sub not in _seen: |
|||
_seen.add(sub) |
|||
yield sub |
|||
for sub in itersubclasses(sub, _seen): |
|||
yield sub |
|||
|
|||
|
|||
def _get_erp_module_name(module_path): |
|||
# see this PR for v9 https://github.com/odoo/odoo/pull/11084 |
|||
""" Extract the name of the Odoo module from the path of the |
|||
Python module. |
|||
|
|||
Taken from Odoo server: ``openerp.models.MetaModel`` |
|||
|
|||
The (Odoo) module name can be in the ``openerp.addons`` namespace |
|||
or not. For instance module ``sale`` can be imported as |
|||
``openerp.addons.sale`` (the good way) or ``sale`` (for backward |
|||
compatibility). |
|||
""" |
|||
module_parts = module_path.split('.') |
|||
if len(module_parts) > 2 and module_parts[:2] == ['openerp', 'addons']: |
|||
module_name = module_parts[2] |
|||
else: |
|||
module_name = module_parts[0] |
|||
return module_name |
|||
|
|||
|
|||
def is_module_installed(env, module_name): |
|||
""" Check if an Odoo addon is installed. |
|||
|
|||
:param module_name: name of the addon |
|||
""" |
|||
# the registry maintains a set of fully loaded modules so we can |
|||
# lookup for our module there |
|||
return module_name in env.registry._init_modules |
|||
|
|||
|
|||
def get_erp_module(cls_or_func): |
|||
""" For a top level function or class, returns the |
|||
name of the Odoo module where it lives. |
|||
|
|||
So we will be able to filter them according to the modules |
|||
installation state. |
|||
""" |
|||
return _get_erp_module_name(cls_or_func.__module__) |
@ -1,4 +1,3 @@ |
|||
from . import abstract_fs |
|||
from . import ftp |
|||
from . import sftp |
|||
from . import filestore |
@ -1,196 +0,0 @@ |
|||
# coding: utf-8 |
|||
# Copyright (C) 2014 initOS GmbH & Co. KG (<http://www.initos.com>). |
|||
# @ 2015 Valentin CHEMIERE @ 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). |
|||
import logging |
|||
import os |
|||
import fnmatch |
|||
import datetime |
|||
|
|||
from openerp import tools |
|||
|
|||
from .abstract_task import AbstractTask |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
try: |
|||
# We use a jinja2 sandboxed environment to render mako templates. |
|||
# Note that the rendering does not cover all the mako syntax, in particular |
|||
# arbitrary Python statements are not accepted, and not all expressions are |
|||
# allowed: only "public" attributes (not starting with '_') of objects may |
|||
# be accessed. |
|||
# This is done on purpose: it prevents incidental or malicious execution of |
|||
# Python code that may break the security of the server. |
|||
from jinja2.sandbox import SandboxedEnvironment |
|||
mako_template_env = SandboxedEnvironment( |
|||
variable_start_string="${", |
|||
variable_end_string="}", |
|||
line_statement_prefix="%", |
|||
trim_blocks=True, # do not output newline after blocks |
|||
) |
|||
mako_template_env.globals.update({ |
|||
'str': str, |
|||
'datetime': datetime, |
|||
'len': len, |
|||
'abs': abs, |
|||
'min': min, |
|||
'max': max, |
|||
'sum': sum, |
|||
'filter': filter, |
|||
'reduce': reduce, |
|||
'map': map, |
|||
'round': round, |
|||
}) |
|||
except ImportError: |
|||
_logger.warning("jinja2 not available, templating features will not work!") |
|||
|
|||
|
|||
class AbstractFSTask(AbstractTask): |
|||
|
|||
_name = None |
|||
_key = None |
|||
_synchronize_type = None |
|||
_default_port = None |
|||
|
|||
def __init__(self, env, config): |
|||
self.env = env |
|||
self.host = config.get('host', '') |
|||
self.user = config.get('user', '') |
|||
self.pwd = config.get('pwd', '') |
|||
self.port = config.get('port', '') |
|||
self.allow_dir_creation = config.get('allow_dir_creation', '') |
|||
self.file_name = config.get('file_name', '') |
|||
self.path = config.get('path') or '.' |
|||
self.move_path = config.get('move_path', '') |
|||
self.new_name = config.get('new_name', '') |
|||
self.after_import = config.get('after_import', False) |
|||
self.file_type = config.get('file_type', False) |
|||
self.attachment_ids = config.get('attachment_ids', False) |
|||
self.task = config.get('task', False) |
|||
self.ext_hash = False |
|||
self.md5_check = config.get('md5_check', False) |
|||
|
|||
def _handle_new_source(self, fs_conn, download_directory, file_name, |
|||
move_directory): |
|||
"""open and read given file into create_file method, |
|||
move file if move_directory is given""" |
|||
with fs_conn.open(self._source_name(download_directory, file_name), |
|||
"rb") as fileobj: |
|||
data = fileobj.read() |
|||
return self.create_file(file_name, data) |
|||
|
|||
def _source_name(self, download_directory, file_name): |
|||
"""helper to get the full name""" |
|||
return os.path.join(download_directory, file_name) |
|||
|
|||
def _move_file(self, fs_conn, source, target): |
|||
"""Moves a file on the server""" |
|||
_logger.info('Moving file %s %s' % (source, target)) |
|||
fs_conn.rename(source, target) |
|||
if self.md5_check: |
|||
fs_conn.rename(source + '.md5', target + '.md5') |
|||
|
|||
def _delete_file(self, fs_conn, source): |
|||
"""Deletes a file from the server""" |
|||
_logger.info('Deleting file %s' % source) |
|||
fs_conn.remove(source) |
|||
if self.md5_check: |
|||
fs_conn.remove(source + '.md5') |
|||
|
|||
def _get_hash(self, file_name, fs_conn): |
|||
hash_file_name = file_name + '.md5' |
|||
with fs_conn.open(hash_file_name, 'rb') as f: |
|||
return f.read().rstrip('\r\n') |
|||
|
|||
def _get_files(self, conn, path): |
|||
process_files = [] |
|||
files_list = conn.listdir(path) |
|||
pattern = self.file_name |
|||
for file_name in fnmatch.filter(files_list, pattern): |
|||
source_name = self._source_name(self.path, file_name) |
|||
process_files.append((file_name, source_name)) |
|||
return process_files |
|||
|
|||
def _template_render(self, template, record): |
|||
try: |
|||
template = mako_template_env.from_string(tools.ustr(template)) |
|||
except Exception: |
|||
_logger.exception("Failed to load template %r", template) |
|||
|
|||
variables = {'obj': record} |
|||
try: |
|||
render_result = template.render(variables) |
|||
except Exception: |
|||
_logger.exception( |
|||
"Failed to render template %r using values %r" % |
|||
(template, variables)) |
|||
render_result = u"" |
|||
if render_result == u"False": |
|||
render_result = u"" |
|||
return render_result |
|||
|
|||
def _process_file(self, conn, file_to_process): |
|||
if self.md5_check: |
|||
self.ext_hash = self._get_hash(file_to_process[1], conn) |
|||
att_id = self._handle_new_source( |
|||
conn, |
|||
self.path, |
|||
self.file_name, |
|||
self.move_path) |
|||
move = False |
|||
rename = False |
|||
if self.after_import: |
|||
move = 'move' in self.after_import |
|||
rename = 'rename' in self.after_import |
|||
|
|||
# Move/rename/delete files only after all |
|||
# files have been processed. |
|||
if self.after_import == 'delete': |
|||
self._delete_file(conn, file_to_process[1]) |
|||
elif rename or move: |
|||
new_name = file_to_process[0] |
|||
if rename and self.new_name: |
|||
new_name_render = self._template_render( |
|||
self.new_name, att_id) |
|||
if new_name_render: |
|||
# Avoid space in file name |
|||
new_name = new_name_render.replace(' ', '_') |
|||
if self.move_path and not conn.exists(self.move_path): |
|||
conn.makedir(self.move_path) |
|||
move_path = self.move_path if self.move_path else self.path |
|||
self._move_file( |
|||
conn, |
|||
file_to_process[1], |
|||
self._source_name(move_path, new_name)) |
|||
return att_id |
|||
|
|||
def _handle_existing_target(self, fs_conn, target_name, filedata): |
|||
raise Exception("%s already exists" % target_name) |
|||
|
|||
def _handle_new_target(self, fs_conn, target_name, filedata): |
|||
try: |
|||
with fs_conn.open(target_name, mode='wb') as fileobj: |
|||
fileobj.write(filedata) |
|||
_logger.info('wrote %s, size %d', target_name, len(filedata)) |
|||
self.attachment_id.state = 'done' |
|||
self.attachment_id.state_message = '' |
|||
except IOError: |
|||
self.attachment_id.state = 'failed' |
|||
self.attachment_id.state_message = ( |
|||
'The directory doesn\'t exist or had insufficient rights') |
|||
|
|||
def _target_name(self, fs_conn, upload_directory, filename): |
|||
return os.path.join(upload_directory, filename) |
|||
|
|||
def _upload_file(self, conn, host, port, user, pwd, |
|||
path, filename, filedata): |
|||
upload_directory = path or '.' |
|||
target_name = self._target_name(conn, |
|||
upload_directory, |
|||
filename) |
|||
if conn.isfile(target_name): |
|||
self._handle_existing_target(conn, target_name, filedata) |
|||
else: |
|||
self._handle_new_target(conn, target_name, filedata) |
@ -1,28 +0,0 @@ |
|||
# coding: utf-8 |
|||
# @ 2015 Valentin CHEMIERE @ Akretion |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from base64 import b64encode |
|||
|
|||
|
|||
class AbstractTask(object): |
|||
|
|||
_name = None |
|||
_key = None |
|||
_synchronize_type = None |
|||
_default_port = None |
|||
_hide_login = False |
|||
_hide_password = False |
|||
_hide_port = False |
|||
|
|||
def create_file(self, filename, data): |
|||
ir_attachment_id = self.env['ir.attachment.metadata'].create({ |
|||
'name': filename, |
|||
'datas': b64encode(data), |
|||
'datas_fname': filename, |
|||
'task_id': self.task and self.task.id or False, |
|||
'location_id': self.task and self.task.location_id.id or False, |
|||
'external_hash': self.ext_hash, |
|||
'file_type': self.file_type, |
|||
}) |
|||
return ir_attachment_id |
@ -1,53 +1,27 @@ |
|||
# coding: utf-8 |
|||
# Copyright (C) 2014 initOS GmbH & Co. KG (<http://www.initos.com>). |
|||
# @ 2015 Valentin CHEMIERE @ Akretion |
|||
# @ 2016 Florian DA COSTA @ Akretion |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from .abstract_fs import AbstractFSTask |
|||
from base64 import b64decode |
|||
from fs import osfs |
|||
import logging |
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
try: |
|||
from fs import osfs |
|||
except ImportError: |
|||
_logger.debug('Cannot `import fs`.') |
|||
|
|||
class FileStoreTask(AbstractFSTask): |
|||
|
|||
class FileStoreTask(osfs.OSFS): |
|||
|
|||
_key = 'filestore' |
|||
_name = 'File Store' |
|||
_synchronize_type = None |
|||
_default_port = None |
|||
_hide_login = True |
|||
_hide_password = True |
|||
_hide_port = True |
|||
|
|||
|
|||
class FileStoreImportTask(FileStoreTask): |
|||
|
|||
_synchronize_type = 'import' |
|||
|
|||
def run(self): |
|||
att_ids = [] |
|||
with osfs.OSFS(self.host) as fs_conn: |
|||
files_to_process = self._get_files(fs_conn, self.path) |
|||
for file_to_process in files_to_process: |
|||
att_ids.append(self._process_file(fs_conn, file_to_process)) |
|||
return att_ids |
|||
|
|||
|
|||
class FileStoreExportTask(FileStoreTask): |
|||
|
|||
_synchronize_type = 'export' |
|||
|
|||
def run(self, async=True): |
|||
for attachment in self.attachment_ids: |
|||
if attachment.state in ('pending', 'failed'): |
|||
self.attachment_id = attachment |
|||
with osfs.OSFS(self.host) as fs_conn: |
|||
self._upload_file(fs_conn, |
|||
self.host, |
|||
self.port, |
|||
self.user, |
|||
self.pwd, |
|||
self.path, |
|||
attachment.datas_fname, |
|||
b64decode(attachment.datas)) |
|||
@staticmethod |
|||
def connect(location): |
|||
rootpath = location.filestore_rootpath or '/' |
|||
conn = FileStoreTask(rootpath) |
|||
return conn |
@ -1,51 +1,30 @@ |
|||
# coding: utf-8 |
|||
# Copyright (C) 2014 initOS GmbH & Co. KG (<http://www.initos.com>). |
|||
# @ 2015 Valentin CHEMIERE @ Akretion |
|||
# @ 2016 Florian DA COSTA @ Akretion |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from .abstract_fs import AbstractFSTask |
|||
from base64 import b64decode |
|||
from fs import ftpfs |
|||
import logging |
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
try: |
|||
from fs import ftpfs |
|||
except ImportError: |
|||
_logger.debug('Cannot `import fs`.') |
|||
|
|||
class FtpTask(AbstractFSTask): |
|||
|
|||
_key = 'ftp' |
|||
_name = 'FTP' |
|||
class FtpTask(ftpfs.FTPFS): |
|||
|
|||
_key = 'sftp' |
|||
_name = 'SFTP' |
|||
_synchronize_type = None |
|||
_default_port = 21 |
|||
_default_port = 22 |
|||
_hide_login = False |
|||
_hide_password = False |
|||
_hide_port = False |
|||
|
|||
|
|||
class FtpImportTask(FtpTask): |
|||
|
|||
_synchronize_type = 'import' |
|||
|
|||
def run(self): |
|||
att_ids = [] |
|||
with ftpfs.FTPFS( |
|||
self.host, self.user, self.pwd, port=self.port) as ftp_conn: |
|||
files_to_process = self._get_files(ftp_conn, self.path) |
|||
for file_to_process in files_to_process: |
|||
att_ids.append(self._process_file(ftp_conn, file_to_process)) |
|||
return att_ids |
|||
|
|||
|
|||
class FtpExportTask(FtpTask): |
|||
|
|||
_synchronize_type = 'export' |
|||
|
|||
def run(self, async=True): |
|||
for attachment in self.attachment_ids: |
|||
if attachment.state in ('pending', 'failed'): |
|||
self.attachment_id = attachment |
|||
with ftpfs.FTPFS(self.host, self.user, self.pwd, |
|||
port=self.port) as ftp_conn: |
|||
self._upload_file(ftp_conn, self.host, self.port, |
|||
self.user, self.pwd, self.path, |
|||
attachment.datas_fname, |
|||
b64decode(attachment.datas)) |
|||
@staticmethod |
|||
def connect(location): |
|||
conn = FtpTask(location.address, |
|||
location.login, |
|||
location.password, |
|||
location.port) |
|||
return conn |
@ -1,2 +1,4 @@ |
|||
from . import mock_server |
|||
from . import test_ftp |
|||
from . import test_sftp |
|||
from . import test_filestore |
@ -0,0 +1,32 @@ |
|||
# coding: utf-8 |
|||
# @ 2016 Florian da Costa @ Akretion |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
import openerp.tests.common as common |
|||
from openerp import api |
|||
from StringIO import StringIO |
|||
|
|||
|
|||
class ContextualStringIO(StringIO): |
|||
""" |
|||
snippet from http://bit.ly/1HfH6uW (stackoverflow) |
|||
""" |
|||
|
|||
def __enter__(self): |
|||
return self |
|||
|
|||
def __exit__(self, *args): |
|||
self.close() |
|||
return False |
|||
|
|||
|
|||
class TestConnection(common.TransactionCase): |
|||
|
|||
def setUp(self): |
|||
super(TestConnection, self).setUp() |
|||
self.registry.enter_test_mode() |
|||
self.env = api.Environment(self.registry.test_cr, self.env.uid, |
|||
self.env.context) |
|||
|
|||
def tearDown(self): |
|||
self.registry.leave_test_mode() |
|||
super(TestConnection, self).tearDown() |
@ -0,0 +1,50 @@ |
|||
# coding: utf-8 |
|||
# @ 2015 Valentin CHEMIERE @ 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). |
|||
import logging |
|||
from base64 import b64decode |
|||
from .common import TestConnection, ContextualStringIO |
|||
from .mock_server import server_mock_filestore |
|||
|
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class TestfilestoreConnection(TestConnection): |
|||
|
|||
def setUp(self): |
|||
super(TestfilestoreConnection, self).setUp() |
|||
self.test_file_filestore = ContextualStringIO() |
|||
self.test_file_filestore.write('import filestore') |
|||
self.test_file_filestore.seek(0) |
|||
|
|||
def test_00_filestore_import(self): |
|||
self.task = self.env.ref( |
|||
'external_file_location.filestore_import_task') |
|||
with server_mock_filestore( |
|||
{'open': self.test_file_filestore, |
|||
'listdir': ['test-import-filestore.txt']}): |
|||
self.task.run_import() |
|||
search_file = self.env['ir.attachment.metadata'].search( |
|||
[('name', '=', 'test-import-filestore.txt')]) |
|||
self.assertEqual(len(search_file), 1) |
|||
self.assertEqual(b64decode(search_file[0].datas), 'import filestore') |
|||
|
|||
def test_01_filestore_export(self): |
|||
self.task = self.env.ref( |
|||
'external_file_location.filestore_export_task') |
|||
self.filestore_attachment = self.env.ref( |
|||
'external_file_location.ir_attachment_export_file_filestore') |
|||
with server_mock_filestore( |
|||
{'setcontents': ''}) as Fakefilestore: |
|||
self.task.run_export() |
|||
if Fakefilestore: |
|||
self.assertEqual('setcontents', Fakefilestore[-1]['method']) |
|||
self.assertEqual('done', self.filestore_attachment.state) |
|||
self.assertEqual( |
|||
'/home/user/test/filestore_test_export.txt', |
|||
Fakefilestore[-1]['args'][0]) |
|||
self.assertEqual( |
|||
'test filestore file export', |
|||
Fakefilestore[-1]['kwargs']['data']) |
@ -0,0 +1,86 @@ |
|||
# coding: utf-8 |
|||
# @ 2015 Valentin CHEMIERE @ 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). |
|||
import logging |
|||
from base64 import b64decode |
|||
import hashlib |
|||
from .common import TestConnection, ContextualStringIO |
|||
from .mock_server import server_mock_ftp |
|||
from .mock_server import MultiResponse |
|||
from openerp.exceptions import UserError |
|||
|
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class TestFtpConnection(TestConnection): |
|||
|
|||
def setUp(self): |
|||
super(TestFtpConnection, self).setUp() |
|||
self.test_file_ftp = ContextualStringIO() |
|||
self.test_file_ftp.write('import ftp') |
|||
self.test_file_ftp.seek(0) |
|||
|
|||
def test_00_ftp_import(self): |
|||
self.task = self.env.ref('external_file_location.ftp_import_task') |
|||
with server_mock_ftp( |
|||
{'open': self.test_file_ftp, |
|||
'listdir': ['test-import-ftp.txt']}): |
|||
self.task.run_import() |
|||
search_file = self.env['ir.attachment.metadata'].search( |
|||
[('name', '=', 'test-import-ftp.txt')]) |
|||
self.assertEqual(len(search_file), 1) |
|||
self.assertEqual(b64decode(search_file[0].datas), 'import ftp') |
|||
|
|||
def test_01_ftp_export(self): |
|||
self.task = self.env.ref('external_file_location.ftp_export_task') |
|||
self.ftp_attachment = self.env.ref( |
|||
'external_file_location.ir_attachment_export_file_ftp') |
|||
with server_mock_ftp( |
|||
{'setcontents': ''}) as FakeFTP: |
|||
self.task.run_export() |
|||
if FakeFTP: |
|||
self.assertEqual('setcontents', FakeFTP[-1]['method']) |
|||
self.assertEqual('done', self.ftp_attachment.state) |
|||
self.assertEqual( |
|||
'/home/user/test/ftp_test_export.txt', |
|||
FakeFTP[-1]['args'][0]) |
|||
self.assertEqual( |
|||
'test ftp file export', |
|||
FakeFTP[-1]['kwargs']['data']) |
|||
|
|||
def test_02_ftp_import_md5(self): |
|||
md5_file = ContextualStringIO() |
|||
md5_file.write(hashlib.md5('import ftp').hexdigest()) |
|||
md5_file.seek(0) |
|||
task = self.env.ref('external_file_location.ftp_import_task') |
|||
task.md5_check = True |
|||
with server_mock_ftp( |
|||
{'open': MultiResponse({ |
|||
1: md5_file, |
|||
0: self.test_file_ftp}), |
|||
'listdir': [task.filename]}) as Fakeftp: |
|||
task.run_import() |
|||
search_file = self.env['ir.attachment.metadata'].search( |
|||
(('name', '=', task.filename),)) |
|||
self.assertEqual(len(search_file), 1) |
|||
self.assertEqual(b64decode(search_file[0].datas), |
|||
'import ftp') |
|||
self.assertEqual('open', Fakeftp[-1]['method']) |
|||
self.assertEqual(hashlib.md5('import ftp').hexdigest(), |
|||
search_file.external_hash) |
|||
|
|||
def test_03_ftp_import_md5_corrupt_file(self): |
|||
md5_file = ContextualStringIO() |
|||
md5_file.write(hashlib.md5('import test ftp corrupted').hexdigest()) |
|||
md5_file.seek(0) |
|||
task = self.env.ref('external_file_location.ftp_import_task') |
|||
task.md5_check = True |
|||
with server_mock_ftp( |
|||
{'open': MultiResponse({ |
|||
1: md5_file, |
|||
0: self.test_file_ftp}), |
|||
'listdir': [task.filename]}): |
|||
with self.assertRaises(UserError): |
|||
task.run_import() |
Write
Preview
Loading…
Cancel
Save
Reference in new issue