[ADD] OCA codesprint fixes

- a few bugfixes, including the grave one that everyone read with admin
permissions
- write/create attachment support
This commit is contained in:
Holger Brunn 2016-10-04 17:12:25 +02:00
parent a57aadd3aa
commit 7ccb6914b2
No known key found for this signature in database
GPG Key ID: 01C9760FECA3AE18
7 changed files with 78 additions and 25 deletions

View File

@ -71,7 +71,7 @@ Images
Contributors
------------
* Holger Brunn <hbrunn@therp.nl>
* Holger Brunn <hbrunn@therp.nl>
Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues.

View File

@ -1,20 +1,44 @@
# -*- coding: utf-8 -*-
# © 2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from paramiko import SFTP_EOF, SFTPHandle
from base64 import b64decode
from paramiko import SFTP_EOF, SFTP_OK, SFTP_PERMISSION_DENIED, SFTPHandle
from base64 import b64decode, b64encode
from openerp.models import NewId
from openerp.exceptions import AccessError
class DocumentSFTPHandle(SFTPHandle):
def __init__(self, attachment, flags=0):
self.attachment = attachment
def __init__(self, record, flags=0):
self.record = record
super(DocumentSFTPHandle, self).__init__(flags)
def stat(self):
return self.attachment.env['document.sftp.root']._file(self.attachment)
return self.record.env['document.sftp.root']._file(self.record)
def read(self, offset, length):
data = b64decode(self.attachment.datas)
data = b64decode(self.record.datas)
if offset > len(data):
return SFTP_EOF
return data[offset:offset + length]
def write(self, offset, write_data):
data = b64decode(self.record.datas) if self.record.datas else ''
if offset > len(data):
return SFTP_EOF
try:
self.record.update({
'datas': b64encode(
data[0:offset] + write_data +
data[offset + len(write_data):]
),
})
if isinstance(self.record.id, NewId):
self.record.create(self.record._cache)
except AccessError:
return SFTP_PERMISSION_DENIED
# we need this commit, because this runs in its own thread with its own
# cursor
self.record.env.cr.commit()
# TODO: do we want to clear caches here?
return SFTP_OK

View File

@ -19,6 +19,7 @@ class DocumentSFTPServer(ServerInterface):
if not user:
return AUTH_FAILED
user.sudo(user.id).check_credentials(password)
self.env = self.env(user=user.id)
return AUTH_SUCCESSFUL
except AccessDenied:
pass
@ -37,6 +38,7 @@ class DocumentSFTPServer(ServerInterface):
'Ignoring key of unknown type for line %s', line)
continue
if RSAKey(data=decodebytes(key_data)) == key:
self.env = self.env(user=user.id)
return AUTH_SUCCESSFUL
return AUTH_FAILED

View File

@ -7,7 +7,7 @@ from openerp import api
class DocumentSFTPSftpServerInterface(SFTPServerInterface):
def __init__(self, server, env):
self.env = env
self.env = server.env
def list_folder(self, path):
if not path or path in ('/', '.'):
@ -38,6 +38,7 @@ class DocumentSFTPSftpServerInterface(SFTPServerInterface):
return handler._open(path, flags, attr)
def session_ended(self):
self.env.cr.commit()
self.env.cr.close()
return super(DocumentSFTPSftpServerInterface, self).session_ended()

View File

@ -2,12 +2,13 @@
# © 2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import stat
import time
try:
from paramiko import SFTPAttributes
from ..document_sftp_handle import DocumentSFTPHandle
except ImportError: # pragma: no cover
pass
from openerp import api, models
from ..document_sftp_handle import DocumentSFTPHandle
from openerp import api, models, fields
class DocumentSFTPRoot(models.AbstractModel):
@ -36,6 +37,9 @@ class DocumentSFTPRoot(models.AbstractModel):
result.st_group = 0
result.st_size = attachment.file_size
result.st_mode = stat.S_IFREG | stat.S_IRUSR
result.st_mtime = time.mktime(fields.Datetime.from_string(
attachment.create_date
).timetuple())
return result
@api.model
@ -62,3 +66,10 @@ class DocumentSFTPRoot(models.AbstractModel):
def _lstat(self, path):
"""Return attributes about a link"""
return self._stat(path)
@api.model
def _split_path(self, path):
"""Return a list of normalized and stripped path components"""
# TODO: normalization
path = path.strip('/')
return path.split('/')

View File

@ -41,8 +41,7 @@ class DocumentSFTPRootByModel(models.Model):
@api.model
def _list_folder(self, path):
path = path.strip('/')
components = path.split('/')
components = self._split_path(path)
result = []
if len(components) == 1:
for model in self.env['ir.model'].search([
@ -55,17 +54,11 @@ class DocumentSFTPRootByModel(models.Model):
result.append(self._directory(model.model))
elif len(components) == 2:
model = components[-1]
seen = set([])
if model not in self.env.registry:
return SFTP_NO_SUCH_FILE
for attachment in self.env['ir.attachment'].search([
('res_model', '=', model),
('res_id', '!=', False),
], order='res_id asc'):
for record in self.env[model].search([], order='id asc'):
# TODO: better lump ids together in steps of 100 or something?
if attachment.res_id not in seen:
seen.add(attachment.res_id)
result.append(self._directory(str(attachment.res_id)))
result.append(self._directory(str(record.id)))
elif len(components) == 3:
model = components[-2]
res_id = int(components[-1])
@ -81,10 +74,32 @@ class DocumentSFTPRootByModel(models.Model):
@api.model
def _open(self, path, flags, attr):
if flags & os.O_WRONLY or flags & os.O_RDWR:
# TODO: do something more sensible here
return SFTP_PERMISSION_DENIED
path = path.strip('/')
components = path.split('/')
return self._open_write(path, flags, attr)
return self._open_read(path, flags, attr)
@api.model
def _open_write(self, path, flags, attr):
components = self._split_path(path)
if len(components) == 4:
# TODO: locking!
existing = self.env['ir.attachment'].search([
('res_model', '=', components[-3]),
('res_id', '=', int(components[-2])),
('datas_fname', '=', components[-1]),
])
return self._file_handle(
existing or self.env['ir.attachment'].new({
'res_model': components[-3],
'res_id': int(components[-2]),
'datas_fname': components[-1],
'name': components[-1],
})
)
return SFTP_PERMISSION_DENIED
@api.model
def _open_read(self, path, flags, attr):
components = self._split_path(path)
if len(components) == 4:
return self._file_handle(self.env['ir.attachment'].search([
('res_model', '=', components[-3]),

View File

@ -20,7 +20,7 @@
<field name="arch" type="xml">
<xpath expr="//footer" position="before">
<group name="document_sftp" string="SSH">
<field name="authorized_keys" />
<field name="authorized_keys" readonly="False" />
</group>
</xpath>
</field>