From 53920fae31bda506ef30f7f218071791bb11a814 Mon Sep 17 00:00:00 2001
From: rde <rde@odoo.com>
Date: Wed, 11 Oct 2017 14:09:34 +0200
Subject: [PATCH] [FIX] website: key from page's view was not unique in every
 cases

Before this commit, if you created a page with the same name as another one
(which is allowed) it would set the same key for that second page.
Indeed, the code was setting correctly the path uniqueness but it was then
setting the key based on the name and not on the unique url we found free.

Now, the key is correctly uniquely set and even better, it is now completely
independant from the url and has its own 'find unique' method to be sure it is
correctly working.
It was not clever to have key & url being linked.

To be more clear:
1. Create page 'aboutus'
	key  is 'website.aboutus'
	name is 'aboutus'
	url  is '/aboutus'
2. Create page 'aboutus' ->
	key  is 'website.aboutus'
	name is 'aboutus'
	url  is '/aboutus-1'
Problem: key should be unique (for t-call for specific files & website_version)
Cause: key is set based on name which is not checking for uniqueness like url.
Two possible solutions:
	1. Set key based on url (which is being checked for uniqueness)
	2. Create & Use a specific method to get unique key
Fixed with solution 2 which is more clean.

--

It also fix an invisible 'bug':
Saving a page being in menu would cause the menu's URL to get it's trailing '/'
to be removed. It was only a problem when you were getting the warning about
dependencies (the menu wouldn't be recognized as dependencies because of the
removed '/')
---
 addons/website/models/website.py | 41 ++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 593959b41a89..888c876a9301 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -103,7 +103,7 @@ class Website(models.Model):
             template_module, _ = template.split('.')
         page_url = '/' + slugify(name, max_length=1024, path=True)
         page_url = self.get_unique_path(page_url)
-        page_key = self.get_unique_path(slugify(name))
+        page_key = slugify(name)
         result = dict({'url': page_url, 'view_id': False})
 
         if not name:
@@ -112,7 +112,7 @@ class Website(models.Model):
 
         template_record = self.env.ref(template)
         website_id = self._context.get('website_id')
-        key = '%s.%s' % (template_module, page_key)
+        key = self.get_unique_key(page_key, template_module)
         view = template_record.copy({'website_id': website_id, 'key': key})
 
         view.with_context(lang=None).write({
@@ -149,6 +149,28 @@ class Website(models.Model):
             page_temp = page_url + (inc and "-%s" % inc or "")
         return page_temp
 
+    def get_unique_key(self, string, template_module=False):
+        """ Given a string, return an unique key including module prefix.
+            It will be suffixed by a counter if it already exists to garantee uniqueness.
+            :param string : the key to be checked for uniqueness, you can pass it with 'website.' or not
+            :param template_module : the module to be prefixed on the key, if not set, we will use website
+        """
+        website_id = self.get_current_website().id
+        if template_module:
+            string = template_module + '.' + string
+        else:
+            if not string.startswith('website.'):
+                string = 'website.' + string
+
+        #Look for unique key
+        key_copy = string
+        inc = 0
+        domain_static = ['|', ('website_ids', '=', False), ('website_ids', 'in', website_id)]
+        while self.env['website.page'].with_context(active_test=False).sudo().search([('key', '=', key_copy)] + domain_static):
+            inc += 1
+            key_copy = string + (inc and "-%s" % inc or "")
+        return key_copy
+
     def key_to_view_id(self, view_id):
         return self.env['ir.ui.view'].search([
             ('id', '=', view_id),
@@ -568,13 +590,22 @@ class Page(models.Model):
     @api.model
     def save_page_info(self, website_id, data):
         website = self.env['website'].browse(website_id)
+        page = self.browse(int(data['id']))
 
         #If URL has been edited, slug it
-        page = self.browse(int(data['id']))
         original_url = page.url
         url = data['url']
+        if not url.startswith('/'):
+            url = '/' + url
         if page.url != url:
-            url = slugify(url, max_length=200, path=True)
+            url = '/' + slugify(url, max_length=1024, path=True)
+            url = self.env['website'].get_unique_path(url)
+
+        #If name has changed, check for key uniqueness
+        if page.name != data['name']:
+            page_key = self.env['website'].get_unique_key(slugify(data['name']))
+        else:
+            page_key = page.key
 
         menu = self.env['website.menu'].search([('page_id', '=', int(data['id']))])
         if not data['is_menu']:
@@ -595,7 +626,7 @@ class Page(models.Model):
                 })
 
         page.write({
-            'key': 'website.' + slugify(data['name'], 50),
+            'key': page_key,
             'name': data['name'],
             'url': url,
             'website_published': data['website_published'],
-- 
GitLab