Skip to content

Commit

Permalink
[ADD] Added website event copy module
Browse files Browse the repository at this point in the history
- Shows website_menu checkbox
- Added button to duplicate an event with its website when website_menu is True
- Delete the website attached to an event when that last is deleted

Squash of the following commits:
[IMP] Removed dot files and fix pre-commit issues
[IMP] Added more test coverage
[IMP] More test cover
[IMP] More test cover
[IMP] Added missing dosctring and trimed too long lines
[IMP] Added tests coverage
[WIP] Added copy and delete of website event views
[WIP] Copy and delete cascade on event website
  • Loading branch information
thibaud committed Jan 23, 2024
1 parent aa0b551 commit 07668df
Show file tree
Hide file tree
Showing 16 changed files with 533 additions and 0 deletions.
1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mock==5.1.0
1 change: 1 addition & 0 deletions setup/website_event_copy/odoo/addons/website_event_copy
6 changes: 6 additions & 0 deletions setup/website_event_copy/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
25 changes: 25 additions & 0 deletions website_event_copy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Le Filament - Website event copy

## Description

This module is used to copy the website associated to an event when the last is copied.

## Exemple

A golf tournament event has a website A. Click on "copy with website" button and you now
have another golf tournament event with a website A'

## Credits

## Contributors

- Thibaud <[email protected]>

## Maintainer

[![Le Filament](https://le-filament.com/img/logo-lefilament.png)](https://le-filament.com)
This module is maintained by Le Filament

## Licenses

This repository is licensed under [AGPL-3.0](LICENSE).
1 change: 1 addition & 0 deletions website_event_copy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
30 changes: 30 additions & 0 deletions website_event_copy/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "Le Filament - Website event copy",
"summary": "Allow website linked to an event to be copied "
"when the event is duplicated",
"author": "Le Filament, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/event",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"depends": [
"event_session",
"website_event",
],
"data": [
"security/ir.model.access.csv",
# datas
# views
"views/event_views.xml",
# views menu
# wizard
],
"assets": {
"web._assets_primary_variables": [],
"web._assets_frontend_helpers": [],
"web.assets_frontend": [],
"web.assets_tests": [],
"web.assets_qweb": [],
},
"installable": True,
"auto_install": False,
}
26 changes: 26 additions & 0 deletions website_event_copy/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * website_event_copy
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-18 10:32+0000\n"
"PO-Revision-Date: 2023-12-18 10:32+0000\n"
"Last-Translator: Thibaud Bruge\n"
"Language-Team: Le Filament\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: website_event_copy
#: model_terms:ir.ui.view,arch_db:website_event_copy.view_restrict_event_session_form
msgid "Duplicate with website"
msgstr "Dupliquer avec site web"

#. module: website_event_copy
#: model:ir.model,name:website_event_copy.model_event_event
msgid "Event"
msgstr "Event"
26 changes: 26 additions & 0 deletions website_event_copy/i18n/website_event_copy.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * website_event_copy
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-18 10:32+0000\n"
"PO-Revision-Date: 2023-12-18 10:32+0000\n"
"Last-Translator: Thibaud Bruge\n"
"Language-Team: Le Filament\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: website_event_copy
#: model_terms:ir.ui.view,arch_db:website_event_copy.view_restrict_event_session_form
msgid "Dupliquer avec site web"
msgstr "Duplicate with website"

#. module: website_event_copy
#: model:ir.model,name:website_event_copy.model_event_event
msgid "Event"
msgstr "Event"
1 change: 1 addition & 0 deletions website_event_copy/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import event_event, ir_ui_view
181 changes: 181 additions & 0 deletions website_event_copy/models/event_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import re

from odoo import api, models

from odoo.addons.http_routing.models.ir_http import slug


class Event(models.Model):
_inherit = "event.event"

# ------------------------------------------------------
# Action button
# ------------------------------------------------------

def action_dup_event_and_web(self):
new_event = self.duplicate_event_and_website({"new_name": self.name})
return {

Check warning on line 17 in website_event_copy/models/event_event.py

View check run for this annotation

Codecov / codecov/patch

website_event_copy/models/event_event.py#L16-L17

Added lines #L16 - L17 were not covered by tests
"view_type": "form",
"view_mode": "form",
"res_model": "event.event",
"type": "ir.actions.act_window",
"res_id": new_event.id,
}

def duplicate_event_and_website(self, default_dict: dict = None):
"""
Create a new event along with its website pages
One view as an inheritance there other one might not if only the title has been
changed
If the structure of the view hasn't been changed, the view with inherit_id won't
be created therefore the copy won't happen even if the title only has been
changed.
:param default_dict: A dict of default value that will be used as new event
properties use the key "new_name" to give a specific name to the new event
:return: The new event
"""
self.ensure_one()
new_event = None
if self.website_menu:
# If the name is not provided for the copy then the new event take the
# same name as the original event
new_event = self.copy(default=default_dict) # Copy current event
key_part = f"{slug(self)}"

views_to_copy = self.env["ir.ui.view"].search(
[("key", "like", key_part), ("inherit_id", "!=", False)]
)

for view in views_to_copy:
# Order of creation matter for the later delete
new_inherited_view = view.inherit_id.copy()
new_view = view.copy()

# Replace ids in keys for each view
new_view.update(
{
"key": self.replace_key_id(new_view.key, new_event.id),
"inherit_id": new_inherited_view.id,
}
)
new_inherited_view.update(
{"key": self.replace_key_id(new_inherited_view.key, new_event.id)}
)
else:
new_event = self.copy()

return new_event

def replace_key_id(self, key: str, replace_id: int) -> str:
"""
This method is used to replace the id that has been added
in the key. During the copy process the view will keep the
old reference id, therefore it needs to be changed to the new
one
:param key (str): the key you want to change the id in
:param replace_id (int): the id you wish the change for
:return (str): the new key
"""
# regex = r"(?<=-)[0-9]+"
# new_key = re.sub(regex, str(replace_id), key, count=0, flags=re.MULTILINE)
# return new_key

regex = r"(?<=-)([0-9]+-*)+"
result = re.sub(regex, str(replace_id), key, count=0, flags=re.MULTILINE)

return result

# ------------------------------------------------------
# Default functions
# ------------------------------------------------------

# ------------------------------------------------------
# CRUD methods (ORM overrides)
# ------------------------------------------------------

@api.returns("self", lambda value: value.id)
def copy_data(self, default: dict = None) -> [dict]:
"""
Inheritance of copy_data() from models module in order to counter the spread of
the string 'copy' in the new event name.
:param default: The default dict containing fields and their value for the copy
:return: A list of dictionnary (default) that key will be used as fields during
the copy process
"""
self.ensure_one()
if default.get("new_name"):
default["name"] = default["new_name"]
default.pop("new_name")
return super().copy_data(default)

@api.ondelete(at_uninstall=True)
def _flush_website_event_menus_and_views(self):
"""
Make sure both associated views and menus of an event are deleted when the last
is deleted.
"""
for event in self:
if event.website_menu:
website_menu_events = self.env["website.event.menu"].search(
[("event_id", "=", event.id)]
)

menus = []
key = None
for website_menu_event in website_menu_events:
menus.append(website_menu_event.menu_id)
if key is None and website_menu_event.view_id.key:
view = website_menu_event.view_id
# The key we are looking for is not the same as the menu one,
# we separate the menu name from the key to be able to identify
# all views regardless of the menu. The later views will be
# deleted
key = view.get_website_event_view_key()

menu_parents = {menu.parent_id for menu in menus}
for parent in menu_parents:
parent.unlink()

if key:
views = self.env["ir.ui.view"].search(
[("key", "like", key)], order="id"
)
view_list = [view for view in views]
view_list.reverse()

for view in view_list:
view.unlink()

def _create_menu(self, sequence, name, url, xml_id, menu_type):
"""
Ensure the menu is created with the right view. Before this override the menus
were referencing a wrong view. For 2 website events with the same name for
instance "golf-tournament", two views were created, golf-tournament and
golf-tournament-1
The second view whould never be called because the menu of the second
website_event would refer to the view of the first website_event and
not of the second
This behaviour has been identified of use of key which has no unicity constraint
"""
website_menu = super()._create_menu(sequence, name, url, xml_id, menu_type)

website_event_menu = (
self.env["website.event.menu"]
.sudo()
.search([("menu_id", "=", website_menu.id)])
)
view_id = website_event_menu.view_id
if view_id:
view_id.update({"key": f"{view_id.key}-{self.id}"})
key = view_id.get_website_event_menu_key()
url_splitted = website_menu.url.split("/")
url_splitted[-1] = key

website_menu.update({"url": "/".join(url_splitted)})
return website_menu
42 changes: 42 additions & 0 deletions website_event_copy/models/ir_ui_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import re

from odoo import models


class View(models.Model):
_inherit = "ir.ui.view"

# ------------------------------------------------------
# Action button
# ------------------------------------------------------

# ------------------------------------------------------
# Default functions
# ------------------------------------------------------

# ------------------------------------------------------
# CRUD methods (ORM overrides)
# ------------------------------------------------------
SEPARATOR = "-"

def get_website_event_menu_key(self):
"""
Find the useful part in the view key mainely for menu creation and unlink
during the flush.
:return: <menu_name>-<event_name>-<event_id> key format
"""
regex = r"(?<=\.)[a-zA-Z-]+[0-9].*"
result = re.search(regex, self.key)
return result[0]

def get_website_event_view_key(self):
"""
Find the useful part in the view key that is common to all views linked to an
event. We can achieve that thanks to the event_ID we injected earlier in the
view key.
:return: <event_name>-<event_id> key format
"""
key = self.get_website_event_menu_key()
return self.SEPARATOR.join(key.split(self.SEPARATOR)[1:])
1 change: 1 addition & 0 deletions website_event_copy/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
Binary file added website_event_copy/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions website_event_copy/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_website_event_copy
Loading

0 comments on commit 07668df

Please sign in to comment.