diff --git a/ir_rule_website/README.rst b/ir_rule_website/README.rst new file mode 100644 index 00000000..7e0d039b --- /dev/null +++ b/ir_rule_website/README.rst @@ -0,0 +1,43 @@ +.. image:: https://itpp.dev/images/infinity-readme.png + :alt: Tested and maintained by IT Projects Labs + :target: https://itpp.dev + +========================== + Multi-Brand Access Rules +========================== + +Allows to use new variables to be used in ``domain_force`` field of Record Rules (``ir.rule``): + +* ``website_ids`` -- equal to ``context["allowed_website_ids"]`` (see module ``web_website``) +* ``websites`` -- browsed ``website_ids`` + +For your information: Odoo provides ``website`` variable, which is equal to current website in frontend and is empty in backend + +Example of usage: + +* Show a blog on specific websites only (TODO: add link to the module) +* Show an event on specific websites only (TODO: add link to the module) +* Show a product on specific websites only (TODO: add link to the module) + +Roadmap +======= + +* This module can be merged to ``web_website`` module +* Website rules don't work for ``/mail/read_followers`` method: https://github.com/itpp-labs/access-addons/issues/232 + +Questions? +========== + +To get an assistance on this module contact us by email :arrow_right: help@itpp.dev + +Contributors +============ +* `Ivan Yelizariev `__ +* `Ildar Nasyrov `__ + +=================== + +Odoo Apps Store: https://apps.odoo.com/apps/modules/13.0/ir_rule_website + + +Tested on `Odoo 14.0 `_ diff --git a/ir_rule_website/__init__.py b/ir_rule_website/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/ir_rule_website/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/ir_rule_website/__manifest__.py b/ir_rule_website/__manifest__.py new file mode 100644 index 00000000..910615ff --- /dev/null +++ b/ir_rule_website/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright 2020 Ivan Yelizariev +# License MIT (https://opensource.org/licenses/MIT). +{ + "name": """Multi-Brand Access Rules""", + "summary": """Provide access depending on current website""", + "category": "Access", + "images": ["images/ir_rule_website.jpg"], + "version": "14.0.1.0.0", + "application": False, + "author": "IT-Projects LLC, Ildar Nasyrov", + "support": "help@itpp.dev", + "website": "https://twitter.com/OdooFree", + "license": "Other OSI approved licence", # MIT + "depends": ["web_website"], + "external_dependencies": {"python": [], "bin": []}, + "data": [], + "qweb": [], + "demo": [], + "post_load": None, + "pre_init_hook": None, + "post_init_hook": None, + "uninstall_hook": None, + "auto_install": False, + "installable": True, +} diff --git a/ir_rule_website/doc/changelog.rst b/ir_rule_website/doc/changelog.rst new file mode 100644 index 00000000..fed318fe --- /dev/null +++ b/ir_rule_website/doc/changelog.rst @@ -0,0 +1,34 @@ +`2.0.0` +------- + +- **Improvement**: simplify code, get rid of ``backend_behavior`` field + +`1.3.2` +------- + +- **Fix**: Models without group binded rules were then wrongly reduced to an 'AND FALSE' condition. After https://github.com/odoo/odoo/commit/023dfaeb6b9499943315358edaa01c8f823ee695 + +`1.3.1` +------- + +- **Fix**: Random wrong result on applying rules in backend + +`1.3.0` +------- + +- **New:** add ``website`` object to a rule evaluation context - to be able to use rules as such ``[('id','=', website.company_id.id)]`` + +`1.2.0` +------- + +- **Add:** Use user's **Current Backend Website** from ``web_website`` module on evaluating website rules in Odoo backend + +`1.1.0` +------- + +- **Add:** New setting in ``ir.rule`` model - to bypass website rules when working from backend + +`1.0.0` +------- + +- **Init version** diff --git a/ir_rule_website/doc/index.rst b/ir_rule_website/doc/index.rst new file mode 100644 index 00000000..d7434383 --- /dev/null +++ b/ir_rule_website/doc/index.rst @@ -0,0 +1,34 @@ +========================== + Multi-Brand Access Rules +========================== + +Installation +============ + +* `Install `__ this module in a usual way + +Backend Usage +============= + +* As usual open ``[[ Settings ]] >> Technical >> Security >> Record Rules`` to create a new rule or edit existing one +* RESULT: you can use variables ``websites`` and ``website_ids`` in **domain_force** field + +Usage in a module +================= + +If you have a model accessible through a website, you can apply restriction in a following way: + +* Add field ``website_ids`` to your model to specify on which websites the record should be available +* Add this ``ir_rule_website`` into the ``"depends"`` section of your manifest file +* Create a security rule using ``website_ids`` in ``domain_force`` field. For example, + +:: + + + + + Blogs available only for specifed websites + + [('website_ids', 'in', website_ids)] + + diff --git a/ir_rule_website/i18n/de.po b/ir_rule_website/i18n/de.po new file mode 100644 index 00000000..7e6ea999 --- /dev/null +++ b/ir_rule_website/i18n/de.po @@ -0,0 +1,56 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * ir_rule_website +# +# Translators: +# Dawid Runowski , 2019 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-04-26 19:17+0000\n" +"PO-Revision-Date: 2018-04-18 13:56+0000\n" +"Last-Translator: Dawid Runowski , 2019\n" +"Language-Team: German (https://www.transifex.com/it-projects-llc/teams/76080/" +"de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: ir_rule_website +#: model:ir.model.fields,field_description:ir_rule_website.field_ir_rule_backend_behaviour +msgid "Backend behaviour" +msgstr "" + +#. module: ir_rule_website +#: selection:ir.rule,backend_behaviour:0 +msgid "Deny access" +msgstr "den Zugang verweiger" + +#. module: ir_rule_website +#: selection:ir.rule,backend_behaviour:0 +msgid "Grant access" +msgstr "den Zugang erlauben" + +#. module: ir_rule_website +#: model:ir.ui.view,arch_db:ir_rule_website.view_rule_form_inherit_ir_rule_website +msgid "Multi-website extension" +msgstr "" + +#. module: ir_rule_website +#: model:ir.model.fields,help:ir_rule_website.field_ir_rule_backend_behaviour +msgid "" +"This is bypass for main rule definition.\n" +" When working from backend there is usually no 'website_id' value in " +"the rule evaluation context\n" +" what leads to SQL syntax error such as 'WHERE website_id IN ()' in " +"rules that using 'website_id'" +msgstr "" + +#. module: ir_rule_website +#: model:ir.model,name:ir_rule_website.model_ir_rule +msgid "ir.rule" +msgstr "" diff --git a/ir_rule_website/i18n/es_CR.po b/ir_rule_website/i18n/es_CR.po new file mode 100644 index 00000000..35c8c606 --- /dev/null +++ b/ir_rule_website/i18n/es_CR.po @@ -0,0 +1,59 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * ir_rule_website +# +# Translators: +# Randall , 2018 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-04-21 00:17+0000\n" +"PO-Revision-Date: 2018-04-21 00:17+0000\n" +"Last-Translator: Randall , 2018\n" +"Language-Team: Spanish (Costa Rica) (https://www.transifex.com/it-projects-" +"llc/teams/76080/es_CR/)\n" +"Language: es_CR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: ir_rule_website +#: model:ir.model.fields,field_description:ir_rule_website.field_ir_rule__backend_behaviour +msgid "Backend behaviour" +msgstr "" + +#. module: ir_rule_website +#: selection:ir.rule,backend_behaviour:0 +msgid "Deny access" +msgstr "" + +#. module: ir_rule_website +#: selection:ir.rule,backend_behaviour:0 +msgid "Grant access" +msgstr "" + +#. module: ir_rule_website +#: model_terms:ir.ui.view,arch_db:ir_rule_website.view_rule_form_inherit_ir_rule_website +msgid "Multi-website extension" +msgstr "" + +#. module: ir_rule_website +#: model:ir.model,name:ir_rule_website.model_ir_rule +msgid "Record Rule" +msgstr "" + +#. module: ir_rule_website +#: model:ir.model.fields,help:ir_rule_website.field_ir_rule__backend_behaviour +msgid "" +"This is bypass for main rule definition.\n" +" When working from backend there is usually no 'website_id' value in " +"the rule evaluation context\n" +" and rules that using 'website_id' evaluated as False which is not " +"always desirable" +msgstr "" + +#~ msgid "ir.rule" +#~ msgstr "ir.rule" diff --git a/ir_rule_website/i18n/ir_rule_website.pot b/ir_rule_website/i18n/ir_rule_website.pot new file mode 100644 index 00000000..8a98b3f2 --- /dev/null +++ b/ir_rule_website/i18n/ir_rule_website.pot @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * ir_rule_website +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.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" + +#. module: ir_rule_website +#: model:ir.model.fields,field_description:ir_rule_website.field_ir_rule__backend_behaviour +msgid "Backend behaviour" +msgstr "" + +#. module: ir_rule_website +#: selection:ir.rule,backend_behaviour:0 +msgid "Deny access" +msgstr "" + +#. module: ir_rule_website +#: selection:ir.rule,backend_behaviour:0 +msgid "Grant access" +msgstr "" + +#. module: ir_rule_website +#: model_terms:ir.ui.view,arch_db:ir_rule_website.view_rule_form_inherit_ir_rule_website +msgid "Multi-website extension" +msgstr "" + +#. module: ir_rule_website +#: model:ir.model,name:ir_rule_website.model_ir_rule +msgid "Record Rule" +msgstr "" + +#. module: ir_rule_website +#: model:ir.model.fields,help:ir_rule_website.field_ir_rule__backend_behaviour +msgid "This is bypass for main rule definition.\n" +" When working from backend there is usually no 'website_id' value in the rule evaluation context\n" +" and rules that using 'website_id' evaluated as False which is not always desirable" +msgstr "" + diff --git a/ir_rule_website/images/ir_rule_website.jpg b/ir_rule_website/images/ir_rule_website.jpg new file mode 100644 index 00000000..1b2c94d5 Binary files /dev/null and b/ir_rule_website/images/ir_rule_website.jpg differ diff --git a/ir_rule_website/models/__init__.py b/ir_rule_website/models/__init__.py new file mode 100644 index 00000000..fc1cd7bf --- /dev/null +++ b/ir_rule_website/models/__init__.py @@ -0,0 +1 @@ +from . import ir_rule diff --git a/ir_rule_website/models/ir_rule.py b/ir_rule_website/models/ir_rule.py new file mode 100644 index 00000000..1679936b --- /dev/null +++ b/ir_rule_website/models/ir_rule.py @@ -0,0 +1,18 @@ +# Copyright 2020 Ivan Yelizariev +# License MIT (https://opensource.org/licenses/MIT). +from odoo import api, models + + +class IrRule(models.Model): + _inherit = "ir.rule" + + @api.model + def _eval_context(self): + context = super(IrRule, self)._eval_context() + context["website_ids"] = self.env.context.get("allowed_website_ids", []) + context["websites"] = self.env["website"].browse(context["website_ids"]) + return context + + def _compute_domain_keys(self): + """ Return the list of context keys to use for caching ``_compute_domain``. """ + return super(IrRule, self)._compute_domain_keys() + ["allowed_website_ids"] diff --git a/ir_rule_website/static/description/icon.png b/ir_rule_website/static/description/icon.png new file mode 100644 index 00000000..b43a0a13 Binary files /dev/null and b/ir_rule_website/static/description/icon.png differ diff --git a/ir_rule_website/static/description/index.html b/ir_rule_website/static/description/index.html new file mode 100644 index 00000000..5bd710cb --- /dev/null +++ b/ir_rule_website/static/description/index.html @@ -0,0 +1,91 @@ +
+
+
+

Multi-website support in Security Rules

+

Make website-dependent access to pages, products, etc.

+
+
+
+ +
+
+
+ +
+ Technical module that allows implementing different features. For example: +
    + +
  • + + Show a blog on specific websites only +
  • + +
  • + + Show an event on specific websites only +
  • + +
  • + + Show a product on specific websites only +
  • + +
+
+ +
+
+
+ +
+
+
+

Need our service?

+

Contact us by email or fill out request form

+ +
+
+
+
+ Tested on Odoo
13.0 community +
+ +
+
+
+
diff --git a/ir_rule_website/tests/__init__.py b/ir_rule_website/tests/__init__.py new file mode 100644 index 00000000..753b4f70 --- /dev/null +++ b/ir_rule_website/tests/__init__.py @@ -0,0 +1 @@ +from . import test_backend_website_rule diff --git a/ir_rule_website/tests/test_backend_website_rule.py b/ir_rule_website/tests/test_backend_website_rule.py new file mode 100644 index 00000000..40b2446e --- /dev/null +++ b/ir_rule_website/tests/test_backend_website_rule.py @@ -0,0 +1,116 @@ +# Copyright 2020 Ivan Yelizariev +# License MIT (https://opensource.org/licenses/MIT). +from odoo.exceptions import AccessError +from odoo.tests.common import TransactionCase + +# TODO: the tests are quick fixes of the tests for 1.x.x version and need to be cleanup + + +class TestBackendWebsiteRule(TransactionCase): + at_install = True + post_install = True + + def setUp(self): + super(TestBackendWebsiteRule, self).setUp() + self.website1 = self.env.ref("website.default_website") + self.website2 = self.env.ref("website.website2") + self.user1 = self.env.ref("base.user_demo") + self.user1.write( + {"backend_website_id": self.env.ref("website.default_website").id} + ) + + model_res_users = self.env.ref("base.model_res_users") + self.env["ir.rule"].create( + { + "name": "test backend website rule", + "model_id": model_res_users.id, + "domain_force": "[('backend_website_id', 'in', website_ids)]", + } + ) + + User = self.env["res.users"] + self.user2 = User.create( + {"name": "user2", "login": "user2", "backend_website_id": self.website1.id} + ) + self.user3 = User.create( + {"name": "user3", "login": "user3", "backend_website_id": self.website2.id} + ) + + # case for an object references another object + # e.g. [('id','=', website.company_id.id)] + model_res_company = self.env.ref("base.model_res_company") + company2_partner = self.env["res.partner"].create( + {"name": "Partner for Comapny2", "is_company": True} + ) + self.company1 = self.env.ref("base.main_company") + self.company2 = self.env["res.company"].create( + { + "name": "Test Company2", + "partner_id": company2_partner.id, + "parent_id": False, + } + ) + self.website2.company_id = self.company2.id + self.env["ir.rule"].create( + { + "name": "test websites references company", + "model_id": model_res_company.id, + "domain_force": "[('id','=', websites[0].company_id.id)]", + } + ) + + def test_backend_website_rule(self): + users = ( + self.env["res.users"] + .with_user(self.user1) + .with_context(allowed_website_ids=[self.website1.id]) + .search([]) + ) + self.assertIn(self.user2, users) + self.assertNotIn(self.user3, users) + users = ( + self.env["res.users"] + .with_user(self.user1) + .with_context(allowed_website_ids=[self.website2.id]) + .search([]) + ) + self.assertNotIn(self.user2, users) + self.assertIn(self.user3, users) + + # case when in a rule the `website` object references another object (`res.company` in that case) + companies = ( + self.env["res.company"] + .with_user(self.user1) + .with_context(allowed_website_ids=[self.website1.id]) + .search([]) + ) + self.assertNotIn(self.company2, companies) + self.env["res.company"].invalidate_cache() + with self.assertRaises(AccessError): + ( + self.env["res.company"] + .with_user(self.user1) + .with_context(allowed_website_ids=[self.website1.id]) + .browse(self.company2.id) + .name + ) + + self.env["res.company"].invalidate_cache() + self.user1.write( + {"company_id": self.company2.id, "company_ids": [(4, self.company2.id, 0)]} + ) + companies = ( + self.env["res.company"] + .with_user(self.user1) + .with_context(allowed_website_ids=[self.website2.id]) + .search([]) + ) + self.assertIn(self.company2, companies) + name = ( + self.env["res.company"] + .with_user(self.user1) + .with_context(allowed_website_ids=[self.website2.id]) + .browse(self.company2.id) + .name + ) + self.assertEqual(name, self.company2.name) diff --git a/setup/ir_rule_protected/odoo/addons/ir_rule_protected b/setup/ir_rule_protected/odoo/addons/ir_rule_protected deleted file mode 120000 index 3b0299b1..00000000 --- a/setup/ir_rule_protected/odoo/addons/ir_rule_protected +++ /dev/null @@ -1 +0,0 @@ -../../../../ir_rule_protected \ No newline at end of file diff --git a/setup/ir_rule_website/odoo/addons/ir_rule_website b/setup/ir_rule_website/odoo/addons/ir_rule_website new file mode 120000 index 00000000..4166a7dc --- /dev/null +++ b/setup/ir_rule_website/odoo/addons/ir_rule_website @@ -0,0 +1 @@ +../../../../ir_rule_website \ No newline at end of file diff --git a/setup/ir_rule_protected/setup.py b/setup/ir_rule_website/setup.py similarity index 100% rename from setup/ir_rule_protected/setup.py rename to setup/ir_rule_website/setup.py