2018-01-16 06:58:15 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-01-16 11:34:37 +01:00
|
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
import logging
|
|
|
|
import random
|
|
|
|
import re
|
|
|
|
import string
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
from flectra import api, models, _
|
|
|
|
from flectra.exceptions import UserError
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
from ..py_etherpad import EtherpadLiteClient
|
|
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class PadCommon(models.AbstractModel):
|
|
|
|
_name = 'pad.common'
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def pad_is_configured(self):
|
|
|
|
return bool(self.env.user.company_id.pad_server)
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def pad_generate_url(self):
|
|
|
|
company = self.env.user.sudo().company_id
|
|
|
|
|
|
|
|
pad = {
|
|
|
|
"server": company.pad_server,
|
|
|
|
"key": company.pad_key,
|
|
|
|
}
|
|
|
|
|
|
|
|
# make sure pad server in the form of http://hostname
|
|
|
|
if not pad["server"]:
|
|
|
|
return pad
|
|
|
|
if not pad["server"].startswith('http'):
|
|
|
|
pad["server"] = 'http://' + pad["server"]
|
|
|
|
pad["server"] = pad["server"].rstrip('/')
|
|
|
|
# generate a salt
|
|
|
|
s = string.ascii_uppercase + string.digits
|
|
|
|
salt = ''.join([s[random.SystemRandom().randint(0, len(s) - 1)] for i in range(10)])
|
|
|
|
# path
|
|
|
|
# etherpad hardcodes pad id length limit to 50
|
|
|
|
path = '-%s-%s' % (self._name, salt)
|
|
|
|
path = '%s%s' % (self.env.cr.dbname.replace('_', '-')[0:50 - len(path)], path)
|
|
|
|
# contruct the url
|
|
|
|
url = '%s/p/%s' % (pad["server"], path)
|
|
|
|
|
|
|
|
# if create with content
|
|
|
|
if self.env.context.get('field_name') and self.env.context.get('model') and self.env.context.get('object_id'):
|
|
|
|
myPad = EtherpadLiteClient(pad["key"], pad["server"] + '/api')
|
|
|
|
try:
|
|
|
|
myPad.createPad(path)
|
|
|
|
except IOError:
|
|
|
|
raise UserError(_("Pad creation failed, either there is a problem with your pad server URL or with your connection."))
|
|
|
|
|
|
|
|
# get attr on the field model
|
|
|
|
model = self.env[self.env.context["model"]]
|
|
|
|
field = model._fields[self.env.context['field_name']]
|
|
|
|
real_field = field.pad_content_field
|
|
|
|
|
|
|
|
# get content of the real field
|
|
|
|
for record in model.browse([self.env.context["object_id"]]):
|
|
|
|
if record[real_field]:
|
2018-04-05 10:25:40 +02:00
|
|
|
myPad.setHtmlFallbackText(path, record[real_field])
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
return {
|
|
|
|
"server": pad["server"],
|
|
|
|
"path": path,
|
|
|
|
"url": url,
|
|
|
|
}
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def pad_get_content(self, url):
|
2018-04-05 10:25:40 +02:00
|
|
|
company = self.env.user.sudo().company_id
|
2018-07-13 11:51:12 +02:00
|
|
|
myPad = EtherpadLiteClient(company.pad_key, (company.pad_server or '') + '/api')
|
2018-01-16 06:58:15 +01:00
|
|
|
content = ''
|
|
|
|
if url:
|
2018-04-05 10:25:40 +02:00
|
|
|
split_url = url.split('/p/')
|
|
|
|
path = len(split_url) == 2 and split_url[1]
|
2018-01-16 06:58:15 +01:00
|
|
|
try:
|
2018-04-05 10:25:40 +02:00
|
|
|
content = myPad.getHtml(path).get('html', '')
|
|
|
|
except IOError:
|
|
|
|
_logger.warning('Http Error: the credentials might be absent for url: "%s". Falling back.' % url)
|
|
|
|
try:
|
|
|
|
r = requests.get('%s/export/html' % url)
|
|
|
|
r.raise_for_status()
|
|
|
|
except Exception:
|
|
|
|
_logger.warning("No pad found with url '%s'.", url)
|
|
|
|
else:
|
|
|
|
mo = re.search('<body>(.*)</body>', r.content.decode(), re.DOTALL)
|
|
|
|
if mo:
|
|
|
|
content = mo.group(1)
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
return content
|
|
|
|
|
|
|
|
# TODO
|
|
|
|
# reverse engineer protocol to be setHtml without using the api key
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def write(self, vals):
|
2018-04-05 10:25:40 +02:00
|
|
|
self._set_field_to_pad(vals)
|
|
|
|
self._set_pad_to_field(vals)
|
2018-01-16 06:58:15 +01:00
|
|
|
return super(PadCommon, self).write(vals)
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def create(self, vals):
|
2018-04-05 10:25:40 +02:00
|
|
|
# Case of a regular creation: we receive the pad url, so we need to update the
|
|
|
|
# corresponding field
|
|
|
|
self._set_pad_to_field(vals)
|
2018-01-16 06:58:15 +01:00
|
|
|
pad = super(PadCommon, self).create(vals)
|
|
|
|
|
2018-04-05 10:25:40 +02:00
|
|
|
# Case of a programmatical creation (e.g. copy): we receive the field content, so we need
|
|
|
|
# to create the corresponding pad
|
2018-01-16 06:58:15 +01:00
|
|
|
if self.env.context.get('pad_no_create', False):
|
|
|
|
return pad
|
|
|
|
for k, field in self._fields.items():
|
|
|
|
if hasattr(field, 'pad_content_field') and k not in vals:
|
|
|
|
ctx = {
|
|
|
|
'model': self._name,
|
|
|
|
'field_name': k,
|
|
|
|
'object_id': pad.id,
|
|
|
|
}
|
|
|
|
pad_info = self.with_context(**ctx).pad_generate_url()
|
|
|
|
pad[k] = pad_info.get('url')
|
|
|
|
return pad
|
|
|
|
|
2018-04-05 10:25:40 +02:00
|
|
|
def _set_field_to_pad(self, vals):
|
2018-01-16 06:58:15 +01:00
|
|
|
# Update the pad if the `pad_content_field` is modified
|
|
|
|
for k, field in self._fields.items():
|
|
|
|
if hasattr(field, 'pad_content_field') and vals.get(field.pad_content_field) and self[k]:
|
|
|
|
company = self.env.user.sudo().company_id
|
2018-07-13 11:51:12 +02:00
|
|
|
myPad = EtherpadLiteClient(company.pad_key, (company.pad_server or '') + '/api')
|
2018-01-16 06:58:15 +01:00
|
|
|
path = self[k].split('/p/')[1]
|
2018-04-05 10:25:40 +02:00
|
|
|
myPad.setHtmlFallbackText(path, vals[field.pad_content_field])
|
2018-01-16 06:58:15 +01:00
|
|
|
|
2018-04-05 10:25:40 +02:00
|
|
|
def _set_pad_to_field(self, vals):
|
2018-01-16 06:58:15 +01:00
|
|
|
# Update the `pad_content_field` if the pad is modified
|
|
|
|
for k, v in list(vals.items()):
|
2018-04-05 10:25:40 +02:00
|
|
|
field = self._fields.get(k)
|
2018-01-16 06:58:15 +01:00
|
|
|
if hasattr(field, 'pad_content_field'):
|
|
|
|
vals[field.pad_content_field] = self.pad_get_content(v)
|