diff --git a/README.md b/README.md index 1c6aa646b5..4b39d1f48c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Available addons ---------------- addon | version | maintainers | summary --- | --- | --- | --- -[website_altcha](website_altcha/) | 18.0.1.0.1 | | Use self hosted privacy friendly captcha for verifying website users are not bots +[website_altcha](website_altcha/) | 18.0.1.1.0 | hbrunn | Use self hosted privacy friendly captcha for verifying website users are not bots [website_analytics_matomo](website_analytics_matomo/) | 18.0.1.0.0 | | Track website users using matomo [website_blog_scheduled_publication](website_blog_scheduled_publication/) | 18.0.1.1.0 | marcelsavegnago CristianoMafraJunior | Schedule blog posts publication date [website_breadcrumb](website_breadcrumb/) | 18.0.1.0.0 | | Let you have breadcrumbs in website pages @@ -30,6 +30,7 @@ addon | version | maintainers | summary [website_cookiebot](website_cookiebot/) | 18.0.1.0.0 | | Ask for cookies consent connecting with Cookiebot [website_cookiefirst](website_cookiefirst/) | 18.0.2.0.0 | | Cookiefirst integration [website_crm_quick_answer](website_crm_quick_answer/) | 18.0.1.0.0 | | Add an automatic answer for contacts asking for info +[website_event_altcha](website_event_altcha/) | 18.0.1.1.0 | hbrunn | Support event registration with ALTCHA [website_form_require_legal](website_form_require_legal/) | 18.0.1.0.2 | | Add possibility to require confirm legal terms. [website_forum_subscription](website_forum_subscription/) | 18.0.1.0.2 | | Adds a button to allow subscription from the website [website_google_tag_manager](website_google_tag_manager/) | 18.0.1.0.0 | | Add support for Google Tag Manager diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index 943fb6d622..9a0685cd10 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "odoo-addons-oca-website" -version = "18.0.20260901.0" +version = "18.0.20260902.0" dependencies = [ "odoo-addon-website_altcha==18.0.*", "odoo-addon-website_analytics_matomo==18.0.*", @@ -10,6 +10,7 @@ dependencies = [ "odoo-addon-website_cookiebot==18.0.*", "odoo-addon-website_cookiefirst==18.0.*", "odoo-addon-website_crm_quick_answer==18.0.*", + "odoo-addon-website_event_altcha==18.0.*", "odoo-addon-website_form_require_legal==18.0.*", "odoo-addon-website_forum_subscription==18.0.*", "odoo-addon-website_google_tag_manager==18.0.*", diff --git a/website_altcha/README.rst b/website_altcha/README.rst index 327a2d7d84..8f4f7a2765 100644 --- a/website_altcha/README.rst +++ b/website_altcha/README.rst @@ -11,7 +11,7 @@ Privacy Friendly Captcha !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:47240fe67bd99327829258a0f654f2a147a5332dca76e6e66d67df44800779c8 + !! source digest: sha256:83e03d4eacacddd6d9b4c9b29eed8eee8f9d1bde28564186bfb553e8f5a29b6f !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -126,6 +126,14 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. +.. |maintainer-hbrunn| image:: https://github.com/hbrunn.png?size=40px + :target: https://github.com/hbrunn + :alt: hbrunn + +Current `maintainer `__: + +|maintainer-hbrunn| + This module is part of the `OCA/website `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_altcha/__manifest__.py b/website_altcha/__manifest__.py index a1a71c6110..73817e4d8b 100644 --- a/website_altcha/__manifest__.py +++ b/website_altcha/__manifest__.py @@ -5,24 +5,28 @@ "name": "Privacy Friendly Captcha", "summary": """Use self hosted privacy friendly captcha for verifying website users are not bots""", - "version": "18.0.1.0.1", + "version": "18.0.1.1.0", "license": "AGPL-3", "author": "Dixmit,Odoo Community Association (OCA)", + "maintainers": ["hbrunn"], "website": "https://github.com/OCA/website", "depends": [ "website", ], "assets": { "web.assets_frontend": [ - "website_altcha/static/src/**/*.esm.js", - "website_altcha/static/src/**/*.xml", - "website_altcha/static/src/**/*.scss", + "website_altcha/static/src/*.esm.js", + "website_altcha/static/src/*.xml", + "website_altcha/static/src/*.scss", ], "web.altcha_libs": [ "website_altcha/static/lib/altcha.js", "website_altcha/static/lib/altcha-l10n.js", "website_altcha/static/lib/altcha.css", ], + "web.assets_tests": [ + "website_altcha/static/tests/tours/*.esm.js", + ], }, "external_dependencies": { "python": ["altcha"], @@ -31,4 +35,7 @@ "security/ir.model.access.csv", "views/res_config_settings_views.xml", ], + "demo": [ + "demo/website_page.xml", + ], } diff --git a/website_altcha/demo/website_page.xml b/website_altcha/demo/website_page.xml new file mode 100644 index 0000000000..ad2f5d5e13 --- /dev/null +++ b/website_altcha/demo/website_page.xml @@ -0,0 +1,36 @@ + + + + /website_altcha_demo + + + + diff --git a/website_altcha/i18n/fr.po b/website_altcha/i18n/fr.po index 6722a27c4e..f025ce9373 100644 --- a/website_altcha/i18n/fr.po +++ b/website_altcha/i18n/fr.po @@ -16,6 +16,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 5.15.2\n" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +". In that case the website_altcha_form class only takes care that " +"the javascript code is loaded and activated." +msgstr "" + #. module: website_altcha #: model_terms:ir.ui.view,arch_db:website_altcha.res_config_settings_view_form msgid "Add Altcha functionality" @@ -144,6 +151,18 @@ msgstr "Dernière mise à jour par" msgid "Last Updated on" msgstr "Dernière mise à jour le" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"Note in both cases, you'll have to verify the token you received in your " +"custom controller." +msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "Submit" +msgstr "" + #. module: website_altcha #. odoo-python #: code:addons/website_altcha/models/ir_http.py:0 @@ -155,6 +174,13 @@ msgstr "Activité suspecte détectée par Altcha" msgid "The Altcha key must be unique." msgstr "La clé Altcha doit être unique." +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"This is a demo form for website_altcha. Note how it automatically inserts " +"the widget in the container containing the submit button" +msgstr "" + #. module: website_altcha #: model:ir.model.fields,help:website_altcha.field_res_config_settings__altcha_timeout #: model:ir.model.fields,help:website_altcha.field_website__altcha_timeout @@ -177,3 +203,15 @@ msgstr "Utilisé" #: model:ir.model,name:website_altcha.model_website msgid "Website" msgstr "Site web" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"You can however also place the widget yourself and configure it according to " +"the" +msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "documentation" +msgstr "" diff --git a/website_altcha/i18n/it.po b/website_altcha/i18n/it.po index 4f917f8381..033f4be3de 100644 --- a/website_altcha/i18n/it.po +++ b/website_altcha/i18n/it.po @@ -16,6 +16,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +". In that case the website_altcha_form class only takes care that " +"the javascript code is loaded and activated." +msgstr "" + #. module: website_altcha #: model_terms:ir.ui.view,arch_db:website_altcha.res_config_settings_view_form msgid "Add Altcha functionality" @@ -144,6 +151,18 @@ msgstr "Ultimo aggiornamento di" msgid "Last Updated on" msgstr "Ultimo aggiornamento il" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"Note in both cases, you'll have to verify the token you received in your " +"custom controller." +msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "Submit" +msgstr "" + #. module: website_altcha #. odoo-python #: code:addons/website_altcha/models/ir_http.py:0 @@ -155,6 +174,13 @@ msgstr "Attività sospetta rilevata da Altcha" msgid "The Altcha key must be unique." msgstr "La chiave Altcha deve essere univoca." +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"This is a demo form for website_altcha. Note how it automatically inserts " +"the widget in the container containing the submit button" +msgstr "" + #. module: website_altcha #: model:ir.model.fields,help:website_altcha.field_res_config_settings__altcha_timeout #: model:ir.model.fields,help:website_altcha.field_website__altcha_timeout @@ -176,3 +202,15 @@ msgstr "Usata" #: model:ir.model,name:website_altcha.model_website msgid "Website" msgstr "Sito web" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"You can however also place the widget yourself and configure it according to " +"the" +msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "documentation" +msgstr "" diff --git a/website_altcha/i18n/website_altcha.pot b/website_altcha/i18n/website_altcha.pot index 5ffdfad4f3..5ec58bd77a 100644 --- a/website_altcha/i18n/website_altcha.pot +++ b/website_altcha/i18n/website_altcha.pot @@ -13,6 +13,13 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +". In that case the website_altcha_form class only takes care that " +"the javascript code is loaded and activated." +msgstr "" + #. module: website_altcha #: model_terms:ir.ui.view,arch_db:website_altcha.res_config_settings_view_form msgid "Add Altcha functionality" @@ -138,6 +145,18 @@ msgstr "" msgid "Last Updated on" msgstr "" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"Note in both cases, you'll have to verify the token you received in your " +"custom controller." +msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "Submit" +msgstr "" + #. module: website_altcha #. odoo-python #: code:addons/website_altcha/models/ir_http.py:0 @@ -149,6 +168,13 @@ msgstr "" msgid "The Altcha key must be unique." msgstr "" +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"This is a demo form for website_altcha. Note how it automatically inserts " +"the widget in the container containing the submit button" +msgstr "" + #. module: website_altcha #: model:ir.model.fields,help:website_altcha.field_res_config_settings__altcha_timeout #: model:ir.model.fields,help:website_altcha.field_website__altcha_timeout @@ -169,3 +195,15 @@ msgstr "" #: model:ir.model,name:website_altcha.model_website msgid "Website" msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "" +"You can however also place the widget yourself and configure it according to" +" the" +msgstr "" + +#. module: website_altcha +#: model_terms:ir.ui.view,arch_db:website_altcha.demo_page_view +msgid "documentation" +msgstr "" diff --git a/website_altcha/static/description/index.html b/website_altcha/static/description/index.html index cc3b4dafcc..9ec2c0824a 100644 --- a/website_altcha/static/description/index.html +++ b/website_altcha/static/description/index.html @@ -372,7 +372,7 @@

Privacy Friendly Captcha

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:47240fe67bd99327829258a0f654f2a147a5332dca76e6e66d67df44800779c8 +!! source digest: sha256:83e03d4eacacddd6d9b4c9b29eed8eee8f9d1bde28564186bfb553e8f5a29b6f !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/website Translate me on Weblate Try me on Runboat

This module allows to use a Captcha System completly handled by Odoo.

@@ -470,6 +470,8 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

+

Current maintainer:

+

hbrunn

This module is part of the OCA/website project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/website_altcha/static/lib/altcha.js b/website_altcha/static/lib/altcha.js index 1b70b870b7..7dab37aa64 100644 --- a/website_altcha/static/lib/altcha.js +++ b/website_altcha/static/lib/altcha.js @@ -1,4 +1,3 @@ -/* @odoo-module */ const DEV = false; var is_array = Array.isArray; var index_of = Array.prototype.indexOf; diff --git a/website_altcha/static/src/altcha.esm.js b/website_altcha/static/src/altcha.esm.js new file mode 100644 index 0000000000..996bfbb97a --- /dev/null +++ b/website_altcha/static/src/altcha.esm.js @@ -0,0 +1,49 @@ +import {loadBundle} from "@web/core/assets"; +import {renderToString} from "@web/core/utils/render"; +import {session} from "@web/session"; + +export const AltchaBaseFunctionality = { + altcha_prepend_to: "div.oe_login_buttons", + altcha_enabled: false, + + altcha_init() { + this.altcha_enabled = Boolean(session.altcha_public_key); + }, + + /** + * Loads the altcha libraries. + * + * @returns {Promise|Boolean} promise if libs are loading else false if the altcha key is empty. + */ + async altcha_load_libs() { + if (this.altcha_enabled) { + this._altchaReady = loadBundle(`web.altcha_libs`); + return this._altchaReady; + } + return false; + }, + altcha_insert_widget() { + if (this.altcha_enabled && !this.$el.find("altcha-widget").length) { + this.$el + .find(this.altcha_prepend_to) + .prepend(renderToString("website_altcha.AltchaWidget", {})); + } + }, +}; + +export const AltchaLegacyClassFunctionality = { + ...AltchaBaseFunctionality, + init() { + this._super(...arguments); + this.altcha_init(); + }, + + async willStart() { + this.altcha_load_libs(); + return this._super(...arguments); + }, + start() { + this.altcha_insert_widget(); + return this._super(...arguments); + }, +}; diff --git a/website_altcha/static/src/signup/altcha.scss b/website_altcha/static/src/altcha.scss similarity index 100% rename from website_altcha/static/src/signup/altcha.scss rename to website_altcha/static/src/altcha.scss diff --git a/website_altcha/static/src/signup/altcha.xml b/website_altcha/static/src/altcha.xml similarity index 100% rename from website_altcha/static/src/signup/altcha.xml rename to website_altcha/static/src/altcha.xml diff --git a/website_altcha/static/src/altcha/altcha.esm.js b/website_altcha/static/src/altcha/altcha.esm.js deleted file mode 100644 index 4f18e82e33..0000000000 --- a/website_altcha/static/src/altcha/altcha.esm.js +++ /dev/null @@ -1,27 +0,0 @@ -/* global document */ - -import {loadBundle} from "@web/core/assets"; -import {session} from "@web/session"; - -export class Altcha { - /** - * @override - */ - constructor() { - this._publicKey = session.altcha_public_key; - } - /** - * Loads the altcha libraries. - * - * @returns {Promise|Boolean} promise if libs are loading else false if the altcha key is empty. - */ - loadLibs() { - if (this._publicKey) { - this._altchaReady = loadBundle(`web.altcha_libs`); - return this._altchaReady.then(() => - Boolean(document.querySelector(".o_altcha_widget")) - ); - } - return false; - } -} diff --git a/website_altcha/static/src/generic.esm.js b/website_altcha/static/src/generic.esm.js new file mode 100644 index 0000000000..c1130b6845 --- /dev/null +++ b/website_altcha/static/src/generic.esm.js @@ -0,0 +1,9 @@ +import {AltchaLegacyClassFunctionality} from "@website_altcha/altcha.esm"; +import publicWidget from "@web/legacy/js/public/public_widget"; + +publicWidget.registry.GenericAltcha = publicWidget.Widget.extend({ + ...AltchaLegacyClassFunctionality, + selector: "form.website_altcha_form, form.js_website_submit_form", + altcha_prepend_to: + "*:has( > input[type='submit']), *:has( > button[type='submit'])", +}); diff --git a/website_altcha/static/src/signup.esm.js b/website_altcha/static/src/signup.esm.js new file mode 100644 index 0000000000..49954f71b2 --- /dev/null +++ b/website_altcha/static/src/signup.esm.js @@ -0,0 +1,12 @@ +import {AltchaLegacyClassFunctionality} from "./altcha.esm"; +import publicWidget from "@web/legacy/js/public/public_widget"; + +publicWidget.registry.SignupAltcha = publicWidget.Widget.extend({ + ...AltchaLegacyClassFunctionality, + selector: ".oe_signup_form", +}); + +publicWidget.registry.ResetPasswordAltcha = publicWidget.Widget.extend({ + ...AltchaLegacyClassFunctionality, + selector: ".oe_reset_password_form", +}); diff --git a/website_altcha/static/src/signup/signup.esm.js b/website_altcha/static/src/signup/signup.esm.js deleted file mode 100644 index fb5de1032d..0000000000 --- a/website_altcha/static/src/signup/signup.esm.js +++ /dev/null @@ -1,73 +0,0 @@ -import "@website/snippets/s_website_form/000"; -import {Altcha} from "@website_altcha/altcha/altcha.esm"; -import publicWidget from "@web/legacy/js/public/public_widget"; -import {renderToString} from "@web/core/utils/render"; - -export const AltchaFunctionality = { - init() { - this._super(...arguments); - this._altcha = new Altcha(); - }, - - async willStart() { - this._altcha.loadLibs(); - return this._super(...arguments); - }, - start: function () { - if (this._altcha._publicKey && !this.$el.find(".o_altcha_widget").length) { - this.$el - .find("div.oe_login_buttons") - .prepend(renderToString("website_altcha.AltchaWidget", {})); - } - return this._super(...arguments); - }, -}; - -publicWidget.registry.SignupAltcha = publicWidget.Widget.extend({ - ...AltchaFunctionality, - selector: ".oe_signup_form", -}); - -publicWidget.registry.ResetPasswordAltcha = publicWidget.Widget.extend({ - ...AltchaFunctionality, - selector: ".oe_reset_password_form", -}); - -publicWidget.registry.s_website_form.include({ - init() { - this._super(...arguments); - this._altcha = new Altcha(); - }, - - async willStart() { - this._altcha.loadLibs(); - return this._super(...arguments); - }, - - /** - * @override - */ - start: function () { - const res = this._super(...arguments); - if (this.$target[0].classList.contains("s_website_form_no_recaptcha")) { - return res; - } - if (this._altcha._publicKey) { - this.$el - .find(".s_website_form_submit") - .before(renderToString("website_altcha.AltchaWidget", {})); - } - return res; - }, -}); -publicWidget.registry.EditModeWebsiteForm.include({ - start: function () { - const res = this._super(...arguments); - if (this.editableMode) { - // We should delete the altcha widget in edit mode - this.$el.find(".o_altcha_widget").remove(); - this.$el.find(".o_altcha_widget_container").remove(); - } - return res; - }, -}); diff --git a/website_altcha/static/src/website_form.esm.js b/website_altcha/static/src/website_form.esm.js new file mode 100644 index 0000000000..f97201195d --- /dev/null +++ b/website_altcha/static/src/website_form.esm.js @@ -0,0 +1,36 @@ +import "@website/snippets/s_website_form/000"; +import {AltchaLegacyClassFunctionality} from "./altcha.esm"; +import publicWidget from "@web/legacy/js/public/public_widget"; +import {renderToString} from "@web/core/utils/render"; + +publicWidget.registry.s_website_form.include({ + ...AltchaLegacyClassFunctionality, +}); +publicWidget.registry.s_website_form.include({ + altcha_insert_widget() { + // Intentional no-op + }, + start: function () { + const res = this._super(...arguments); + if (this.$target[0].classList.contains("s_website_form_no_recaptcha")) { + return res; + } + if (this.altcha_enabled) { + this.$el + .find(".s_website_form_submit") + .before(renderToString("website_altcha.AltchaWidget", {})); + } + return res; + }, +}); +publicWidget.registry.EditModeWebsiteForm.include({ + start: function () { + const res = this._super(...arguments); + if (this.editableMode) { + // We should delete the altcha widget in edit mode + this.$el.find(".o_altcha_widget").remove(); + this.$el.find(".o_altcha_widget_container").remove(); + } + return res; + }, +}); diff --git a/website_altcha/static/tests/tours/website_altcha_contact.esm.js b/website_altcha/static/tests/tours/website_altcha_contact.esm.js new file mode 100644 index 0000000000..68321c3d08 --- /dev/null +++ b/website_altcha/static/tests/tours/website_altcha_contact.esm.js @@ -0,0 +1,41 @@ +/* Copyright 2026 Hunki Enterprises BV */ +import {registry} from "@web/core/registry"; + +registry.category("web_tour.tours").add("website_altcha_contact", { + steps: () => [ + { + content: "Fill in a name", + trigger: "input[name='name']", + run: "fill Testname", + }, + { + content: "Fill in an email", + trigger: "input[name='email_from']", + run: "fill test_website_altcha@test.com", + }, + { + content: "Fill in a subject", + trigger: "input[name='subject']", + run: "fill the subject", + }, + { + content: "Fill in a question", + trigger: "textarea[name='description']", + run: "fill the question", + }, + { + content: "Verify altcha", + trigger: "altcha-widget input[type='checkbox']", + run: "click", + }, + { + content: "Verify altcha value exists", + trigger: "input[name='altcha']:not(:visible):not(:empty)", + }, + { + content: "Click Submit", + trigger: "div.s_website_form_submit a", + run: "click", + }, + ], +}); diff --git a/website_altcha/static/tests/tours/website_altcha_generic.esm.js b/website_altcha/static/tests/tours/website_altcha_generic.esm.js new file mode 100644 index 0000000000..3d4ad89cf0 --- /dev/null +++ b/website_altcha/static/tests/tours/website_altcha_generic.esm.js @@ -0,0 +1,21 @@ +/* Copyright 2026 Hunki Enterprises BV */ +import {registry} from "@web/core/registry"; + +registry.category("web_tour.tours").add("website_altcha_generic", { + steps: () => [ + { + content: "Verify altcha", + trigger: "altcha-widget input[type='checkbox']", + run: "click", + }, + { + content: "Verify altcha value exists", + trigger: "input[name='altcha']:not(:visible):not(:empty)", + }, + { + content: "Click Submit", + trigger: "button[type='submit']", + run: "click", + }, + ], +}); diff --git a/website_altcha/static/tests/tours/website_altcha_signup.esm.js b/website_altcha/static/tests/tours/website_altcha_signup.esm.js new file mode 100644 index 0000000000..824087f07d --- /dev/null +++ b/website_altcha/static/tests/tours/website_altcha_signup.esm.js @@ -0,0 +1,26 @@ +/* Copyright 2026 Hunki Enterprises BV */ +import {registry} from "@web/core/registry"; + +registry.category("web_tour.tours").add("website_altcha_signup", { + steps: () => [ + { + content: "Fill in a login", + trigger: "input[name='login']", + run: "fill admin", + }, + { + content: "Verify altcha", + trigger: "altcha-widget input[type='checkbox']", + run: "click", + }, + { + content: "Verify altcha value exists", + trigger: "input[name='altcha']:not(:visible):not(:empty)", + }, + { + content: "Click Submit", + trigger: "button[type='submit']", + run: "click", + }, + ], +}); diff --git a/website_altcha/tests/__init__.py b/website_altcha/tests/__init__.py index 65d22d8cf1..2fb64ca391 100644 --- a/website_altcha/tests/__init__.py +++ b/website_altcha/tests/__init__.py @@ -1 +1,2 @@ from . import test_altcha +from . import test_altcha_tours diff --git a/website_altcha/tests/common.py b/website_altcha/tests/common.py new file mode 100644 index 0000000000..dadd8112b2 --- /dev/null +++ b/website_altcha/tests/common.py @@ -0,0 +1,18 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests import HttpCase, tagged + + +@tagged("-at_install", "post_install") +class Common(HttpCase): + @classmethod + def setUpClass(cls): + result = super().setUpClass() + cls.website = cls.env["website"].get_current_website() + cls.website.altcha_key = "test_key" + cls.website.altcha_private_key = "test_secret_key" + cls.website.altcha_cost = 2 + # Forcing a small power of 2 cost for allowing scrypt to work + # and make everything faster + return result diff --git a/website_altcha/tests/test_altcha.py b/website_altcha/tests/test_altcha.py index 462f16638b..0fea6cb962 100644 --- a/website_altcha/tests/test_altcha.py +++ b/website_altcha/tests/test_altcha.py @@ -8,13 +8,15 @@ from requests.exceptions import HTTPError from odoo.exceptions import UserError -from odoo.tests import Form, HttpCase +from odoo.tests import Form from odoo.tools import mute_logger from odoo.addons.website.tools import MockRequest +from .common import Common -class TestAltchaCreation(HttpCase): + +class TestAltchaCreation(Common): @classmethod def setUpClass(cls): result = super().setUpClass() diff --git a/website_altcha/tests/test_altcha_tours.py b/website_altcha/tests/test_altcha_tours.py new file mode 100644 index 0000000000..4cfeef523e --- /dev/null +++ b/website_altcha/tests/test_altcha_tours.py @@ -0,0 +1,24 @@ +# Copyright 2026 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.addons.website_altcha.tests.common import Common + + +class TestWebsiteAltchaTours(Common): + def test_contact_tour(self): + """ + Run the contact test tour + """ + self.start_tour("/contactus", "website_altcha_contact") + + def test_signup_tour(self): + """ + Run the signup test tour + """ + self.start_tour("/web/reset_password", "website_altcha_signup") + + def test_generic_tour(self): + """ + Run the generic test tour + """ + self.start_tour("/website_altcha_demo", "website_altcha_generic") diff --git a/website_event_altcha/README.rst b/website_event_altcha/README.rst new file mode 100644 index 0000000000..a093f1b4ec --- /dev/null +++ b/website_event_altcha/README.rst @@ -0,0 +1,89 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +============================================= +Privacy Friendly Captcha - Event Registration +============================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:f2eb50353d5a95993455af76b139a72c0735ecfa07a9cf5e016198b817a5d06c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fwebsite-lightgray.png?logo=github + :target: https://github.com/OCA/website/tree/18.0/website_event_altcha + :alt: OCA/website +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/website-18-0/website-18-0-website_event_altcha + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/website&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds ALTCHA support to event registration forms + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Hunki Enterprises BV + +Contributors +------------ + +- Holger Brunn + (https://hunki-enterprises.com) + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-hbrunn| image:: https://github.com/hbrunn.png?size=40px + :target: https://github.com/hbrunn + :alt: hbrunn + +Current `maintainer `__: + +|maintainer-hbrunn| + +This module is part of the `OCA/website `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_event_altcha/__init__.py b/website_event_altcha/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/website_event_altcha/__manifest__.py b/website_event_altcha/__manifest__.py new file mode 100644 index 0000000000..8134b74d0b --- /dev/null +++ b/website_event_altcha/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright 2026 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Privacy Friendly Captcha - Event Registration", + "summary": "Support event registration with ALTCHA", + "version": "18.0.1.1.0", + "license": "AGPL-3", + "author": "Hunki Enterprises BV,Odoo Community Association (OCA)", + "maintainers": ["hbrunn"], + "website": "https://github.com/OCA/website", + "depends": [ + "website_altcha", + "website_event", + ], + "assets": { + "web.assets_frontend": [ + "website_event_altcha/static/src/*.esm.js", + ], + "web.assets_tests": [ + "website_event_altcha/static/tests/tours/website_event_altcha.esm.js", + ], + }, + "auto_install": True, +} diff --git a/website_event_altcha/i18n/website_event_altcha.pot b/website_event_altcha/i18n/website_event_altcha.pot new file mode 100644 index 0000000000..aadee09bfe --- /dev/null +++ b/website_event_altcha/i18n/website_event_altcha.pot @@ -0,0 +1,13 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" diff --git a/website_event_altcha/pyproject.toml b/website_event_altcha/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/website_event_altcha/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/website_event_altcha/readme/CONTRIBUTORS.md b/website_event_altcha/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..cf8bf7205a --- /dev/null +++ b/website_event_altcha/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Holger Brunn \ (https://hunki-enterprises.com) diff --git a/website_event_altcha/readme/DESCRIPTION.md b/website_event_altcha/readme/DESCRIPTION.md new file mode 100644 index 0000000000..33a3690849 --- /dev/null +++ b/website_event_altcha/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module adds ALTCHA support to event registration forms diff --git a/website_event_altcha/static/description/icon.png b/website_event_altcha/static/description/icon.png new file mode 100644 index 0000000000..d8e30bafa5 Binary files /dev/null and b/website_event_altcha/static/description/icon.png differ diff --git a/website_event_altcha/static/description/index.html b/website_event_altcha/static/description/index.html new file mode 100644 index 0000000000..b515601620 --- /dev/null +++ b/website_event_altcha/static/description/index.html @@ -0,0 +1,432 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Privacy Friendly Captcha - Event Registration

+ +

Beta License: AGPL-3 OCA/website Translate me on Weblate Try me on Runboat

+

This module adds ALTCHA support to event registration forms

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Hunki Enterprises BV
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

hbrunn

+

This module is part of the OCA/website project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/website_event_altcha/static/src/EventRegistrationForm.esm.js b/website_event_altcha/static/src/EventRegistrationForm.esm.js new file mode 100644 index 0000000000..f375ef6324 --- /dev/null +++ b/website_event_altcha/static/src/EventRegistrationForm.esm.js @@ -0,0 +1,32 @@ +/* Copyright 2026 Hunki Enterprises BV */ +import {AltchaLegacyClassFunctionality} from "@website_altcha/altcha.esm"; +import EventRegistrationForm from "@website_event/js/website_event"; + +EventRegistrationForm.include({ + ...AltchaLegacyClassFunctionality, +}); + +EventRegistrationForm.include({ + altcha_prepend_to: "div.modal-footer", + start() { + const result = this._super(...arguments); + const altcha_widget = this.el.querySelector("altcha-widget"); + if (altcha_widget) { + const button = this.el.querySelector("button.btn-primary"); + altcha_widget.addEventListener("statechange", (ev) => { + button.disabled = ev.detail.state !== "verified"; + }); + altcha_widget.addEventListener("load", () => { + button.disabled = altcha_widget.getState() !== "verified"; + }); + } + return result; + }, + _addTurnstile(form) { + const altcha_widget = this.el.querySelector("altcha-widget"); + if (altcha_widget) { + form.querySelector("div.modal-footer").prepend(altcha_widget); + } + this._super(...arguments); + }, +}); diff --git a/website_event_altcha/static/src/ticketDetailsWidget.esm.js b/website_event_altcha/static/src/ticketDetailsWidget.esm.js new file mode 100644 index 0000000000..0a3c3548e0 --- /dev/null +++ b/website_event_altcha/static/src/ticketDetailsWidget.esm.js @@ -0,0 +1,20 @@ +/* Copyright 2026 Hunki Enterprises BV */ +import ticketDetailsWidget from "@website_event/js/website_event_ticket_details"; + +ticketDetailsWidget.include({ + start() { + this.disableSubmitIfUnverified(); + return this._super(...arguments); + }, + _onTicketQuantityChange() { + this._super(...arguments); + this.disableSubmitIfUnverified(); + }, + disableSubmitIfUnverified() { + const altcha_widget = this.el.querySelector("altcha-widget"); + if (altcha_widget) { + const button = this.el.querySelector("button.btn-primary"); + button.disabled = altcha_widget.getState() !== "verified"; + } + }, +}); diff --git a/website_event_altcha/static/tests/tours/website_event_altcha.esm.js b/website_event_altcha/static/tests/tours/website_event_altcha.esm.js new file mode 100644 index 0000000000..74983b2a3f --- /dev/null +++ b/website_event_altcha/static/tests/tours/website_event_altcha.esm.js @@ -0,0 +1,51 @@ +/* Copyright 2026 Hunki Enterprises BV */ +import {registry} from "@web/core/registry"; + +registry.category("web_tour.tours").add("website_event_altcha", { + steps: () => [ + { + content: "Click register button", + trigger: "button[data-bs-target='#modal_ticket_registration']", + run: "click", + }, + { + content: "Select a ticket", + trigger: "#o_wevent_tickets_collapse select", + run: "selectByIndex 1", + }, + { + content: "Verify altcha", + trigger: "altcha-widget input[type='checkbox']", + run: "click", + }, + { + content: "Click Submit", + trigger: "#registration_form button[type='submit']:enabled", + run: "click", + }, + { + content: "Fill in name", + trigger: "#attendee_registration input[name*='-name-']:enabled", + async run() { + this.anchor.value = "Testname"; + }, + }, + { + content: "Fill in email", + trigger: "#attendee_registration input[name*='-email-']:enabled", + async run() { + this.anchor.value = "test_website_altcha@test.com"; + }, + }, + { + content: "Verify altcha value exists", + trigger: + "#attendee_registration input[name='altcha']:not(:visible):not(:empty)", + }, + { + content: "Click submit", + trigger: "#attendee_registration button[type='submit']", + run: "click", + }, + ], +}); diff --git a/website_event_altcha/tests/__init__.py b/website_event_altcha/tests/__init__.py new file mode 100644 index 0000000000..75a0c88ebe --- /dev/null +++ b/website_event_altcha/tests/__init__.py @@ -0,0 +1 @@ +from . import test_website_event_altcha diff --git a/website_event_altcha/tests/test_website_event_altcha.py b/website_event_altcha/tests/test_website_event_altcha.py new file mode 100644 index 0000000000..f23594165b --- /dev/null +++ b/website_event_altcha/tests/test_website_event_altcha.py @@ -0,0 +1,13 @@ +# Copyright 2026 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.addons.website_altcha.tests.common import Common + + +class TestWebsiteEventAltcha(Common): + def test_event_registration_with_questions(self): + """ + Test an event registration that contains questions + """ + event = self.env.ref("event.event_7") + self.start_tour(f"/event/{event.id}", "website_event_altcha")