From 193465c4ea95c515f780a02a7e87a76494fef746 Mon Sep 17 00:00:00 2001 From: Valentin Chemiere Date: Tue, 24 Feb 2015 18:11:58 +0100 Subject: [PATCH] FTP import working with subclass discovery --- external_file_location/__init__.py | 7 +- external_file_location/abstract_task.py | 23 ++++++ external_file_location/attachment.py | 7 +- external_file_location/backend.py | 38 --------- external_file_location/helper.py | 60 ++++++++++++++ external_file_location/location.py | 44 +--------- external_file_location/location_view.xml | 6 +- external_file_location/task.py | 78 ++++-------------- external_file_location/task_view.xml | 2 + .../{backends => tasks}/.filestore.py.swp | Bin external_file_location/tasks/__init__.py | 23 ++++++ .../{backends => tasks}/filestore.py | 0 .../{backends => tasks}/ftp.py | 31 ++++--- .../{backends => tasks}/ftp_backup.py | 0 .../{backends => tasks}/sftp.py | 0 ir_attachment_metadata/__init__.py | 7 +- ir_attachment_metadata/__openerp__.py | 9 +- ir_attachment_metadata/attachment.py | 15 ++-- 18 files changed, 173 insertions(+), 177 deletions(-) create mode 100755 external_file_location/abstract_task.py delete mode 100755 external_file_location/backend.py create mode 100644 external_file_location/helper.py rename external_file_location/{backends => tasks}/.filestore.py.swp (100%) create mode 100644 external_file_location/tasks/__init__.py rename external_file_location/{backends => tasks}/filestore.py (100%) rename external_file_location/{backends => tasks}/ftp.py (90%) rename external_file_location/{backends => tasks}/ftp_backup.py (100%) rename external_file_location/{backends => tasks}/sftp.py (100%) diff --git a/external_file_location/__init__.py b/external_file_location/__init__.py index 046125d4..258d23ad 100644 --- a/external_file_location/__init__.py +++ b/external_file_location/__init__.py @@ -20,7 +20,8 @@ # ############################################################################### -import attachment -import location -import task +from . import attachment +from . import location +from . import task +from . import tasks diff --git a/external_file_location/abstract_task.py b/external_file_location/abstract_task.py new file mode 100755 index 00000000..322f0062 --- /dev/null +++ b/external_file_location/abstract_task.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from base64 import b64encode + + +class AbstractTask(object): + + def create_file(self, filename, data): + ir_attachment_id = self.env['ir.attachment'].create( + { + 'name': filename, + 'datas': b64encode(data), + 'datas_fname': filename + } + ) + return ir_attachment_id + + # def load_file(self, file_id): + # f = self.session.browse('impexp.file', file_id) + # if not f.attachment_id.datas: + # return None + # return b64decode(f.attachment_id.datas) diff --git a/external_file_location/attachment.py b/external_file_location/attachment.py index fc1d479e..cb23810d 100644 --- a/external_file_location/attachment.py +++ b/external_file_location/attachment.py @@ -20,12 +20,10 @@ # ############################################################################### -from openerp import models, fields, api, _ -from openerp.exceptions import Warning -import hashlib +from openerp import models, fields -class AttachmentMetadata(models.Model): +class IrAttachment(models.Model): _inherit = 'ir.attachment' sync_date = fields.Datetime() @@ -34,4 +32,3 @@ class AttachmentMetadata(models.Model): ('failed', 'Failed'), ('done', 'Done'), ], readonly=True, required=True, default='pending') - diff --git a/external_file_location/backend.py b/external_file_location/backend.py deleted file mode 100755 index d01c4793..00000000 --- a/external_file_location/backend.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - - -#class AbstractConnection(object): -# -# def __init__(self, host, user, pwd, port=None, allow_dir_creation=False): -# self.host = host -# self.user = user -# self.pwd = pwd -# self.port = port -# self.allow_dir_creation = allow_dir_creation -# self.connection = None -# -# def connect(self): -# return NotImplemented -# -# def close(self): -# return NotImplemented -# -# def get(self, filename, path=None): -# return NotImplemented -# -# def put(self, fileobject, filename, path=None): -# return NotImplemented -# -# def search(self, filename, path=None): -# return NotImplemented -# -# def move(self, filename, oldpath, newpath): -# return NotImplemented -# -# def rename(self, oldfilename, newfilename, path=None): -# return NotImplemented - -class AbstractTask(): - - diff --git a/external_file_location/helper.py b/external_file_location/helper.py new file mode 100644 index 00000000..ad5fd0a8 --- /dev/null +++ b/external_file_location/helper.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +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', ...] + """ + #import pdb; pdb.set_trace() + 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 diff --git a/external_file_location/location.py b/external_file_location/location.py index ea0a6499..74ef9eef 100644 --- a/external_file_location/location.py +++ b/external_file_location/location.py @@ -21,10 +21,11 @@ ############################################################################### from openerp import models, fields -from backend import AbstractTask +from abstract_task import AbstractTask +from helper import itersubclasses class Location(models.Model): - _name = 'ir.location' + _name = 'external.file.location' _description = 'Description' name = fields.Char(string='Name') @@ -43,42 +44,3 @@ class Location(models.Model): res.append(cls_info) return res - -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 diff --git a/external_file_location/location_view.xml b/external_file_location/location_view.xml index c4d4ffcf..71adbf82 100644 --- a/external_file_location/location_view.xml +++ b/external_file_location/location_view.xml @@ -3,7 +3,7 @@ - ir.location + external.file.location
@@ -22,7 +22,7 @@ - ir.location + external.file.location @@ -38,7 +38,7 @@ Locations ir.actions.act_window - ir.location + external.file.location form diff --git a/external_file_location/task.py b/external_file_location/task.py index 51500cda..3cbf9994 100644 --- a/external_file_location/task.py +++ b/external_file_location/task.py @@ -2,8 +2,8 @@ ############################################################################### # # Module for OpenERP -# Copyright (C) 2014 Akretion (http://www.akretion.com). -# @author Sébastien BEAU +# Copyright (C) 2015 Akretion (http://www.akretion.com). +# @author Valentin CHEMIERE # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -20,87 +20,45 @@ # ############################################################################### -import sys -from openerp import models, fields +from openerp import models, fields, api +from helper import itersubclasses +from abstract_task import AbstractTask + class Task(models.Model): _name = 'ir.location.task' _description = 'Description' - + name = fields.Char() - # method = fields.Selection([ - # ('ftp_import', 'FTP import'), - # ('ftp_export', 'FTP export'), - # ('sftp_import', 'SFTP import'), - # ('sftp_export', 'SFTP export'), - # ('filestore_import', 'Filestore import'), - # ('filestore_export', 'Filestore export'), - # ]) method = fields.Selection(selection='_get_method') filename = fields.Char() filepath = fields.Char() - location_id = fields.Many2one('ir.location', string='Location') + location_id = fields.Many2one('external.file.location', string='Location') def _get_method(self): res = [] for cls in itersubclasses(AbstractTask): if cls._synchronize_type: - cls_info = (cls._key + cls._synchronize_type, cls._name + cls._synchronize_type) + cls_info = (cls._key + '_' + cls._synchronize_type, + cls._name + ' ' + cls._synchronize_type) res.append(cls_info) return res + @api.multi def run(self): - connection_class = ... - - method_class = getattr(sys.modules[__name__], self.method) + for cls in itersubclasses(AbstractTask): + if cls._synchronize_type and \ + cls._key + '_' + cls._synchronize_type == self.method: + method_class = cls config = { 'host': self.location_id.address, 'user': self.location_id.login, 'pwd': self.location_id.password, 'port': self.location_id.port, 'allow_dir_creation': False, - 'filename': self.filename, + 'file_name': self.filename, 'path': self.filepath } - conn = method_class(config) - conn.run() + conn = method_class(self.env, config) + file_id = conn.run() - -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 diff --git a/external_file_location/task_view.xml b/external_file_location/task_view.xml index b8e928b1..ddbfded9 100644 --- a/external_file_location/task_view.xml +++ b/external_file_location/task_view.xml @@ -10,8 +10,10 @@ + +