Merge pull request #2300 from odoo-dev/master-website-multi-sig
[MERGE] Domain name based multi website
This commit is contained in:
@@ -164,11 +164,11 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
def pagenew(self, path, noredirect=False, add_menu=None):
|
||||
xml_id = request.registry['website'].new_page(request.cr, request.uid, path, context=request.context)
|
||||
if add_menu:
|
||||
model, id = request.registry["ir.model.data"].get_object_reference(request.cr, request.uid, 'website', 'main_menu')
|
||||
request.registry['website.menu'].create(request.cr, request.uid, {
|
||||
'name': path,
|
||||
'url': "/page/" + xml_id,
|
||||
'parent_id': id,
|
||||
'parent_id': request.website.menu_id.id,
|
||||
'website_id': request.website.id,
|
||||
}, context=request.context)
|
||||
# Reverse action in order to allow shortcut for /page/<website_xml_id>
|
||||
url = "/page/" + re.sub(r"^website\.", '', xml_id)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
<record id="main_menu" model="website.menu">
|
||||
<field name="name">Top Menu</field>
|
||||
<field name="website_id" ref="default_website"/>
|
||||
</record>
|
||||
|
||||
<record id="menu_homepage" model="website.menu">
|
||||
@@ -18,6 +19,7 @@
|
||||
<field name="url">/page/homepage</field>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">10</field>
|
||||
<field name="website_id" ref="default_website"/>
|
||||
</record>
|
||||
|
||||
<record id="menu_contactus" model="website.menu">
|
||||
@@ -25,6 +27,7 @@
|
||||
<field name="url">/page/website.contactus</field>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">60</field>
|
||||
<field name="website_id" ref="default_website"/>
|
||||
</record>
|
||||
|
||||
<record id="base.group_website_publisher" model="res.groups">
|
||||
|
||||
@@ -132,5 +132,79 @@ response = request.render("website.template_partner_comment", values)
|
||||
<field name="state">code</field>
|
||||
<field name="type">ir.actions.server</field>
|
||||
</record>
|
||||
|
||||
<record id="website2" model="website">
|
||||
<field name="name">0.0.0.0</field>
|
||||
<field name="social_twitter">https://twitter.com/odooapps</field>
|
||||
<field name="social_facebook">https://www.facebook.com/Odoo</field>
|
||||
<field name="social_googleplus">https://plus.google.com/+Odooapps</field>
|
||||
<field name="social_linkedin">http://www.linkedin.com/company/odoo</field>
|
||||
<field name="language_ids" eval="[(6, 0, [ ref('base.lang_en')])]"/>
|
||||
<field name="default_lang_id" ref="base.lang_en"/>
|
||||
</record>
|
||||
|
||||
<record id="website2_homepage" model="ir.ui.view">
|
||||
<field name="name">Homepage</field>
|
||||
<field name="type">qweb</field>
|
||||
<field name="key">website.homepage</field>
|
||||
<field name="website_id" ref="website2"/>
|
||||
<field name="arch" type="xml">
|
||||
<t name="Homepage" priority="29" t-name="website.homepage">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap" class="oe_structure oe_empty">
|
||||
<div class="carousel slide mb32" id="myCarousel0" style="height: 320px;">
|
||||
<ol class="carousel-indicators hidden">
|
||||
<li class="active" data-slide-to="0" data-target="#myCarousel0"/>
|
||||
</ol>
|
||||
<div class="carousel-inner">
|
||||
<div class="item image_text oe_img_bg active" style="background-image: url(http://0.0.0.0:8069/website/static/src/img/banner/mountains.jpg);">
|
||||
<div class="container">
|
||||
<div class="row content">
|
||||
<div class="carousel-content col-md-6 col-sm-12">
|
||||
<h2>Homepage 0.0.0.0</h2>
|
||||
<h3>Click to customize this text</h3>
|
||||
<p>
|
||||
<a class="btn btn-success btn-large" href="/page/website.contactus">Contact us</a>
|
||||
</p>
|
||||
</div>
|
||||
<span class="carousel-img col-md-6 hidden-sm hidden-xs"> </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-control left hidden" data-slide="prev" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
|
||||
<i class="fa fa-chevron-left"/>
|
||||
</div>
|
||||
<div class="carousel-control right hidden" data-slide="next" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
|
||||
<i class="fa fa-chevron-right"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="website2_main_menu" model="website.menu">
|
||||
<field name="name">Top Menu</field>
|
||||
<field name="website_id" ref="website2"/>
|
||||
</record>
|
||||
|
||||
<record id="website2_menu_homepage" model="website.menu">
|
||||
<field name="name">Home</field>
|
||||
<field name="url">/page/homepage</field>
|
||||
<field name="parent_id" ref="website.website2_main_menu"/>
|
||||
<field name="sequence" type="int">10</field>
|
||||
<field name="website_id" ref="website2"/>
|
||||
</record>
|
||||
|
||||
<record id="website2_menu_contactus" model="website.menu">
|
||||
<field name="name">Contact us</field>
|
||||
<field name="url">/page/website.contactus</field>
|
||||
<field name="parent_id" ref="website.website2_main_menu"/>
|
||||
<field name="sequence" type="int">60</field>
|
||||
<field name="website_id" ref="website2"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -88,6 +88,7 @@ class ir_http(orm.AbstractModel):
|
||||
|
||||
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.context['website_id'] = request.website.id
|
||||
langs = [lg[0] for lg in request.website.get_languages()]
|
||||
path = request.httprequest.path.split('/')
|
||||
if first_pass:
|
||||
@@ -122,6 +123,8 @@ class ir_http(orm.AbstractModel):
|
||||
# to url without language so google doesn't see duplicate content
|
||||
return request.redirect(path + '?' + request.httprequest.query_string, code=301)
|
||||
return self.reroute(path)
|
||||
# bind modified context
|
||||
request.website = request.website.with_context(request.context)
|
||||
return super(ir_http, self)._dispatch()
|
||||
|
||||
def reroute(self, path):
|
||||
|
||||
@@ -3,7 +3,7 @@ import copy
|
||||
|
||||
from lxml import etree, html
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import SUPERUSER_ID, tools
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.http import request
|
||||
from openerp.osv import osv, fields
|
||||
@@ -16,13 +16,19 @@ class view(osv.osv):
|
||||
'website_meta_description': fields.text("Website meta description", size=160, translate=True),
|
||||
'website_meta_keywords': fields.char("Website meta keywords", translate=True),
|
||||
'customize_show': fields.boolean("Show As Optional Inherit"),
|
||||
'website_id': fields.many2one('website',ondelete='cascade', string="Website"),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('key_website_id_uniq', 'unique(key, website_id)',
|
||||
'Key must be unique per website.'),
|
||||
]
|
||||
|
||||
_defaults = {
|
||||
'page': False,
|
||||
'customize_show': False,
|
||||
}
|
||||
|
||||
|
||||
def _view_obj(self, cr, uid, view_id, context=None):
|
||||
if isinstance(view_id, basestring):
|
||||
return self.pool['ir.model.data'].xmlid_to_object(
|
||||
@@ -133,6 +139,15 @@ class view(osv.osv):
|
||||
|
||||
return arch
|
||||
|
||||
@tools.ormcache_context(accepted_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)]
|
||||
[xml_id] = self.search(cr, uid, domain, order='website_id', limit=1, context=context)
|
||||
else:
|
||||
xml_id = super(view, self).get_view_id(cr, uid, xml_id, context=context)
|
||||
return xml_id
|
||||
|
||||
def render(self, cr, uid, id_or_xml_id, values=None, engine='ir.qweb', context=None):
|
||||
if request and getattr(request, 'website_enabled', False):
|
||||
engine='website.qweb'
|
||||
|
||||
@@ -29,6 +29,7 @@ from openerp.tools import html_escape as escape
|
||||
from openerp.tools import ustr as ustr
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
from openerp.addons.web.http import request
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -137,15 +138,13 @@ def urlplus(url, params):
|
||||
return werkzeug.Href(url)(params or None)
|
||||
|
||||
class website(osv.osv):
|
||||
def _get_menu_website(self, cr, uid, ids, context=None):
|
||||
# IF a menu is changed, update all websites
|
||||
return self.search(cr, uid, [], context=context)
|
||||
|
||||
def _get_menu(self, cr, uid, ids, name, arg, context=None):
|
||||
root_domain = [('parent_id', '=', False)]
|
||||
menus = self.pool.get('website.menu').search(cr, uid, root_domain, order='id', context=context)
|
||||
menu = menus and menus[0] or False
|
||||
return dict( map(lambda x: (x, menu), ids) )
|
||||
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
|
||||
|
||||
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
|
||||
_description = "Website"
|
||||
@@ -164,14 +163,12 @@ class website(osv.osv):
|
||||
'google_analytics_key': fields.char('Google Analytics Key'),
|
||||
'user_id': fields.many2one('res.users', string='Public User'),
|
||||
'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',
|
||||
store= {
|
||||
'website.menu': (_get_menu_website, ['sequence','parent_id','website_id'], 10)
|
||||
})
|
||||
'menu_id': fields.function(_get_menu, relation='website.menu', type='many2one', string='Main Menu')
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'company_id': lambda self,cr,uid,c: self.pool['ir.model.data'].xmlid_to_res_id(cr, openerp.SUPERUSER_ID, 'base.public_user'),
|
||||
'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'),
|
||||
|
||||
}
|
||||
|
||||
# cf. Wizard hack in website_views.xml
|
||||
@@ -198,20 +195,15 @@ class website(osv.osv):
|
||||
except ValueError:
|
||||
# new page
|
||||
_, template_id = imd.get_object_reference(cr, uid, template_module, template_name)
|
||||
page_id = view.copy(cr, uid, template_id, context=context)
|
||||
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=context)
|
||||
page.write({
|
||||
'arch': page.arch.replace(template, page_xmlid),
|
||||
'name': page_name,
|
||||
'page': ispage,
|
||||
})
|
||||
imd.create(cr, uid, {
|
||||
'name': page_name,
|
||||
'module': template_module,
|
||||
'model': 'ir.ui.view',
|
||||
'res_id': page_id,
|
||||
'noupdate': True
|
||||
}, context=context)
|
||||
return page_xmlid
|
||||
|
||||
def page_for_name(self, cr, uid, ids, name, module='website', context=None):
|
||||
@@ -259,9 +251,19 @@ class website(osv.osv):
|
||||
lang['hreflang'] = lang['short']
|
||||
return langs
|
||||
|
||||
@openerp.tools.ormcache(skiparg=4)
|
||||
def _get_current_website_id(self, cr, uid, domain_name, context=None):
|
||||
website_id = 1
|
||||
if request:
|
||||
ids = self.search(cr, uid, [('name', '=', domain_name)], context=context)
|
||||
if ids:
|
||||
website_id = ids[0]
|
||||
return website_id
|
||||
|
||||
def get_current_website(self, cr, uid, context=None):
|
||||
# TODO: Select website, currently hard coded
|
||||
return self.pool['website'].browse(cr, uid, 1, context=context)
|
||||
domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0]
|
||||
website_id = self._get_current_website_id(cr, uid, domain_name, context=context)
|
||||
return self.browse(cr, uid, website_id, context=context)
|
||||
|
||||
def is_publisher(self, cr, uid, ids, context=None):
|
||||
Access = self.pool['ir.model.access']
|
||||
@@ -273,14 +275,13 @@ class website(osv.osv):
|
||||
return Access.check(cr, uid, 'ir.ui.menu', 'read', False, context=context)
|
||||
|
||||
def get_template(self, cr, uid, ids, template, context=None):
|
||||
if isinstance(template, (int, long)):
|
||||
view_id = template
|
||||
else:
|
||||
if '.' not in template:
|
||||
template = 'website.%s' % template
|
||||
module, xmlid = template.split('.', 1)
|
||||
model, view_id = request.registry["ir.model.data"].get_object_reference(cr, uid, module, xmlid)
|
||||
return self.pool["ir.ui.view"].browse(cr, uid, view_id, context=context)
|
||||
if not isinstance(template, (int, long)) and '.' not in template:
|
||||
template = 'website.%s' % template
|
||||
View = self.pool['ir.ui.view']
|
||||
view_id = View.get_view_id(cr, uid, template, context=context)
|
||||
if not view_id:
|
||||
raise NotFound
|
||||
return View.browse(cr, uid, view_id, context=context)
|
||||
|
||||
def _render(self, cr, uid, ids, template, values=None, context=None):
|
||||
# TODO: remove this. (just kept for backward api compatibility for saas-3)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
<div>
|
||||
<field name="website_id" invisible="True" on_change="on_change_website_id(website_id)"/>
|
||||
<field name="website_id" on_change="on_change_website_id(website_id)"/>
|
||||
<group string="Domain">
|
||||
<label for="google_analytics_key"/>
|
||||
<div name="google_analytics_key">
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<field name="name">Website Menu</field>
|
||||
<field name="res_model">website.menu</field>
|
||||
<field name="view_mode">list</field>
|
||||
<field name="context">{'search_default_my_websites':1}</field>
|
||||
</record>
|
||||
|
||||
<record id="menu_tree" model="ir.ui.view">
|
||||
@@ -95,5 +96,37 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="menu_search" model="ir.ui.view">
|
||||
<field name="name">website.menu.search</field>
|
||||
<field name="model">website.menu</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Menus">
|
||||
<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'}"/>
|
||||
<filter string="website" name="my_websites" domain="[]" context="{'group_by':'website_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<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"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<field name="name" position="after">
|
||||
<field name="website_id"/>
|
||||
<field name="key"/>
|
||||
</field>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<field name="url" eval="'/blog/'+str(ref('website_blog.blog_blog_1'))"/>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">40</field>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
|
||||
@@ -179,12 +179,6 @@ class website_event(http.Controller):
|
||||
if '.' not in page:
|
||||
page = 'website_event.%s' % page
|
||||
|
||||
try:
|
||||
request.website.get_template(page)
|
||||
except ValueError, e:
|
||||
# page not found
|
||||
raise NotFound
|
||||
|
||||
return request.website.render(page, values)
|
||||
|
||||
@http.route(['/event/<model("event.event"):event>'], type='http', auth="public", website=True)
|
||||
|
||||
@@ -179,6 +179,7 @@ class view(osv.osv):
|
||||
_columns = {
|
||||
'name': fields.char('View Name', required=True),
|
||||
'model': fields.char('Object', select=True),
|
||||
'key': fields.char(string='Key'),
|
||||
'priority': fields.integer('Sequence', required=True),
|
||||
'type': fields.selection([
|
||||
('tree','Tree'),
|
||||
@@ -312,7 +313,7 @@ class view(osv.osv):
|
||||
if not values.get('name'):
|
||||
values['name'] = "%s %s" % (values.get('model'), values['type'])
|
||||
|
||||
self.read_template.clear_cache(self)
|
||||
self._read_template.clear_cache(self)
|
||||
return super(view, self).create(
|
||||
cr, uid,
|
||||
self._compute_defaults(cr, uid, values, context=context),
|
||||
@@ -335,7 +336,7 @@ class view(osv.osv):
|
||||
if custom_view_ids:
|
||||
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
|
||||
|
||||
self.read_template.clear_cache(self)
|
||||
self._read_template.clear_cache(self)
|
||||
ret = super(view, self).write(
|
||||
cr, uid, ids,
|
||||
self._compute_defaults(cr, uid, vals, context=context),
|
||||
@@ -896,18 +897,11 @@ class view(osv.osv):
|
||||
#------------------------------------------------------
|
||||
# QWeb template views
|
||||
#------------------------------------------------------
|
||||
read_template_cache = dict(accepted_keys=('lang','inherit_branding', 'editable', 'translatable'))
|
||||
_read_template_cache = dict(accepted_keys=('lang','inherit_branding', 'editable', 'translatable'))
|
||||
if config['dev_mode']:
|
||||
read_template_cache['size'] = 0
|
||||
@tools.ormcache_context(**read_template_cache)
|
||||
def read_template(self, cr, uid, xml_id, context=None):
|
||||
if isinstance(xml_id, (int, long)):
|
||||
view_id = xml_id
|
||||
else:
|
||||
if '.' not in xml_id:
|
||||
raise ValueError('Invalid template id: %r' % (xml_id,))
|
||||
view_id = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, xml_id, raise_if_not_found=True)
|
||||
|
||||
_read_template_cache['size'] = 0
|
||||
@tools.ormcache_context(**_read_template_cache)
|
||||
def _read_template(self, cr, uid, view_id, context=None):
|
||||
arch = self.read_combined(cr, uid, view_id, fields=['arch'], context=context)['arch']
|
||||
arch_tree = etree.fromstring(arch)
|
||||
|
||||
@@ -920,8 +914,21 @@ class view(osv.osv):
|
||||
arch = etree.tostring(root, encoding='utf-8', xml_declaration=True)
|
||||
return arch
|
||||
|
||||
def read_template(self, cr, uid, xml_id, context=None):
|
||||
if isinstance(xml_id, (int, long)):
|
||||
view_id = xml_id
|
||||
else:
|
||||
if '.' not in xml_id:
|
||||
raise ValueError('Invalid template id: %r' % (xml_id,))
|
||||
view_id = self.get_view_id(cr, uid, xml_id, context=context)
|
||||
return self._read_template(cr, uid, view_id, context=context)
|
||||
|
||||
@tools.ormcache(skiparg=3)
|
||||
def get_view_id(self, cr, uid, xml_id, context=None):
|
||||
return self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, xml_id, raise_if_not_found=True)
|
||||
|
||||
def clear_cache(self):
|
||||
self.read_template.clear_cache(self)
|
||||
self._read_template.clear_cache(self)
|
||||
|
||||
def _contains_branded(self, node):
|
||||
return node.tag == 't'\
|
||||
|
||||
@@ -804,6 +804,7 @@ form: module.record_id""" % (xml_id,)
|
||||
|
||||
record = etree.Element('record', attrib=record_attrs)
|
||||
record.append(Field(name, name='name'))
|
||||
record.append(Field(full_tpl_id, name='key'))
|
||||
record.append(Field("qweb", name='type'))
|
||||
record.append(Field(el.get('priority', "16"), name='priority'))
|
||||
if 'inherit_id' in el.attrib:
|
||||
|
||||
Reference in New Issue
Block a user