[REF] web, *: share common parts of main frontend layouts
* http_routing, portal, rating, survey, website, website_survey, website_slides_survey Before this commit, the final base layout of website was a fully overridden layout of the one in portal, which was somehow a duplicated one of the login one in web, which... so lots of duplicated code. This commit is a first step towards a better organization: 1) The web app defines a frontend layout (to include base frontend assets), with a base company logo as header. 2) The portal app modifies that layout in place to include the base header, footer, ... It also uses a primary extension of it for portal pages. The survey app simply uses the above layout instead of defining its own (by primary extension to include its own assets for its own pages) Same goes for the rating app and pages. 3) The website app modifies that layout in place to include the UI assets, to add website UI, ... This allows to create frontend apps which do not depend on website, with a non duplicated layout that will be automatically adapted if website is ever installed (this therefore allows to get rid of website_survey definitely) This commit also fixes the session info system and the translation URL on the frontend side to not require to redefine the whole session_info for portal, website, ... Now the frontend session_info is defined in web and http_routing extends it to add translation informations, then website extends it again to add its own elements (not to redefine them all as before). Note: before, http_routing defined the translation route but only portal was adding it in its layout... This is an adaptation of the work that was done with commit https://github.com/odoo/odoo/commit/99821fdcf89aa66ac9561a972c6823135ebf65c0 Note 1: Many frontend but non-website apps (not only survey / rating) could probably use this too but this would be the topic of another task. Note 2: survey currently depends on http_routing but does not add itself in the list of frontend apps to translate, it probably should. Note 3: web_editor does currently not depend on http_routing but does add itself in the list of frontend apps to translate, it thus uses a function it does not really depend on... to check after its work-in- progress refactoring. task-1961045 closes odoo/odoo#33825 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
@@ -1,23 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import odoo
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.osv import expression
|
||||
from odoo.addons.web.controllers.main import WebClient, Home
|
||||
|
||||
|
||||
class Routing(Home):
|
||||
|
||||
@http.route('/website/translations/<string:unique>', type='http', auth="public", website=True)
|
||||
def get_website_translations(self, unique, lang, mods=None):
|
||||
Modules = request.env['ir.module.module'].sudo()
|
||||
IrHttp = request.env['ir.http'].sudo()
|
||||
domain = IrHttp._get_translation_frontend_modules_domain()
|
||||
modules = Modules.search(
|
||||
expression.AND([domain, [('state', '=', 'installed')]])
|
||||
).mapped('name')
|
||||
modules = IrHttp.get_translation_frontend_modules()
|
||||
if mods:
|
||||
modules += mods
|
||||
return WebClient().translations(unique, mods=','.join(modules), lang=lang)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
@@ -16,6 +18,7 @@ import odoo
|
||||
from odoo import api, models
|
||||
from odoo.addons.base.models.ir_http import RequestUID, ModelConverter
|
||||
from odoo.http import request
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import config, ustr, pycompat
|
||||
|
||||
from ..geoipresolver import GeoIPResolver
|
||||
@@ -236,6 +239,32 @@ class IrHttp(models.AbstractModel):
|
||||
return request.env['res.lang'].search([('code', '=', lang_code)], limit=1)
|
||||
return request.env['res.lang'].search([], limit=1)
|
||||
|
||||
@api.model
|
||||
def get_frontend_session_info(self):
|
||||
session_info = super(IrHttp, self).get_frontend_session_info()
|
||||
|
||||
IrHttpModel = request.env['ir.http'].sudo()
|
||||
modules = IrHttpModel.get_translation_frontend_modules()
|
||||
user_context = request.session.get_context() if request.session.uid else {}
|
||||
lang = user_context.get('lang')
|
||||
translations, _ = request.env['ir.translation'].get_translations_for_webclient(modules, lang)
|
||||
|
||||
session_info.update({
|
||||
'translationURL': '/website/translations/',
|
||||
'cache_hashes': {
|
||||
'translations': hashlib.sha1(json.dumps(translations, sort_keys=True).encode()).hexdigest(),
|
||||
},
|
||||
})
|
||||
return session_info
|
||||
|
||||
@api.model
|
||||
def get_translation_frontend_modules(self):
|
||||
Modules = request.env['ir.module.module'].sudo()
|
||||
domain = self._get_translation_frontend_modules_domain()
|
||||
return Modules.search(
|
||||
expression.AND([domain, [('state', '=', 'installed')]])
|
||||
).mapped('name')
|
||||
|
||||
@classmethod
|
||||
def _get_translation_frontend_modules_domain(cls):
|
||||
""" Return a domain to list the domain adding web-translations and
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import models
|
||||
from odoo.osv import expression
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class IrHttp(models.AbstractModel):
|
||||
@@ -15,27 +12,3 @@ class IrHttp(models.AbstractModel):
|
||||
def _get_translation_frontend_modules_domain(cls):
|
||||
domain = super(IrHttp, cls)._get_translation_frontend_modules_domain()
|
||||
return expression.OR([domain, [('name', '=', 'portal')]])
|
||||
|
||||
@api.model
|
||||
def get_portal_session_info(self):
|
||||
# see http_routing/main.py
|
||||
Modules = request.env['ir.module.module'].sudo()
|
||||
IrHttp = request.env['ir.http'].sudo()
|
||||
domain = IrHttp._get_translation_frontend_modules_domain()
|
||||
modules = Modules.search(
|
||||
expression.AND([domain, [('state', '=', 'installed')]])
|
||||
).mapped('name')
|
||||
user_context = request.session.get_context() if request.session.uid else {}
|
||||
lang = user_context.get('lang')
|
||||
translations, _ = request.env['ir.translation'].get_translations_for_webclient(modules, lang)
|
||||
return {
|
||||
'is_admin': self.env.user._is_admin(),
|
||||
'is_system': self.env.user._is_system(),
|
||||
'is_website_user': self.env.user._is_public(),
|
||||
'user_id': self.env.user.id,
|
||||
'is_frontend': True,
|
||||
'translationURL': '/website/translations',
|
||||
'cache_hashes': {
|
||||
'translations': hashlib.sha1(json.dumps(translations, sort_keys=True).encode()).hexdigest(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,67 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="frontend_layout" name="Main Frontend Layout">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="head_website">
|
||||
<script type="text/javascript">
|
||||
odoo.session_info = <t t-raw="json.dumps(request.env['ir.http'].get_portal_session_info())"/>;
|
||||
</script>
|
||||
|
||||
<t t-call-assets="web.assets_common" t-js="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-js="false"/>
|
||||
|
||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-css="false"/>
|
||||
</t>
|
||||
<t t-set="head" t-value="head_website + (head or '')"/>
|
||||
|
||||
<t t-set="direction" t-value="request.env['res.lang'].search([('code', '=', request.env.lang)]).direction"/>
|
||||
<div id="wrapwrap" t-attf-class="#{pageName or ''} #{direction == 'rtl' and 'o_rtl' or ''} #{'o_portal' if is_portal else ''}">
|
||||
<header id="top" data-anchor="true" t-if="not hide_header">
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a href="/" class="navbar-brand logo">
|
||||
<img t-att-src="'/logo.png?company=%s' % res_company.id" t-att-alt="'Logo of %s' % res_company.name" t-att-title="res_company.name"/>
|
||||
</a>
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#top_menu_collapse">
|
||||
<span class="navbar-toggler-icon"/>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="top_menu_collapse">
|
||||
<!-- FIXME We want menu to open to the right by default (except cases handled in JS) -->
|
||||
<ul class="nav navbar-nav ml-auto text-right" id="top_menu">
|
||||
<li class="nav-item divider" t-ignore="true" t-if="not user_id._is_public()"/>
|
||||
<li class="nav-item dropdown" t-ignore="true" t-if="not user_id._is_public()">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">
|
||||
<b>
|
||||
<span t-esc="user_id.name[:23] + '...' if user_id.name and len(user_id.name) > 25 else user_id.name"/>
|
||||
</b>
|
||||
</a>
|
||||
<div class="dropdown-menu js_usermenu" role="menu">
|
||||
<a id="o_logout" class="dropdown-item" t-attf-href="/web/session/logout?redirect=/" role="menuitem">Logout</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<div t-if="o_portal_fullwidth_alert" class="alert alert-info alert-dismissible rounded-0 fade show d-print-none css_editable_mode_hidden">
|
||||
<div class="container">
|
||||
<t t-raw="o_portal_fullwidth_alert"/>
|
||||
</div>
|
||||
<template id="frontend_layout" name="Main Frontend Layout" inherit_id="web.frontend_layout">
|
||||
<xpath expr="//div[@id='wrapwrap']" position="attributes">
|
||||
<attribute name="t-attf-class" add="#{request.env['res.lang'].search([('code', '=', request.env.lang)]).direction == 'rtl' and 'o_rtl' or ''}" separator=" "/>
|
||||
<attribute name="t-attf-class" add="#{'o_portal' if is_portal else ''}" separator=" "/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='wrapwrap']/header/img" position="replace">
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a href="/" class="navbar-brand logo">
|
||||
<img t-att-src="'/logo.png?company=%s' % res_company.id" t-att-alt="'Logo of %s' % res_company.name" t-att-title="res_company.name"/>
|
||||
</a>
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#top_menu_collapse">
|
||||
<span class="navbar-toggler-icon"/>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="top_menu_collapse">
|
||||
<!-- FIXME We want menu to open to the right by default (except cases handled in JS) -->
|
||||
<ul class="nav navbar-nav ml-auto text-right" id="top_menu">
|
||||
<li class="nav-item divider" t-ignore="true" t-if="not user_id._is_public()"/>
|
||||
<li class="nav-item dropdown" t-ignore="true" t-if="not user_id._is_public()">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">
|
||||
<b>
|
||||
<span t-esc="user_id.name[:23] + '...' if user_id.name and len(user_id.name) > 25 else user_id.name"/>
|
||||
</b>
|
||||
</a>
|
||||
<div class="dropdown-menu js_usermenu" role="menu">
|
||||
<a id="o_logout" class="dropdown-item" t-attf-href="/web/session/logout?redirect=/" role="menuitem">Logout</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<t t-raw="0"/>
|
||||
</main>
|
||||
<footer id="bottom" data-anchor="true" class="bg-light o_footer" t-if="not hide_footer">
|
||||
<div class="container mt16 mb16" id="footer">
|
||||
<div class="float-right mb16" t-ignore="true" t-if="not editable">
|
||||
Powered by <a target="_blank" href="http://www.odoo.com?utm_source=db&utm_medium=portal">Odoo</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</nav>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='wrapwrap']/main/t[@t-raw='0']" position="before">
|
||||
<div t-if="o_portal_fullwidth_alert" class="alert alert-info alert-dismissible rounded-0 fade show d-print-none css_editable_mode_hidden">
|
||||
<div class="container">
|
||||
<t t-raw="o_portal_fullwidth_alert"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="portal_breadcrumbs" name="Portal Breadcrumbs">
|
||||
|
||||
@@ -10,13 +10,13 @@ from odoo.tools.translate import _
|
||||
|
||||
class Rating(http.Controller):
|
||||
|
||||
@http.route('/rating/<string:token>/<int:rate>', type='http', auth="public")
|
||||
@http.route('/rating/<string:token>/<int:rate>', type='http', auth="public", website=True)
|
||||
def open_rating(self, token, rate, **kwargs):
|
||||
assert rate in (1, 5, 10), "Incorrect rating"
|
||||
rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)])
|
||||
if not rating:
|
||||
return request.not_found()
|
||||
rate_names={
|
||||
rate_names = {
|
||||
5: _("not satisfied"),
|
||||
1: _("highly dissatisfied"),
|
||||
10: _("satisfied")
|
||||
@@ -28,7 +28,7 @@ class Rating(http.Controller):
|
||||
'rate_name': rate_names[rate], 'rate': rate
|
||||
})
|
||||
|
||||
@http.route(['/rating/<string:token>/<int:rate>/submit_feedback'], type="http", auth="public", methods=['post'])
|
||||
@http.route(['/rating/<string:token>/<int:rate>/submit_feedback'], type="http", auth="public", methods=['post'], website=True)
|
||||
def submit_rating(self, token, rate, **kwargs):
|
||||
rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)])
|
||||
if not rating:
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- External page : thanks message -->
|
||||
<template id="rating_external_page_view" name="Rating Page Done">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="head">
|
||||
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
|
||||
<link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/>
|
||||
</t>
|
||||
<t t-call="web.frontend_layout">
|
||||
<div class="container">
|
||||
<div class="text-center" style="margin-top:128px">
|
||||
<i class="fa fa-check-circle fa-5x text-success" role="img" aria-label="Thank you!" title="Thank you!"/>
|
||||
@@ -22,10 +17,7 @@
|
||||
|
||||
<!-- External page: rate and submit feedback -->
|
||||
<template id="rating_external_page_submit" name="Rating Page Submit">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="head">
|
||||
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
|
||||
</t>
|
||||
<t t-call="web.frontend_layout">
|
||||
<div class="container">
|
||||
<div clas="row">
|
||||
<h1 class="text-center">Thanks! We appreciate your feedback.</h1>
|
||||
@@ -51,5 +43,4 @@
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -19,22 +19,6 @@
|
||||
<link href="/survey/static/src/css/survey_result.css" rel="stylesheet" type="text/css"></link>
|
||||
</template>
|
||||
|
||||
<template id="survey_web_assets" name="Survey Web Assets">
|
||||
<script type="text/javascript" src="/web/static/src/js/public/public_root.js"/>
|
||||
<script type="text/javascript" src="/web/static/src/js/public/public_root_instance.js"/>
|
||||
<script type="text/javascript" src="/web/static/src/js/public/public_widget.js"/>
|
||||
<script type="text/javascript" src="/web/static/src/js/services/session.js"></script>
|
||||
|
||||
<t t-call="web._assets_helpers">
|
||||
<t t-call="web._assets_frontend_helpers"/>
|
||||
</t>
|
||||
<t t-call="web._assets_bootstrap"/>
|
||||
<link rel="stylesheet" type="text/less" href="/web/static/src/scss/fonts.scss" />
|
||||
<!-- Some helper classes (like mt- mb-) are required for survey templates -->
|
||||
<link rel="stylesheet" type="text/less" href="/web_editor/static/src/scss/web_editor.common.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/survey/static/src/scss/survey_templates.scss"/>
|
||||
</template>
|
||||
|
||||
<template id="survey_report_assets_pdf" inherit_id="web.report_assets_pdf">
|
||||
<xpath expr="link[last()]" position="after">
|
||||
<link rel="stylesheet" type="text/scss" href="/survey/static/src/scss/survey_reports.scss"/>
|
||||
|
||||
@@ -132,44 +132,17 @@
|
||||
</template>
|
||||
|
||||
<!-- new layout for survey -->
|
||||
<template id="survey.layout" name="Survey Layout">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="head">
|
||||
<script type="text/javascript">
|
||||
odoo.session_info = {
|
||||
is_admin: <t t-esc="json.dumps(request.env.user._is_admin())"/>,
|
||||
is_system: <t t-esc="json.dumps(request.env.user._is_system())"/>,
|
||||
is_website_user: <t t-esc="json.dumps(request.env.user._is_public())"/>,
|
||||
user_id: <t t-esc="json.dumps(request.env.user.id)" />,
|
||||
is_frontend: true
|
||||
};
|
||||
</script>
|
||||
<t t-call-assets="web.assets_common"/>
|
||||
<t t-call-assets="survey.survey_web_assets"/>
|
||||
<t t-call-assets="survey.survey_assets"/>
|
||||
</t>
|
||||
<body>
|
||||
<header t-if="not survey.certificate">
|
||||
<div><title>Odoo</title></div>
|
||||
<div class="text-center">
|
||||
<img t-attf-src="/web/binary/company_logo" alt="Logo"/>
|
||||
</div>
|
||||
</header>
|
||||
<div id="wrap" class="oe_structure oe_empty"/>
|
||||
<main>
|
||||
<t t-raw="0"/>
|
||||
</main>
|
||||
</body>
|
||||
<div t-if="not survey.certificate" class="container mt16 mb8">
|
||||
<div class="float-right" t-ignore="true" t-if="not editable">
|
||||
Create a <a target="_blank" href="https://www.odoo.com/page/website-builder">free website</a> with
|
||||
<a target="_blank" class="badge badge-danger" href="https://www.odoo.com/page/website-builder">Odoo</a>
|
||||
</div>
|
||||
<div class="float-left text-muted" itemscope="itemscope" itemtype="https://schema.org/Organization">
|
||||
Copyright &copy; <span t-field="res_company.name" itemprop="name">Company name</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<template id="survey.layout" name="Survey Layout" inherit_id="web.frontend_layout" primary="True">
|
||||
<xpath expr="//head/t[@t-call-assets][last()]" position="after">
|
||||
<t t-call-assets="survey.survey_assets"/>
|
||||
</xpath>
|
||||
<xpath expr="//header" position="before">
|
||||
<t t-set="no_header" t-value="no_header or survey.certificate"/>
|
||||
<t t-set="no_footer" t-value="no_footer or survey.certificate"/>
|
||||
</xpath>
|
||||
<xpath expr="//header" position="after">
|
||||
<div id="wrap" class="oe_structure oe_empty"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- First page of a survey -->
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from odoo import models
|
||||
from odoo import api, models
|
||||
from odoo.http import request
|
||||
from odoo.tools import ustr
|
||||
|
||||
@@ -64,6 +64,16 @@ class Http(models.AbstractModel):
|
||||
},
|
||||
}
|
||||
|
||||
@api.model
|
||||
def get_frontend_session_info(self):
|
||||
return {
|
||||
'is_admin': self.env.user._is_admin(),
|
||||
'is_system': self.env.user._is_system(),
|
||||
'is_website_user': self.env.user._is_public(),
|
||||
'user_id': self.env.user.id,
|
||||
'is_frontend': True,
|
||||
}
|
||||
|
||||
def get_currencies(self):
|
||||
Currency = request.env['res.currency']
|
||||
currencies = Currency.search([]).read(['symbol', 'position', 'decimal_places'])
|
||||
|
||||
@@ -382,19 +382,62 @@
|
||||
</html>
|
||||
</template>
|
||||
|
||||
<template id="web.login_layout" name="Login Layout">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
|
||||
<t t-set="head">
|
||||
<t t-call-assets="web.assets_common" t-js="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-js="false"/>
|
||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-css="false"/>
|
||||
</t>
|
||||
<t t-set="body_classname" t-value="'bg-100'"/>
|
||||
<template id="web.frontend_layout" name="Frontend Layout" inherit_id="web.layout" primary="True">
|
||||
<xpath expr="//head/link[last()]" position="after">
|
||||
<t t-call-assets="web.assets_common" t-js="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-js="false"/>
|
||||
</xpath>
|
||||
<xpath expr="//head/script" position="after">
|
||||
<script type="text/javascript">
|
||||
odoo.session_info = <t t-raw="json.dumps(request.env['ir.http'].get_frontend_session_info())"/>;
|
||||
</script>
|
||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-css="false"/>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-raw='0']" position="replace">
|
||||
<div id="wrapwrap" t-attf-class="#{pageName or ''}">
|
||||
<header t-if="not no_header" id="top" data-anchor="true">
|
||||
<img class="img-responsive d-block mx-auto"
|
||||
t-attf-src="/web/binary/company_logo"
|
||||
alt="Logo"/>
|
||||
</header>
|
||||
<main>
|
||||
<t t-raw="0"/>
|
||||
</main>
|
||||
<footer t-if="not no_footer" id="bottom" data-anchor="true" class="bg-light o_footer">
|
||||
<div id="footer"/>
|
||||
<div class="o_footer_copyright">
|
||||
<div class="container py-3">
|
||||
<div class="row">
|
||||
<div class="col-sm text-center text-sm-left text-muted">
|
||||
<span>Copyright &copy;</span> <span t-field="res_company.name" itemprop="name">Company name</span>
|
||||
</div>
|
||||
<div class="col-sm text-center text-sm-right">
|
||||
<t t-call="web.brand_promotion"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<div class="container mb-5 pb-5">
|
||||
<div t-attf-class="card border-0 mx-auto mt-5 bg-100 {{login_card_classes}} o_database_list" style="max-width: 300px;">
|
||||
<template id="brand_promotion" name="Brand Promotion">
|
||||
<div class="o_brand_promotion">
|
||||
Powered by <a target="_blank" href="http://www.odoo.com?utm_source=db&utm_medium=portal">Odoo</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="web.login_layout" name="Login Layout">
|
||||
<t t-call="web.frontend_layout">
|
||||
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
|
||||
<t t-set="body_classname" t-value="'bg-100'"/>
|
||||
<t t-set="no_header" t-value="True"/>
|
||||
<t t-set="no_footer" t-value="True"/>
|
||||
|
||||
<div class="container py-5">
|
||||
<div t-attf-class="card border-0 mx-auto bg-100 {{login_card_classes}} o_database_list" style="max-width: 300px;">
|
||||
<div class="card-body">
|
||||
<div t-attf-class="text-center pb-3 border-bottom {{'mb-3' if form_small else 'mb-4'}}">
|
||||
<img t-attf-src="/web/binary/company_logo{{ '?dbname='+db if db else '' }}" alt="Logo" style="max-height:120px; max-width: 100%; width:auto"/>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import hashlib
|
||||
import logging
|
||||
from lxml import etree
|
||||
import traceback
|
||||
import os
|
||||
import json
|
||||
import unittest
|
||||
|
||||
import pytz
|
||||
@@ -19,7 +17,6 @@ from odoo import SUPERUSER_ID
|
||||
from odoo.http import request
|
||||
from odoo.tools import config
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.osv import expression
|
||||
from odoo.osv.expression import FALSE_DOMAIN, OR
|
||||
|
||||
from odoo.addons.base.models.qweb import QWebException
|
||||
@@ -317,28 +314,17 @@ class Http(models.AbstractModel):
|
||||
return super(Http, cls)._xmlid_to_obj(env, xmlid)
|
||||
|
||||
@api.model
|
||||
def get_website_session_info(self):
|
||||
# see http_routing/main.py
|
||||
Modules = request.env['ir.module.module'].sudo()
|
||||
IrHttp = request.env['ir.http'].sudo()
|
||||
domain = IrHttp._get_translation_frontend_modules_domain()
|
||||
modules = Modules.search(
|
||||
expression.AND([domain, [('state', '=', 'installed')]])
|
||||
).mapped('name')
|
||||
user_context = request.session.get_context() if request.session.uid else {}
|
||||
lang = user_context.get('lang')
|
||||
translations, _ = request.env['ir.translation'].get_translations_for_webclient(modules, lang)
|
||||
return {
|
||||
'is_admin': request.env.user._is_admin(),
|
||||
'is_system': request.env.user._is_system(),
|
||||
'is_frontend': True,
|
||||
'translationURL': '/website/translations',
|
||||
def get_frontend_session_info(self):
|
||||
session_info = super(Http, self).get_frontend_session_info()
|
||||
session_info.update({
|
||||
'is_website_user': request.env.user.id == request.website.user_id.id,
|
||||
'user_id': request.env.user.id,
|
||||
'cache_hashes': {
|
||||
'translations': hashlib.sha1(json.dumps(translations, sort_keys=True).encode()).hexdigest(),
|
||||
},
|
||||
}
|
||||
})
|
||||
if request.env.user.has_group('website.group_website_publisher'):
|
||||
session_info.update({
|
||||
'website_id': request.website.id,
|
||||
'website_company_id': request.website.company_id.id,
|
||||
})
|
||||
return session_info
|
||||
|
||||
|
||||
class ModelConverter(ModelConverter):
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
</template>
|
||||
|
||||
<template id="layout" name="Main layout" inherit_id="portal.frontend_layout">
|
||||
<xpath expr="//t[@t-set='head_website']" position="before">
|
||||
<xpath expr="//html" position="before">
|
||||
<t t-set="html_data" t-value="{
|
||||
'lang': lang and lang.replace('_', '-'),
|
||||
'data-website-id': website.id if website else None,
|
||||
@@ -172,6 +172,8 @@
|
||||
'data-main-object': repr(main_object) if editable or translatable else None,
|
||||
'data-oe-company-name': res_company.name
|
||||
}"/>
|
||||
</xpath>
|
||||
<xpath expr="//head" position="before">
|
||||
<t t-if="not title">
|
||||
<t t-if="not additional_title and main_object and 'name' in main_object">
|
||||
<t t-set="additional_title" t-value="main_object.name"/>
|
||||
@@ -186,61 +188,51 @@
|
||||
</t>
|
||||
<t t-set="x_icon" t-value="'/web/image/website/%s/favicon/' % website.id"/>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-set='head_website']" position="replace">
|
||||
<t t-set="head_website">
|
||||
<meta name="generator" content="Odoo"/>
|
||||
<t t-set="website_meta" t-value="main_object and main_object.get_website_meta() or {}"/>
|
||||
<meta name="default_title" t-att-content="default_title" groups="website.group_website_designer"/>
|
||||
<meta t-if="main_object and 'website_indexed' in main_object
|
||||
and not main_object.website_indexed" name="robots" content="noindex"/>
|
||||
<t t-set="meta_description" t-value="main_object and 'website_meta_description' in main_object
|
||||
and main_object.website_meta_description or website_meta_description or website_meta.get('meta_description', '')"/>
|
||||
<t t-set="meta_keywords" t-value="main_object and 'website_meta_keywords' in main_object
|
||||
and main_object.website_meta_keywords or website_meta_keywords"/>
|
||||
<meta t-if="meta_description or editable" name="description" t-att-content="meta_description"/>
|
||||
<meta t-if="meta_keywords or editable" name="keywords" t-att-content="meta_keywords"/>
|
||||
<t t-if="main_object">
|
||||
<meta name="default_description" t-att-content="website_meta_description or website_meta.get('meta_description')" groups="website.group_website_designer"/>
|
||||
<!-- OpenGraph tags for Facebook sharing -->
|
||||
<t t-set="opengraph_meta" t-value="website_meta.get('opengraph_meta')"/>
|
||||
<t t-if="opengraph_meta">
|
||||
<t t-foreach="opengraph_meta" t-as="og_meta">
|
||||
<meta t-att-property="og_meta" t-att-content="opengraph_meta[og_meta]"/>
|
||||
</t>
|
||||
</t>
|
||||
<!-- Twitter tags for sharing -->
|
||||
<t t-set="twitter_meta" t-value="website_meta.get('twitter_meta')"/>
|
||||
<t t-if="opengraph_meta">
|
||||
<t t-foreach="twitter_meta" t-as="t_meta">
|
||||
<meta t-att-name="t_meta" t-att-content="twitter_meta[t_meta]"/>
|
||||
</t>
|
||||
<xpath expr="//head/meta[last()]" position="after">
|
||||
<meta name="generator" content="Odoo"/>
|
||||
<t t-set="website_meta" t-value="main_object and main_object.get_website_meta() or {}"/>
|
||||
<meta name="default_title" t-att-content="default_title" groups="website.group_website_designer"/>
|
||||
<meta t-if="main_object and 'website_indexed' in main_object
|
||||
and not main_object.website_indexed" name="robots" content="noindex"/>
|
||||
<t t-set="meta_description" t-value="main_object and 'website_meta_description' in main_object
|
||||
and main_object.website_meta_description or website_meta_description or website_meta.get('meta_description', '')"/>
|
||||
<t t-set="meta_keywords" t-value="main_object and 'website_meta_keywords' in main_object
|
||||
and main_object.website_meta_keywords or website_meta_keywords"/>
|
||||
<meta t-if="meta_description or editable" name="description" t-att-content="meta_description"/>
|
||||
<meta t-if="meta_keywords or editable" name="keywords" t-att-content="meta_keywords"/>
|
||||
<t t-if="main_object">
|
||||
<meta name="default_description" t-att-content="website_meta_description or website_meta.get('meta_description')" groups="website.group_website_designer"/>
|
||||
<!-- OpenGraph tags for Facebook sharing -->
|
||||
<t t-set="opengraph_meta" t-value="website_meta.get('opengraph_meta')"/>
|
||||
<t t-if="opengraph_meta">
|
||||
<t t-foreach="opengraph_meta" t-as="og_meta">
|
||||
<meta t-att-property="og_meta" t-att-content="opengraph_meta[og_meta]"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-set="languages" t-value="website.get_languages() if website else None"/>
|
||||
<t t-if="request and request.is_frontend_multilang and website">
|
||||
<t t-foreach="website.get_alternate_languages(request.httprequest)" t-as="lg">
|
||||
<link rel="alternate" t-att-hreflang="lg['hreflang']" t-att-href="lg['href']"/>
|
||||
<!-- Twitter tags for sharing -->
|
||||
<t t-set="twitter_meta" t-value="website_meta.get('twitter_meta')"/>
|
||||
<t t-if="opengraph_meta">
|
||||
<t t-foreach="twitter_meta" t-as="t_meta">
|
||||
<meta t-att-name="t_meta" t-att-content="twitter_meta[t_meta]"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<script type="text/javascript">
|
||||
odoo.session_info = <t t-raw="json.dumps(request.env['ir.http'].get_website_session_info())"/>;
|
||||
<t groups="website.group_website_publisher">
|
||||
odoo.session_info.website_id = <t t-esc="json.dumps(request.website.id)" />;
|
||||
odoo.session_info.website_company_id = <t t-esc="json.dumps(request.website.company_id.id)" />;
|
||||
</t>
|
||||
</script>
|
||||
|
||||
<t t-call-assets="web.assets_common" t-js="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-js="false"/>
|
||||
<t t-call-assets="website.assets_editor" t-js="false" groups="website.group_website_publisher"/>
|
||||
|
||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||
<t t-call-assets="web.assets_frontend" t-css="false"/>
|
||||
<t t-call-assets="website.assets_editor" t-css="false" groups="website.group_website_publisher"/>
|
||||
<t t-set="languages" t-value="website.get_languages() if website else None"/>
|
||||
<t t-if="request and request.is_frontend_multilang and website">
|
||||
<t t-foreach="website.get_alternate_languages(request.httprequest)" t-as="lg">
|
||||
<link rel="alternate" t-att-hreflang="lg['hreflang']" t-att-href="lg['href']"/>
|
||||
</t>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//head/t[@t-js='false'][last()]" position="after">
|
||||
<t t-call-assets="website.assets_editor" t-js="false" groups="website.group_website_publisher"/>
|
||||
</xpath>
|
||||
<xpath expr="//head/t[@t-css='false'][last()]" position="after">
|
||||
<t t-call-assets="website.assets_editor" t-css="false" groups="website.group_website_publisher"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//header//a[hasclass('navbar-brand')]" position="replace">
|
||||
<a class="navbar-brand" href="/" t-if="website" t-field="website.name">My Website</a>
|
||||
</xpath>
|
||||
@@ -261,6 +253,15 @@
|
||||
</t>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//div[hasclass('o_footer_copyright')]//span[@t-field='res_company.name']" position="after">
|
||||
<t t-call="website.language_selector"/>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-call='web.brand_promotion']/.." position="attributes">
|
||||
<attribute name="class" add="o_not_editable" separator=" "/>
|
||||
<attribute name="t-if">not editable</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//div[@id='wrapwrap']" position="after">
|
||||
<script id='tracking_code' t-if="website and website.google_analytics_key and not editable">
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
@@ -289,31 +290,15 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="layout_footer_copyright" inherit_id="website.layout" name="Footer Copyright">
|
||||
<xpath expr="//footer" position="inside">
|
||||
<div class="o_footer_copyright">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 text-muted text-center text-md-left">
|
||||
<span>Copyright &copy;</span> <span t-field="res_company.name" itemprop="name">Company name</span>
|
||||
<t t-call="website.language_selector"/>
|
||||
</div>
|
||||
<div class="col-lg-6 text-right o_not_editable" t-if="not editable">
|
||||
<t t-call="website.brand_promotion"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template id="brand_promotion" inherit_id="web.brand_promotion" name="Brand Promotion">
|
||||
<xpath expr="//div[hasclass('o_brand_promotion')]" position="replace">
|
||||
<div class="o_brand_promotion">
|
||||
Create a <a target="_blank" href="http://www.odoo.com/page/website-builder?utm_source=db&utm_medium=website">free website</a> with
|
||||
<a target="_blank" class="badge badge-danger" href="http://www.odoo.com/page/website-builder?utm_source=db&utm_medium=website">Odoo</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="brand_promotion" name="Brand Promotion">
|
||||
<div class="o_brand_promotion">
|
||||
Create a <a target="_blank" href="http://www.odoo.com/page/website-builder?utm_source=db&utm_medium=website">free website</a> with
|
||||
<a target="_blank" class="badge badge-danger" href="http://www.odoo.com/page/website-builder?utm_source=db&utm_medium=website">Odoo</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="layout_logo_show" inherit_id="website.layout" name="Show Logo">
|
||||
<xpath expr="//header//a[hasclass('navbar-brand')]" position="replace">
|
||||
<a href="/" class="navbar-brand logo">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'description': """This module lets you use the full power of certifications within your courses.""",
|
||||
'category': 'Hidden',
|
||||
'version': '1.0',
|
||||
'depends': ['website_slides', 'website_survey'],
|
||||
'depends': ['website_slides', 'survey'],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'data': [
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# coding: utf-8
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
@@ -1,21 +0,0 @@
|
||||
# coding: utf-8
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Website Survey',
|
||||
'version': '1.0',
|
||||
'category': 'Marketing',
|
||||
'description': """
|
||||
Create beautiful surveys and display them on your website
|
||||
=========================================================
|
||||
|
||||
Use the styling and layout of your website for your surveys.
|
||||
""",
|
||||
'website': 'https://www.odoo.com/page/survey',
|
||||
'depends': ['website', 'survey'],
|
||||
'data': [
|
||||
'views/website_survey_templates.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': True
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<odoo>
|
||||
<template id="website_survey_layout" inherit_id="survey.layout" name="Website Survey Layout">
|
||||
<xpath expr="t" position="replace">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="head">
|
||||
<t t-raw="head"/>
|
||||
<t t-call-assets="survey.survey_assets"/>
|
||||
</t>
|
||||
<t t-raw="0"/>
|
||||
</t>
|
||||
</xpath>
|
||||
<xpath expr="t" position="before">
|
||||
<t t-set="hide_header" t-value="survey.certificate" />
|
||||
<t t-set="hide_footer" t-value="survey.certificate" />
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user