[MERGE] website: migration to new API
No functionnaly changes, only code migration and cleaning
This commit is contained in:
@@ -24,15 +24,15 @@ class WebsiteSurvey(http.Controller):
|
||||
|
||||
# In case of auth required, block public user
|
||||
if survey.auth_required and request.env.user == request.website.user_id:
|
||||
return request.website.render("survey.auth_required", {'survey': survey, 'token': token})
|
||||
return request.render("survey.auth_required", {'survey': survey, 'token': token})
|
||||
|
||||
# In case of non open surveys
|
||||
if survey.stage_id.closed:
|
||||
return request.website.render("survey.notopen")
|
||||
return request.render("survey.notopen")
|
||||
|
||||
# If there is no pages
|
||||
if not survey.page_ids:
|
||||
return request.website.render("survey.nopages")
|
||||
return request.render("survey.nopages")
|
||||
|
||||
# Everything seems to be ok
|
||||
return None
|
||||
@@ -46,7 +46,7 @@ class WebsiteSurvey(http.Controller):
|
||||
dt_deadline = fields.Datetime.from_string(deadline)
|
||||
dt_now = datetime.now()
|
||||
if dt_now > dt_deadline: # survey is not open anymore
|
||||
return request.website.render("survey.notopen")
|
||||
return request.render("survey.notopen")
|
||||
return None
|
||||
|
||||
## ROUTES HANDLERS ##
|
||||
@@ -63,7 +63,7 @@ class WebsiteSurvey(http.Controller):
|
||||
_logger.info("[survey] Phantom mode")
|
||||
user_input = UserInput.create({'survey_id': survey.id, 'test_entry': True})
|
||||
data = {'survey': survey, 'page': None, 'token': user_input.token}
|
||||
return request.website.render('survey.survey_init', data)
|
||||
return request.render('survey.survey_init', data)
|
||||
# END Test mode
|
||||
|
||||
# Controls if the survey can be displayed
|
||||
@@ -80,7 +80,7 @@ class WebsiteSurvey(http.Controller):
|
||||
else:
|
||||
user_input = UserInput.sudo().search([('token', '=', token)], limit=1)
|
||||
if not user_input:
|
||||
return request.website.render("website.403")
|
||||
return request.render("website.403")
|
||||
|
||||
# Do not open expired survey
|
||||
errpage = self._check_deadline(user_input)
|
||||
@@ -90,7 +90,7 @@ class WebsiteSurvey(http.Controller):
|
||||
# Select the right page
|
||||
if user_input.state == 'new': # Intro page
|
||||
data = {'survey': survey, 'page': None, 'token': user_input.token}
|
||||
return request.website.render('survey.survey_init', data)
|
||||
return request.render('survey.survey_init', data)
|
||||
else:
|
||||
return request.redirect('/survey/fill/%s/%s' % (survey.id, user_input.token))
|
||||
|
||||
@@ -112,7 +112,7 @@ class WebsiteSurvey(http.Controller):
|
||||
try:
|
||||
user_input = UserInput.sudo().search([('token', '=', token)], limit=1)
|
||||
except IndexError: # Invalid token
|
||||
return request.website.render("website.403")
|
||||
return request.render("website.403")
|
||||
|
||||
# Do not display expired survey (even if some pages have already been
|
||||
# displayed -- There's a time for everything!)
|
||||
@@ -126,9 +126,9 @@ class WebsiteSurvey(http.Controller):
|
||||
data = {'survey': survey, 'page': page, 'page_nr': page_nr, 'token': user_input.token}
|
||||
if last:
|
||||
data.update({'last': True})
|
||||
return request.website.render('survey.survey', data)
|
||||
return request.render('survey.survey', data)
|
||||
elif user_input.state == 'done': # Display success message
|
||||
return request.website.render('survey.sfinished', {'survey': survey,
|
||||
return request.render('survey.sfinished', {'survey': survey,
|
||||
'token': token,
|
||||
'user_input': user_input})
|
||||
elif user_input.state == 'skip':
|
||||
@@ -142,9 +142,9 @@ class WebsiteSurvey(http.Controller):
|
||||
data = {'survey': survey, 'page': page, 'page_nr': page_nr, 'token': user_input.token}
|
||||
if last:
|
||||
data.update({'last': True})
|
||||
return request.website.render('survey.survey', data)
|
||||
return request.render('survey.survey', data)
|
||||
else:
|
||||
return request.website.render("website.403")
|
||||
return request.render("website.403")
|
||||
|
||||
# AJAX prefilling of a survey
|
||||
@http.route(['/survey/prefill/<model("survey.survey"):survey>/<string:token>',
|
||||
@@ -225,7 +225,7 @@ class WebsiteSurvey(http.Controller):
|
||||
try:
|
||||
user_input = request.env['survey.user_input'].sudo().search([('token', '=', post['token'])], limit=1)
|
||||
except KeyError: # Invalid token
|
||||
return request.website.render("website.403")
|
||||
return request.render("website.403")
|
||||
user_id = request.env.user.id if user_input.type != 'link' else SUPERUSER_ID
|
||||
|
||||
for question in questions:
|
||||
@@ -252,7 +252,7 @@ class WebsiteSurvey(http.Controller):
|
||||
def print_survey(self, survey, token=None, **post):
|
||||
'''Display an survey in printable view; if <token> is set, it will
|
||||
grab the answers of the user_input_id that has <token>.'''
|
||||
return request.website.render('survey.survey_print',
|
||||
return request.render('survey.survey_print',
|
||||
{'survey': survey,
|
||||
'token': token,
|
||||
'page_nr': 0,
|
||||
@@ -276,7 +276,7 @@ class WebsiteSurvey(http.Controller):
|
||||
filter_data = self.get_filter_data(post)
|
||||
current_filters = survey.filter_input_ids(filter_data, filter_finish)
|
||||
filter_display_data = survey.get_filter_display_data(filter_data)
|
||||
return request.website.render(result_template,
|
||||
return request.render(result_template,
|
||||
{'survey': survey,
|
||||
'survey_dict': self.prepare_result_dict(survey, current_filters),
|
||||
'page_range': self.page_range,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import controllers
|
||||
import models
|
||||
import wizard
|
||||
import tests
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Website Builder',
|
||||
'category': 'Website',
|
||||
@@ -14,19 +16,22 @@ Odoo Website CMS
|
||||
'depends': ['web', 'web_editor', 'web_planner'],
|
||||
'installable': True,
|
||||
'data': [
|
||||
'data/data.xml',
|
||||
'data/website_data.xml',
|
||||
'data/web_planner_data.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/ir_ui_view.xml',
|
||||
'security/website_security.xml',
|
||||
|
||||
'views/website_templates.xml',
|
||||
'views/website_views.xml',
|
||||
'views/website_navbar_templates.xml',
|
||||
'views/snippets.xml',
|
||||
'views/res_config.xml',
|
||||
'views/ir_actions.xml',
|
||||
'views/website_backend_navbar.xml',
|
||||
'views/website_views.xml',
|
||||
'views/res_config_views.xml',
|
||||
'views/ir_actions_views.xml',
|
||||
|
||||
'wizard/base_language_install_views.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/demo.xml',
|
||||
'data/website_demo.xml',
|
||||
],
|
||||
'qweb': ['static/src/xml/website.backend.xml'],
|
||||
'application': True,
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import backend
|
||||
import main
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import http
|
||||
from openerp.http import request
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime, date, timedelta
|
||||
from math import floor
|
||||
import time
|
||||
import operator
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class WebsiteBackend(http.Controller):
|
||||
|
||||
+110
-126
@@ -1,22 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import datetime
|
||||
from itertools import islice
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
import werkzeug.utils
|
||||
import urllib2
|
||||
import werkzeug.utils
|
||||
import werkzeug.wrappers
|
||||
|
||||
import openerp
|
||||
from openerp.addons.web.controllers.main import WebClient, Binary
|
||||
from openerp import http
|
||||
from openerp.http import request
|
||||
from openerp.osv.orm import browse_record
|
||||
from openerp.addons.website.models.website import slug
|
||||
import odoo
|
||||
from odoo import http
|
||||
from odoo import fields
|
||||
from odoo.http import request
|
||||
from odoo.osv.orm import browse_record
|
||||
|
||||
from odoo.addons.website.models.website import slug
|
||||
from odoo.addons.web.controllers.main import WebClient, Binary, Home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -34,8 +36,8 @@ class QueryURL(object):
|
||||
|
||||
def __call__(self, path=None, path_args=None, **kw):
|
||||
path = path or self.path
|
||||
for k, v in self.args.items():
|
||||
kw.setdefault(k, v)
|
||||
for key, value in self.args.items():
|
||||
kw.setdefault(key, value)
|
||||
path_args = set(path_args or []).union(self.path_args)
|
||||
paths, fragments = [], []
|
||||
for key, value in kw.items():
|
||||
@@ -56,40 +58,40 @@ class QueryURL(object):
|
||||
return path
|
||||
|
||||
|
||||
class Website(openerp.addons.web.controllers.main.Home):
|
||||
#------------------------------------------------------
|
||||
# View
|
||||
#------------------------------------------------------
|
||||
class Website(Home):
|
||||
|
||||
@http.route('/', type='http', auth="public", website=True)
|
||||
def index(self, **kw):
|
||||
page = 'homepage'
|
||||
try:
|
||||
main_menu = request.env.ref('website.main_menu')
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
main_menu = request.env.ref('website.main_menu', raise_if_not_found=False)
|
||||
if main_menu:
|
||||
first_menu = main_menu.child_id and main_menu.child_id[0]
|
||||
if first_menu:
|
||||
if first_menu.url and (not (first_menu.url.startswith(('/page/', '/?', '/#')) or (first_menu.url == '/'))):
|
||||
return request.redirect(first_menu.url)
|
||||
if first_menu.url and first_menu.url.startswith('/page/'):
|
||||
return request.registry['ir.http'].reroute(first_menu.url)
|
||||
return request.env['ir.http'].reroute(first_menu.url)
|
||||
return self.page(page)
|
||||
|
||||
#------------------------------------------------------
|
||||
# Login - overwrite of the web login so that regular users are redirected to the backend
|
||||
# Login - overwrite of the web login so that regular users are redirected to the backend
|
||||
# while portal users are redirected to the frontend by default
|
||||
#------------------------------------------------------
|
||||
|
||||
@http.route(website=True, auth="public")
|
||||
def web_login(self, redirect=None, *args, **kw):
|
||||
r = super(Website, self).web_login(redirect=redirect, *args, **kw)
|
||||
response = super(Website, self).web_login(redirect=redirect, *args, **kw)
|
||||
if not redirect and request.params['login_success']:
|
||||
if request.registry['res.users'].has_group(request.cr, request.uid, 'base.group_user'):
|
||||
if request.env.user.has_group('base.group_user'):
|
||||
redirect = '/web?' + request.httprequest.query_string
|
||||
else:
|
||||
redirect = '/'
|
||||
return http.redirect_with_hash(redirect)
|
||||
return r
|
||||
return response
|
||||
|
||||
#------------------------------------------------------
|
||||
# Business
|
||||
#------------------------------------------------------
|
||||
|
||||
@http.route('/website/lang/<lang>', type='http', auth="public", website=True, multilang=False)
|
||||
def change_lang(self, lang, r='/', **kwargs):
|
||||
@@ -104,7 +106,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
def page(self, page, **opt):
|
||||
values = {
|
||||
'path': page,
|
||||
'deletable': True, # used to add 'delete this page' in content menu
|
||||
'deletable': True, # used to add 'delete this page' in content menu
|
||||
}
|
||||
# /page/website.XXX --> /page/XXX
|
||||
if page.startswith('website.'):
|
||||
@@ -120,7 +122,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
values.pop('deletable')
|
||||
page = 'website.page_404'
|
||||
else:
|
||||
return request.registry['ir.http']._handle_exception(e, 404)
|
||||
return request.env['ir.http']._handle_exception(e, 404)
|
||||
|
||||
return request.render(page, values)
|
||||
|
||||
@@ -135,35 +137,32 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
|
||||
@http.route('/sitemap.xml', type='http', auth="public", website=True)
|
||||
def sitemap_xml_index(self):
|
||||
cr, uid, context = request.cr, openerp.SUPERUSER_ID, request.context
|
||||
ira = request.registry['ir.attachment']
|
||||
iuv = request.registry['ir.ui.view']
|
||||
mimetype ='application/xml;charset=utf-8'
|
||||
Attachment = request.env['ir.attachment'].sudo()
|
||||
View = request.env['ir.ui.view'].sudo()
|
||||
mimetype = 'application/xml;charset=utf-8'
|
||||
content = None
|
||||
|
||||
def create_sitemap(url, content):
|
||||
return ira.create(cr, uid, dict(
|
||||
datas=content.encode('base64'),
|
||||
mimetype=mimetype,
|
||||
type='binary',
|
||||
name=url,
|
||||
url=url,
|
||||
), context=context)
|
||||
return Attachment.create({
|
||||
'datas': content.encode('base64'),
|
||||
'mimetype': mimetype,
|
||||
'type': 'binary',
|
||||
'name': url,
|
||||
'url': url,
|
||||
})
|
||||
|
||||
sitemap = ira.search_read(cr, uid, [('url', '=' , '/sitemap.xml'), ('type', '=', 'binary')], ('datas', 'create_date'), context=context)
|
||||
sitemap = Attachment.search([('url', '=', '/sitemap.xml'), ('type', '=', 'binary')], limit=1)
|
||||
if sitemap:
|
||||
# Check if stored version is still valid
|
||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
create_date = datetime.datetime.strptime(sitemap[0]['create_date'], server_format)
|
||||
create_date = fields.Datetime.from_string(sitemap.create_date)
|
||||
delta = datetime.datetime.now() - create_date
|
||||
if delta < SITEMAP_CACHE_TIME:
|
||||
content = sitemap[0]['datas'].decode('base64')
|
||||
content = sitemap.datas.decode('base64')
|
||||
|
||||
if not content:
|
||||
# Remove all sitemaps in ir.attachments as we're going to regenerated them
|
||||
sitemap_ids = ira.search(cr, uid, [('url', '=like' , '/sitemap%.xml'), ('type', '=', 'binary')], context=context)
|
||||
if sitemap_ids:
|
||||
ira.unlink(cr, uid, sitemap_ids, context=context)
|
||||
sitemaps = Attachment.search([('url', '=like', '/sitemap%.xml'), ('type', '=', 'binary')])
|
||||
sitemaps.unlink()
|
||||
|
||||
pages = 0
|
||||
locs = request.website.sudo(user=request.website.user_id.id).enumerate_pages()
|
||||
@@ -172,23 +171,27 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
'locs': islice(locs, 0, LOC_PER_SITEMAP),
|
||||
'url_root': request.httprequest.url_root[:-1],
|
||||
}
|
||||
urls = iuv.render_template(cr, uid, 'website.sitemap_locs', values, context=context)
|
||||
urls = View.render_template('website.sitemap_locs', values)
|
||||
if urls.strip():
|
||||
content = iuv.render_template(cr, uid, 'website.sitemap_xml', dict(content=urls), context=context)
|
||||
content = View.render_template('website.sitemap_xml', {'content': urls})
|
||||
pages += 1
|
||||
last = create_sitemap('/sitemap-%d.xml' % pages, content)
|
||||
last_sitemap = create_sitemap('/sitemap-%d.xml' % pages, content)
|
||||
else:
|
||||
break
|
||||
|
||||
if not pages:
|
||||
return request.not_found()
|
||||
elif pages == 1:
|
||||
ira.write(cr, uid, last, dict(url="/sitemap.xml", name="/sitemap.xml"), context=context)
|
||||
last_sitemap.write({
|
||||
'url': "/sitemap.xml",
|
||||
'name': "/sitemap.xml"
|
||||
})
|
||||
else:
|
||||
# Sitemaps must be split in several smaller files with a sitemap index
|
||||
content = iuv.render_template(cr, uid, 'website.sitemap_index_xml', dict(
|
||||
pages=range(1, pages + 1),
|
||||
url_root=request.httprequest.url_root,
|
||||
), context=context)
|
||||
content = View.render_template('website.sitemap_index_xml', {
|
||||
'pages': range(1, pages + 1),
|
||||
'url_root': request.httprequest.url_root,
|
||||
})
|
||||
create_sitemap('/sitemap.xml', content)
|
||||
|
||||
return request.make_response(content, [('Content-Type', mimetype)])
|
||||
@@ -198,34 +201,34 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
try:
|
||||
request.website.get_template('website.info').name
|
||||
except Exception, e:
|
||||
return request.registry['ir.http']._handle_exception(e, 404)
|
||||
irm = request.env['ir.module.module'].sudo()
|
||||
apps = irm.search([('state','=','installed'),('application','=',True)])
|
||||
modules = irm.search([('state','=','installed'),('application','=',False)])
|
||||
return request.env['ir.http']._handle_exception(e, 404)
|
||||
Module = request.env['ir.module.module'].sudo()
|
||||
apps = Module.search([('state', '=', 'installed'), ('application', '=', True)])
|
||||
modules = Module.search([('state', '=', 'installed'), ('application', '=', False)])
|
||||
values = {
|
||||
'apps': apps,
|
||||
'modules': modules,
|
||||
'version': openerp.service.common.exp_version()
|
||||
'version': odoo.service.common.exp_version()
|
||||
}
|
||||
return request.render('website.info', values)
|
||||
|
||||
#------------------------------------------------------
|
||||
# Edit
|
||||
#------------------------------------------------------
|
||||
|
||||
@http.route('/website/add/<path:path>', type='http', auth="user", website=True)
|
||||
def pagenew(self, path, noredirect=False, add_menu=None, template=False):
|
||||
if template:
|
||||
xml_id = request.registry['website'].new_page(request.cr, request.uid, path, template=template, context=request.context)
|
||||
xml_id = request.env['website'].new_page(path, template=template)
|
||||
else:
|
||||
xml_id = request.registry['website'].new_page(request.cr, request.uid, path, context=request.context)
|
||||
xml_id = request.env['website'].new_page(path)
|
||||
if add_menu:
|
||||
request.registry['website.menu'].create(
|
||||
request.cr, request.uid, {
|
||||
'name': path,
|
||||
'url': "/page/" + xml_id[8:],
|
||||
'parent_id': request.website.menu_id.id,
|
||||
'website_id': request.website.id,
|
||||
}, context=request.context)
|
||||
request.env['website.menu'].create({
|
||||
'name': path,
|
||||
'url': "/page/" + xml_id[8:],
|
||||
'parent_id': request.website.menu_id.id,
|
||||
'website_id': request.website.id,
|
||||
})
|
||||
# Reverse action in order to allow shortcut for /page/<website_xml_id>
|
||||
url = "/page/" + re.sub(r"^website\.", '', xml_id)
|
||||
|
||||
@@ -235,14 +238,14 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
|
||||
@http.route(['/website/snippets'], type='json', auth="user", website=True)
|
||||
def snippets(self):
|
||||
return request.website._render('website.snippets')
|
||||
return request.env['ir.ui.view'].render_template('website.snippets')
|
||||
|
||||
@http.route('/website/reset_templates', type='http', auth='user', methods=['POST'], website=True)
|
||||
def reset_template(self, templates, redirect='/'):
|
||||
templates = request.httprequest.form.getlist('templates')
|
||||
modules_to_update = []
|
||||
for temp_id in templates:
|
||||
view = request.registry['ir.ui.view'].browse(request.cr, request.uid, int(temp_id), context=request.context)
|
||||
view = request.env['ir.ui.view'].browse(int(temp_id))
|
||||
if view.page:
|
||||
continue
|
||||
view.model_data_id.write({
|
||||
@@ -252,8 +255,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
modules_to_update.append(view.model_data_id.module)
|
||||
|
||||
if modules_to_update:
|
||||
module_obj = request.env['ir.module.module'].sudo()
|
||||
modules = module_obj.search([('name', 'in', modules_to_update)])
|
||||
modules = request.env['ir.module.module'].sudo().search([('name', 'in', modules_to_update)])
|
||||
if modules:
|
||||
modules.button_immediate_upgrade()
|
||||
return request.redirect(redirect)
|
||||
@@ -261,13 +263,11 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
@http.route('/website/customize_template_get', type='json', auth='user', website=True)
|
||||
def customize_template_get(self, key, full=False, bundles=False):
|
||||
""" Get inherit view's informations of the template ``key``. By default, only
|
||||
returns ``customize_show`` templates (which can be active or not), if
|
||||
``full=True`` returns inherit view's informations of the template ``key``.
|
||||
``bundles=True`` returns also the asset bundles
|
||||
:returns ``customize_show`` templates (which can be active or not), if
|
||||
``full=True`` returns inherit view's informations of the template ``key``.
|
||||
``bundles=True`` returns also the asset bundles
|
||||
"""
|
||||
return request.registry["ir.ui.view"].customize_template_get(
|
||||
request.cr, request.uid, key, full=full, bundles=bundles,
|
||||
context=request.context)
|
||||
return request.env["ir.ui.view"].customize_template_get(key, full=full, bundles=bundles)
|
||||
|
||||
@http.route('/website/translations', type='json', auth="public", website=True)
|
||||
def get_website_translations(self, lang, mods=None):
|
||||
@@ -282,18 +282,14 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
|
||||
@http.route(['/website/publish'], type='json', auth="public", website=True)
|
||||
def publish(self, id, object):
|
||||
_id = int(id)
|
||||
_object = request.registry[object]
|
||||
obj = _object.browse(request.cr, request.uid, _id)
|
||||
Model = request.env[object]
|
||||
record = Model.browse(int(id))
|
||||
|
||||
values = {}
|
||||
if 'website_published' in _object._fields:
|
||||
values['website_published'] = not obj.website_published
|
||||
_object.write(request.cr, request.uid, [_id],
|
||||
values, context=request.context)
|
||||
|
||||
obj = _object.browse(request.cr, request.uid, _id)
|
||||
return bool(obj.website_published)
|
||||
if 'website_published' in Model._fields:
|
||||
values['website_published'] = not record.website_published
|
||||
record.write(values)
|
||||
return bool(record.website_published)
|
||||
|
||||
@http.route(['/website/seo_suggest'], type='json', auth="user", website=True)
|
||||
def seo_suggest(self, keywords=None, lang=None):
|
||||
@@ -302,10 +298,10 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
try:
|
||||
req = urllib2.Request("%s?%s" % (url, werkzeug.url_encode({
|
||||
'ie': 'utf8', 'oe': 'utf8', 'output': 'toolbar', 'q': keywords, 'hl': language[0], 'gl': language[1]})))
|
||||
request = urllib2.urlopen(req)
|
||||
response = urllib2.urlopen(req)
|
||||
except (urllib2.HTTPError, urllib2.URLError):
|
||||
return []
|
||||
xmlroot = ET.fromstring(request.read())
|
||||
xmlroot = ET.fromstring(response.read())
|
||||
return json.dumps([sugg[0].attrib['data'] for sugg in xmlroot if len(sugg) and sugg[0].attrib['data']])
|
||||
|
||||
#------------------------------------------------------
|
||||
@@ -314,54 +310,46 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
|
||||
def get_view_ids(self, xml_ids):
|
||||
ids = []
|
||||
imd = request.registry['ir.model.data']
|
||||
for xml_id in xml_ids:
|
||||
if "." in xml_id:
|
||||
xml = xml_id.split(".")
|
||||
view_model, id = imd.get_object_reference(request.cr, request.uid, xml[0], xml[1])
|
||||
record_id = request.env.ref(xml_id).id
|
||||
else:
|
||||
id = int(xml_id)
|
||||
ids.append(id)
|
||||
record_id = int(xml_id)
|
||||
ids.append(record_id)
|
||||
return ids
|
||||
|
||||
@http.route(['/website/theme_customize_get'], type='json', auth="public", website=True)
|
||||
def theme_customize_get(self, xml_ids):
|
||||
view = request.registry["ir.ui.view"]
|
||||
enable = []
|
||||
disable = []
|
||||
ids = self.get_view_ids(xml_ids)
|
||||
context = dict(request.context or {}, active_test=True)
|
||||
for v in view.browse(request.cr, request.uid, ids, context=context):
|
||||
if v.active:
|
||||
enable.append(v.xml_id)
|
||||
for view in request.env['ir.ui.view'].with_context(active_test=True).browse(ids):
|
||||
if view.active:
|
||||
enable.append(view.xml_id)
|
||||
else:
|
||||
disable.append(v.xml_id)
|
||||
disable.append(view.xml_id)
|
||||
return [enable, disable]
|
||||
|
||||
@http.route(['/website/theme_customize'], type='json', auth="public", website=True)
|
||||
def theme_customize(self, enable, disable, get_bundle=False):
|
||||
""" enable or Disable lists of ``xml_id`` of the inherit templates
|
||||
"""
|
||||
cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
|
||||
view = pool["ir.ui.view"]
|
||||
|
||||
context = dict(request.context or {}, active_test=True)
|
||||
|
||||
""" enable or Disable lists of ``xml_id`` of the inherit templates """
|
||||
def set_active(ids, active):
|
||||
if ids:
|
||||
view.write(cr, uid, self.get_view_ids(ids), {'active': active}, context=context)
|
||||
real_ids = self.get_view_ids(ids)
|
||||
request.env['ir.ui.view'].with_context(active_test=True).browse(real_ids).write({'active': active})
|
||||
|
||||
set_active(disable, False)
|
||||
set_active(enable, True)
|
||||
|
||||
if get_bundle:
|
||||
context = dict(request.context, active_test=True)
|
||||
return request.env["ir.qweb"]._get_asset('web.assets_frontend', options=context)
|
||||
|
||||
return True
|
||||
|
||||
@http.route(['/website/theme_customize_reload'], type='http', auth="public", website=True)
|
||||
def theme_customize_reload(self, href, enable, disable):
|
||||
self.theme_customize(enable and enable.split(",") or [],disable and disable.split(",") or [])
|
||||
self.theme_customize(enable and enable.split(",") or [], disable and disable.split(",") or [])
|
||||
return request.redirect(href + ("&theme=true" if "#" in href else "#theme=true"))
|
||||
|
||||
@http.route(['/website/multi_render'], type='json', auth="public", website=True)
|
||||
@@ -375,22 +363,20 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
#------------------------------------------------------
|
||||
# Server actions
|
||||
#------------------------------------------------------
|
||||
|
||||
@http.route([
|
||||
'/website/action/<path_or_xml_id_or_id>',
|
||||
'/website/action/<path_or_xml_id_or_id>/<path:path>',
|
||||
], type='http', auth="public", website=True)
|
||||
def actions_server(self, path_or_xml_id_or_id, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
res, action_id, action = None, None, None
|
||||
ServerActions = request.registry['ir.actions.server']
|
||||
ServerActions = request.env['ir.actions.server']
|
||||
|
||||
# find the action_id: either an xml_id, the path, or an ID
|
||||
if isinstance(path_or_xml_id_or_id, basestring) and '.' in path_or_xml_id_or_id:
|
||||
action_id = request.registry['ir.model.data'].xmlid_to_res_id(request.cr, request.uid, path_or_xml_id_or_id, raise_if_not_found=False)
|
||||
if not action_id:
|
||||
action_ids = ServerActions.search(cr, uid, [('website_path', '=', path_or_xml_id_or_id), ('website_published', '=', True)], context=context)
|
||||
action_id = action_ids and action_ids[0] or None
|
||||
if not action_id:
|
||||
action = request.env.ref(path_or_xml_id_or_id, raise_if_not_found=False)
|
||||
if not action:
|
||||
action = ServerActions.search([('website_path', '=', path_or_xml_id_or_id), ('website_published', '=', True)], limit=1)
|
||||
if not action:
|
||||
try:
|
||||
action_id = int(path_or_xml_id_or_id)
|
||||
except ValueError:
|
||||
@@ -398,24 +384,22 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
|
||||
# check it effectively exists
|
||||
if action_id:
|
||||
action_ids = ServerActions.exists(cr, uid, [action_id], context=context)
|
||||
action_id = action_ids and action_ids[0] or None
|
||||
action = ServerActions.browse(action_id).exists()
|
||||
# run it, return only if we got a Response object
|
||||
if action_id:
|
||||
action = ServerActions.browse(cr, uid, action_id, context=context)
|
||||
if action:
|
||||
if action.state == 'code' and action.website_published:
|
||||
action_res = ServerActions.run(cr, uid, [action_id], context=context)
|
||||
action_res = action.run()
|
||||
if isinstance(action_res, werkzeug.wrappers.Response):
|
||||
res = action_res
|
||||
if res:
|
||||
return res
|
||||
return action_res
|
||||
|
||||
return request.redirect('/')
|
||||
|
||||
|
||||
#------------------------------------------------------
|
||||
# Retrocompatibility routes
|
||||
#------------------------------------------------------
|
||||
class WebsiteBinary(openerp.http.Controller):
|
||||
class WebsiteBinary(http.Controller):
|
||||
|
||||
@http.route([
|
||||
'/website/image',
|
||||
'/website/image/<xmlid>',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="default_website" model="website">
|
||||
<field name="name">Website localhost</field>
|
||||
@@ -368,4 +368,4 @@
|
||||
<field name="url">/web/image/website.s_background_image_01</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="default_website" model="website">
|
||||
@@ -15,28 +15,26 @@
|
||||
</data>
|
||||
|
||||
<data noupdate="1">
|
||||
|
||||
<!--
|
||||
Some demo data for front-end server action generating templates
|
||||
-->
|
||||
|
||||
-->
|
||||
<template id="template_partner_post" name="Partner Post and Thanks (Website Server Action Demo)">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="additional_title">Partner Detail</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure">
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>Thank you for posting a message !</h2>
|
||||
</div>
|
||||
<t t-call="website.layout">
|
||||
<t t-set="additional_title">Partner Detail</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure">
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>Thank you for posting a message !</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<record id="action_partner_post" model="ir.actions.server">
|
||||
@@ -207,4 +205,4 @@ response = request.render("website.template_partner_comment", values)
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
@@ -1,10 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# flake8:noqa
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import ir_actions
|
||||
import ir_ui_view
|
||||
import website
|
||||
import ir_qweb
|
||||
import ir_http
|
||||
import ir_attachment
|
||||
import res_company
|
||||
import res_partner
|
||||
import res_config
|
||||
import website
|
||||
import web_planner
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import urlparse
|
||||
|
||||
@@ -6,16 +7,16 @@ from odoo import api, fields, models
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class actions_server(models.Model):
|
||||
class ServerAction(models.Model):
|
||||
""" Add website option in server actions. """
|
||||
|
||||
_name = 'ir.actions.server'
|
||||
_inherit = 'ir.actions.server'
|
||||
|
||||
xml_id = fields.Char(compute='_compute_xml_id', string="External ID",
|
||||
help="ID of the action if defined in a XML file")
|
||||
website_path = fields.Char()
|
||||
website_url = fields.Char(compute='_get_website_url', help='The full URL to access the server action through the website.')
|
||||
website_published = fields.Boolean(string='Available on the Website', copy=False,
|
||||
xml_id = fields.Char('External ID', compute='_compute_xml_id', help="ID of the action if defined in a XML file")
|
||||
website_path = fields.Char('Website Path')
|
||||
website_url = fields.Char('Website Url', compute='_get_website_url', help='The full URL to access the server action through the website.')
|
||||
website_published = fields.Boolean('Available on the Website', copy=False,
|
||||
help='A code server action can be executed from the website, using a dedicated '
|
||||
'controller. The address is <base>/website/action/<website_path>. '
|
||||
'Set this field as True to allow users to run this action. If it '
|
||||
@@ -43,7 +44,7 @@ class actions_server(models.Model):
|
||||
@api.model
|
||||
def _get_eval_context(self, action):
|
||||
""" Override to add the request object in eval_context. """
|
||||
eval_context = super(actions_server, self)._get_eval_context(action)
|
||||
eval_context = super(ServerAction, self)._get_eval_context(action)
|
||||
if action.state == 'code':
|
||||
eval_context['request'] = request
|
||||
return eval_context
|
||||
@@ -51,7 +52,8 @@ class actions_server(models.Model):
|
||||
@api.model
|
||||
def run_action_code_multi(self, action, eval_context=None):
|
||||
""" Override to allow returning response the same way action is already
|
||||
returned by the basic server action behavior. Note that response has
|
||||
priority over action, avoid using both. """
|
||||
res = super(actions_server, self).run_action_code_multi(action, eval_context)
|
||||
returned by the basic server action behavior. Note that response has
|
||||
priority over action, avoid using both.
|
||||
"""
|
||||
res = super(ServerAction, self).run_action_code_multi(action, eval_context)
|
||||
return eval_context.get('response', res)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class Attachment(models.Model):
|
||||
|
||||
_inherit = "ir.attachment"
|
||||
|
||||
# related for backward compatibility with saas-6
|
||||
website_url = fields.Char(string="Attachment URL", related='local_url', deprecated=True)
|
||||
@@ -1,67 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import traceback
|
||||
|
||||
import werkzeug
|
||||
import werkzeug.routing
|
||||
import werkzeug.utils
|
||||
|
||||
import openerp
|
||||
from openerp.addons.base import ir
|
||||
import odoo
|
||||
from odoo import api, models
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo.http import request
|
||||
from odoo.tools import config
|
||||
from odoo.exceptions import QWebException
|
||||
from openerp.addons.website.models.website import slug, url_for, _UNSLUG_RE
|
||||
from openerp.http import request
|
||||
from openerp.tools import config
|
||||
from openerp.osv import orm
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
from odoo.addons.base import ir
|
||||
from odoo.addons.website.models.website import slug, url_for, _UNSLUG_RE
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RequestUID(object):
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
|
||||
class ir_http(orm.AbstractModel):
|
||||
|
||||
class Http(models.AbstractModel):
|
||||
|
||||
_inherit = 'ir.http'
|
||||
|
||||
rerouting_limit = 10
|
||||
_geoip_resolver = None
|
||||
|
||||
def _get_converters(self):
|
||||
""" Get the converters list for custom url pattern werkzeug need to
|
||||
match Rule. This override adds the website ones.
|
||||
"""
|
||||
return dict(
|
||||
super(ir_http, self)._get_converters(),
|
||||
super(Http, self)._get_converters(),
|
||||
model=ModelConverter,
|
||||
page=PageConverter,
|
||||
)
|
||||
|
||||
def _auth_method_public(self):
|
||||
""" If no user logged, set the public user of current website, or default
|
||||
public user as request uid.
|
||||
After this method `request.env` can be called, since the `request.uid` is
|
||||
set. The `env` lazy property of `request` will be correct.
|
||||
"""
|
||||
if not request.session.uid:
|
||||
website = self.pool['website'].get_current_website(request.cr, openerp.SUPERUSER_ID, context=request.context)
|
||||
env = api.Environment(request.cr, SUPERUSER_ID, request.context)
|
||||
website = env['website'].get_current_website()
|
||||
if website:
|
||||
request.uid = website.user_id.id
|
||||
else:
|
||||
request.uid = self.pool['ir.model.data'].xmlid_to_res_id(request.cr, openerp.SUPERUSER_ID, 'base', 'public_user')
|
||||
request.uid = env.ref('base.public_user').id
|
||||
else:
|
||||
request.uid = request.session.uid
|
||||
|
||||
bots = "bot|crawl|slurp|spider|curl|wget|facebookexternalhit".split("|")
|
||||
|
||||
def is_a_bot(self):
|
||||
# We don't use regexp and ustr voluntarily
|
||||
# timeit has been done to check the optimum method
|
||||
ua = request.httprequest.environ.get('HTTP_USER_AGENT', '').lower()
|
||||
user_agent = request.httprequest.environ.get('HTTP_USER_AGENT', '').lower()
|
||||
try:
|
||||
return any(bot in ua for bot in self.bots)
|
||||
return any(bot in user_agent for bot in self.bots)
|
||||
except UnicodeDecodeError:
|
||||
return any(bot in ua.encode('ascii', 'ignore') for bot in self.bots)
|
||||
return any(bot in user_agent.encode('ascii', 'ignore') for bot in self.bots)
|
||||
|
||||
def get_nearest_lang(self, lang):
|
||||
# Try to find a similar lang. Eg: fr_BE and fr_FR
|
||||
short = lang.partition('_')[0]
|
||||
short_match = False
|
||||
for code, name in request.website.get_languages():
|
||||
for code, dummy in request.website.get_languages():
|
||||
if code == lang:
|
||||
return lang
|
||||
if not short_match and code.startswith(short):
|
||||
@@ -94,6 +111,14 @@ class ir_http(orm.AbstractModel):
|
||||
return (self._name, "cache", request.uid, request.lang, request.httprequest.full_path)
|
||||
|
||||
def _dispatch(self):
|
||||
""" Before executing the endpoint method, add website params on request, such as
|
||||
- current website (record)
|
||||
- multilang support (set on cookies)
|
||||
- geoip dict data are added in the session
|
||||
Then follow the parent dispatching.
|
||||
Reminder : Do not use `request.env` before authentication phase, otherwise the env
|
||||
set on request will be created with uid=None (and it is a lazy property)
|
||||
"""
|
||||
first_pass = not hasattr(request, 'website')
|
||||
request.website = None
|
||||
func = None
|
||||
@@ -116,6 +141,7 @@ class ir_http(orm.AbstractModel):
|
||||
self._geoip_setup_resolver()
|
||||
self._geoip_resolve()
|
||||
|
||||
# For website routes (only), add website params on `request`
|
||||
cook_lang = request.httprequest.cookies.get('website_lang')
|
||||
if request.website_enabled:
|
||||
try:
|
||||
@@ -127,7 +153,7 @@ class ir_http(orm.AbstractModel):
|
||||
return self._handle_exception(e)
|
||||
|
||||
request.redirect = lambda url, code=302: werkzeug.utils.redirect(url_for(url), code)
|
||||
request.website = request.registry['website'].get_current_website(request.cr, request.uid, context=request.context)
|
||||
request.website = request.env['website'].get_current_website() # can use `request.env` since auth methods are called
|
||||
request.context['website_id'] = request.website.id
|
||||
langs = [lg[0] for lg in request.website.get_languages()]
|
||||
path = request.httprequest.path.split('/')
|
||||
@@ -170,7 +196,7 @@ class ir_http(orm.AbstractModel):
|
||||
|
||||
# removed cache for auth public
|
||||
request.cache_save = False
|
||||
resp = super(ir_http, self)._dispatch()
|
||||
resp = super(Http, self)._dispatch()
|
||||
|
||||
if request.website_enabled and cook_lang != request.lang and hasattr(resp, 'set_cookie'):
|
||||
resp.set_cookie('website_lang', request.lang)
|
||||
@@ -192,11 +218,11 @@ class ir_http(orm.AbstractModel):
|
||||
return self._dispatch()
|
||||
|
||||
def _postprocess_args(self, arguments, rule):
|
||||
super(ir_http, self)._postprocess_args(arguments, rule)
|
||||
super(Http, self)._postprocess_args(arguments, rule)
|
||||
|
||||
for key, val in arguments.items():
|
||||
# Replace uid placeholder by the current request.uid
|
||||
if isinstance(val, orm.BaseModel) and isinstance(val._uid, RequestUID):
|
||||
if isinstance(val, models.BaseModel) and isinstance(val._uid, RequestUID):
|
||||
arguments[key] = val.sudo(request.uid)
|
||||
|
||||
try:
|
||||
@@ -219,10 +245,10 @@ class ir_http(orm.AbstractModel):
|
||||
is_website_request = bool(getattr(request, 'website_enabled', False) and request.website)
|
||||
if not is_website_request:
|
||||
# Don't touch non website requests exception handling
|
||||
return super(ir_http, self)._handle_exception(exception)
|
||||
return super(Http, self)._handle_exception(exception)
|
||||
else:
|
||||
try:
|
||||
response = super(ir_http, self)._handle_exception(exception)
|
||||
response = super(Http, self)._handle_exception(exception)
|
||||
if isinstance(response, Exception):
|
||||
exception = response
|
||||
else:
|
||||
@@ -246,21 +272,20 @@ class ir_http(orm.AbstractModel):
|
||||
else:
|
||||
code = exception.code
|
||||
|
||||
if isinstance(exception, openerp.exceptions.AccessError):
|
||||
if isinstance(exception, odoo.exceptions.AccessError):
|
||||
code = 403
|
||||
|
||||
if isinstance(exception, QWebException):
|
||||
values.update(qweb_exception=exception)
|
||||
if isinstance(exception.qweb.get('cause'), openerp.exceptions.AccessError):
|
||||
if isinstance(exception.qweb.get('cause'), odoo.exceptions.AccessError):
|
||||
code = 403
|
||||
|
||||
if code == 500:
|
||||
logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
|
||||
if 'qweb_exception' in values:
|
||||
view = request.registry.get("ir.ui.view")
|
||||
views = view._views_get(request.cr, request.uid, exception.qweb['template'],
|
||||
context=request.context)
|
||||
to_reset = [v for v in views if v.model_data_id.noupdate is True and not v.page]
|
||||
view = request.env["ir.ui.view"]
|
||||
views = view._views_get(exception.qweb['template'])
|
||||
to_reset = views.filtered(lambda view: view.model_data_id.noupdate is True and not view.page)
|
||||
values['views'] = to_reset
|
||||
elif code == 403:
|
||||
logger.warn("403 Forbidden:\n\n%s", values['traceback'])
|
||||
@@ -274,9 +299,9 @@ class ir_http(orm.AbstractModel):
|
||||
self._auth_method_public()
|
||||
|
||||
try:
|
||||
html = request.website._render('website.%s' % code, values)
|
||||
html = request.env['ir.ui.view'].render_template('website.%s' % code, values)
|
||||
except Exception:
|
||||
html = request.website._render('website.http_error', values)
|
||||
html = request.env['ir.ui.view'].render_template('website.http_error', values)
|
||||
return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
|
||||
|
||||
def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None):
|
||||
@@ -288,10 +313,12 @@ class ir_http(orm.AbstractModel):
|
||||
obj = env[model].browse(int(id))
|
||||
if obj and 'website_published' in obj._fields:
|
||||
if env[obj._name].sudo().search([('id', '=', obj.id), ('website_published', '=', True)]):
|
||||
env = env(user=openerp.SUPERUSER_ID)
|
||||
return super(ir_http, self).binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype=default_mimetype, env=env)
|
||||
env = env(user=SUPERUSER_ID)
|
||||
return super(Http, self).binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype=default_mimetype, env=env)
|
||||
|
||||
|
||||
class ModelConverter(ir.ir_http.ModelConverter):
|
||||
|
||||
def __init__(self, url_map, model=False, domain='[]'):
|
||||
super(ModelConverter, self).__init__(url_map, model)
|
||||
self.domain = domain
|
||||
@@ -301,43 +328,46 @@ class ModelConverter(ir.ir_http.ModelConverter):
|
||||
return slug(value)
|
||||
|
||||
def to_python(self, value):
|
||||
m = re.match(self.regex, value)
|
||||
_uid = RequestUID(value=value, match=m, converter=self)
|
||||
record_id = int(m.group(2))
|
||||
matching = re.match(self.regex, value)
|
||||
_uid = RequestUID(value=value, match=matching, converter=self)
|
||||
record_id = int(matching.group(2))
|
||||
env = api.Environment(request.cr, _uid, request.context)
|
||||
if record_id < 0:
|
||||
# limited support for negative IDs due to our slug pattern, assume abs() if not found
|
||||
if not request.registry[self.model].exists(request.cr, _uid, [record_id]):
|
||||
if not env[self.model].browse(record_id).exists():
|
||||
record_id = abs(record_id)
|
||||
return request.registry[self.model].browse(
|
||||
request.cr, _uid, record_id, context=request.context)
|
||||
return env[self.model].browse(record_id)
|
||||
|
||||
def generate(self, cr, uid, query=None, args=None, context=None):
|
||||
obj = request.registry[self.model]
|
||||
domain = eval( self.domain, (args or {}).copy())
|
||||
def generate(self, query=None, args=None):
|
||||
Model = request.env[self.model]
|
||||
domain = safe_eval(self.domain, (args or {}).copy())
|
||||
if query:
|
||||
domain.append((obj._rec_name, 'ilike', '%'+query+'%'))
|
||||
for record in obj.search_read(cr, uid, domain=domain, fields=['write_date',obj._rec_name], context=context):
|
||||
if record.get(obj._rec_name, False):
|
||||
yield {'loc': (record['id'], record[obj._rec_name])}
|
||||
domain.append((Model._rec_name, 'ilike', '%' + query + '%'))
|
||||
for record in Model.search_read(domain=domain, fields=['write_date', Model._rec_name]):
|
||||
if record.get(Model._rec_name, False):
|
||||
yield {'loc': (record['id'], record[Model._rec_name])}
|
||||
|
||||
|
||||
class PageConverter(werkzeug.routing.PathConverter):
|
||||
""" Only point of this converter is to bundle pages enumeration logic """
|
||||
def generate(self, cr, uid, query=None, args={}, context=None):
|
||||
View = request.registry['ir.ui.view']
|
||||
|
||||
def generate(self, query=None, args={}):
|
||||
View = request.env['ir.ui.view']
|
||||
domain = [('page', '=', True)]
|
||||
query = query and query.startswith('website.') and query[8:] or query
|
||||
if query:
|
||||
domain += [('key', 'like', query)]
|
||||
|
||||
views = View.search_read(cr, uid, domain, fields=['key', 'priority', 'write_date'], order='name', context=context)
|
||||
views = View.search_read(domain, fields=['key', 'priority', 'write_date'], order='name')
|
||||
for view in views:
|
||||
xid = view['key'].startswith('website.') and view['key'][8:] or view['key']
|
||||
# the 'page/homepage' url is indexed as '/', avoid aving the same page referenced twice
|
||||
# when we will have an url mapping mechanism, replace this by a rule: page/homepage --> /
|
||||
if xid=='homepage': continue
|
||||
if xid == 'homepage':
|
||||
continue
|
||||
record = {'loc': xid}
|
||||
if view['priority'] <> 16:
|
||||
record['__priority'] = min(round(view['priority'] / 32.0,1), 1)
|
||||
if view['priority'] != 16:
|
||||
record['__priority'] = min(round(view['priority'] / 32.0, 1), 1)
|
||||
if view['write_date']:
|
||||
record['__lastmod'] = view['write_date'][:10]
|
||||
yield record
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp.http import request
|
||||
from openerp.osv import orm
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import ast
|
||||
|
||||
from odoo import models
|
||||
from odoo.http import request
|
||||
|
||||
class QWeb(orm.AbstractModel):
|
||||
""" QWeb object for rendering stuff in the website context
|
||||
"""
|
||||
|
||||
class QWeb(models.AbstractModel):
|
||||
""" QWeb object for rendering stuff in the website context """
|
||||
|
||||
_inherit = 'ir.qweb'
|
||||
|
||||
@@ -36,6 +38,7 @@ class QWeb(orm.AbstractModel):
|
||||
|
||||
url_att = self.URL_ATTRS.get(el.tag)
|
||||
cdn_att = self.CDN_TRIGGERS.get(el.tag)
|
||||
|
||||
def process(item):
|
||||
if isinstance(item, tuple) and (item[0] in (url_att, cdn_att)):
|
||||
return (item[0], ast.Call(
|
||||
|
||||
+114
-124
@@ -1,100 +1,96 @@
|
||||
# -*- coding: ascii -*-
|
||||
import copy
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
|
||||
from itertools import groupby
|
||||
from lxml import etree, html
|
||||
from lxml import etree
|
||||
|
||||
from openerp import SUPERUSER_ID, api, tools
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.http import request
|
||||
from openerp.osv import osv, fields
|
||||
from odoo import api, fields, models
|
||||
from odoo import tools
|
||||
|
||||
from odoo.addons.website.models import website
|
||||
from odoo.http import request
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class view(osv.osv):
|
||||
class View(models.Model):
|
||||
|
||||
_name = "ir.ui.view"
|
||||
_inherit = ["ir.ui.view", "website.seo.metadata"]
|
||||
_columns = {
|
||||
'page': fields.boolean("Whether this view is a web page template (complete)"),
|
||||
'customize_show': fields.boolean("Show As Optional Inherit"),
|
||||
'website_id': fields.many2one('website', ondelete='cascade', string="Website"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'page': False,
|
||||
'customize_show': False,
|
||||
}
|
||||
page = fields.Boolean("Whether this view is a web page template (complete)", default=False)
|
||||
customize_show = fields.Boolean("Show As Optional Inherit", default=False)
|
||||
website_id = fields.Many2one('website', ondelete='cascade', string="Website")
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
res = super(view, self).unlink(cr, uid, ids, context=context)
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
result = super(View, self).unlink()
|
||||
self.clear_caches()
|
||||
return res
|
||||
return result
|
||||
|
||||
@api.multi
|
||||
def _sort_suitability_key(self):
|
||||
""" Key function to sort views by descending suitability
|
||||
Suitability of a view is defined as follow:
|
||||
* if the view and request website_id are matched
|
||||
* then if the view has no set website
|
||||
"""
|
||||
Key function to sort views by descending suitability
|
||||
Suitability of a view is defined as follow:
|
||||
|
||||
* if the view and request website_id are matched
|
||||
* then if the view has no set website
|
||||
"""
|
||||
self.ensure_one()
|
||||
context_website_id = self.env.context.get('website_id', 1)
|
||||
website_id = self.website_id.id or 0
|
||||
different_website = context_website_id != website_id
|
||||
|
||||
return (different_website, website_id)
|
||||
|
||||
def filter_duplicate(self):
|
||||
"""
|
||||
Filter current recordset only keeping the most suitable view per distinct key
|
||||
"""
|
||||
filtered = self.browse([])
|
||||
for _, group in groupby(self, key=lambda r:r.key):
|
||||
filtered += sorted(group, key=lambda r:r._sort_suitability_key())[0]
|
||||
""" Filter current recordset only keeping the most suitable view per distinct key """
|
||||
filtered = self.env['ir.ui.view']
|
||||
for dummy, group in groupby(self, key=lambda record: record.key):
|
||||
filtered += sorted(group, key=lambda record: record._sort_suitability_key())[0]
|
||||
return filtered
|
||||
|
||||
def _view_obj(self, cr, uid, view_id, context=None):
|
||||
@api.model
|
||||
def _view_obj(self, view_id):
|
||||
if isinstance(view_id, basestring):
|
||||
if 'website_id' in (context or {}):
|
||||
domain = [('key', '=', view_id), '|', ('website_id', '=', False), ('website_id', '=', context.get('website_id'))]
|
||||
rec_id = self.search(cr, uid, domain, order='website_id', context=context)
|
||||
if 'website_id' in self._context:
|
||||
domain = [('key', '=', view_id), '|', ('website_id', '=', False), ('website_id', '=', self._context.get('website_id'))]
|
||||
order = 'website_id'
|
||||
else:
|
||||
rec_id = self.search(cr, uid, [('key', '=', view_id)], context=context)
|
||||
if rec_id:
|
||||
return self.browse(cr, uid, rec_id, context=context).filter_duplicate()
|
||||
domain = [('key', '=', view_id)]
|
||||
order = self._order
|
||||
views = self.search(domain, order=order)
|
||||
if views:
|
||||
return views.filter_duplicate()
|
||||
else:
|
||||
return self.pool['ir.model.data'].xmlid_to_object(
|
||||
cr, uid, view_id, raise_if_not_found=True, context=context)
|
||||
return self.env.ref(view_id)
|
||||
elif isinstance(view_id, (int, long)):
|
||||
return self.browse(cr, uid, view_id, context=context)
|
||||
return self.browse(view_id)
|
||||
|
||||
# assume it's already a view object (WTF?)
|
||||
return view_id
|
||||
|
||||
# Returns all views (called and inherited) related to a view
|
||||
# Used by translation mechanism, SEO and optional templates
|
||||
def _views_get(self, cr, uid, view_id, options=True, bundles=False, context=None, root=True):
|
||||
|
||||
@api.model
|
||||
def _views_get(self, view_id, options=True, bundles=False, root=True):
|
||||
""" For a given view ``view_id``, should return:
|
||||
|
||||
* the view itself
|
||||
* all views inheriting from it, enabled or not
|
||||
- but not the optional children of a non-enabled child
|
||||
* all views called from it (via t-call)
|
||||
* the view itself
|
||||
* all views inheriting from it, enabled or not
|
||||
- but not the optional children of a non-enabled child
|
||||
* all views called from it (via t-call)
|
||||
:returns recordset of ir.ui.view
|
||||
"""
|
||||
|
||||
try:
|
||||
view = self._view_obj(cr, uid, view_id, context=context)
|
||||
view = self._view_obj(view_id)
|
||||
except ValueError:
|
||||
_logger.warning("Could not find view object with view_id '%s'" % (view_id))
|
||||
# Shall we log that ? Yes, you should !
|
||||
_logger.warning("Could not find view object with view_id '%s'", view_id)
|
||||
return []
|
||||
|
||||
while root and view.inherit_id:
|
||||
view = view.inherit_id
|
||||
|
||||
result = [view]
|
||||
views_to_return = view
|
||||
|
||||
node = etree.fromstring(view.arch)
|
||||
xpath = "//t[@t-call]"
|
||||
@@ -102,49 +98,44 @@ class view(osv.osv):
|
||||
xpath += "| //t[@t-call-assets]"
|
||||
for child in node.xpath(xpath):
|
||||
try:
|
||||
called_view = self._view_obj(cr, uid, child.get('t-call', child.get('t-call-assets')), context=context)
|
||||
called_view = self._view_obj(child.get('t-call', child.get('t-call-assets')))
|
||||
except ValueError:
|
||||
continue
|
||||
if called_view not in result:
|
||||
result += self._views_get(cr, uid, called_view, options=options, bundles=bundles, context=context)
|
||||
if called_view not in views_to_return:
|
||||
views_to_return += self._views_get(called_view, options=options, bundles=bundles)
|
||||
|
||||
extensions = view.inherit_children_ids
|
||||
if not options:
|
||||
# only active children
|
||||
extensions = (v for v in view.inherit_children_ids if v.active)
|
||||
extensions = view.inherit_children_ids.filtered(lambda view: view.active)
|
||||
|
||||
# Keep options in a deterministic order regardless of their applicability
|
||||
for extension in sorted(extensions, key=lambda v: v.id):
|
||||
for r in self._views_get(
|
||||
cr, uid, extension,
|
||||
# only return optional grandchildren if this child is enabled
|
||||
options=extension.active,
|
||||
context=context, root=False):
|
||||
if r not in result:
|
||||
result.append(r)
|
||||
return result
|
||||
for extension in extensions.sorted(key=lambda v: v.id):
|
||||
# only return optional grandchildren if this child is enabled
|
||||
for ext_view in self._views_get(extension, options=extension.active, root=False):
|
||||
if ext_view not in views_to_return:
|
||||
views_to_return += ext_view
|
||||
return views_to_return
|
||||
|
||||
@tools.ormcache_context('uid', 'xml_id', keys=('website_id',))
|
||||
def get_view_id(self, cr, uid, xml_id, context=None):
|
||||
if context and 'website_id' in context and not isinstance(xml_id, (int, long)):
|
||||
domain = [('key', '=', xml_id), '|', ('website_id', '=', context['website_id']), ('website_id', '=', False)]
|
||||
[view_id] = self.search(cr, uid, domain, order='website_id', limit=1, context=context) or [None]
|
||||
if not view_id:
|
||||
_logger.warning("Could not find view object with xml_id '%s'" % (xml_id))
|
||||
raise ValueError('View %r in website %r not found' % (xml_id, context['website_id']))
|
||||
else:
|
||||
view_id = super(view, self).get_view_id(cr, uid, xml_id, context=context)
|
||||
return view_id
|
||||
@api.model
|
||||
@tools.ormcache_context('self._uid', 'xml_id', keys=('website_id',))
|
||||
def get_view_id(self, xml_id):
|
||||
if 'website_id' in self._context and not isinstance(xml_id, (int, long)):
|
||||
domain = [('key', '=', xml_id), '|', ('website_id', '=', self._context['website_id']), ('website_id', '=', False)]
|
||||
view = self.search(domain, order='website_id', limit=1)
|
||||
if not view:
|
||||
_logger.warning("Could not find view object with xml_id '%s'", xml_id)
|
||||
raise ValueError('View %r in website %r not found' % (xml_id, self._context['website_id']))
|
||||
return view.id
|
||||
return super(View, self).get_view_id(xml_id)
|
||||
|
||||
@api.cr_uid_ids_context
|
||||
def render(self, cr, uid, id_or_xml_id, values=None, engine='ir.qweb', context=None):
|
||||
@api.multi
|
||||
def render(self, values=None, engine='ir.qweb'):
|
||||
""" Render the template. If website is enabled on request, then extend rendering context with website values. """
|
||||
new_context = dict(self._context)
|
||||
if request and getattr(request, 'website_enabled', False):
|
||||
engine = 'ir.qweb'
|
||||
|
||||
if isinstance(id_or_xml_id, list):
|
||||
id_or_xml_id = id_or_xml_id[0]
|
||||
|
||||
qcontext = self._prepare_qcontext(cr, uid, context=context)
|
||||
qcontext = self._prepare_qcontext()
|
||||
|
||||
# add some values
|
||||
if values:
|
||||
@@ -153,78 +144,77 @@ class view(osv.osv):
|
||||
# in edit mode ir.ui.view will tag nodes
|
||||
if not qcontext.get('translatable') and not qcontext.get('rendering_bundle'):
|
||||
if qcontext.get('editable'):
|
||||
context = dict(context, inherit_branding=True)
|
||||
elif request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher'):
|
||||
context = dict(context, inherit_branding_auto=True)
|
||||
new_context = dict(self._context, inherit_branding=True)
|
||||
elif request.env.user.has_group('base.group_website_publisher'):
|
||||
new_context = dict(self._context, inherit_branding_auto=True)
|
||||
|
||||
view_obj = request.website.get_template(id_or_xml_id)
|
||||
if 'main_object' not in qcontext:
|
||||
qcontext['main_object'] = view_obj
|
||||
qcontext['main_object'] = self
|
||||
|
||||
values = qcontext
|
||||
|
||||
return super(view, self).render(cr, uid, id_or_xml_id, values=values, engine=engine, context=context)
|
||||
return super(View, self.with_context(new_context)).render(values, engine=engine)
|
||||
|
||||
def _prepare_qcontext(self, cr, uid, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
company = self.pool['res.company'].browse(cr, SUPERUSER_ID, request.website.company_id.id, context=context)
|
||||
@api.model
|
||||
def _prepare_qcontext(self):
|
||||
""" Returns the qcontext : rendering context with website specific value (required
|
||||
to render website layout template)
|
||||
"""
|
||||
company = request.website.company_id.sudo()
|
||||
|
||||
editable = request.website.is_publisher()
|
||||
translatable = editable and context.get('lang') != request.website.default_lang_code
|
||||
translatable = editable and self._context.get('lang') != request.website.default_lang_code
|
||||
editable = not translatable and editable
|
||||
|
||||
qcontext = dict(
|
||||
context.copy(),
|
||||
self._context.copy(),
|
||||
website=request.website,
|
||||
url_for=website.url_for,
|
||||
slug=website.slug,
|
||||
res_company=company,
|
||||
user_id=self.pool.get("res.users").browse(cr, uid, uid),
|
||||
user_id=self.env["res.users"].browse(self.env.user.id),
|
||||
default_lang_code=request.website.default_lang_code,
|
||||
languages=request.website.get_languages(),
|
||||
translatable=translatable,
|
||||
editable=editable,
|
||||
menu_data=self.pool['ir.ui.menu'].load_menus_root(cr, uid, context=context) if request.website.is_user() else None,
|
||||
menu_data=self.env['ir.ui.menu'].load_menus_root() if request.website.is_user() else None,
|
||||
)
|
||||
return qcontext
|
||||
|
||||
def customize_template_get(self, cr, uid, key, full=False, bundles=False, context=None):
|
||||
@api.model
|
||||
def customize_template_get(self, key, full=False, bundles=False):
|
||||
""" Get inherit view's informations of the template ``key``. By default, only
|
||||
returns ``customize_show`` templates (which can be active or not), if
|
||||
``full=True`` returns inherit view's informations of the template ``key``.
|
||||
``bundles=True`` returns also the asset bundles
|
||||
returns ``customize_show`` templates (which can be active or not), if
|
||||
``full=True`` returns inherit view's informations of the template ``key``.
|
||||
``bundles=True`` returns also the asset bundles
|
||||
"""
|
||||
imd = self.pool['ir.model.data']
|
||||
theme_view_id = imd.xmlid_to_res_id(cr, uid, 'website.theme')
|
||||
user = self.pool['res.users'].browse(cr, uid, context=context)
|
||||
imd = self.env['ir.model.data']
|
||||
view_theme_id = imd.xmlid_to_res_id('website.theme')
|
||||
user = self.env.user
|
||||
user_groups = set(user.groups_id)
|
||||
views = self._views_get(
|
||||
cr, uid, key, bundles=bundles,
|
||||
context=dict(context or {}, active_test=False))
|
||||
views = self.with_context(active_test=False)._views_get(key, bundles=bundles)
|
||||
done = set()
|
||||
result = []
|
||||
for v in views:
|
||||
if not user_groups.issuperset(v.groups_id):
|
||||
for view in views:
|
||||
if not user_groups.issuperset(view.groups_id):
|
||||
continue
|
||||
if full or (v.customize_show and v.inherit_id.id != theme_view_id):
|
||||
if v.inherit_id not in done:
|
||||
if full or (view.customize_show and view.inherit_id.id != view_theme_id):
|
||||
if view.inherit_id not in done:
|
||||
result.append({
|
||||
'name': v.inherit_id.name,
|
||||
'id': v.id,
|
||||
'key': v.key,
|
||||
'inherit_id': v.inherit_id.id,
|
||||
'name': view.inherit_id.name,
|
||||
'id': view.id,
|
||||
'key': view.key,
|
||||
'inherit_id': view.inherit_id.id,
|
||||
'header': True,
|
||||
'active': False
|
||||
})
|
||||
done.add(v.inherit_id)
|
||||
done.add(view.inherit_id)
|
||||
result.append({
|
||||
'name': v.name,
|
||||
'id': v.id,
|
||||
'key': v.key,
|
||||
'inherit_id': v.inherit_id.id,
|
||||
'name': view.name,
|
||||
'id': view.id,
|
||||
'key': view.key,
|
||||
'inherit_id': view.inherit_id.id,
|
||||
'header': False,
|
||||
'active': v.active,
|
||||
'active': view.active,
|
||||
})
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class Company(models.Model):
|
||||
|
||||
_inherit = "res.company"
|
||||
|
||||
@api.multi
|
||||
def google_map_img(self, zoom=8, width=298, height=298):
|
||||
partner = self.sudo().partner_id
|
||||
return partner and partner.google_map_img(zoom, width, height) or None
|
||||
|
||||
@api.multi
|
||||
def google_map_link(self, zoom=8):
|
||||
partner = self.sudo().partner_id
|
||||
return partner and partner.google_map_link(zoom) or None
|
||||
@@ -1,52 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class WebsiteConfigSettings(models.TransientModel):
|
||||
|
||||
class website_config_settings(osv.osv_memory):
|
||||
_name = 'website.config.settings'
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
_columns = {
|
||||
'website_id': fields.many2one('website', string="website", required=True),
|
||||
'website_name': fields.related('website_id', 'name', type="char", string="Website Name"),
|
||||
def _default_website(self):
|
||||
return self.env['website'].search([], limit=1)
|
||||
|
||||
'language_ids': fields.related('website_id', 'language_ids', type='many2many', relation='res.lang', string='Languages'),
|
||||
'default_lang_id': fields.related('website_id', 'default_lang_id', type='many2one', relation='res.lang', string='Default language'),
|
||||
'default_lang_code': fields.related('website_id', 'default_lang_code', type="char", string="Default language code"),
|
||||
'google_analytics_key': fields.related('website_id', 'google_analytics_key', type="char", string='Google Analytics Key'),
|
||||
|
||||
'social_twitter': fields.related('website_id', 'social_twitter', type="char", string='Twitter Account'),
|
||||
'social_facebook': fields.related('website_id', 'social_facebook', type="char", string='Facebook Account'),
|
||||
'social_github': fields.related('website_id', 'social_github', type="char", string='GitHub Account'),
|
||||
'social_linkedin': fields.related('website_id', 'social_linkedin', type="char", string='LinkedIn Account'),
|
||||
'social_youtube': fields.related('website_id', 'social_youtube', type="char", string='Youtube Account'),
|
||||
'social_googleplus': fields.related('website_id', 'social_googleplus', type="char", string='Google+ Account'),
|
||||
'compress_html': fields.related('website_id', 'compress_html', type="boolean", string='Compress rendered HTML for a better Google PageSpeed result'),
|
||||
'cdn_activated': fields.related('website_id', 'cdn_activated', type="boolean", string='Use a Content Delivery Network (CDN)'),
|
||||
'cdn_url': fields.related('website_id', 'cdn_url', type="char", string='CDN Base URL'),
|
||||
'cdn_filters': fields.related('website_id', 'cdn_filters', type="text", string='CDN Filters'),
|
||||
'module_website_form_editor': fields.boolean("Form builder: create and customize forms"),
|
||||
'module_website_version': fields.boolean("A/B testing and versioning"),
|
||||
'favicon': fields.related('website_id', 'favicon', type="binary", string="Favicon", help="This field holds the image used to display a favicon on the website."),
|
||||
}
|
||||
website_id = fields.Many2one('website', string="website", default=_default_website, required=True)
|
||||
website_name = fields.Char('Website Name', related='website_id.name')
|
||||
|
||||
def on_change_website_id(self, cr, uid, ids, website_id, context=None):
|
||||
if not website_id:
|
||||
return {'value': {}}
|
||||
website_data = self.pool.get('website').read(cr, uid, [website_id], [], context=context)[0]
|
||||
values = {'website_name': website_data['name']}
|
||||
for fname, v in website_data.items():
|
||||
if fname in self._columns:
|
||||
values[fname] = v[0] if v and self._columns[fname]._type == 'many2one' else v
|
||||
return {'value' : values}
|
||||
language_ids = fields.Many2many(related='website_id.language_ids', relation='res.lang')
|
||||
default_lang_id = fields.Many2one(related='website_id.default_lang_id', relation='res.lang')
|
||||
default_lang_code = fields.Char('Default language code', related='website_id.default_lang_code')
|
||||
google_analytics_key = fields.Char('Google Analytics Key', related='website_id.google_analytics_key')
|
||||
|
||||
# FIXME in trunk for god sake. Change the fields above to fields.char instead of fields.related,
|
||||
# and create the function set_website who will set the value on the website_id
|
||||
# create does not forward the values to the related many2one. Write does.
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
config_id = super(website_config_settings, self).create(cr, uid, vals, context=context)
|
||||
self.write(cr, uid, config_id, vals, context=context)
|
||||
return config_id
|
||||
|
||||
_defaults = {
|
||||
'website_id': lambda self,cr,uid,c: self.pool.get('website').search(cr, uid, [], context=c)[0],
|
||||
}
|
||||
social_twitter = fields.Char(related='website_id.social_twitter')
|
||||
social_facebook = fields.Char(related='website_id.social_facebook')
|
||||
social_github = fields.Char(related='website_id.social_github')
|
||||
social_linkedin = fields.Char(related='website_id.social_linkedin')
|
||||
social_youtube = fields.Char(related='website_id.social_youtube')
|
||||
social_googleplus = fields.Char(related='website_id.social_googleplus')
|
||||
compress_html = fields.Boolean('Compress rendered HTML for a better Google PageSpeed result', related='website_id.compress_html')
|
||||
cdn_activated = fields.Boolean('Use a Content Delivery Network (CDN)', related='website_id.cdn_activated')
|
||||
cdn_url = fields.Char(related='website_id.cdn_url')
|
||||
cdn_filters = fields.Text(related='website_id.cdn_filters')
|
||||
module_website_form_editor = fields.Boolean("Form builde = create and customize forms")
|
||||
module_website_version = fields.Boolean("A/B testing and versioning")
|
||||
favicon = fields.Binary('Favicon', related='website_id.favicon')
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import werkzeug
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
def urlplus(url, params):
|
||||
return werkzeug.Href(url)(params or None)
|
||||
|
||||
|
||||
class Partner(models.Model):
|
||||
|
||||
_inherit = "res.partner"
|
||||
|
||||
@api.multi
|
||||
def google_map_img(self, zoom=8, width=298, height=298):
|
||||
params = {
|
||||
'center': '%s, %s %s, %s' % (self.street or '', self.city or '', self.zip or '', self.country_id and self.country_id.name_get()[0][1] or ''),
|
||||
'size': "%sx%s" % (height, width),
|
||||
'zoom': zoom,
|
||||
'sensor': 'false',
|
||||
}
|
||||
return urlplus('//maps.googleapis.com/maps/api/staticmap', params)
|
||||
|
||||
@api.multi
|
||||
def google_map_link(self, zoom=10):
|
||||
params = {
|
||||
'q': '%s, %s %s, %s' % (self.street or '', self.city or '', self.zip or '', self.country_id and self.country_id.name_get()[0][1] or ''),
|
||||
'z': zoom,
|
||||
}
|
||||
return urlplus('https://maps.google.com/maps', params)
|
||||
@@ -1,7 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import json
|
||||
|
||||
from openerp import api, models
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class WebsitePlanner(models.Model):
|
||||
|
||||
+308
-372
@@ -1,4 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
import math
|
||||
@@ -6,26 +8,34 @@ import unicodedata
|
||||
import re
|
||||
import urlparse
|
||||
import hashlib
|
||||
|
||||
from sys import maxint
|
||||
|
||||
import werkzeug
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
# optional python-slugify import (https://github.com/un33k/python-slugify)
|
||||
try:
|
||||
import slugify as slugify_lib
|
||||
except ImportError:
|
||||
slugify_lib = None
|
||||
|
||||
import openerp
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv import orm, osv, fields
|
||||
from openerp.tools import html_escape as escape, ustr, image_resize_and_sharpen, image_save_for_web
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
from openerp.http import request
|
||||
from werkzeug.exceptions import NotFound
|
||||
from odoo import api, fields, models
|
||||
from odoo import tools
|
||||
from odoo.tools import ustr
|
||||
from odoo.http import request
|
||||
from odoo.tools.translate import _
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
DEFAULT_CDN_FILTERS = [
|
||||
"^/[^/]+/static/",
|
||||
"^/web/(css|js)/",
|
||||
"^/web/image",
|
||||
"^/web/content",
|
||||
# retrocompatibility
|
||||
"^/website/image/",
|
||||
]
|
||||
|
||||
|
||||
def url_for(path_or_uri, lang=None):
|
||||
if isinstance(path_or_uri, unicode):
|
||||
path_or_uri = path_or_uri.encode('utf-8')
|
||||
@@ -58,6 +68,7 @@ def url_for(path_or_uri, lang=None):
|
||||
|
||||
return location.decode('utf-8')
|
||||
|
||||
|
||||
def is_multilang_url(local_url, langs=None):
|
||||
if not langs:
|
||||
langs = [lg[0] for lg in request.website.get_languages()]
|
||||
@@ -79,17 +90,20 @@ def is_multilang_url(local_url, langs=None):
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
####################################################
|
||||
# Slug API
|
||||
####################################################
|
||||
|
||||
def slugify(s, max_length=None):
|
||||
""" Transform a string to a slug that can be used in a url path.
|
||||
|
||||
This method will first try to do the job with python-slugify if present.
|
||||
Otherwise it will process string by stripping leading and ending spaces,
|
||||
converting unicode chars to ascii, lowering all chars and replacing spaces
|
||||
and underscore with hyphen "-".
|
||||
|
||||
:param s: str
|
||||
:param max_length: int
|
||||
:rtype: str
|
||||
This method will first try to do the job with python-slugify if present.
|
||||
Otherwise it will process string by stripping leading and ending spaces,
|
||||
converting unicode chars to ascii, lowering all chars and replacing spaces
|
||||
and underscore with hyphen "-".
|
||||
:param s: str
|
||||
:param max_length: int
|
||||
:rtype: str
|
||||
"""
|
||||
s = ustr(s)
|
||||
if slugify_lib:
|
||||
@@ -99,35 +113,27 @@ def slugify(s, max_length=None):
|
||||
except TypeError:
|
||||
pass
|
||||
uni = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').decode('ascii')
|
||||
slug = re.sub('[\W_]', ' ', uni).strip().lower()
|
||||
slug = re.sub('[-\s]+', '-', slug)
|
||||
slug_str = re.sub('[\W_]', ' ', uni).strip().lower()
|
||||
slug_str = re.sub('[-\s]+', '-', slug_str)
|
||||
|
||||
return slug_str[:max_length]
|
||||
|
||||
return slug[:max_length]
|
||||
|
||||
def slug(value):
|
||||
if isinstance(value, orm.browse_record):
|
||||
if isinstance(value, models.BaseModel):
|
||||
# [(id, name)] = value.name_get()
|
||||
id, name = value.id, value.display_name
|
||||
identifier, name = value.id, value.display_name
|
||||
else:
|
||||
# assume name_search result tuple
|
||||
id, name = value
|
||||
identifier, name = value
|
||||
slugname = slugify(name or '').strip().strip('-')
|
||||
if not slugname:
|
||||
return str(id)
|
||||
return "%s-%d" % (slugname, id)
|
||||
|
||||
return str(identifier)
|
||||
return "%s-%d" % (slugname, identifier)
|
||||
|
||||
# NOTE: as the pattern is used as it for the ModelConverter (ir_http.py), do not use any flags
|
||||
_UNSLUG_RE = re.compile(r'(?:(\w{1,2}|\w[A-Za-z0-9-_]+?\w)-)?(-?\d+)(?=$|/)')
|
||||
|
||||
DEFAULT_CDN_FILTERS = [
|
||||
"^/[^/]+/static/",
|
||||
"^/web/(css|js)/",
|
||||
"^/web/image",
|
||||
"^/web/content",
|
||||
# retrocompatibility
|
||||
"^/website/image/",
|
||||
]
|
||||
|
||||
def unslug(s):
|
||||
"""Extract slug and id from a string.
|
||||
@@ -138,75 +144,71 @@ def unslug(s):
|
||||
return None, None
|
||||
return m.group(1), int(m.group(2))
|
||||
|
||||
def urlplus(url, params):
|
||||
return werkzeug.Href(url)(params or None)
|
||||
|
||||
class website(osv.osv):
|
||||
def _get_menu(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
menu_obj = self.pool.get('website.menu')
|
||||
for id in ids:
|
||||
menu_ids = menu_obj.search(cr, uid, [('parent_id', '=', False), ('website_id', '=', id)], order='id', context=context)
|
||||
res[id] = menu_ids and menu_ids[0] or False
|
||||
return res
|
||||
class Website(models.Model):
|
||||
|
||||
def _active_languages(self, cr, uid, context=None):
|
||||
return self.pool['res.lang'].search(cr, uid, [], context=context)
|
||||
|
||||
def _default_language(self, cr, uid, context=None):
|
||||
lang_code = self.pool['ir.values'].get_default(cr, uid, 'res.partner', 'lang')
|
||||
def_langs = self.pool['res.lang'].search(cr, uid, [('code', '=', lang_code)], context=context)
|
||||
return def_langs[0] if def_langs else self._active_languages(cr, uid, context=context)[0]
|
||||
|
||||
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
|
||||
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
|
||||
_description = "Website"
|
||||
_columns = {
|
||||
'name': fields.char('Website Name'),
|
||||
'domain': fields.char('Website Domain'),
|
||||
'company_id': fields.many2one('res.company', string="Company"),
|
||||
'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'),
|
||||
'default_lang_id': fields.many2one('res.lang', string="Default language"),
|
||||
'default_lang_code': fields.related('default_lang_id', 'code', type="char", string="Default language code", store=True),
|
||||
'social_twitter': fields.char('Twitter Account'),
|
||||
'social_facebook': fields.char('Facebook Account'),
|
||||
'social_github': fields.char('GitHub Account'),
|
||||
'social_linkedin': fields.char('LinkedIn Account'),
|
||||
'social_youtube': fields.char('Youtube Account'),
|
||||
'social_googleplus': fields.char('Google+ Account'),
|
||||
'google_analytics_key': fields.char('Google Analytics Key'),
|
||||
'user_id': fields.many2one('res.users', string='Public User'),
|
||||
'compress_html': fields.boolean('Compress HTML'),
|
||||
'cdn_activated': fields.boolean('Activate CDN for assets'),
|
||||
'cdn_url': fields.char('CDN Base URL'),
|
||||
'cdn_filters': fields.text('CDN Filters', help="URL matching those filters will be rewritten using the CDN Base URL"),
|
||||
'partner_id': fields.related('user_id','partner_id', type='many2one', relation='res.partner', string='Public Partner'),
|
||||
'menu_id': fields.function(_get_menu, relation='website.menu', type='many2one', string='Main Menu'),
|
||||
'favicon': fields.binary(string="Website Favicon", help="This field holds the image used to display a favicon on the website."),
|
||||
}
|
||||
_defaults = {
|
||||
'user_id': lambda self,cr,uid,c: self.pool['ir.model.data'].xmlid_to_res_id(cr, openerp.SUPERUSER_ID, 'base.public_user'),
|
||||
'company_id': lambda self,cr,uid,c: self.pool['ir.model.data'].xmlid_to_res_id(cr, openerp.SUPERUSER_ID,'base.main_company'),
|
||||
'compress_html': False,
|
||||
'cdn_activated': False,
|
||||
'cdn_url': '',
|
||||
'cdn_filters': '\n'.join(DEFAULT_CDN_FILTERS),
|
||||
'language_ids': _active_languages,
|
||||
'default_lang_id': _default_language,
|
||||
}
|
||||
|
||||
def _active_languages(self):
|
||||
return self.env['res.lang'].search([]).ids
|
||||
|
||||
def _default_language(self):
|
||||
lang_code = self.env['ir.values'].get_default('res.partner', 'lang')
|
||||
def_lang = self.env['res.lang'].search([('code', '=', lang_code)], limit=1)
|
||||
return def_lang.id if def_lang else self._active_languages()[0]
|
||||
|
||||
name = fields.Char('Website Name')
|
||||
domain = fields.Char('Website Domain')
|
||||
company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.ref('base.main_company').id)
|
||||
language_ids = fields.Many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages', default=_active_languages)
|
||||
default_lang_id = fields.Many2one('res.lang', string="Default language", default=_default_language)
|
||||
default_lang_code = fields.Char(related='default_lang_id.code', string="Default language code", store=True)
|
||||
|
||||
social_twitter = fields.Char('Twitter Account')
|
||||
social_facebook = fields.Char('Facebook Account')
|
||||
social_github = fields.Char('GitHub Account')
|
||||
social_linkedin = fields.Char('LinkedIn Account')
|
||||
social_youtube = fields.Char('Youtube Account')
|
||||
social_googleplus = fields.Char('Google+ Account')
|
||||
google_analytics_key = fields.Char('Google Analytics Key')
|
||||
|
||||
user_id = fields.Many2one('res.users', string='Public User', default=lambda self: self.env.ref('base.public_user').id)
|
||||
compress_html = fields.Boolean('Compress HTML')
|
||||
cdn_activated = fields.Boolean('Activate CDN for assets')
|
||||
cdn_url = fields.Char('CDN Base URL', default='')
|
||||
cdn_filters = fields.Text('CDN Filters', default=lambda s: '\n'.join(DEFAULT_CDN_FILTERS), help="URL matching those filters will be rewritten using the CDN Base URL")
|
||||
partner_id = fields.Many2one(related='user_id.partner_id', relation='res.partner', string='Public Partner')
|
||||
menu_id = fields.Many2one('website.menu', compute='_compute_menu', string='Main Menu')
|
||||
favicon = fields.Binary(string="Website Favicon", help="This field holds the image used to display a favicon on the website.")
|
||||
|
||||
@api.multi
|
||||
def _compute_menu(self):
|
||||
Menu = self.env['website.menu']
|
||||
for website in self:
|
||||
website.menu_id = Menu.search([('parent_id', '=', False), ('website_id', '=', website.id)], order='id', limit=1).id
|
||||
|
||||
# cf. Wizard hack in website_views.xml
|
||||
def noop(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
@api.multi
|
||||
def write(self, values):
|
||||
self._get_languages.clear_cache(self)
|
||||
return super(website, self).write(cr, uid, ids, vals, context)
|
||||
return super(Website, self).write(values)
|
||||
|
||||
def new_page(self, cr, uid, name, template='website.default_page', ispage=True, context=None):
|
||||
context = context or {}
|
||||
imd = self.pool.get('ir.model.data')
|
||||
view = self.pool.get('ir.ui.view')
|
||||
template_module, template_name = template.split('.')
|
||||
#----------------------------------------------------------
|
||||
# Page Management
|
||||
#----------------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def new_page(self, name, template='website.default_page', ispage=True):
|
||||
""" Create a new website page, and assign it a xmlid based on the given one
|
||||
:param name : the name of the page
|
||||
:param template : potential xml_id of the page to create
|
||||
"""
|
||||
template_module, dummy = template.split('.')
|
||||
website_id = self._context.get('website_id')
|
||||
|
||||
# completely arbitrary max_length
|
||||
page_name = slugify(name, max_length=50)
|
||||
@@ -214,77 +216,76 @@ class website(osv.osv):
|
||||
|
||||
# find a free xmlid
|
||||
inc = 0
|
||||
dom = [('website_id', '=', False), ('website_id', '=', context.get('website_id'))]
|
||||
while view.search(cr, openerp.SUPERUSER_ID, [('key', '=', page_xmlid), '|'] + dom, context=dict(context or {}, active_test=False)):
|
||||
domain_static = [('website_id', '=', False), ('website_id', '=', website_id)]
|
||||
while self.env['ir.ui.view'].with_context(active_test=False).sudo().search([('key', '=', page_xmlid), '|'] + domain_static):
|
||||
inc += 1
|
||||
page_xmlid = "%s.%s" % (template_module, page_name + (inc and "-%s" % inc or ""))
|
||||
page_xmlid = "%s.%s" % (template_module, page_name + ("-%s" % inc if inc else ""))
|
||||
page_name += (inc and "-%s" % inc or "")
|
||||
|
||||
# new page
|
||||
_, template_id = imd.get_object_reference(cr, uid, template_module, template_name)
|
||||
website_id = context.get('website_id')
|
||||
key = template_module+'.'+page_name
|
||||
page_id = view.copy(cr, uid, template_id, {'website_id': website_id, 'key': key}, context=context)
|
||||
page = view.browse(cr, uid, page_id, context=dict(context, lang=None))
|
||||
page.write({
|
||||
template_record = self.env.ref(template)
|
||||
key = '%s.%s' % (template_module, page_name)
|
||||
page = template_record.copy({'website_id': website_id, 'key': key})
|
||||
page.with_context(lang=None).write({
|
||||
'arch': page.arch.replace(template, page_xmlid),
|
||||
'name': page_name,
|
||||
'page': ispage,
|
||||
})
|
||||
return page_xmlid
|
||||
|
||||
def key_to_view_id(self, cr, uid, view_id, context=None):
|
||||
View = self.pool.get('ir.ui.view')
|
||||
return View.search(cr, uid, [
|
||||
def key_to_view_id(self, view_id):
|
||||
return self.env['ir.ui.view'].search([
|
||||
('id', '=', view_id),
|
||||
"|", ('website_id', '=', context.get('website_id')), ('website_id', '=', False),
|
||||
'|', ('website_id', '=', self._context.get('website_id')), ('website_id', '=', False),
|
||||
('page', '=', True),
|
||||
('type', '=', 'qweb')
|
||||
], context=context)
|
||||
])
|
||||
|
||||
def delete_page(self, cr, uid, view_id, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
View = self.pool.get('ir.ui.view')
|
||||
view_find = self.key_to_view_id(cr, uid, view_id, context=context)
|
||||
if view_find:
|
||||
View.unlink(cr, uid, view_find, context=context)
|
||||
|
||||
def rename_page(self, cr, uid, view_id, new_name, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
View = self.pool.get('ir.ui.view')
|
||||
view_find = self.key_to_view_id(cr, uid, view_id, context=context)
|
||||
if view_find:
|
||||
v = View.browse(cr, uid, view_find, context=context)
|
||||
@api.model
|
||||
def delete_page(self, view_id):
|
||||
""" Delete a page, given its identifier
|
||||
:param view_id : ir.ui.view identifier
|
||||
"""
|
||||
view = self.key_to_view_id(view_id)
|
||||
if view:
|
||||
view.unlink()
|
||||
|
||||
@api.model
|
||||
def rename_page(self, view_id, new_name):
|
||||
""" Change the name of the given page
|
||||
:param view_id : id of the view to rename
|
||||
:param new_name : name to use
|
||||
"""
|
||||
view = self.key_to_view_id(view_id)
|
||||
if view:
|
||||
# slugify the new name and prefix by module if
|
||||
# not already done by end user
|
||||
new_name = slugify(new_name, max_length=50)
|
||||
# Prefix by module if not already done by end user
|
||||
prefix = v.key.split('.')[0]
|
||||
prefix = view.key.split('.')[0]
|
||||
if not new_name.startswith(prefix):
|
||||
new_name = "%s.%s" % (prefix, new_name)
|
||||
|
||||
View.write(cr, uid, view_find, {
|
||||
view.write({
|
||||
'key': new_name,
|
||||
'arch_db': v.arch_db.replace(v.key, new_name, 1)
|
||||
'arch_db': view.arch_db.replace(view.key, new_name, 1)
|
||||
})
|
||||
return new_name
|
||||
return False
|
||||
|
||||
def page_search_dependencies(self, cr, uid, view_id=False, context=None):
|
||||
dep = {}
|
||||
@api.model
|
||||
def page_search_dependencies(self, view_id=False):
|
||||
""" Search dependencies just for information. It will not catch 100%
|
||||
of dependencies and False positive is more than possible
|
||||
Each module could add dependences in this dict
|
||||
:returns a dictionnary where key is the 'categorie' of object related to the given
|
||||
view, and the value is the list of text and link to the resource using given page
|
||||
"""
|
||||
dependencies = {}
|
||||
if not view_id:
|
||||
return dep
|
||||
return dependencies
|
||||
|
||||
# search dependencies just for information.
|
||||
# It will not catch 100% of dependencies and False positive is more than possible
|
||||
# Each module could add dependences in this dict
|
||||
if context is None:
|
||||
context = {}
|
||||
View = self.pool.get('ir.ui.view')
|
||||
Menu = self.pool.get('website.menu')
|
||||
|
||||
view = View.browse(cr, uid, view_id, context=context)
|
||||
website_id = context.get('website_id')
|
||||
view = self.env['ir.ui.view'].browse(view_id)
|
||||
website_id = self._context.get('website_id')
|
||||
name = view.key.replace("website.", "")
|
||||
fullname = "website.%s" % name
|
||||
|
||||
@@ -294,18 +295,18 @@ class website(osv.osv):
|
||||
'|', ('website_id', '=', website_id), ('website_id', '=', False),
|
||||
'|', ('arch_db', 'ilike', '/page/%s' % name), ('arch_db', 'ilike', '/page/%s' % fullname)
|
||||
]
|
||||
pages = View.search(cr, uid, page_search_dom, context=context)
|
||||
if pages:
|
||||
page_key = _('Page')
|
||||
dep[page_key] = []
|
||||
for page in View.browse(cr, uid, pages, context=context):
|
||||
|
||||
page_key = _('Page')
|
||||
pages = self.env['ir.ui.view'].search(page_search_dom)
|
||||
for page in pages:
|
||||
dependencies.setdefault(page_key, [])
|
||||
if page.page:
|
||||
dep[page_key].append({
|
||||
dependencies[page_key].append({
|
||||
'text': _('Page <b>%s</b> contains a link to this page') % page.key,
|
||||
'link': '/page/%s' % page.key
|
||||
})
|
||||
else:
|
||||
dep[page_key].append({
|
||||
dependencies[page_key].append({
|
||||
'text': _('Template <b>%s (id:%s)</b> contains a link to this page') % (page.key, page.id),
|
||||
'link': '#'
|
||||
})
|
||||
@@ -316,73 +317,65 @@ class website(osv.osv):
|
||||
'|', ('url', 'ilike', '/page/%s' % name), ('url', 'ilike', '/page/%s' % fullname)
|
||||
]
|
||||
|
||||
menus = Menu.search(cr, uid, menu_search_dom, context=context)
|
||||
if menus:
|
||||
menu_key = _('Menu')
|
||||
dep[menu_key] = []
|
||||
for menu in Menu.browse(cr, uid, menus, context=context):
|
||||
dep[menu_key].append({
|
||||
menu_key = _('Menu')
|
||||
menus = self.env['website.menu'].search(menu_search_dom)
|
||||
for menu in menus:
|
||||
dependencies.setdefault(menu_key, []).append({
|
||||
'text': _('This page is in the menu <b>%s</b>') % menu.name,
|
||||
'link': False
|
||||
})
|
||||
|
||||
return dep
|
||||
return dependencies
|
||||
|
||||
def page_for_name(self, cr, uid, ids, name, module='website', context=None):
|
||||
# whatever
|
||||
return '%s.%s' % (module, slugify(name, max_length=50))
|
||||
|
||||
def page_exists(self, cr, uid, ids, name, module='website', context=None):
|
||||
@api.model
|
||||
def page_exists(self, name, module='website'):
|
||||
try:
|
||||
name = (name or "").replace("/page/website.", "").replace("/page/", "")
|
||||
if not name:
|
||||
return False
|
||||
return self.pool["ir.model.data"].get_object_reference(cr, uid, module, name)
|
||||
return self.env.ref('%s.%s' % module, name)
|
||||
except:
|
||||
return False
|
||||
|
||||
@openerp.tools.ormcache('id')
|
||||
def _get_languages(self, cr, uid, id, context=None):
|
||||
website = self.browse(cr, uid, id)
|
||||
return [(lg.code, lg.name) for lg in website.language_ids]
|
||||
#----------------------------------------------------------
|
||||
# Languages
|
||||
#----------------------------------------------------------
|
||||
|
||||
def get_cdn_url(self, cr, uid, uri, context=None):
|
||||
# Currently only usable in a website_enable request context
|
||||
if request and request.website and not request.debug and request.website.user_id.id == request.uid:
|
||||
cdn_url = request.website.cdn_url
|
||||
cdn_filters = (request.website.cdn_filters or '').splitlines()
|
||||
for flt in cdn_filters:
|
||||
if flt and re.match(flt, uri):
|
||||
return urlparse.urljoin(cdn_url, uri)
|
||||
return uri
|
||||
@api.multi
|
||||
def get_languages(self):
|
||||
self.ensure_one()
|
||||
return self._get_languages()
|
||||
|
||||
def get_languages(self, cr, uid, ids, context=None):
|
||||
return self._get_languages(cr, uid, ids[0])
|
||||
@tools.cache('self.id')
|
||||
def _get_languages(self):
|
||||
return [(lg.code, lg.name) for lg in self.language_ids]
|
||||
|
||||
def get_alternate_languages(self, cr, uid, ids, req=None, context=None):
|
||||
@api.multi
|
||||
def get_alternate_languages(self, req=None):
|
||||
langs = []
|
||||
if req is None:
|
||||
req = request.httprequest
|
||||
default = self.get_current_website(cr, uid, context=context).default_lang_code
|
||||
default = self.get_current_website().default_lang_code
|
||||
shorts = []
|
||||
|
||||
def get_url_localized(router, lang):
|
||||
arguments = dict(request.endpoint_arguments)
|
||||
for k, v in arguments.items():
|
||||
if isinstance(v, orm.browse_record):
|
||||
arguments[k] = v.with_context(lang=lang)
|
||||
for key, val in arguments.items():
|
||||
if isinstance(val, models.BaseModel):
|
||||
arguments[key] = val.with_context(lang=lang)
|
||||
return router.build(request.endpoint, arguments)
|
||||
|
||||
router = request.httprequest.app.get_db_router(request.db).bind('')
|
||||
for code, name in self.get_languages(cr, uid, ids, context=context):
|
||||
for code, dummy in self.get_languages():
|
||||
lg_path = ('/' + code) if code != default else ''
|
||||
lg = code.split('_')
|
||||
shorts.append(lg[0])
|
||||
uri = request.endpoint and get_url_localized(router, code) or request.httprequest.path
|
||||
lg_codes = code.split('_')
|
||||
shorts.append(lg_codes[0])
|
||||
uri = get_url_localized(router, code) if request.endpoint else request.httprequest.path
|
||||
if req.query_string:
|
||||
uri += '?' + req.query_string
|
||||
lang = {
|
||||
'hreflang': ('-'.join(lg)).lower(),
|
||||
'short': lg[0],
|
||||
'hreflang': ('-'.join(lg_codes)).lower(),
|
||||
'short': lg_codes[0],
|
||||
'href': req.url_root[0:-1] + lg_path + uri,
|
||||
}
|
||||
langs.append(lang)
|
||||
@@ -391,47 +384,59 @@ class website(osv.osv):
|
||||
lang['hreflang'] = lang['short']
|
||||
return langs
|
||||
|
||||
@openerp.tools.ormcache('domain_name')
|
||||
def _get_current_website_id(self, cr, uid, domain_name, context=None):
|
||||
ids = self.search(cr, uid, [('domain', '=', domain_name)], limit=1, context=context)
|
||||
return ids and ids[0] or self.search(cr, uid, [], limit=1)[0]
|
||||
#----------------------------------------------------------
|
||||
# Utilities
|
||||
#----------------------------------------------------------
|
||||
|
||||
def get_current_website(self, cr, uid, context=None):
|
||||
@api.model
|
||||
def get_current_website(self):
|
||||
domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0]
|
||||
website_id = self._get_current_website_id(cr, uid, domain_name)
|
||||
website_id = self._get_current_website_id(domain_name)
|
||||
request.context['website_id'] = website_id
|
||||
return self.browse(cr, uid, website_id, context=context)
|
||||
return self.browse(website_id)
|
||||
|
||||
def is_publisher(self, cr, uid, ids, context=None):
|
||||
Access = self.pool['ir.model.access']
|
||||
is_website_publisher = Access.check(cr, uid, 'ir.ui.view', 'write', False, context=context)
|
||||
return is_website_publisher
|
||||
@tools.cache('domain_name')
|
||||
def _get_current_website_id(self, domain_name):
|
||||
""" Reminder : cached method should be return record, since they will use a closed cursor. """
|
||||
website = self.search([('domain', '=', domain_name)], limit=1)
|
||||
if not website:
|
||||
website = self.search([], limit=1)
|
||||
return website.id
|
||||
|
||||
def is_user(self, cr, uid, ids, context=None):
|
||||
Access = self.pool['ir.model.access']
|
||||
return Access.check(cr, uid, 'ir.ui.menu', 'read', False, context=context)
|
||||
@api.model
|
||||
def is_publisher(self):
|
||||
return self.env['ir.model.access'].check('ir.ui.view', 'write', False)
|
||||
|
||||
def get_template(self, cr, uid, ids, template, context=None):
|
||||
View = self.pool['ir.ui.view']
|
||||
@api.model
|
||||
def is_user(self):
|
||||
return self.env['ir.model.access'].check('ir.ui.menu', 'read', False)
|
||||
|
||||
@api.model
|
||||
def get_template(self, template):
|
||||
View = self.env['ir.ui.view']
|
||||
if isinstance(template, (int, long)):
|
||||
view_id = template
|
||||
else:
|
||||
if '.' not in template:
|
||||
template = 'website.%s' % template
|
||||
view_id = View.get_view_id(cr, uid, template, context=context)
|
||||
view_id = View.get_view_id(template)
|
||||
if not view_id:
|
||||
raise NotFound
|
||||
return View.browse(cr, uid, view_id, context=context)
|
||||
return View.browse(view_id)
|
||||
|
||||
def _render(self, cr, uid, ids, template, values=None, context=None):
|
||||
# TODO: remove this. (just kept for backward api compatibility for saas-3)
|
||||
return self.pool['ir.ui.view'].render_template(cr, uid, template, values=values, context=context)
|
||||
|
||||
def render(self, cr, uid, ids, template, values=None, status_code=None, context=None):
|
||||
# TODO: remove this. (just kept for backward api compatibility for saas-3)
|
||||
return request.render(template, values, uid=uid)
|
||||
|
||||
def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None, context=None):
|
||||
@api.model
|
||||
def pager(self, url, total, page=1, step=30, scope=5, url_args=None):
|
||||
""" Generate a dict with required value to render `website.pager` template. This method compute
|
||||
url, page range to display, ... in the pager.
|
||||
:param url : base url of the page link
|
||||
:param total : number total of item to be splitted into pages
|
||||
:param page : current page
|
||||
:param step : item per page
|
||||
:param scope : number of page to display on pager
|
||||
:param url_args : additionnal parameters to add as query params to page url
|
||||
:type url_args : dict
|
||||
:returns dict
|
||||
"""
|
||||
# Compute Pager
|
||||
page_count = int(math.ceil(float(total) / step))
|
||||
|
||||
@@ -474,17 +479,15 @@ class website(osv.osv):
|
||||
'num': pmax
|
||||
},
|
||||
"pages": [
|
||||
{'url': get_url(page), 'num': page}
|
||||
for page in xrange(pmin, pmax+1)
|
||||
{'url': get_url(page), 'num': page} for page in xrange(pmin, pmax+1)
|
||||
]
|
||||
}
|
||||
|
||||
def rule_is_enumerable(self, rule):
|
||||
""" Checks that it is possible to generate sensible GET queries for
|
||||
a given rule (if the endpoint matches its own requirements)
|
||||
|
||||
:type rule: werkzeug.routing.Rule
|
||||
:rtype: bool
|
||||
a given rule (if the endpoint matches its own requirements)
|
||||
:type rule: werkzeug.routing.Rule
|
||||
:rtype: bool
|
||||
"""
|
||||
endpoint = rule.endpoint
|
||||
methods = endpoint.routing.get('methods') or ['GET']
|
||||
@@ -506,21 +509,20 @@ class website(osv.osv):
|
||||
args = spec.args[1:(-defaults_count or None)]
|
||||
|
||||
# check that all args have a converter
|
||||
return all( (arg in rule._converters) for arg in args)
|
||||
return all((arg in rule._converters) for arg in args)
|
||||
|
||||
def enumerate_pages(self, cr, uid, ids, query_string=None, context=None):
|
||||
@api.multi
|
||||
def enumerate_pages(self, query_string=None):
|
||||
""" Available pages in the website/CMS. This is mostly used for links
|
||||
generation and can be overridden by modules setting up new HTML
|
||||
controllers for dynamic pages (e.g. blog).
|
||||
|
||||
By default, returns template views marked as pages.
|
||||
|
||||
:param str query_string: a (user-provided) string, fetches pages
|
||||
matching the string
|
||||
:returns: a list of mappings with two keys: ``name`` is the displayable
|
||||
name of the resource (page), ``url`` is the absolute URL
|
||||
of the same.
|
||||
:rtype: list({name: str, url: str})
|
||||
generation and can be overridden by modules setting up new HTML
|
||||
controllers for dynamic pages (e.g. blog).
|
||||
By default, returns template views marked as pages.
|
||||
:param str query_string: a (user-provided) string, fetches pages
|
||||
matching the string
|
||||
:returns: a list of mappings with two keys: ``name`` is the displayable
|
||||
name of the resource (page), ``url`` is the absolute URL
|
||||
of the same.
|
||||
:rtype: list({name: str, url: str})
|
||||
"""
|
||||
router = request.httprequest.app.get_db_router(request.db)
|
||||
# Force enumeration to be performed as public user
|
||||
@@ -535,23 +537,23 @@ class website(osv.osv):
|
||||
values = [{}]
|
||||
convitems = converters.items()
|
||||
# converters with a domain are processed after the other ones
|
||||
gd = lambda x: hasattr(x[1], 'domain') and (x[1].domain <> '[]')
|
||||
gd = lambda x: hasattr(x[1], 'domain') and (x[1].domain != '[]')
|
||||
convitems.sort(lambda x, y: cmp(gd(x), gd(y)))
|
||||
for (i,(name, converter)) in enumerate(convitems):
|
||||
for (i, (name, converter)) in enumerate(convitems):
|
||||
newval = []
|
||||
for val in values:
|
||||
query = i==(len(convitems)-1) and query_string
|
||||
for v in converter.generate(request.cr, uid, query=query, args=val, context=context):
|
||||
newval.append( val.copy() )
|
||||
v[name] = v['loc']
|
||||
del v['loc']
|
||||
newval[-1].update(v)
|
||||
query = i == len(convitems)-1 and query_string
|
||||
for value_dict in converter.generate(query=query, args=val):
|
||||
newval.append(val.copy())
|
||||
value_dict[name] = value_dict['loc']
|
||||
del value_dict['loc']
|
||||
newval[-1].update(value_dict)
|
||||
values = newval
|
||||
|
||||
for value in values:
|
||||
domain_part, url = rule.build(value, append_unknown=False)
|
||||
page = {'loc': url}
|
||||
for key,val in value.items():
|
||||
for key, val in value.items():
|
||||
if key.startswith('__'):
|
||||
page[key[2:]] = val
|
||||
if url in ('/sitemap.xml',):
|
||||
@@ -562,54 +564,63 @@ class website(osv.osv):
|
||||
|
||||
yield page
|
||||
|
||||
def search_pages(self, cr, uid, ids, needle=None, limit=None, context=None):
|
||||
@api.multi
|
||||
def search_pages(self, needle=None, limit=None):
|
||||
name = re.sub(r"^/p(a(g(e(/(w(e(b(s(i(t(e(\.)?)?)?)?)?)?)?)?)?)?)?)?", "", needle or "")
|
||||
res = []
|
||||
for page in self.enumerate_pages(cr, uid, ids, query_string=name, context=context):
|
||||
for page in self.enumerate_pages(query_string=name):
|
||||
if needle in page['loc']:
|
||||
res.append(page)
|
||||
if len(res) == limit:
|
||||
break
|
||||
return res
|
||||
|
||||
def image_url(self, cr, uid, record, field, size=None, context=None):
|
||||
"""Returns a local url that points to the image field of a given browse record."""
|
||||
@api.model
|
||||
def image_url(self, record, field, size=None):
|
||||
""" Returns a local url that points to the image field of a given browse record. """
|
||||
sudo_record = record.sudo()
|
||||
sha = hashlib.sha1(getattr(sudo_record, '__last_update')).hexdigest()[0:7]
|
||||
size = '' if size is None else '/%s' % size
|
||||
return '/web/image/%s/%s/%s%s?unique=%s' % (record._name, record.id, field, size, sha)
|
||||
|
||||
class website_menu(osv.osv):
|
||||
@api.model
|
||||
def get_cdn_url(self, uri):
|
||||
# Currently only usable in a website_enable request context
|
||||
if request and request.website and not request.debug and request.website.user_id.id == request.uid:
|
||||
cdn_url = request.website.cdn_url
|
||||
cdn_filters = (request.website.cdn_filters or '').splitlines()
|
||||
for flt in cdn_filters:
|
||||
if flt and re.match(flt, uri):
|
||||
return urlparse.urljoin(cdn_url, uri)
|
||||
return uri
|
||||
|
||||
|
||||
class Menu(models.Model):
|
||||
|
||||
_name = "website.menu"
|
||||
_description = "Website Menu"
|
||||
_columns = {
|
||||
'name': fields.char('Menu', required=True, translate=True),
|
||||
'url': fields.char('Url'),
|
||||
'new_window': fields.boolean('New Window'),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
# TODO: support multiwebsite once done for ir.ui.views
|
||||
'website_id': fields.many2one('website', 'Website'),
|
||||
'parent_id': fields.many2one('website.menu', 'Parent Menu', select=True, ondelete="cascade"),
|
||||
'child_id': fields.one2many('website.menu', 'parent_id', string='Child Menus'),
|
||||
'parent_left': fields.integer('Parent Left', select=True),
|
||||
'parent_right': fields.integer('Parent Right', select=True),
|
||||
}
|
||||
|
||||
def __defaults_sequence(self, cr, uid, context):
|
||||
menu = self.search_read(cr, uid, [(1,"=",1)], ["sequence"], limit=1, order="sequence DESC", context=context)
|
||||
return menu and menu[0]["sequence"] or 0
|
||||
|
||||
_defaults = {
|
||||
'url': '',
|
||||
'sequence': __defaults_sequence,
|
||||
'new_window': False,
|
||||
}
|
||||
_parent_store = True
|
||||
_parent_order = 'sequence'
|
||||
_order = "sequence"
|
||||
|
||||
def _default_sequence(self):
|
||||
menu = self.search(["sequence"], limit=1, order="sequence DESC")
|
||||
return menu.sequence or 0
|
||||
|
||||
name = fields.Char('Menu', required=True, translate=True)
|
||||
url = fields.Char('Url', default='')
|
||||
new_window = fields.Boolean('New Window')
|
||||
sequence = fields.Integer(defualt=_default_sequence)
|
||||
website_id = fields.Many2one('website', 'Website') # TODO: support multiwebsite once done for ir.ui.views
|
||||
parent_id = fields.Many2one('website.menu', 'Parent Menu', index=True, ondelete="cascade")
|
||||
child_id = fields.One2many('website.menu', 'parent_id', string='Child Menus')
|
||||
parent_left = fields.Integer('Parent Left', index=True)
|
||||
parent_right = fields.Integer('Parent Rigth', index=True)
|
||||
|
||||
# would be better to take a menu_id as argument
|
||||
def get_tree(self, cr, uid, website_id, menu_id=None, context=None):
|
||||
@api.model
|
||||
def get_tree(self, website_id, menu_id=None):
|
||||
def make_tree(node):
|
||||
menu_node = dict(
|
||||
id=node.id,
|
||||
@@ -624,12 +635,13 @@ class website_menu(osv.osv):
|
||||
menu_node['children'].append(make_tree(child))
|
||||
return menu_node
|
||||
if menu_id:
|
||||
menu = self.browse(cr, uid, menu_id, context=context)
|
||||
menu = self.browse(menu_id)
|
||||
else:
|
||||
menu = self.pool.get('website').browse(cr, uid, website_id, context=context).menu_id
|
||||
menu = self.env['website'].browse(website_id).menu_id
|
||||
return make_tree(menu)
|
||||
|
||||
def save(self, cr, uid, website_id, data, context=None):
|
||||
@api.model
|
||||
def save(self, website_id, data):
|
||||
def replace_id(old_id, new_id):
|
||||
for menu in data['data']:
|
||||
if menu['id'] == old_id:
|
||||
@@ -638,125 +650,49 @@ class website_menu(osv.osv):
|
||||
menu['parent_id'] = new_id
|
||||
to_delete = data['to_delete']
|
||||
if to_delete:
|
||||
self.unlink(cr, uid, to_delete, context=context)
|
||||
self.browse(to_delete).unlink()
|
||||
for menu in data['data']:
|
||||
mid = menu['id']
|
||||
if isinstance(mid, basestring):
|
||||
new_id = self.create(cr, uid, {'name': menu['name']}, context=context)
|
||||
replace_id(mid, new_id)
|
||||
new_menu = self.create({'name': menu['name']})
|
||||
replace_id(mid, new_menu.id)
|
||||
for menu in data['data']:
|
||||
self.write(cr, uid, [menu['id']], menu, context=context)
|
||||
self.browse(menu['id']).write(menu)
|
||||
return True
|
||||
|
||||
|
||||
class ir_attachment(osv.osv):
|
||||
_inherit = "ir.attachment"
|
||||
class SeoMetadata(models.AbstractModel):
|
||||
|
||||
_columns = {
|
||||
'website_url': fields.related("local_url", string="Attachment URL", type='char', deprecated=True), # related for backward compatibility with saas-6
|
||||
}
|
||||
|
||||
class res_partner(osv.osv):
|
||||
_inherit = "res.partner"
|
||||
|
||||
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
|
||||
partner = self.browse(cr, uid, ids[0], context=context)
|
||||
params = {
|
||||
'center': '%s, %s %s, %s' % (partner.street or '', partner.city or '', partner.zip or '', partner.country_id and partner.country_id.name_get()[0][1] or ''),
|
||||
'size': "%sx%s" % (height, width),
|
||||
'zoom': zoom,
|
||||
'sensor': 'false',
|
||||
}
|
||||
return urlplus('//maps.googleapis.com/maps/api/staticmap' , params)
|
||||
|
||||
def google_map_link(self, cr, uid, ids, zoom=10, context=None):
|
||||
partner = self.browse(cr, uid, ids[0], context=context)
|
||||
params = {
|
||||
'q': '%s, %s %s, %s' % (partner.street or '', partner.city or '', partner.zip or '', partner.country_id and partner.country_id.name_get()[0][1] or ''),
|
||||
'z': zoom,
|
||||
}
|
||||
return urlplus('https://maps.google.com/maps' , params)
|
||||
|
||||
class res_company(osv.osv):
|
||||
_inherit = "res.company"
|
||||
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
|
||||
partner = self.browse(cr, openerp.SUPERUSER_ID, ids[0], context=context).partner_id
|
||||
return partner and partner.google_map_img(zoom, width, height, context=context) or None
|
||||
def google_map_link(self, cr, uid, ids, zoom=8, context=None):
|
||||
partner = self.browse(cr, openerp.SUPERUSER_ID, ids[0], context=context).partner_id
|
||||
return partner and partner.google_map_link(zoom, context=context) or None
|
||||
|
||||
class base_language_install(osv.osv_memory):
|
||||
_inherit = "base.language.install"
|
||||
_columns = {
|
||||
'website_ids': fields.many2many('website', string='Websites to translate'),
|
||||
}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
defaults = super(base_language_install, self).default_get(cr, uid, fields, context)
|
||||
website_id = context.get('params', {}).get('website_id')
|
||||
if website_id:
|
||||
if 'website_ids' not in defaults:
|
||||
defaults['website_ids'] = []
|
||||
defaults['website_ids'].append(website_id)
|
||||
return defaults
|
||||
|
||||
def lang_install(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
action = super(base_language_install, self).lang_install(cr, uid, ids, context)
|
||||
language_obj = self.browse(cr, uid, ids)[0]
|
||||
website_ids = [website.id for website in language_obj['website_ids']]
|
||||
lang_id = self.pool['res.lang'].search(cr, uid, [('code', '=', language_obj['lang'])])
|
||||
if website_ids and lang_id:
|
||||
data = {'language_ids': [(4, lang_id[0])]}
|
||||
self.pool['website'].write(cr, uid, website_ids, data)
|
||||
params = context.get('params', {})
|
||||
if 'url_return' in params:
|
||||
return {
|
||||
'url': params['url_return'].replace('[lang]', language_obj['lang']),
|
||||
'type': 'ir.actions.act_url',
|
||||
'target': 'self'
|
||||
}
|
||||
return action
|
||||
|
||||
class website_seo_metadata(osv.AbstractModel):
|
||||
_name = 'website.seo.metadata'
|
||||
_description = 'SEO metadata'
|
||||
|
||||
_columns = {
|
||||
'website_meta_title': fields.char("Website meta title", translate=True),
|
||||
'website_meta_description': fields.text("Website meta description", translate=True),
|
||||
'website_meta_keywords': fields.char("Website meta keywords", translate=True),
|
||||
}
|
||||
website_meta_title = fields.Char("Website meta title", translate=True)
|
||||
website_meta_description = fields.Text("Website meta description", translate=True)
|
||||
website_meta_keywords = fields.Char("Website meta keywords", translate=True)
|
||||
|
||||
|
||||
class website_published_mixin(osv.AbstractModel):
|
||||
class WebsitePublishedMixin(models.AbstractModel):
|
||||
|
||||
_name = "website.published.mixin"
|
||||
|
||||
_website_url_proxy = lambda self, *a, **kw: self._website_url(*a, **kw)
|
||||
website_published = fields.Boolean('Visible in Website', copy=False)
|
||||
website_url = fields.Char('Website URL', compute='_compute_website_url', help='The full URL to access the document through the website.')
|
||||
|
||||
_columns = {
|
||||
'website_published': fields.boolean('Visible in Website', copy=False),
|
||||
'website_url': fields.function(_website_url_proxy, type='char', string='Website URL',
|
||||
help='The full URL to access the document through the website.'),
|
||||
}
|
||||
@api.multi
|
||||
def _compute_website_url(self):
|
||||
for record in self:
|
||||
record.website_url = '#'
|
||||
|
||||
def _website_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
return dict.fromkeys(ids, '#')
|
||||
@api.multi
|
||||
def website_publish_button(self):
|
||||
self.ensure_one()
|
||||
if self.env.user.has_group('base.group_website_publisher') and self.website_url != '#':
|
||||
return self.open_website_url()
|
||||
return self.write({'website_published': not self.website_published})
|
||||
|
||||
def website_publish_button(self, cr, uid, ids, context=None):
|
||||
for i in self.browse(cr, uid, ids, context):
|
||||
if self.pool['res.users'].has_group(cr, uid, 'base.group_website_publisher') and i.website_url != '#':
|
||||
return self.open_website_url(cr, uid, ids, context)
|
||||
i.write({'website_published': not i.website_published})
|
||||
return True
|
||||
|
||||
def open_website_url(self, cr, uid, ids, context=None):
|
||||
def open_website_url(self):
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': self.browse(cr, uid, ids[0]).website_url,
|
||||
'url': self.website_url,
|
||||
'target': 'self',
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
<record id="website_designer_edit_qweb" model="ir.rule">
|
||||
<field name="name">website_designer: Manage Website and qWeb view</field>
|
||||
<field name="model_id" ref="base.model_ir_ui_view"/>
|
||||
@@ -31,5 +30,4 @@
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
@@ -1,4 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import test_converter
|
||||
import test_crawl
|
||||
import test_ui
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import unittest
|
||||
from openerp.addons.website.models.website import slugify, unslug
|
||||
from odoo.addons.website.models.website import slugify, unslug
|
||||
|
||||
|
||||
class TestUnslug(unittest.TestCase):
|
||||
|
||||
def test_unslug(self):
|
||||
tests = {
|
||||
'': (None, None),
|
||||
@@ -28,6 +32,7 @@ class TestTitleToSlug(unittest.TestCase):
|
||||
Those tests should pass with or without python-slugify
|
||||
See website/models/website.py slugify method
|
||||
"""
|
||||
|
||||
def test_spaces(self):
|
||||
self.assertEqual(
|
||||
"spaces",
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
import urlparse
|
||||
import time
|
||||
|
||||
import lxml.html
|
||||
|
||||
import openerp
|
||||
import odoo
|
||||
import re
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class Crawler(openerp.tests.HttpCase):
|
||||
""" Test suite crawling an openerp CMS instance and checking that all
|
||||
|
||||
class Crawler(odoo.tests.HttpCase):
|
||||
""" Test suite crawling an Odoo CMS instance and checking that all
|
||||
internal links lead to a 200 response.
|
||||
|
||||
If a username and a password are provided, authenticates the user before
|
||||
@@ -22,7 +25,7 @@ class Crawler(openerp.tests.HttpCase):
|
||||
post_install = True
|
||||
|
||||
def crawl(self, url, seen=None, msg=''):
|
||||
if seen == None:
|
||||
if seen is None:
|
||||
seen = set()
|
||||
|
||||
url_slug = re.sub(r"[/](([^/=?&]+-)?[0-9]+)([/]|$)", '/<slug>/', url)
|
||||
@@ -35,7 +38,7 @@ class Crawler(openerp.tests.HttpCase):
|
||||
_logger.info("%s %s", msg, url)
|
||||
r = self.url_open(url)
|
||||
code = r.getcode()
|
||||
self.assertIn( code, xrange(200, 300), "%s Fetching %s returned error response (%d)" % (msg, url, code))
|
||||
self.assertIn(code, xrange(200, 300), "%s Fetching %s returned error response (%d)" % (msg, url, code))
|
||||
|
||||
if r.info().gettype() == 'text/html':
|
||||
doc = lxml.html.fromstring(r.read())
|
||||
@@ -64,7 +67,6 @@ class Crawler(openerp.tests.HttpCase):
|
||||
self.crawl(href, seen, msg)
|
||||
return seen
|
||||
|
||||
|
||||
def test_10_crawl_public(self):
|
||||
t0 = time.time()
|
||||
t0_sql = self.registry.test_cr.sql_log_count
|
||||
@@ -72,7 +74,7 @@ class Crawler(openerp.tests.HttpCase):
|
||||
count = len(seen)
|
||||
duration = time.time() - t0
|
||||
sql = self.registry.test_cr.sql_log_count - t0_sql
|
||||
_logger.log(25, "public crawled %s urls in %.2fs %s queries, %.3fs %.2fq per request, ", count, duration, sql, duration/count, float(sql)/count)
|
||||
_logger.log(25, "public crawled %s urls in %.2fs %s queries, %.3fs %.2fq per request, ", count, duration, sql, duration / count, float(sql) / count)
|
||||
|
||||
def test_20_crawl_demo(self):
|
||||
t0 = time.time()
|
||||
@@ -82,7 +84,7 @@ class Crawler(openerp.tests.HttpCase):
|
||||
count = len(seen)
|
||||
duration = time.time() - t0
|
||||
sql = self.registry.test_cr.sql_log_count - t0_sql
|
||||
_logger.log(25, "demo crawled %s urls in %.2fs %s queries, %.3fs %.2fq per request", count, duration, sql, duration/count, float(sql)/count)
|
||||
_logger.log(25, "demo crawled %s urls in %.2fs %s queries, %.3fs %.2fq per request", count, duration, sql, duration / count, float(sql) / count)
|
||||
|
||||
def test_30_crawl_admin(self):
|
||||
t0 = time.time()
|
||||
@@ -92,4 +94,4 @@ class Crawler(openerp.tests.HttpCase):
|
||||
count = len(seen)
|
||||
duration = time.time() - t0
|
||||
sql = self.registry.test_cr.sql_log_count - t0_sql
|
||||
_logger.log(25, "admin crawled %s urls in %.2fs %s queries, %.3fs %.2fq per request", count, duration, sql, duration/count, float(sql)/count)
|
||||
_logger.log(25, "admin crawled %s urls in %.2fs %s queries, %.3fs %.2fq per request", count, duration, sql, duration / count, float(sql) / count)
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import openerp.tests
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import odoo
|
||||
import odoo.tests
|
||||
|
||||
|
||||
class TestUi(openerp.tests.HttpCase):
|
||||
class TestUi(odoo.tests.HttpCase):
|
||||
|
||||
def test_01_public_homepage(self):
|
||||
self.phantom_js("/", "console.log('ok')", "'website.snippets.animation' in odoo.__DEBUG__.services")
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import itertools
|
||||
|
||||
import unittest
|
||||
from lxml import etree as ET, html
|
||||
from lxml.html import builder as h
|
||||
|
||||
from openerp.tests import common
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
def attrs(**kwargs):
|
||||
@@ -13,6 +15,7 @@ def attrs(**kwargs):
|
||||
|
||||
|
||||
class TestViewSaving(common.TransactionCase):
|
||||
|
||||
def eq(self, a, b):
|
||||
self.assertEqual(a.tag, b.tag)
|
||||
self.assertEqual(a.attrib, b.attrib)
|
||||
@@ -38,7 +41,7 @@ class TestViewSaving(common.TransactionCase):
|
||||
h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')))
|
||||
))
|
||||
)
|
||||
self.view_id = self.registry('ir.ui.view').create(self.cr, self.uid, {
|
||||
self.view_id = self.env['ir.ui.view'].create({
|
||||
'name': "Test View",
|
||||
'type': 'qweb',
|
||||
'arch': ET.tostring(self.arch, encoding='utf-8').decode('utf-8')
|
||||
@@ -60,7 +63,7 @@ class TestViewSaving(common.TransactionCase):
|
||||
|
||||
self.env['ir.ui.view'].save_embedded_field(embedded)
|
||||
|
||||
company = self.registry('res.company').browse(self.cr, self.uid, 1)
|
||||
company = self.env['res.company'].browse(1)
|
||||
self.assertEqual(company.phone, "+00 00 000 00 0 000")
|
||||
|
||||
@unittest.skip("save conflict for embedded (saved by third party or previous version in page) not implemented")
|
||||
@@ -91,31 +94,26 @@ class TestViewSaving(common.TransactionCase):
|
||||
att['class'] = "foo bar"
|
||||
embedded = h.SPAN("My Company", att)
|
||||
|
||||
self.eq(View.to_field_ref(embedded),
|
||||
h.SPAN({'t-field': 'bob', 'class': 'foo bar', 'id': 'whop'}))
|
||||
self.eq(View.to_field_ref(embedded), h.SPAN({'t-field': 'bob', 'class': 'foo bar', 'id': 'whop'}))
|
||||
|
||||
def test_replace_arch(self):
|
||||
replacement = h.P("Wheee")
|
||||
|
||||
result = self.registry('ir.ui.view').replace_arch_section(
|
||||
self.cr, self.uid, [self.view_id], None, replacement)
|
||||
result = self.view_id.replace_arch_section(None, replacement)
|
||||
|
||||
self.eq(result, h.DIV("Wheee"))
|
||||
|
||||
def test_replace_arch_2(self):
|
||||
replacement = h.DIV(h.P("Wheee"))
|
||||
|
||||
result = self.registry('ir.ui.view').replace_arch_section(
|
||||
self.cr, self.uid, [self.view_id], None, replacement)
|
||||
result = self.view_id.replace_arch_section(None, replacement)
|
||||
|
||||
self.eq(result, replacement)
|
||||
|
||||
def test_fixup_arch(self):
|
||||
replacement = h.H1("I am the greatest title alive!")
|
||||
|
||||
result = self.registry('ir.ui.view').replace_arch_section(
|
||||
self.cr, self.uid, [self.view_id], '/div/div[1]/h3',
|
||||
replacement)
|
||||
result = self.view_id.replace_arch_section('/div/div[1]/h3', replacement)
|
||||
|
||||
self.eq(result, h.DIV(
|
||||
h.DIV(
|
||||
@@ -135,12 +133,10 @@ class TestViewSaving(common.TransactionCase):
|
||||
|
||||
def test_multiple_xpath_matches(self):
|
||||
with self.assertRaises(ValueError):
|
||||
self.registry('ir.ui.view').replace_arch_section(
|
||||
self.cr, self.uid, [self.view_id], '/div/div/h3',
|
||||
h.H6("Lol nope"))
|
||||
self.view_id.replace_arch_section('/div/div/h3', h.H6("Lol nope"))
|
||||
|
||||
def test_save(self):
|
||||
Company = self.registry('res.company')
|
||||
Company = self.env['res.company']
|
||||
View = self.env['ir.ui.view']
|
||||
|
||||
replacement = ET.tostring(h.DIV(
|
||||
@@ -151,13 +147,13 @@ class TestViewSaving(common.TransactionCase):
|
||||
h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund", type='char'))),
|
||||
)
|
||||
), encoding='utf-8')
|
||||
View.browse(self.view_id).save(value=replacement, xpath='/div/div[2]')
|
||||
self.view_id.save(value=replacement, xpath='/div/div[2]')
|
||||
|
||||
company = Company.browse(self.cr, self.uid, 1)
|
||||
company = Company.browse(1)
|
||||
self.assertEqual(company.name, "Acme Corporation")
|
||||
self.assertEqual(company.phone, "+12 3456789")
|
||||
self.eq(
|
||||
ET.fromstring(View.browse(self.view_id).arch.encode('utf-8')),
|
||||
ET.fromstring(self.view_id.arch.encode('utf-8')),
|
||||
h.DIV(
|
||||
h.DIV(
|
||||
h.H3("Column 1"),
|
||||
@@ -177,49 +173,46 @@ class TestViewSaving(common.TransactionCase):
|
||||
|
||||
def test_save_escaped_text(self):
|
||||
""" Test saving html special chars in text nodes """
|
||||
view_id = self.registry('ir.ui.view').create(self.cr, self.uid, {
|
||||
'arch':'<t><p><h1>hello world</h1></p></t>',
|
||||
'type':'qweb'
|
||||
view = self.env['ir.ui.view'].create({
|
||||
'arch': '<t><p><h1>hello world</h1></p></t>',
|
||||
'type': 'qweb'
|
||||
})
|
||||
view = self.env['ir.ui.view'].browse(view_id)
|
||||
# script and style text nodes should not escaped client side
|
||||
replacement = '<script>1 && "hello & world"</script>'
|
||||
view.save(replacement, xpath='/t/p/h1')
|
||||
self.assertIn(
|
||||
replacement.replace('&', '&'),
|
||||
view.arch,
|
||||
'inline script should be escaped server side'
|
||||
replacement.replace('&', '&'),
|
||||
view.arch,
|
||||
'inline script should be escaped server side'
|
||||
)
|
||||
self.assertIn(
|
||||
replacement,
|
||||
view.render(),
|
||||
'inline script should not be escaped when rendering'
|
||||
replacement,
|
||||
view.render(),
|
||||
'inline script should not be escaped when rendering'
|
||||
)
|
||||
# common text nodes should be be escaped client side
|
||||
replacement = 'world &amp; &lt;b&gt;cie'
|
||||
view.save(replacement, xpath='/t/p')
|
||||
self.assertIn(replacement, view.arch, 'common text node should not be escaped server side')
|
||||
self.assertIn(
|
||||
replacement,
|
||||
view.render().replace('&', '&'),
|
||||
'text node characters wrongly unescaped when rendering'
|
||||
replacement,
|
||||
view.render().replace('&', '&'),
|
||||
'text node characters wrongly unescaped when rendering'
|
||||
)
|
||||
|
||||
def test_save_only_embedded(self):
|
||||
Company = self.registry('res.company')
|
||||
Company = self.env['res.company']
|
||||
company_id = 1
|
||||
Company.write(self.cr, self.uid, company_id, {'name': "Foo Corporation"})
|
||||
company = Company.browse(company_id)
|
||||
company.write({'name': "Foo Corporation"})
|
||||
|
||||
node = html.tostring(h.SPAN(
|
||||
"Acme Corporation",
|
||||
attrs(model='res.company', id=company_id, field="name", expression='bob', type='char')))
|
||||
View = self.env['ir.ui.view']
|
||||
View.browse(company_id).save(value=node)
|
||||
|
||||
company = Company.browse(self.cr, self.uid, company_id)
|
||||
self.assertEqual(company.name, "Acme Corporation")
|
||||
|
||||
|
||||
def test_field_tail(self):
|
||||
View = self.env['ir.ui.view']
|
||||
replacement = ET.tostring(
|
||||
@@ -228,10 +221,10 @@ class TestViewSaving(common.TransactionCase):
|
||||
field='phone', expression="edmund")),
|
||||
"whop whop"
|
||||
), encoding="utf-8")
|
||||
View.browse(self.view_id).save(value=replacement, xpath='/div/div[2]/ul/li[3]')
|
||||
self.view_id.save(value=replacement, xpath='/div/div[2]/ul/li[3]')
|
||||
|
||||
self.eq(
|
||||
ET.fromstring(View.browse(self.view_id).arch.encode('utf-8')),
|
||||
ET.fromstring(self.view_id.arch.encode('utf-8')),
|
||||
h.DIV(
|
||||
h.DIV(
|
||||
h.H3("Column 1"),
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<record id="view_website_config_settings" model="ir.ui.view">
|
||||
<field name="name">Website settings</field>
|
||||
@@ -12,7 +11,7 @@
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
<div>
|
||||
<field name="website_id" on_change="on_change_website_id(website_id)" invisible="1"/>
|
||||
<field name="website_id" invisible="1"/>
|
||||
<group string="Domain">
|
||||
<field name="website_name" />
|
||||
<label for="google_analytics_key"/>
|
||||
@@ -159,5 +158,4 @@
|
||||
sequence="100" name="Configuration" groups="base.group_system"/>
|
||||
<menuitem id="menu_website_website_settings" parent="menu_website_global_configuration" name="Settings" action="action_website_configuration"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
@@ -2,6 +2,7 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- website views -->
|
||||
<record id="view_website_form" model="ir.ui.view">
|
||||
<field name="name">website.form</field>
|
||||
<field name="model">website</field>
|
||||
@@ -54,17 +55,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_base_language_install" model="ir.ui.view">
|
||||
<field name="name">view_base_language_install.inherit</field>
|
||||
<field name="model">base.language.install</field>
|
||||
<field name="inherit_id" ref="base.view_base_language_install"/>
|
||||
<field name="arch" type="xml">
|
||||
<group states="init" position="inside">
|
||||
<field name="website_ids" widget="many2many_checkboxes"/>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- website.menu views -->
|
||||
<record id="action_website_menu" model="ir.actions.act_window">
|
||||
<field name="name">Website Menu</field>
|
||||
<field name="res_model">website.menu</field>
|
||||
@@ -96,7 +87,7 @@
|
||||
<field name="name"/>
|
||||
<field name="url"/>
|
||||
<field name="website_id"/>
|
||||
|
||||
|
||||
<group string="Group By">
|
||||
<filter string="name" domain="[]" context="{'group_by':'name'}"/>
|
||||
<filter string="url" domain="[]" context="{'group_by':'url'}"/>
|
||||
@@ -106,7 +97,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_view_form_extend">
|
||||
<!-- ir.ui.view views -->
|
||||
<record model="ir.ui.view" id="view_view_form_extend">
|
||||
<field name="model">ir.ui.view</field>
|
||||
|
||||
<field name="inherit_id" ref="base.view_view_form"/>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base_language_install
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class BaseLanguageInstall(models.TransientModel):
|
||||
|
||||
_inherit = "base.language.install"
|
||||
|
||||
website_ids = fields.Many2many('website', string='Websites to translate')
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
defaults = super(BaseLanguageInstall, self).default_get(fields)
|
||||
website_id = self._context.get('params', {}).get('website_id')
|
||||
if website_id:
|
||||
if 'website_ids' not in defaults:
|
||||
defaults['website_ids'] = []
|
||||
defaults['website_ids'].append(website_id)
|
||||
return defaults
|
||||
|
||||
@api.multi
|
||||
def lang_install(self):
|
||||
action = super(BaseLanguageInstall, self).lang_install()
|
||||
lang = self.env['res.lang'].search([('code', '=', self.lang)], limit=1)
|
||||
if self.website_ids and lang:
|
||||
self.website_ids.write({'language_ids': [(4, lang.id)]})
|
||||
params = self._context.get('params', {})
|
||||
if 'url_return' in params:
|
||||
return {
|
||||
'url': params['url_return'].replace('[lang]', self.lang),
|
||||
'type': 'ir.actions.act_url',
|
||||
'target': 'self'
|
||||
}
|
||||
return action
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_base_language_install" model="ir.ui.view">
|
||||
<field name="name">view_base_language_install.inherit</field>
|
||||
<field name="model">base.language.install</field>
|
||||
<field name="inherit_id" ref="base.view_base_language_install"/>
|
||||
<field name="arch" type="xml">
|
||||
<group states="init" position="inside">
|
||||
<field name="website_ids" widget="many2many_checkboxes"/>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -59,7 +59,7 @@ class WebsiteBlog(http.Controller):
|
||||
post_ids = blog_obj.search(cr, uid, [], offset=(page-1)*self._blog_post_per_page, limit=self._blog_post_per_page, context=context)
|
||||
posts = blog_obj.browse(cr, uid, post_ids, context=context)
|
||||
blog_url = QueryURL('', ['blog', 'tag'])
|
||||
return request.website.render("website_blog.latest_blogs", {
|
||||
return request.render("website_blog.latest_blogs", {
|
||||
'posts': posts,
|
||||
'pager': pager,
|
||||
'blog_url': blog_url,
|
||||
@@ -160,7 +160,7 @@ class WebsiteBlog(http.Controller):
|
||||
'blog_url': blog_url,
|
||||
'date': date_begin,
|
||||
}
|
||||
response = request.website.render("website_blog.blog_post_short", values)
|
||||
response = request.render("website_blog.blog_post_short", values)
|
||||
return response
|
||||
|
||||
@http.route(['/blog/<model("blog.blog"):blog>/feed'], type='http', auth="public")
|
||||
@@ -241,7 +241,7 @@ class WebsiteBlog(http.Controller):
|
||||
'pager': pager,
|
||||
'comments': comments,
|
||||
}
|
||||
response = request.website.render("website_blog.blog_post_complete", values)
|
||||
response = request.render("website_blog.blog_post_complete", values)
|
||||
|
||||
request.session[request.session_id] = request.session.get(request.session_id, [])
|
||||
if not (blog_post.id in request.session[request.session_id]):
|
||||
|
||||
@@ -11,6 +11,8 @@ from openerp.osv import osv, fields
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools.translate import html_translate
|
||||
|
||||
from odoo import api
|
||||
|
||||
|
||||
class Blog(osv.Model):
|
||||
_name = 'blog.blog'
|
||||
@@ -87,11 +89,11 @@ class BlogPost(osv.Model):
|
||||
_order = 'id DESC'
|
||||
_mail_post_access = 'read'
|
||||
|
||||
def _website_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = super(BlogPost, self)._website_url(cr, uid, ids, field_name, arg, context=context)
|
||||
for blog_post in self.browse(cr, uid, ids, context=context):
|
||||
res[blog_post.id] = "/blog/%s/post/%s" % (slug(blog_post.blog_id), slug(blog_post))
|
||||
return res
|
||||
@api.multi
|
||||
def _compute_website_url(self):
|
||||
super(BlogPost, self)._compute_website_url()
|
||||
for blog_post in self:
|
||||
blog_post.website_url = "/blog/%s/post/%s" % (slug(blog_post.blog_id), slug(blog_post))
|
||||
|
||||
def _compute_ranking(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
|
||||
@@ -73,7 +73,7 @@ class WebsiteAccount(website_account):
|
||||
'default_url': '/my/leads',
|
||||
'pager': pager
|
||||
})
|
||||
return request.website.render("website_crm_partner_assign.portal_my_leads", values)
|
||||
return request.render("website_crm_partner_assign.portal_my_leads", values)
|
||||
|
||||
@http.route(['/my/opportunities', '/my/opportunities/page/<int:page>'], type='http', auth="user", website=True)
|
||||
def portal_my_opportunities(self, page=1, date_begin=None, date_end=None, opportunity=None, sortby=None, **kw):
|
||||
@@ -134,15 +134,15 @@ class WebsiteAccount(website_account):
|
||||
'default_url': '/my/opportunities',
|
||||
'pager': pager
|
||||
})
|
||||
return request.website.render("website_crm_partner_assign.portal_my_opportunities", values)
|
||||
return request.render("website_crm_partner_assign.portal_my_opportunities", values)
|
||||
|
||||
@http.route(['/my/lead/<model("crm.lead"):lead>'], type='http', auth="user", website=True)
|
||||
def portal_my_lead(self, lead=None, **kw):
|
||||
return request.website.render("website_crm_partner_assign.portal_my_lead", {'lead': lead})
|
||||
return request.render("website_crm_partner_assign.portal_my_lead", {'lead': lead})
|
||||
|
||||
@http.route(['/my/opportunity/<model("crm.lead"):lead>'], type='http', auth="user", website=True)
|
||||
def portal_my_opportunity(self, lead=None, **kw):
|
||||
return request.website.render(
|
||||
return request.render(
|
||||
"website_crm_partner_assign.portal_my_opportunity", {
|
||||
'opportunity': lead,
|
||||
'stages': request.env['crm.stage'].search([('probability', '!=', '100')], order='sequence desc'),
|
||||
@@ -292,5 +292,5 @@ class WebsiteCrmPartnerAssign(WebsitePartnerPage):
|
||||
'current_grade': current_grade,
|
||||
'current_country': current_country
|
||||
}
|
||||
return request.website.render("website_crm_partner_assign.partner", values)
|
||||
return request.render("website_crm_partner_assign.partner", values)
|
||||
return self.partners(**post)
|
||||
|
||||
@@ -17,11 +17,10 @@ class ResPartnerGrade(models.Model):
|
||||
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)")
|
||||
|
||||
@api.multi
|
||||
def _website_url(self, field_name, arg):
|
||||
res = super(ResPartnerGrade, self)._website_url(field_name, arg)
|
||||
def _compute_website_url(self):
|
||||
super(ResPartnerGrade, self)._compute_website_url()
|
||||
for grade in self:
|
||||
res[grade.id] = "/partners/grade/%s" % (slug(grade))
|
||||
return res
|
||||
grade.website_url = "/partners/grade/%s" % (slug(grade))
|
||||
|
||||
|
||||
class ResPartnerActivation(models.Model):
|
||||
|
||||
@@ -96,7 +96,7 @@ class WebsiteCustomer(http.Controller):
|
||||
'tag': tag,
|
||||
'tags': tags,
|
||||
}
|
||||
return request.website.render("website_customer.index", values)
|
||||
return request.render("website_customer.index", values)
|
||||
|
||||
# Do not use semantic controller due to SUPERUSER_ID
|
||||
@http.route(['/customers/<partner_id>'], type='http', auth="public", website=True)
|
||||
@@ -107,5 +107,5 @@ class WebsiteCustomer(http.Controller):
|
||||
if partner.exists() and partner.website_published:
|
||||
values = {}
|
||||
values['main_object'] = values['partner'] = partner
|
||||
return request.website.render("website_customer.details", values)
|
||||
return request.render("website_customer.details", values)
|
||||
return self.customers(**post)
|
||||
|
||||
@@ -131,7 +131,7 @@ class WebsiteEventController(http.Controller):
|
||||
'search_path': "?%s" % werkzeug.url_encode(searches),
|
||||
}
|
||||
|
||||
return request.website.render("website_event.index", values)
|
||||
return request.render("website_event.index", values)
|
||||
|
||||
@http.route(['/event/<model("event.event"):event>/page/<path:page>'], type='http', auth="public", website=True)
|
||||
def event_page(self, event, page, **post):
|
||||
@@ -151,7 +151,7 @@ class WebsiteEventController(http.Controller):
|
||||
values['from_template'] = 'website_event.default_page' # .strip('website_event.')
|
||||
page = 'website.page_404'
|
||||
|
||||
return request.website.render(page, values)
|
||||
return request.render(page, values)
|
||||
|
||||
@http.route(['/event/<model("event.event"):event>'], type='http', auth="public", website=True)
|
||||
def event(self, event, **post):
|
||||
@@ -170,7 +170,7 @@ class WebsiteEventController(http.Controller):
|
||||
'main_object': event,
|
||||
'range': range,
|
||||
}
|
||||
return request.website.render("website_event.event_description_full", values)
|
||||
return request.render("website_event.event_description_full", values)
|
||||
|
||||
@http.route('/event/add_event', type='http', auth="user", methods=['POST'], website=True)
|
||||
def add_event(self, event_name="New Event", **kwargs):
|
||||
@@ -215,7 +215,7 @@ class WebsiteEventController(http.Controller):
|
||||
"date": self.get_formated_date(event),
|
||||
"event": event,
|
||||
"url": event.website_url})
|
||||
return request.website.render("website_event.country_events_list", result)
|
||||
return request.render("website_event.country_events_list", result)
|
||||
|
||||
def _process_tickets_details(self, data):
|
||||
nb_register = int(data.get('nb_register-0', 0))
|
||||
@@ -228,7 +228,7 @@ class WebsiteEventController(http.Controller):
|
||||
tickets = self._process_tickets_details(post)
|
||||
if not tickets:
|
||||
return request.redirect("/event/%s" % slug(event))
|
||||
return request.website._render("website_event.registration_attendee_details", {'tickets': tickets, 'event': event})
|
||||
return request.env['ir.ui.view'].render_template("website_event.registration_attendee_details", {'tickets': tickets, 'event': event})
|
||||
|
||||
def _process_registration_details(self, details):
|
||||
''' Process data posted from the attendee details form. '''
|
||||
@@ -255,7 +255,7 @@ class WebsiteEventController(http.Controller):
|
||||
Attendees += Attendees.sudo().create(
|
||||
Attendees._prepare_attendee_values(registration))
|
||||
|
||||
return request.website.render("website_event.registration_complete", {
|
||||
return request.render("website_event.registration_complete", {
|
||||
'attendees': Attendees,
|
||||
'event': event,
|
||||
})
|
||||
|
||||
@@ -41,10 +41,10 @@ class Event(models.Model):
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def _website_url(self, name, arg):
|
||||
res = super(Event, self)._website_url(name, arg)
|
||||
res.update({(event.id, '/event/%s' % slug(event)) for event in self})
|
||||
return res
|
||||
def _compute_website_url(self):
|
||||
super(Event, self)._compute_website_url()
|
||||
for event in self:
|
||||
event.website_url = '/event/%s' % slug(event)
|
||||
|
||||
@api.multi
|
||||
def _get_new_menu_pages(self):
|
||||
|
||||
@@ -16,7 +16,7 @@ class WebsiteEventSaleController(WebsiteEventController):
|
||||
'main_object': event.with_context(pricelist=pricelist_id),
|
||||
'range': range,
|
||||
}
|
||||
return request.website.render("website_event.event_description_full", values)
|
||||
return request.render("website_event.event_description_full", values)
|
||||
|
||||
def _process_tickets_details(self, data):
|
||||
ticket_post = {}
|
||||
@@ -47,7 +47,7 @@ class WebsiteEventSaleController(WebsiteEventController):
|
||||
attendees = request.env['event.registration'].browse(list(attendee_ids))
|
||||
# clean context and session, then redirect to the confirmation page
|
||||
request.website.sale_reset()
|
||||
return request.website.render("website_event.registration_complete", {
|
||||
return request.render("website_event.registration_complete", {
|
||||
'attendees': attendees,
|
||||
'event': event,
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ class WebsiteEventTrackController(http.Controller):
|
||||
def event_track_view(self, event, track, **post):
|
||||
track = track.sudo()
|
||||
values = {'track': track, 'event': track.event_id, 'main_object': track}
|
||||
return request.website.render("website_event_track.track_view", values)
|
||||
return request.render("website_event_track.track_view", values)
|
||||
|
||||
def _prepare_calendar(self, event, event_track_ids):
|
||||
local_tz = pytz.timezone(event.date_tz or 'UTC')
|
||||
@@ -72,7 +72,7 @@ class WebsiteEventTrackController(http.Controller):
|
||||
speakers_name = u" – ".join(track.speaker_ids.mapped('name'))
|
||||
speakers[track.id] = speakers_name
|
||||
|
||||
return request.website.render("website_event_track.agenda", {
|
||||
return request.render("website_event_track.agenda", {
|
||||
'event': event,
|
||||
'days': days,
|
||||
'days_nbr': days_tracks_count,
|
||||
@@ -100,11 +100,11 @@ class WebsiteEventTrackController(http.Controller):
|
||||
'searches': searches,
|
||||
'html2plaintext': html2plaintext
|
||||
}
|
||||
return request.website.render("website_event_track.tracks", values)
|
||||
return request.render("website_event_track.tracks", values)
|
||||
|
||||
@http.route(['''/event/<model("event.event", "[('show_track_proposal','=',1)]"):event>/track_proposal'''], type='http', auth="public", website=True)
|
||||
def event_track_proposal(self, event, **post):
|
||||
return request.website.render("website_event_track.event_track_proposal", {'event': event})
|
||||
return request.render("website_event_track.event_track_proposal", {'event': event})
|
||||
|
||||
@http.route(['/event/<model("event.event"):event>/track_proposal/post'], type='http', auth="public", methods=['POST'], website=True)
|
||||
def event_track_proposal_post(self, event, **post):
|
||||
@@ -130,4 +130,4 @@ class WebsiteEventTrackController(http.Controller):
|
||||
partner = request.env['res.partner'].sudo().search([('email', '=', post['email_from'])])
|
||||
if partner:
|
||||
track.sudo().message_subscribe(partner_ids=partner.ids)
|
||||
return request.website.render("website_event_track.event_track_proposal_success", {'track': track, 'event': event})
|
||||
return request.render("website_event_track.event_track_proposal_success", {'track': track, 'event': event})
|
||||
|
||||
@@ -82,10 +82,10 @@ class Track(models.Model):
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def _website_url(self, field_name, arg):
|
||||
res = super(Track, self)._website_url(field_name, arg)
|
||||
res.update({(track.id, '/event/%s/track/%s' % (slug(track.event_id), slug(track))) for track in self})
|
||||
return res
|
||||
def _compute_website_url(self):
|
||||
super(Track, self)._compute_website_url()
|
||||
for track in self:
|
||||
track.website_url = '/event/%s/track/%s' % (slug(track.event_id), slug(track))
|
||||
|
||||
@api.model
|
||||
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
|
||||
@@ -81,7 +81,7 @@ class WebsiteForum(http.Controller):
|
||||
@http.route(['/forum'], type='http', auth="public", website=True)
|
||||
def forum(self, **kwargs):
|
||||
forums = request.env['forum.forum'].search([])
|
||||
return request.website.render("website_forum.forum_all", {'forums': forums})
|
||||
return request.render("website_forum.forum_all", {'forums': forums})
|
||||
|
||||
@http.route('/forum/new', type='http', auth="user", methods=['POST'], website=True)
|
||||
def forum_create(self, forum_name="New Forum", add_menu=False):
|
||||
@@ -163,12 +163,12 @@ class WebsiteForum(http.Controller):
|
||||
'search': search,
|
||||
'post_type': post_type,
|
||||
})
|
||||
return request.website.render("website_forum.forum_index", values)
|
||||
return request.render("website_forum.forum_index", values)
|
||||
|
||||
@http.route(['/forum/<model("forum.forum"):forum>/faq'], type='http', auth="public", website=True)
|
||||
def forum_faq(self, forum, **post):
|
||||
values = self._prepare_forum_values(forum=forum, searches=dict(), header={'is_guidelines': True}, **post)
|
||||
return request.website.render("website_forum.faq", values)
|
||||
return request.render("website_forum.faq", values)
|
||||
|
||||
@http.route('/forum/get_tags', type='http', auth="public", methods=['GET'], website=True)
|
||||
def tag_read(self, q='', l=25, **post):
|
||||
@@ -204,11 +204,11 @@ class WebsiteForum(http.Controller):
|
||||
'pager_tag_chars': first_char_list,
|
||||
'active_char_tag': active_char_tag,
|
||||
})
|
||||
return request.website.render("website_forum.tag", values)
|
||||
return request.render("website_forum.tag", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/edit_welcome_message', auth="user", website=True)
|
||||
def edit_welcome_message(self, forum, **kw):
|
||||
return request.website.render("website_forum.edit_welcome_message", {'forum': forum})
|
||||
return request.render("website_forum.edit_welcome_message", {'forum': forum})
|
||||
|
||||
# Questions
|
||||
# --------------------------------------------------
|
||||
@@ -247,7 +247,7 @@ class WebsiteForum(http.Controller):
|
||||
'filters': filters,
|
||||
'reversed': reversed,
|
||||
})
|
||||
return request.website.render("website_forum.post_description_full", values)
|
||||
return request.render("website_forum.post_description_full", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/toggle_favourite', type='json', auth="user", methods=['POST'], website=True)
|
||||
def question_toggle_favorite(self, forum, question, **post):
|
||||
@@ -272,7 +272,7 @@ class WebsiteForum(http.Controller):
|
||||
'forum': forum,
|
||||
'reasons': reasons,
|
||||
})
|
||||
return request.website.render("website_forum.close_post", values)
|
||||
return request.render("website_forum.close_post", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/edit_answer', type='http', auth="user", website=True)
|
||||
def question_edit_answer(self, forum, question, **kwargs):
|
||||
@@ -312,14 +312,14 @@ class WebsiteForum(http.Controller):
|
||||
if not user.email or not tools.single_email_re.match(user.email):
|
||||
return werkzeug.utils.redirect("/forum/%s/user/%s/edit?email_required=1" % (slug(forum), request.session.uid))
|
||||
values = self._prepare_forum_values(forum=forum, searches={}, header={'ask_hide': True})
|
||||
return request.website.render("website_forum.new_%s" % post_type, values)
|
||||
return request.render("website_forum.new_%s" % post_type, values)
|
||||
|
||||
@http.route(['/forum/<model("forum.forum"):forum>/new',
|
||||
'/forum/<model("forum.forum"):forum>/<model("forum.post"):post_parent>/reply'],
|
||||
type='http', auth="user", methods=['POST'], website=True)
|
||||
def post_create(self, forum, post_parent=None, post_type=None, **post):
|
||||
if post_type == 'question' and not post.get('post_name', '').strip():
|
||||
return request.website.render('website.http_error', {'status_code': _('Bad Request'), 'status_message': _('Title should not be empty.')})
|
||||
return request.render('website.http_error', {'status_code': _('Bad Request'), 'status_message': _('Title should not be empty.')})
|
||||
post_tag_ids = forum._tag_to_write_vals(post.get('post_tags', ''))
|
||||
new_question = request.env['forum.post'].create({
|
||||
'forum_id': forum.id,
|
||||
@@ -378,12 +378,12 @@ class WebsiteForum(http.Controller):
|
||||
'content': post.name,
|
||||
})
|
||||
template = "website_forum.new_link" if post.post_type == 'link' and not post.parent_id else "website_forum.edit_post"
|
||||
return request.website.render(template, values)
|
||||
return request.render(template, values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/save', type='http', auth="user", methods=['POST'], website=True)
|
||||
def post_save(self, forum, post, **kwargs):
|
||||
if 'post_name' in kwargs and not kwargs.get('post_name').strip():
|
||||
return request.website.render('website.http_error', {'status_code': _('Bad Request'), 'status_message': _('Title should not be empty.')})
|
||||
return request.render('website.http_error', {'status_code': _('Bad Request'), 'status_message': _('Title should not be empty.')})
|
||||
post_tags = forum._tag_to_write_vals(kwargs.get('post_tags', ''))
|
||||
vals = {
|
||||
'tag_ids': post_tags,
|
||||
@@ -442,7 +442,7 @@ class WebsiteForum(http.Controller):
|
||||
'queue_type': 'validation',
|
||||
})
|
||||
|
||||
return request.website.render("website_forum.moderation_queue", values)
|
||||
return request.render("website_forum.moderation_queue", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/flagged_queue', type='http', auth="user", website=True)
|
||||
def flagged_queue(self, forum):
|
||||
@@ -460,7 +460,7 @@ class WebsiteForum(http.Controller):
|
||||
'queue_type': 'flagged',
|
||||
})
|
||||
|
||||
return request.website.render("website_forum.moderation_queue", values)
|
||||
return request.render("website_forum.moderation_queue", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/offensive_posts', type='http', auth="user", website=True)
|
||||
def offensive_posts(self, forum):
|
||||
@@ -478,7 +478,7 @@ class WebsiteForum(http.Controller):
|
||||
'queue_type': 'offensive',
|
||||
})
|
||||
|
||||
return request.website.render("website_forum.moderation_queue", values)
|
||||
return request.render("website_forum.moderation_queue", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/validate', type='http', auth="user", website=True)
|
||||
def post_accept(self, forum, post):
|
||||
@@ -512,7 +512,7 @@ class WebsiteForum(http.Controller):
|
||||
'reasons': offensive_reasons,
|
||||
'offensive': True,
|
||||
})
|
||||
return request.website.render("website_forum.close_post", values)
|
||||
return request.render("website_forum.close_post", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/mark_as_offensive', type='http', auth="user", methods=["POST"], website=True)
|
||||
def post_mark_as_offensive(self, forum, post, **kwargs):
|
||||
@@ -550,7 +550,7 @@ class WebsiteForum(http.Controller):
|
||||
'pager': pager,
|
||||
})
|
||||
|
||||
return request.website.render("website_forum.users", values)
|
||||
return request.render("website_forum.users", values)
|
||||
|
||||
@http.route(['/forum/<model("forum.forum"):forum>/partner/<int:partner_id>'], type='http', auth="public", website=True)
|
||||
def open_partner(self, forum, partner_id=0, **post):
|
||||
@@ -674,7 +674,7 @@ class WebsiteForum(http.Controller):
|
||||
'posts': posts,
|
||||
'vote_post': vote_ids,
|
||||
})
|
||||
return request.website.render("website_forum.user_detail_full", values)
|
||||
return request.render("website_forum.user_detail_full", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/user/<model("res.users"):user>/edit', type='http', auth="user", website=True)
|
||||
def edit_profile(self, forum, user, **kwargs):
|
||||
@@ -685,7 +685,7 @@ class WebsiteForum(http.Controller):
|
||||
'countries': countries,
|
||||
'notifications': self._get_notifications(),
|
||||
})
|
||||
return request.website.render("website_forum.edit_profile", values)
|
||||
return request.render("website_forum.edit_profile", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/user/<model("res.users"):user>/save', type='http', auth="user", methods=['POST'], website=True)
|
||||
def save_edited_profile(self, forum, user, **kwargs):
|
||||
@@ -714,7 +714,7 @@ class WebsiteForum(http.Controller):
|
||||
values.update({
|
||||
'badges': badges,
|
||||
})
|
||||
return request.website.render("website_forum.badge", values)
|
||||
return request.render("website_forum.badge", values)
|
||||
|
||||
# Messaging
|
||||
# --------------------------------------------------
|
||||
|
||||
@@ -20,7 +20,7 @@ class WebsiteDoc(http.Controller):
|
||||
'forum': forum,
|
||||
'sections': sections,
|
||||
}
|
||||
return request.website.render("website_forum_doc.documentation", value)
|
||||
return request.render("website_forum_doc.documentation", value)
|
||||
|
||||
@http.route(['''/forum/how-to/<model("forum.documentation.toc"):toc>/<model("forum.post", "[('documentation_toc_id','=',toc[0])]"):post>'''], type='http', auth="public", website=True)
|
||||
def post(self, toc, post, **kwargs):
|
||||
@@ -32,7 +32,7 @@ class WebsiteDoc(http.Controller):
|
||||
'main_object': post,
|
||||
'forum': post.forum_id
|
||||
}
|
||||
return request.website.render("website_forum_doc.documentation_post", value)
|
||||
return request.render("website_forum_doc.documentation_post", value)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):post>/promote', type='http', auth="user", website=True)
|
||||
def post_toc(self, forum, post, **kwargs):
|
||||
@@ -42,7 +42,7 @@ class WebsiteDoc(http.Controller):
|
||||
'forum': post.forum_id,
|
||||
'chapters': request.env['forum.documentation.toc'].search([('child_ids', '=', False)])
|
||||
}
|
||||
return request.website.render("website_forum_doc.promote_question", value)
|
||||
return request.render("website_forum_doc.promote_question", value)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/promote_ok', type='http', auth="user", website=True)
|
||||
def post_toc_ok(self, forum, post_id, toc_id, **kwargs):
|
||||
|
||||
@@ -56,4 +56,4 @@ class GoogleMap(http.Controller):
|
||||
'partner_url': partner_url,
|
||||
'partner_data': json.dumps(partner_data)
|
||||
}
|
||||
return request.website.render("website_google_map.google_map", values)
|
||||
return request.render("website_google_map.google_map", values)
|
||||
|
||||
@@ -12,4 +12,4 @@ class WebsiteHr(http.Controller):
|
||||
if not request.env['res.users'].has_group('base.group_website_publisher'):
|
||||
employees_domain += [('website_published', '=', True)]
|
||||
employees = request.env['hr.employee'].search(employees_domain)
|
||||
return request.website.render("website.aboutus", {'employees': employees})
|
||||
return request.render("website.aboutus", {'employees': employees})
|
||||
|
||||
@@ -10,7 +10,7 @@ class HrEmployee(models.Model):
|
||||
public_info = fields.Char(string='Public Info')
|
||||
|
||||
@api.multi
|
||||
def _website_url(self, field_name, arg):
|
||||
res = super(HrEmployee, self)._website_url(field_name, arg)
|
||||
res.update({(employee_id, '/page/website.aboutus#team') for employee_id in self.ids})
|
||||
return res
|
||||
def _compute_website_url(self):
|
||||
super(HrEmployee, self)._compute_website_url()
|
||||
for employee in self:
|
||||
employee.website_url = '/page/website.aboutus#team'
|
||||
|
||||
@@ -58,7 +58,7 @@ class website_hr_recruitment(http.Controller):
|
||||
office_id = False
|
||||
|
||||
# Render page
|
||||
return request.website.render("website_hr_recruitment.index", {
|
||||
return request.render("website_hr_recruitment.index", {
|
||||
'jobs': jobs,
|
||||
'countries': countries,
|
||||
'departments': departments,
|
||||
|
||||
@@ -46,11 +46,10 @@ class Job(models.Model):
|
||||
website_description = fields.Html('Website description', translate=html_translate, sanitize=False)
|
||||
|
||||
@api.multi
|
||||
def _website_url(self, field_name, arg):
|
||||
result = super(Job, self)._website_url(field_name, arg)
|
||||
def _compute_website_url(self):
|
||||
super(Job, self)._compute_website_url()
|
||||
for job in self:
|
||||
result[job.id] = "/jobs/detail/%s" % job.id
|
||||
return result
|
||||
job.website_url = "/jobs/detail/%s" % job.id
|
||||
|
||||
@api.multi
|
||||
def set_open(self):
|
||||
|
||||
@@ -14,7 +14,7 @@ class Website_Url(http.Controller):
|
||||
|
||||
@http.route('/r', type='http', auth='user', website=True)
|
||||
def shorten_url(self, **post):
|
||||
return request.website.render("website_links.page_shorten_url", post)
|
||||
return request.render("website_links.page_shorten_url", post)
|
||||
|
||||
@http.route('/website_links/add_code', type='json', auth='user')
|
||||
def add_code(self, **post):
|
||||
@@ -34,6 +34,6 @@ class Website_Url(http.Controller):
|
||||
code = request.env['link.tracker.code'].search([('code', '=', code)], limit=1)
|
||||
|
||||
if code:
|
||||
return request.website.render("website_links.graphs", code.link_id.read()[0])
|
||||
return request.render("website_links.graphs", code.link_id.read()[0])
|
||||
else:
|
||||
return werkzeug.utils.redirect('', 301)
|
||||
|
||||
@@ -13,7 +13,7 @@ class WebsiteLivechat(http.Controller):
|
||||
values = {
|
||||
'channels': channels
|
||||
}
|
||||
return request.website.render('website_livechat.channel_list_page', values)
|
||||
return request.render('website_livechat.channel_list_page', values)
|
||||
|
||||
|
||||
@http.route('/livechat/channel/<model("im_livechat.channel"):channel>', type='http', auth='public', website=True)
|
||||
@@ -34,4 +34,4 @@ class WebsiteLivechat(http.Controller):
|
||||
'team': channel.sudo().user_ids,
|
||||
'percentage': percentage
|
||||
}
|
||||
return request.website.render("website_livechat.channel_page", values)
|
||||
return request.render("website_livechat.channel_page", values)
|
||||
|
||||
@@ -9,12 +9,10 @@ class ImLivechatChannel(models.Model):
|
||||
_name = 'im_livechat.channel'
|
||||
_inherit = ['im_livechat.channel', 'website.published.mixin']
|
||||
|
||||
@api.v7
|
||||
# TODO : when mixin in new api.v8, change this !
|
||||
def _website_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = super(ImLivechatChannel, self)._website_url(cr, uid, ids, field_name, arg, context=context)
|
||||
for channel in self.browse(cr, uid, ids, context=context):
|
||||
res[channel.id] = "/livechat/channel/%s" % (slug(channel),)
|
||||
return res
|
||||
@api.multi
|
||||
def _compute_website_url(self):
|
||||
super(ImLivechatChannel, self)._compute_website_url()
|
||||
for channel in self:
|
||||
channel.website_url = "/livechat/channel/%s" % (slug(channel),)
|
||||
|
||||
website_description = fields.Html("Website description", default=False, help="Description of the channel displayed on the website page", sanitize=False, translate=html_translate)
|
||||
|
||||
@@ -46,7 +46,7 @@ class MailGroup(http.Controller):
|
||||
message_data = dict((message['res_id'], message['res_id_count']) for message in messages)
|
||||
|
||||
group_data = dict((group.id, {'monthly_message_nbr': message_data.get(group.id, 0)}) for group in groups)
|
||||
return request.website.render('website_mail_channel.mail_channels', {'groups': groups, 'group_data': group_data})
|
||||
return request.render('website_mail_channel.mail_channels', {'groups': groups, 'group_data': group_data})
|
||||
|
||||
@http.route(["/groups/is_member"], type='json', auth="public", website=True)
|
||||
def is_member(self, channel_id=0, **kw):
|
||||
@@ -144,7 +144,7 @@ class MailGroup(http.Controller):
|
||||
'date_end': date_end,
|
||||
'replies_per_page': self._replies_per_page,
|
||||
}
|
||||
return request.website.render('website_mail_channel.group_messages', values)
|
||||
return request.render('website_mail_channel.group_messages', values)
|
||||
|
||||
@http.route([
|
||||
'''/groups/<model('mail.channel'):group>/<model('mail.message', "[('model','=','mail.channel'), ('res_id','=',group[0])]"):message>''',
|
||||
@@ -168,7 +168,7 @@ class MailGroup(http.Controller):
|
||||
'next_message': next_message,
|
||||
'prev_message': prev_message,
|
||||
}
|
||||
return request.website.render('website_mail_channel.group_message', values)
|
||||
return request.render('website_mail_channel.group_message', values)
|
||||
|
||||
@http.route(
|
||||
'''/groups/<model('mail.channel'):group>/<model('mail.message', "[('model','=','mail.channel'), ('res_id','=',group[0])]"):message>/get_replies''',
|
||||
@@ -210,7 +210,7 @@ class MailGroup(http.Controller):
|
||||
# add partner
|
||||
channel.sudo().write({'channel_partner_ids': [(4, partner_id)]})
|
||||
|
||||
return request.website.render("website_mail_channel.confirmation_subscription", {'subscribing': True})
|
||||
return request.render("website_mail_channel.confirmation_subscription", {'subscribing': True})
|
||||
|
||||
@http.route("/groups/unsubscribe/<model('mail.channel'):channel>/<int:partner_id>/<string:token>", type='http', auth='public', website=True)
|
||||
def confirm_unsubscribe(self, channel, partner_id, token, **kw):
|
||||
@@ -226,4 +226,4 @@ class MailGroup(http.Controller):
|
||||
# remove partner
|
||||
channel.sudo().write({'channel_partner_ids': [(3, partner_id)]})
|
||||
|
||||
return request.website.render("website_mail_channel.confirmation_subscription", {'subscribing': False})
|
||||
return request.render("website_mail_channel.confirmation_subscription", {'subscribing': False})
|
||||
|
||||
@@ -13,13 +13,13 @@ class MassMailController(MassMailController):
|
||||
if mailing.exists():
|
||||
if mailing.mailing_model == 'mail.mass_mailing.contact':
|
||||
contacts = request.env['mail.mass_mailing.contact'].sudo().search([('email', '=', email)])
|
||||
return request.website.render('website_mass_mailing.page_unsubscribe', {
|
||||
return request.render('website_mass_mailing.page_unsubscribe', {
|
||||
'contacts': contacts,
|
||||
'email': email,
|
||||
'mailing_id': mailing_id})
|
||||
else:
|
||||
super(MassMailController, self).mailing(mailing_id, email=email, res_id=res_id, **post)
|
||||
return request.website.render('website_mass_mailing.page_unsubscribed')
|
||||
return request.render('website_mass_mailing.page_unsubscribed')
|
||||
|
||||
@http.route(['/mail/mailing/unsubscribe'], type='json', auth='none')
|
||||
def unsubscribe(self, mailing_id, opt_in_ids, opt_out_ids, email):
|
||||
|
||||
@@ -160,7 +160,7 @@ class WebsiteMembership(http.Controller):
|
||||
'post': post,
|
||||
'search': "?%s" % werkzeug.url_encode(post),
|
||||
}
|
||||
return request.website.render("website_membership.index", values)
|
||||
return request.render("website_membership.index", values)
|
||||
|
||||
# Do not use semantic controller due to SUPERUSER_ID
|
||||
@http.route(['/members/<partner_id>'], type='http', auth="public", website=True)
|
||||
@@ -171,5 +171,5 @@ class WebsiteMembership(http.Controller):
|
||||
if partner.exists() and partner.website_published: # TODO should be done with access rules
|
||||
values = {}
|
||||
values['main_object'] = values['partner'] = partner
|
||||
return request.website.render("website_membership.partner", values)
|
||||
return request.render("website_membership.partner", values)
|
||||
return self.members(**post)
|
||||
|
||||
@@ -20,5 +20,5 @@ class WebsitePartnerPage(http.Controller):
|
||||
'partner': partner_sudo,
|
||||
'edit_page': False
|
||||
}
|
||||
return request.website.render("website_partner.partner_page", values)
|
||||
return request.render("website_partner.partner_page", values)
|
||||
return request.not_found()
|
||||
|
||||
@@ -18,8 +18,7 @@ class WebsiteResPartner(models.Model):
|
||||
self.self = self.id
|
||||
|
||||
@api.multi
|
||||
def _website_url(self, field_name, arg):
|
||||
res = super(WebsiteResPartner, self)._website_url(field_name, arg)
|
||||
def _compute_website_url(self):
|
||||
super(WebsiteResPartner, self)._compute_website_url()
|
||||
for partner in self:
|
||||
res[partner.id] = "/partners/%s" % slug(partner)
|
||||
return res
|
||||
partner.website_url = "/partners/%s" % slug(partner)
|
||||
|
||||
@@ -17,7 +17,7 @@ class website_payment(http.Controller):
|
||||
}
|
||||
for acquirer in acquirers:
|
||||
acquirer.form = acquirer.sudo()._registration_render(request.env.user.partner_id.id, {'error': {}, 'error_message': [], 'return_url': '/my/payment_method', 'json': False, 'bootstrap_formatting': True})
|
||||
return request.website.render("website_payment.pay_methods", values)
|
||||
return request.render("website_payment.pay_methods", values)
|
||||
|
||||
@http.route(['/website_payment/delete/'], methods=['POST'], type='http', auth="user", website=True)
|
||||
def delete(self, delete_pm_id=None):
|
||||
@@ -54,7 +54,7 @@ class website_payment(http.Controller):
|
||||
'amount': float(amount),
|
||||
'payment_form': payment_form,
|
||||
}
|
||||
return request.website.render('website_payment.pay', values)
|
||||
return request.render('website_payment.pay', values)
|
||||
|
||||
@http.route(['/website_payment/transaction'], type='json', auth="public", website=True)
|
||||
def transaction(self, reference, amount, currency_id, acquirer_id):
|
||||
@@ -78,6 +78,6 @@ class website_payment(http.Controller):
|
||||
tx = request.env['payment.transaction'].browse(tx_id)
|
||||
status = (tx.state == 'done' and 'success') or 'danger'
|
||||
message = (tx.state == 'done' and 'Your payment was successful! It may take some time to be validated on our end.') or 'OOps! There was a problem with your payment.'
|
||||
return request.website.render('website_payment.confirm', {'tx': tx, 'status': status, 'message': message})
|
||||
return request.render('website_payment.confirm', {'tx': tx, 'status': status, 'message': message})
|
||||
else:
|
||||
return request.redirect('/my/home')
|
||||
|
||||
@@ -53,7 +53,7 @@ class website_account(http.Controller):
|
||||
@http.route(['/my', '/my/home'], type='http', auth="public", website=True)
|
||||
def account(self, **kw):
|
||||
values = self._prepare_portal_layout_values()
|
||||
return request.website.render("website_portal.portal_my_home", values)
|
||||
return request.render("website_portal.portal_my_home", values)
|
||||
|
||||
@http.route(['/my/account'], type='http', auth='user', website=True)
|
||||
def details(self, redirect=None, **post):
|
||||
@@ -86,7 +86,7 @@ class website_account(http.Controller):
|
||||
'redirect': redirect,
|
||||
})
|
||||
|
||||
return request.website.render("website_portal.details", values)
|
||||
return request.render("website_portal.details", values)
|
||||
|
||||
def details_form_validate(self, data):
|
||||
error = dict()
|
||||
|
||||
@@ -77,7 +77,7 @@ class website_account(website_account):
|
||||
'archive_groups': archive_groups,
|
||||
'default_url': '/my/quotes',
|
||||
})
|
||||
return request.website.render("website_portal_sale.portal_my_quotations", values)
|
||||
return request.render("website_portal_sale.portal_my_quotations", values)
|
||||
|
||||
@http.route(['/my/orders', '/my/orders/page/<int:page>'], type='http', auth="user", website=True)
|
||||
def portal_my_orders(self, page=1, date_begin=None, date_end=None, **kw):
|
||||
@@ -114,7 +114,7 @@ class website_account(website_account):
|
||||
'archive_groups': archive_groups,
|
||||
'default_url': '/my/orders',
|
||||
})
|
||||
return request.website.render("website_portal_sale.portal_my_orders", values)
|
||||
return request.render("website_portal_sale.portal_my_orders", values)
|
||||
|
||||
@http.route(['/my/orders/<int:order>'], type='http', auth="user", website=True)
|
||||
def orders_followup(self, order=None, **kw):
|
||||
@@ -123,9 +123,9 @@ class website_account(website_account):
|
||||
order.check_access_rights('read')
|
||||
order.check_access_rule('read')
|
||||
except AccessError:
|
||||
return request.website.render("website.403")
|
||||
return request.render("website.403")
|
||||
order_invoice_lines = {il.product_id.id: il.invoice_id for il in order.invoice_ids.mapped('invoice_line_ids')}
|
||||
return request.website.render("website_portal_sale.orders_followup", {
|
||||
return request.render("website_portal_sale.orders_followup", {
|
||||
'order': order.sudo(),
|
||||
'order_invoice_lines': order_invoice_lines,
|
||||
})
|
||||
@@ -168,7 +168,7 @@ class website_account(website_account):
|
||||
'archive_groups': archive_groups,
|
||||
'default_url': '/my/invoices',
|
||||
})
|
||||
return request.website.render("website_portal_sale.portal_my_invoices", values)
|
||||
return request.render("website_portal_sale.portal_my_invoices", values)
|
||||
|
||||
def details_form_validate(self, data):
|
||||
error, error_message = super(website_account, self).details_form_validate(data)
|
||||
|
||||
@@ -61,11 +61,11 @@ class WebsiteAccount(website_account):
|
||||
'default_url': '/my/projects',
|
||||
'pager': pager
|
||||
})
|
||||
return request.website.render("website_project.my_projects", values)
|
||||
return request.render("website_project.my_projects", values)
|
||||
|
||||
@http.route(['/my/project/<model("project.project"):project>'], type='http', auth="user", website=True)
|
||||
def my_project(self, project=None, **kw):
|
||||
return request.website.render("website_project.my_project", {'project': project})
|
||||
return request.render("website_project.my_project", {'project': project})
|
||||
|
||||
@http.route(['/my/tasks', '/my/tasks/page/<int:page>'], type='http', auth="user", website=True)
|
||||
def my_tasks(self, page=1, date_begin=None, date_end=None, project=None, sortby=None, **kw):
|
||||
@@ -123,8 +123,8 @@ class WebsiteAccount(website_account):
|
||||
'default_url': '/my/tasks',
|
||||
'pager': pager
|
||||
})
|
||||
return request.website.render("website_project.my_tasks", values)
|
||||
return request.render("website_project.my_tasks", values)
|
||||
|
||||
@http.route(['/my/task/<model("project.task"):task>'], type='http', auth="user", website=True)
|
||||
def my_task(self, task=None, **kw):
|
||||
return request.website.render("website_project.my_task", {'task': task, 'user': request.env.user})
|
||||
return request.render("website_project.my_task", {'task': task, 'user': request.env.user})
|
||||
|
||||
@@ -75,9 +75,9 @@ class WebsiteAccount(website_account):
|
||||
'default_url': '/my/issues',
|
||||
'pager': pager
|
||||
})
|
||||
return request.website.render("website_project_issue.my_issues", values)
|
||||
return request.render("website_project_issue.my_issues", values)
|
||||
|
||||
@http.route(['/my/issues/<int:issue_id>'], type='http', auth="user", website=True)
|
||||
def my_issues_issue(self, issue_id=None, **kw):
|
||||
issue = request.env['project.issue'].browse(issue_id)
|
||||
return request.website.render("website_project_issue.my_issues_issue", {'issue': issue})
|
||||
return request.render("website_project_issue.my_issues_issue", {'issue': issue})
|
||||
|
||||
@@ -32,7 +32,7 @@ class sale_quote(http.Controller):
|
||||
order = request.env['sale.order'].search([('id', '=', order_id)])
|
||||
|
||||
if not order:
|
||||
return request.website.render('website.404')
|
||||
return request.render('website.404')
|
||||
|
||||
dummy, action = request.env['ir.model.data'].get_object_reference('sale', 'action_quotations')
|
||||
days = 0
|
||||
@@ -81,16 +81,16 @@ class sale_quote(http.Controller):
|
||||
'partner_id': order.partner_id.id,
|
||||
},
|
||||
context=render_ctx)
|
||||
return request.website.render('website_quote.so_quotation', values)
|
||||
return request.render('website_quote.so_quotation', values)
|
||||
|
||||
@http.route(['/quote/accept'], type='json', auth="public", website=True)
|
||||
def accept(self, order_id, token=None, signer=None, sign=None, **post):
|
||||
order_obj = request.registry.get('sale.order')
|
||||
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
return request.render('website.404')
|
||||
if order.require_payment:
|
||||
return request.website.render('website.404')
|
||||
return request.render('website.404')
|
||||
if order.state != 'sent':
|
||||
return False
|
||||
attachments=sign and [('signature.png', sign.decode('base64'))] or []
|
||||
@@ -104,7 +104,7 @@ class sale_quote(http.Controller):
|
||||
order_obj = request.registry.get('sale.order')
|
||||
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
return request.render('website.404')
|
||||
if order.state != 'sent':
|
||||
return werkzeug.utils.redirect("/quote/%s/%s?message=4" % (order_id, token))
|
||||
request.registry.get('sale.order').action_cancel(request.cr, SUPERUSER_ID, [order_id])
|
||||
@@ -117,7 +117,7 @@ class sale_quote(http.Controller):
|
||||
def update(self, line_id, remove=False, unlink=False, order_id=None, token=None, **post):
|
||||
order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, int(order_id))
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
return request.render('website.404')
|
||||
if order.state not in ('draft','sent'):
|
||||
return False
|
||||
line_id=int(line_id)
|
||||
@@ -135,16 +135,16 @@ class sale_quote(http.Controller):
|
||||
@http.route(["/quote/template/<model('sale.quote.template'):quote>"], type='http', auth="user", website=True)
|
||||
def template_view(self, quote, **post):
|
||||
values = { 'template': quote }
|
||||
return request.website.render('website_quote.so_template', values)
|
||||
return request.render('website_quote.so_template', values)
|
||||
|
||||
@http.route(["/quote/add_line/<int:option_id>/<int:order_id>/<token>"], type='http', auth="public", website=True)
|
||||
def add(self, option_id, order_id, token, **post):
|
||||
vals = {}
|
||||
order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, order_id)
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
return request.render('website.404')
|
||||
if order.state not in ['draft', 'sent']:
|
||||
return request.website.render('website.http_error', {'status_code': 'Forbidden', 'status_message': _('You cannot add options to a confirmed order.')})
|
||||
return request.render('website.http_error', {'status_code': 'Forbidden', 'status_message': _('You cannot add options to a confirmed order.')})
|
||||
option_obj = request.registry.get('sale.order.option')
|
||||
option = option_obj.browse(request.cr, SUPERUSER_ID, option_id)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class WebsiteRatingProject(http.Controller):
|
||||
def index(self, **kw):
|
||||
projects = request.env['project.project'].sudo().search([('rating_status', '!=', 'no'), ('website_published', '=', True)])
|
||||
values = {'projects': projects}
|
||||
return request.website.render('website_rating_project_issue.index', values)
|
||||
return request.render('website_rating_project_issue.index', values)
|
||||
|
||||
@http.route(['/project/rating/<int:project_id>'], type='http', auth="public", website=True)
|
||||
def page(self, project_id=None, **kw):
|
||||
@@ -27,7 +27,7 @@ class WebsiteRatingProject(http.Controller):
|
||||
'task_data': self._calculate_rating(project.id, "project.task"),
|
||||
'issue_data': self._calculate_rating(project.id, "project.issue"),
|
||||
}
|
||||
return request.website.render('website_rating_project_issue.project_rating_page', values)
|
||||
return request.render('website_rating_project_issue.project_rating_page', values)
|
||||
|
||||
def _calculate_rating(self, project_id, model_name):
|
||||
# Calculate rating for Tasks and Issues
|
||||
|
||||
@@ -19,8 +19,7 @@ class Project(models.Model):
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def _website_url(self, field_name, arg):
|
||||
res = dict()
|
||||
def _compute_website_url(self):
|
||||
super(Project, self)._compute_website_url()
|
||||
for project in self:
|
||||
res[project.id] = "/project/rating/%s" % project.id
|
||||
return res
|
||||
project.website_url = "/project/rating/%s" % project.id
|
||||
|
||||
@@ -258,7 +258,7 @@ class WebsiteSale(http.Controller):
|
||||
}
|
||||
if category:
|
||||
values['main_object'] = category
|
||||
return request.website.render("website_sale.products", values)
|
||||
return request.render("website_sale.products", values)
|
||||
|
||||
@http.route(['/shop/product/<model("product.template"):product>'], type='http', auth="public", website=True)
|
||||
def product(self, product, category='', search='', **kwargs):
|
||||
@@ -307,7 +307,7 @@ class WebsiteSale(http.Controller):
|
||||
'rating_message_values': rating_message_values,
|
||||
'rating_product': rating_product
|
||||
}
|
||||
return request.website.render("website_sale.product", values)
|
||||
return request.render("website_sale.product", values)
|
||||
|
||||
@http.route(['/shop/change_pricelist/<model("product.pricelist"):pl_id>'], type='http', auth="public", website=True)
|
||||
def pricelist_change(self, pl_id, **post):
|
||||
@@ -347,12 +347,12 @@ class WebsiteSale(http.Controller):
|
||||
values['suggested_products'] = _order._cart_accessories()
|
||||
|
||||
if post.get('type') == 'popover':
|
||||
return request.website.render("website_sale.cart_popover", values)
|
||||
return request.render("website_sale.cart_popover", values)
|
||||
|
||||
if post.get('code_not_available'):
|
||||
values['code_not_available'] = post.get('code_not_available')
|
||||
|
||||
return request.website.render("website_sale.cart", values)
|
||||
return request.render("website_sale.cart", values)
|
||||
|
||||
@http.route(['/shop/cart/update'], type='http', auth="public", methods=['POST'], website=True, csrf=False)
|
||||
def cart_update(self, product_id, add_qty=1, set_qty=0, **kw):
|
||||
@@ -377,7 +377,7 @@ class WebsiteSale(http.Controller):
|
||||
value['cart_quantity'] = order.cart_quantity
|
||||
from_currency = order.company_id.currency_id
|
||||
to_currency = order.pricelist_id.currency_id
|
||||
value['website_sale.cart_lines'] = request.website._render("website_sale.cart_lines", {
|
||||
value['website_sale.cart_lines'] = request.env['ir.ui.view'].render_template("website_sale.cart_lines", {
|
||||
'website_sale_order': order,
|
||||
'compute_currency': lambda price: from_currency.compute(price, to_currency),
|
||||
'suggested_products': order.with_context(pricelist=order.pricelist_id.id)._cart_accessories()
|
||||
@@ -594,7 +594,7 @@ class WebsiteSale(http.Controller):
|
||||
'error': errors,
|
||||
'callback': kw.get('callback'),
|
||||
}
|
||||
return request.website.render("website_sale.address", render_values)
|
||||
return request.render("website_sale.address", render_values)
|
||||
|
||||
@http.route(['/shop/checkout'], type='http', auth="public", website=True)
|
||||
def checkout(self, **post):
|
||||
@@ -612,7 +612,7 @@ class WebsiteSale(http.Controller):
|
||||
# Avoid useless rendering if called in ajax
|
||||
if post.get('xhr'):
|
||||
return 'ok'
|
||||
return request.website.render("website_sale.checkout", values)
|
||||
return request.render("website_sale.checkout", values)
|
||||
|
||||
@http.route(['/shop/confirm_order'], type='http', auth="public", website=True)
|
||||
def confirm_order(self, **post):
|
||||
@@ -665,7 +665,7 @@ class WebsiteSale(http.Controller):
|
||||
|
||||
values.update(request.env['sale.order']._get_website_data(order))
|
||||
|
||||
return request.website.render("website_sale.extra_info", values)
|
||||
return request.render("website_sale.extra_info", values)
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Payment
|
||||
@@ -721,7 +721,7 @@ class WebsiteSale(http.Controller):
|
||||
acquirer.button = acquirer_button
|
||||
values['acquirers'].append(acquirer)
|
||||
|
||||
return request.website.render("website_sale.payment", values)
|
||||
return request.render("website_sale.payment", values)
|
||||
|
||||
@http.route(['/shop/payment/transaction/<int:acquirer_id>'], type='json', auth="public", website=True)
|
||||
def payment_transaction(self, acquirer_id):
|
||||
@@ -808,7 +808,7 @@ class WebsiteSale(http.Controller):
|
||||
'tx_post_msg': tx.acquirer_id.post_msg or None
|
||||
})
|
||||
|
||||
return {'recall': flag, 'message': request.website._render("website_sale.order_state_message", values)}
|
||||
return {'recall': flag, 'message': request.env['ir.ui.view'].render_template("website_sale.order_state_message", values)}
|
||||
|
||||
@http.route('/shop/payment/validate', type='http', auth="public", website=True)
|
||||
def payment_validate(self, transaction_id=None, sale_order_id=None, **post):
|
||||
@@ -859,7 +859,7 @@ class WebsiteSale(http.Controller):
|
||||
sale_order_id = request.session.get('sale_last_order_id')
|
||||
if sale_order_id:
|
||||
order = request.env['sale.order'].sudo().browse(sale_order_id)
|
||||
return request.website.render("website_sale.confirmation", {'order': order})
|
||||
return request.render("website_sale.confirmation", {'order': order})
|
||||
else:
|
||||
return request.redirect('/shop')
|
||||
|
||||
|
||||
@@ -127,11 +127,10 @@ class ProductTemplate(models.Model):
|
||||
return self.set_sequence_bottom()
|
||||
|
||||
@api.multi
|
||||
def _website_url(self, field_name, arg):
|
||||
res = super(ProductTemplate, self)._website_url(field_name, arg)
|
||||
def _compute_website_url(self):
|
||||
super(ProductTemplate, self)._compute_website_url()
|
||||
for product in self:
|
||||
res[product.id] = "/shop/product/%s" % (product.id,)
|
||||
return res
|
||||
product.website_url = "/shop/product/%s" % (product.id,)
|
||||
|
||||
@api.multi
|
||||
def display_price(self, pricelist, qty=1, public=False, **kw):
|
||||
|
||||
@@ -54,7 +54,7 @@ class WebsiteSaleOptions(WebsiteSale):
|
||||
to_currency = pricelist.currency_id
|
||||
compute_currency = lambda price: request.env['res.currency']._compute(from_currency, to_currency, price)
|
||||
product = request.env['product.product'].with_context(product_context).browse(int(product_id))
|
||||
return request.website._render("website_sale_options.modal", {
|
||||
return request.env['ir.ui.view'].render_template("website_sale_options.modal", {
|
||||
'product': product,
|
||||
'compute_currency': compute_currency,
|
||||
'get_attribute_value_ids': self.get_attribute_value_ids,
|
||||
|
||||
@@ -56,10 +56,10 @@ class website_slides(http.Controller):
|
||||
"""
|
||||
channels = request.env['slide.channel'].search([], order='sequence, id')
|
||||
if not channels:
|
||||
return request.website.render("website_slides.channel_not_found")
|
||||
return request.render("website_slides.channel_not_found")
|
||||
elif len(channels) == 1:
|
||||
return request.redirect("/slides/%s" % channels.id)
|
||||
return request.website.render('website_slides.channels', {
|
||||
return request.render('website_slides.channels', {
|
||||
'channels': channels,
|
||||
'user': request.env.user,
|
||||
'is_public_user': request.env.user == request.website.user_id
|
||||
@@ -131,7 +131,7 @@ class website_slides(http.Controller):
|
||||
}
|
||||
if search:
|
||||
values['search'] = search
|
||||
return request.website.render('website_slides.slides_search', values)
|
||||
return request.render('website_slides.slides_search', values)
|
||||
|
||||
# Display uncategorized slides
|
||||
if not slide_type and not category:
|
||||
@@ -147,7 +147,7 @@ class website_slides(http.Controller):
|
||||
values.update({
|
||||
'category_datas': category_datas,
|
||||
})
|
||||
return request.website.render('website_slides.home', values)
|
||||
return request.render('website_slides.home', values)
|
||||
|
||||
# --------------------------------------------------
|
||||
# SLIDE.SLIDE CONTOLLERS
|
||||
@@ -158,7 +158,7 @@ class website_slides(http.Controller):
|
||||
values = self._get_slide_detail(slide)
|
||||
if not values.get('private'):
|
||||
self._set_viewed_slide(slide, 'slide')
|
||||
return request.website.render('website_slides.slide_detail_view', values)
|
||||
return request.render('website_slides.slide_detail_view', values)
|
||||
|
||||
@http.route('''/slides/slide/<model("slide.slide", "[('channel_id.can_see', '=', True), ('datas', '!=', False), ('slide_type', '=', 'presentation')]"):slide>/pdf_content''', type='http', auth="public", website=True)
|
||||
def slide_get_pdf_content(self, slide):
|
||||
@@ -225,7 +225,7 @@ class website_slides(http.Controller):
|
||||
('Content-Disposition', disposition)])
|
||||
elif not request.session.uid and slide.download_security == 'user':
|
||||
return werkzeug.utils.redirect('/web?redirect=/slides/slide/%s' % (slide.id))
|
||||
return request.website.render("website.403")
|
||||
return request.render("website.403")
|
||||
|
||||
@http.route('''/slides/slide/<model("slide.slide"):slide>/promote''', type='http', auth='user', website=True)
|
||||
def slide_set_promoted(self, slide):
|
||||
@@ -344,8 +344,8 @@ class website_slides(http.Controller):
|
||||
values['is_embedded'] = is_embedded
|
||||
if not values.get('private'):
|
||||
self._set_viewed_slide(slide, 'embed')
|
||||
return request.website.render('website_slides.embed_slide', values)
|
||||
return request.render('website_slides.embed_slide', values)
|
||||
except AccessError: # TODO : please, make it clean one day, or find another secure way to detect
|
||||
# if the slide can be embedded, and properly display the error message.
|
||||
slide = request.env['slide.slide'].sudo().browse(slide_id)
|
||||
return request.website.render('website_slides.embed_slide_forbidden', {'slide': slide})
|
||||
return request.render('website_slides.embed_slide_forbidden', {'slide': slide})
|
||||
|
||||
@@ -142,11 +142,11 @@ class Channel(models.Model):
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def _website_url(self, name, arg):
|
||||
res = super(Channel, self)._website_url(name, arg)
|
||||
def _compute_website_url(self):
|
||||
super(Channel, self)._compute_website_url()
|
||||
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
res.update({(channel.id, '%s/slides/%s' % (base_url, slug(channel))) for channel in self})
|
||||
return res
|
||||
for channel in self:
|
||||
channel.website_url = '%s/slides/%s' % (base_url, slug(channel))
|
||||
|
||||
@api.onchange('visibility')
|
||||
def change_visibility(self):
|
||||
@@ -346,17 +346,16 @@ class Slide(models.Model):
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def _website_url(self, name, arg):
|
||||
res = super(Slide, self)._website_url(name, arg)
|
||||
def _compute_website_url(self):
|
||||
super(Slide, self)._compute_website_url()
|
||||
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
#link_tracker is not in dependencies, so use it to shorten url only if installed.
|
||||
if self.env.registry.get('link.tracker'):
|
||||
LinkTracker = self.env['link.tracker']
|
||||
res.update({(slide.id, LinkTracker.sudo().create({'url': '%s/slides/slide/%s' % (base_url, slug(slide))}).short_url) for slide in self})
|
||||
else:
|
||||
res.update({(slide.id, '%s/slides/slide/%s' % (base_url, slug(slide))) for slide in self})
|
||||
return res
|
||||
|
||||
for slide in self:
|
||||
#link_tracker is not in dependencies, so use it to shorten url only if installed.
|
||||
if self.env.registry.get('link.tracker'):
|
||||
url = self.env['link.tracker'].sudo().create({'url': '%s/slides/slide/%s' % (base_url, slug(slide))}).short_url
|
||||
else:
|
||||
url = '%s/slides/slide/%s' % (base_url, slug(slide))
|
||||
slide.website_url = url
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
|
||||
@@ -205,7 +205,11 @@ class IrHttp(models.AbstractModel):
|
||||
if tools.config['test_enable']:
|
||||
installed.add(odoo.modules.module.current_test)
|
||||
mods = [''] + odoo.conf.server_wide_modules + sorted(installed)
|
||||
self._routing_map = http.routing_map(mods, False, converters=self._get_converters())
|
||||
# Note : when routing map is generated, we put it on the class `type(self)`
|
||||
# to make it available for all instance. Since `env` create an new instance
|
||||
# of the model, each instance will regenared its own routing map and thus
|
||||
# regenerate its EndPoint. The routing map should be static.
|
||||
type(self)._routing_map = http.routing_map(mods, False, converters=self._get_converters())
|
||||
|
||||
return self._routing_map
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||
cr.commit()
|
||||
else:
|
||||
cr.rollback()
|
||||
# avoid keeping stale xml_id, etc. in cache
|
||||
# avoid keeping stale xml_id, etc. in cache
|
||||
openerp.modules.registry.RegistryManager.clear_caches(cr.dbname)
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||
ir_http = registry['ir.http']
|
||||
if hasattr(ir_http, '_routing_map'):
|
||||
# Force routing map to be rebuilt between each module test suite
|
||||
del(ir_http._routing_map)
|
||||
del(type(ir_http)._routing_map)
|
||||
report.record_result(openerp.modules.module.run_unit_tests(module_name, cr.dbname))
|
||||
|
||||
processed_modules.append(package.name)
|
||||
@@ -268,7 +268,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
if 'base' in tools.config['update'] or 'all' in tools.config['update']:
|
||||
cr.execute("update ir_module_module set state=%s where name=%s and state=%s", ('to upgrade', 'base', 'installed'))
|
||||
|
||||
# STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
|
||||
# STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
|
||||
graph = openerp.modules.graph.Graph()
|
||||
graph.add_module(cr, 'base', force)
|
||||
if not graph:
|
||||
|
||||
Reference in New Issue
Block a user