mirror of
https://github.com/OCA/knowledge.git
synced 2025-07-25 18:08:42 -06:00
[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:
parent
a57aadd3aa
commit
7ccb6914b2
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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('/')
|
||||
|
@ -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]),
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user