[IMP] website: warn user about key change when editing special file name
The idea is to warn user if he created a special file (website.page with supported extension) and he wants to change the file's name, which will at the end also change the key). If this special file has been t-called elsewhere, they t-call wont work anymore This is why warning user is needed. Note that this is different than the already existing page_search_dependencies that is just checking if the URL is present in menus, templates, blog or pages. This is about checking if the key is present somewhere. (we assume that if the key is present, it is surely about a t-call. Technically, the flow is: 1. Get supported extension 2. Get key dependencies 3. Check if user modify name 4. If name changed and it is/was a supported extension (special file) and it has dependencies (surely t-call) then warn user these call wont work anymore -- search_page_dependencies is also improved by returning links to be clickable (on delete dialog eg) and splitting template/page results. it also refactor dependencies warning that was creating HTML in javascript into using XML template
This commit is contained in:
@@ -10,7 +10,7 @@ from werkzeug import urls
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
from odoo import api, fields, models, tools
|
||||
from odoo.addons.http_routing.models.ir_http import slugify
|
||||
from odoo.addons.http_routing.models.ir_http import slugify, _guess_mimetype
|
||||
from odoo.addons.website.models.ir_http import sitemap_qs2dom
|
||||
from odoo.addons.portal.controllers.portal import pager
|
||||
from odoo.tools import pycompat
|
||||
@@ -136,6 +136,10 @@ class Website(models.Model):
|
||||
})
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def guess_mimetype(self):
|
||||
return _guess_mimetype()
|
||||
|
||||
def get_unique_path(self, page_url):
|
||||
""" Given an url, return that url suffixed by counter if it already exists
|
||||
:param page_url : the url to be checked for uniqueness
|
||||
@@ -194,20 +198,21 @@ class Website(models.Model):
|
||||
website_id = self._context.get('website_id')
|
||||
url = page.url
|
||||
|
||||
|
||||
page_key = _('Page')
|
||||
|
||||
# search for website_page with link
|
||||
website_page_search_dom = [
|
||||
'|', ('website_ids', 'in', website_id), ('website_ids', '=', False), ('view_id.arch_db', 'ilike', url)
|
||||
]
|
||||
pages = self.env['website.page'].search(website_page_search_dom)
|
||||
page_key = _('Page')
|
||||
if len(pages) > 1:
|
||||
page_key = _('Pages')
|
||||
page_view_ids = []
|
||||
for page in pages:
|
||||
dependencies.setdefault(page_key, [])
|
||||
dependencies[page_key].append({
|
||||
'text': _('Page <b>%s</b> contains a link to this page') % page.url,
|
||||
'link': page.url
|
||||
'item': page.name,
|
||||
'link': page.url,
|
||||
})
|
||||
page_view_ids.append(page.view_id.id)
|
||||
|
||||
@@ -217,23 +222,85 @@ class Website(models.Model):
|
||||
('arch_db', 'ilike', url), ('id', 'not in', page_view_ids)
|
||||
]
|
||||
views = self.env['ir.ui.view'].search(page_search_dom)
|
||||
view_key = _('Template')
|
||||
if len(views) > 1:
|
||||
view_key = _('Templates')
|
||||
for view in views:
|
||||
dependencies.setdefault(page_key, [])
|
||||
dependencies[page_key].append({
|
||||
'text': _('Template <b>%s (id:%s)</b> contains a link to this page') % (view.key or view.name, view.id),
|
||||
'link': '#'
|
||||
dependencies.setdefault(view_key, [])
|
||||
dependencies[view_key].append({
|
||||
'text': _('Template <b>%s (id:%s)</b> contains a link to this page') % (view.key or view.name, view.id),
|
||||
'link': '/web#id=%s&view_type=form&model=ir.ui.view' % view.id,
|
||||
'item': _('%s (id:%s)') % (view.key or view.name, view.id),
|
||||
})
|
||||
# search for menu with link
|
||||
menu_search_dom = [
|
||||
'|', ('website_id', '=', website_id), ('website_id', '=', False), ('url', 'ilike', '%s' % url)
|
||||
]
|
||||
|
||||
menu_key = _('Menu')
|
||||
menus = self.env['website.menu'].search(menu_search_dom)
|
||||
menu_key = _('Menu')
|
||||
if len(menus) > 1:
|
||||
menu_key = _('Menus')
|
||||
for menu in menus:
|
||||
dependencies.setdefault(menu_key, []).append({
|
||||
'text': _('This page is in the menu <b>%s</b>') % menu.name,
|
||||
'link': False
|
||||
'link': '/web#id=%s&view_type=form&model=website.menu' % menu.id,
|
||||
'item': menu.name,
|
||||
})
|
||||
|
||||
return dependencies
|
||||
|
||||
@api.model
|
||||
def page_search_key_dependencies(self, page_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 page_id:
|
||||
return dependencies
|
||||
|
||||
page = self.env['website.page'].browse(int(page_id))
|
||||
website_id = self._context.get('website_id')
|
||||
key = page.key
|
||||
|
||||
# search for website_page with link
|
||||
website_page_search_dom = [
|
||||
'|', ('website_ids', 'in', website_id), ('website_ids', '=', False), ('view_id.arch_db', 'ilike', key),
|
||||
('id', '!=', page.id),
|
||||
]
|
||||
pages = self.env['website.page'].search(website_page_search_dom)
|
||||
page_key = _('Page')
|
||||
if len(pages) > 1:
|
||||
page_key = _('Pages')
|
||||
page_view_ids = []
|
||||
for p in pages:
|
||||
dependencies.setdefault(page_key, [])
|
||||
dependencies[page_key].append({
|
||||
'text': _('Page <b>%s</b> is calling this file') % p.url,
|
||||
'item': p.name,
|
||||
'link': p.url,
|
||||
})
|
||||
page_view_ids.append(p.view_id.id)
|
||||
|
||||
# search for ir_ui_view (not from a website_page) with link
|
||||
page_search_dom = [
|
||||
'|', ('website_id', '=', website_id), ('website_id', '=', False),
|
||||
('arch_db', 'ilike', key), ('id', 'not in', page_view_ids),
|
||||
('id', '!=', page.view_id.id),
|
||||
]
|
||||
views = self.env['ir.ui.view'].search(page_search_dom)
|
||||
view_key = _('Template')
|
||||
if len(views) > 1:
|
||||
view_key = _('Templates')
|
||||
for view in views:
|
||||
dependencies.setdefault(view_key, [])
|
||||
dependencies[view_key].append({
|
||||
'text': _('Template <b>%s (id:%s)</b> is calling this file') % (view.key or view.name, view.id),
|
||||
'item': _('%s (id:%s)') % (view.key or view.name, view.id),
|
||||
'link': '/web#id=%s&view_type=form&model=ir.ui.view' % view.id,
|
||||
})
|
||||
|
||||
return dependencies
|
||||
|
||||
@@ -19,6 +19,7 @@ var PagePropertiesDialog = widget.Dialog.extend({
|
||||
['/website/static/src/xml/website.pageProperties.xml']
|
||||
),
|
||||
events: _.extend({}, widget.Dialog.prototype.events, {
|
||||
'keyup input#page_name': '_onNameChanged',
|
||||
'keyup input#page_url': '_onUrlChanged',
|
||||
'change input#create_redirect': '_onCreateRedirectChanged',
|
||||
}),
|
||||
@@ -90,19 +91,39 @@ var PagePropertiesDialog = widget.Dialog.extend({
|
||||
|
||||
this.$(".ask_for_redirect").hide();
|
||||
this.$(".redirect_type").hide();
|
||||
this.$(".warn_about_call").hide();
|
||||
|
||||
//TODO: remove.html() & set self.var & display in view instead of controller (here)
|
||||
this._getPageDependencies(self.page_id, context)
|
||||
.then(function (dependencies) {
|
||||
var dep = [];
|
||||
_.each(dependencies, function( value, index ) {
|
||||
if (dependencies[index].length > 0) {
|
||||
dep.push(dependencies[index].length + ' ' + index.toLowerCase() + (dependencies[index].length > 1 ? 's': ''));
|
||||
var dep_text = [];
|
||||
_.each(dependencies, function(value, index){
|
||||
if (value.length > 0) {
|
||||
dep_text.push(value.length + ' ' + index.toLowerCase());
|
||||
}
|
||||
});
|
||||
if (dep.length > 0) {
|
||||
$("#dependencies_redirect").html("(" + _("used in") + " " + dep.join(", ") + ")");
|
||||
}
|
||||
dep_text = dep_text.join(', ');
|
||||
$('#dependencies_redirect').html(qweb.render('website.show_page_dependencies', { dependencies: dependencies, dep_text: dep_text }));
|
||||
$('#dependencies_redirect [data-toggle="popover"]').popover({
|
||||
container: 'body'
|
||||
});
|
||||
});
|
||||
this._getSupportedMimetype(context)
|
||||
.then(function (mimetypes) {
|
||||
self.supportedMimetype = mimetypes;
|
||||
});
|
||||
this._getPageKeyDependencies(self.page_id, context)
|
||||
.then(function (dependencies) {
|
||||
var dep_text = [];
|
||||
_.each(dependencies, function(value, index){
|
||||
if (value.length > 0) {
|
||||
dep_text.push(value.length + ' ' + index.toLowerCase());
|
||||
}
|
||||
});
|
||||
dep_text = dep_text.join(', ');
|
||||
$('.warn_about_call').html(qweb.render('website.show_page_key_dependencies', { dependencies: dependencies, dep_text: dep_text }));
|
||||
$('.warn_about_call [data-toggle="popover"]').popover({
|
||||
container: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
var l10n = _t.database.parameters;
|
||||
@@ -133,6 +154,13 @@ var PagePropertiesDialog = widget.Dialog.extend({
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
destroy: function(){
|
||||
$('.popover').popover('hide');
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
@@ -184,7 +212,7 @@ var PagePropertiesDialog = widget.Dialog.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieves the page dependencies for the given object id.
|
||||
* Retrieves the page URL dependencies for the given object id.
|
||||
*
|
||||
* @private
|
||||
* @param {integer} moID
|
||||
@@ -199,6 +227,36 @@ var PagePropertiesDialog = widget.Dialog.extend({
|
||||
context: context,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Retrieves the page's key dependencies for the given object id.
|
||||
*
|
||||
* @private
|
||||
* @param {integer} moID
|
||||
* @param {Object} context
|
||||
* @returns {Deferred<Array>}
|
||||
*/
|
||||
_getPageKeyDependencies: function (moID, context) {
|
||||
return this._rpc({
|
||||
model: 'website',
|
||||
method: 'page_search_key_dependencies',
|
||||
args: [moID],
|
||||
context: context,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Retrieves supported mimtype
|
||||
*
|
||||
* @private
|
||||
* @param {Object} context
|
||||
* @returns {Deferred<Array>}
|
||||
*/
|
||||
_getSupportedMimetype: function (context) {
|
||||
return this._rpc({
|
||||
model: 'website',
|
||||
method: 'guess_mimetype',
|
||||
context: context,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Returns information about the page main object.
|
||||
*
|
||||
@@ -227,6 +285,20 @@ var PagePropertiesDialog = widget.Dialog.extend({
|
||||
this.$(".ask_for_redirect").hide();
|
||||
}
|
||||
},
|
||||
_onNameChanged: function () {
|
||||
var name = this.$('input#page_name').val();
|
||||
//If the file type is a supported mimetype, check if it is t-called. If so, warn user
|
||||
//Note: different from page_search_dependencies which check only for url and not key
|
||||
var ext = '.' + this.page.name.split('.').pop();
|
||||
if(ext in this.supportedMimetype && ext != '.html'){
|
||||
if (name != this.page.name) {
|
||||
this.$(".warn_about_call").show();
|
||||
}
|
||||
else {
|
||||
this.$(".warn_about_call").hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
_onCreateRedirectChanged: function () {
|
||||
var createRedirect = this.$('input#create_redirect').prop('checked');
|
||||
if (createRedirect) {
|
||||
|
||||
@@ -453,8 +453,13 @@ body .modal {
|
||||
}
|
||||
|
||||
// Pages Management
|
||||
.o_page_management_info .o_switch{
|
||||
padding-top: 7px;
|
||||
.o_page_management_info{
|
||||
.o_switch{
|
||||
padding-top: 7px;
|
||||
}
|
||||
}
|
||||
.popover_dep{
|
||||
overflow-x: auto;
|
||||
}
|
||||
#edit_website_pages{
|
||||
.fa-check{
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<!-- Tooltip Dependencies -->
|
||||
|
||||
<t t-name="website.get_tooltip_dependencies">
|
||||
<t t-foreach="dependencies" t-as="dep">
|
||||
<b><t t-esc="dep"/></b>
|
||||
<ul class="popover_dep">
|
||||
<t t-foreach="dep_value" t-as="item">
|
||||
<li><a t-att-href="item_value['link']"><t t-esc="item_value['item']"/></a></li>
|
||||
</t>
|
||||
</ul>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="website.show_page_key_dependencies">
|
||||
<div class="col-sm-9 col-sm-offset-3">
|
||||
<span class="text-muted" id="warn_about_call_message">
|
||||
<t t-set="depTooltip">
|
||||
<t t-call="website.get_tooltip_dependencies"/>
|
||||
</t>
|
||||
It looks like your file is being called by
|
||||
<a href="#" data-toggle="popover" t-att-data-content="depTooltip" data-html="true" title="Dependencies"><t t-esc="dep_text" /></a>.
|
||||
Changing its name will break these calls.
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="website.show_page_dependencies">
|
||||
<t t-set="depTooltip">
|
||||
<t t-call="website.get_tooltip_dependencies"/>
|
||||
</t>
|
||||
(could be used in <a href="#" data-toggle="popover" t-att-data-content="depTooltip" data-html="true" title="Dependencies"><t t-esc="dep_text" /></a>)
|
||||
</t>
|
||||
|
||||
<!-- Page Properties -->
|
||||
|
||||
<div t-name="website.pagesMenu.page_info" class="o_page_management_info">
|
||||
<form class="form-horizontal">
|
||||
<ul class="nav nav-tabs">
|
||||
@@ -14,6 +48,7 @@
|
||||
<input type="text" class="form-control input-sm" id="page_name" t-att-value="widget.page.name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group warn_about_call"></div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="page_url">Page URL</label>
|
||||
<div class="col-sm-9">
|
||||
@@ -24,7 +59,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group ask_for_redirect">
|
||||
<label class="control-label col-sm-3" for="is_homepage">Redirect Old URL</label>
|
||||
<label class="control-label col-sm-3" for="create_redirect">Redirect Old URL</label>
|
||||
<div class="col-sm-2">
|
||||
<a>
|
||||
<label class="o_switch" for="create_redirect" >
|
||||
|
||||
@@ -20,11 +20,39 @@ class Website(models.Model):
|
||||
posts = self.env['blog.post'].search(dom)
|
||||
if posts:
|
||||
page_key = _('Blog Post')
|
||||
if len(posts) > 1:
|
||||
page_key = _('Blog Posts')
|
||||
dep[page_key] = []
|
||||
for p in posts:
|
||||
dep[page_key].append({
|
||||
'text': _('Blog Post <b>%s</b> seems to have a link to this page !') % p.name,
|
||||
'link': p.website_url
|
||||
'item': p.name,
|
||||
'link': p.website_url,
|
||||
})
|
||||
|
||||
return dep
|
||||
|
||||
@api.model
|
||||
def page_search_key_dependencies(self, page_id=False):
|
||||
dep = super(Website, self).page_search_key_dependencies(page_id=page_id)
|
||||
|
||||
page = self.env['website.page'].browse(int(page_id))
|
||||
key = page.key
|
||||
|
||||
dom = [
|
||||
('content', 'ilike', key)
|
||||
]
|
||||
posts = self.env['blog.post'].search(dom)
|
||||
if posts:
|
||||
page_key = _('Blog Post')
|
||||
if len(posts) > 1:
|
||||
page_key = _('Blog Posts')
|
||||
dep[page_key] = []
|
||||
for p in posts:
|
||||
dep[page_key].append({
|
||||
'text': _('Blog Post <b>%s</b> seems to be calling this file !') % p.name,
|
||||
'item': p.name,
|
||||
'link': p.website_url,
|
||||
})
|
||||
|
||||
return dep
|
||||
|
||||
Reference in New Issue
Block a user