Skip to content
Snippets Groups Projects
Commit ee20b1aa712f authored by Vincent Hatakeyama's avatar Vincent Hatakeyama
Browse files

:sparkles: block more discuss features

parent 12af9d60c479
No related branches found
No related tags found
No related merge requests found
This commit is part of merge request !2. Comments created here will be created in the context of that merge request.
<?xml version="1.0" encoding="UTF-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" width="114" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1" />
<stop offset="1" stop-opacity=".1" />
</linearGradient>
<mask id="anybadge_1">
<rect width="114" height="20" rx="3" fill="#fff" />
</mask>
<g mask="url(#anybadge_1)">
<path fill="#555" d="M0 0h72v20H0z" />
<path fill="#000000" d="M72 0h42v20H72z" />
<path fill="url(#b)" d="M0 0h114v20H0z" />
</g>
<g
fill="#fff"
text-anchor="middle"
font-family="DejaVu Sans,Verdana,Geneva,sans-serif"
font-size="11"
>
<text x="37.0" y="15" fill="#010101" fill-opacity=".3">code style</text>
<text x="36.0" y="14">code style</text>
</g>
<g
fill="#fff"
text-anchor="middle"
font-family="DejaVu Sans,Verdana,Geneva,sans-serif"
font-size="11"
>
<text x="94.0" y="15" fill="#010101" fill-opacity=".3">black</text>
<text x="93.0" y="14">black</text>
</g>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="53"
height="20"
role="img"
aria-label="Ruff"
>
<title>Ruff</title>
<linearGradient id="s" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1" />
<stop offset="1" stop-opacity=".1" />
</linearGradient>
<clipPath id="r">
<rect width="53" height="20" rx="3" fill="#fff" />
</clipPath>
<g clip-path="url(#r)">
<rect width="20" height="20" fill="#555" />
<rect x="20" width="33" height="20" fill="#261230" />
<rect width="53" height="20" fill="url(#s)" />
</g>
<g
fill="#fff"
text-anchor="middle"
font-family="Verdana,Geneva,DejaVu Sans,sans-serif"
text-rendering="geometricPrecision"
font-size="110"
>
<image
x="5"
y="3"
width="10"
height="14"
xlink:href="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEwIiBoZWlnaHQ9IjYyMiIgdmlld0JveD0iMCAwIDUxMCA2MjIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMDYuNzAxIDBDMjAwLjk2NCAwIDE5Ni4zMTQgNC42NDEzMSAxOTYuMzE0IDEwLjM2NjdWNDEuNDY2N0MxOTYuMzE0IDQ3LjE5MiAxOTEuNjYzIDUxLjgzMzMgMTg1LjkyNyA1MS44MzMzSDE1Ni44NDNDMTUxLjEwNyA1MS44MzMzIDE0Ni40NTYgNTYuNDc0NiAxNDYuNDU2IDYyLjJWMTQ1LjEzM0MxNDYuNDU2IDE1MC44NTkgMTQxLjgwNiAxNTUuNSAxMzYuMDY5IDE1NS41SDEwNi45ODZDMTAxLjI0OSAxNTUuNSA5Ni41OTg4IDE2MC4xNDEgOTYuNTk4OCAxNjUuODY3VjIyMi44ODNDOTYuNTk4OCAyMjguNjA5IDkxLjk0ODQgMjMzLjI1IDg2LjIxMTggMjMzLjI1SDU3LjEyODNDNTEuMzkxNyAyMzMuMjUgNDYuNzQxMyAyMzcuODkxIDQ2Ljc0MTMgMjQzLjYxN1YzMDAuNjMzQzQ2Ljc0MTMgMzA2LjM1OSA0Mi4wOTA5IDMxMSAzNi4zNTQ0IDMxMUgxMC4zODdDNC42NTA0IDMxMSAwIDMxNS42NDEgMCAzMjEuMzY3VjM1Mi40NjdDMCAzNTguMTkyIDQuNjUwNCAzNjIuODMzIDEwLjM4NyAzNjIuODMzSDE0NS40MThDMTUxLjE1NCAzNjIuODMzIDE1NS44MDQgMzY3LjQ3NSAxNTUuODA0IDM3My4yVjQzMC4yMTdDMTU1LjgwNCA0MzUuOTQyIDE1MS4xNTQgNDQwLjU4MyAxNDUuNDE4IDQ0MC41ODNIMTE2LjMzNEMxMTAuNTk3IDQ0MC41ODMgMTA1Ljk0NyA0NDUuMjI1IDEwNS45NDcgNDUwLjk1VjUwNy45NjdDMTA1Ljk0NyA1MTMuNjkyIDEwMS4yOTcgNTE4LjMzMyA5NS41NjAxIDUxOC4zMzNINjYuNDc2NkM2MC43NCA1MTguMzMzIDU2LjA4OTYgNTIyLjk3NSA1Ni4wODk2IDUyOC43VjYxMS42MzNDNTYuMDg5NiA2MTcuMzU5IDYwLjc0IDYyMiA2Ni40NzY2IDYyMkgxNDkuNTcyQzE1NS4zMDkgNjIyIDE1OS45NTkgNjE3LjM1OSAxNTkuOTU5IDYxMS42MzNWNTcwLjE2N0gyMDEuNTA3QzIwNy4yNDQgNTcwLjE2NyAyMTEuODk0IDU2NS41MjUgMjExLjg5NCA1NTkuOFY1MjguN0MyMTEuODk0IDUyMi45NzUgMjE2LjU0NCA1MTguMzMzIDIyMi4yODEgNTE4LjMzM0gyNTEuMzY1QzI1Ny4xMDEgNTE4LjMzMyAyNjEuNzUyIDUxMy42OTIgMjYxLjc1MiA1MDcuOTY3VjQ3Ni44NjdDMjYxLjc1MiA0NzEuMTQxIDI2Ni40MDIgNDY2LjUgMjcyLjEzOCA0NjYuNUgzMDEuMjIyQzMwNi45NTkgNDY2LjUgMzExLjYwOSA0NjEuODU5IDMxMS42MDkgNDU2LjEzM1Y0MjUuMDMzQzMxMS42MDkgNDE5LjMwOCAzMTYuMjU5IDQxNC42NjcgMzIxLjk5NiA0MTQuNjY3SDM1MS4wNzlDMzU2LjgxNiA0MTQuNjY3IDM2MS40NjYgNDEwLjAyNSAzNjEuNDY2IDQwNC4zVjM3My4yQzM2MS40NjYgMzY3LjQ3NSAzNjYuMTE3IDM2Mi44MzMgMzcxLjg1MyAzNjIuODMzSDQwMC45MzdDNDA2LjY3MyAzNjIuODMzIDQxMS4zMjQgMzU4LjE5MiA0MTEuMzI0IDM1Mi40NjdWMzIxLjM2N0M0MTEuMzI0IDMxNS42NDEgNDE1Ljk3NCAzMTEgNDIxLjcxMSAzMTFINDUwLjc5NEM0NTYuNTMxIDMxMSA0NjEuMTgxIDMwNi4zNTkgNDYxLjE4MSAzMDAuNjMzVjIxNy43QzQ2MS4xODEgMjExLjk3NSA0NTYuNTMxIDIwNy4zMzMgNDUwLjc5NCAyMDcuMzMzSDQyMC42NzJDNDE0LjkzNiAyMDcuMzMzIDQxMC4yODUgMjAyLjY5MiA0MTAuMjg1IDE5Ni45NjdWMTY1Ljg2N0M0MTAuMjg1IDE2MC4xNDEgNDE0LjkzNiAxNTUuNSA0MjAuNjcyIDE1NS41SDQ0OS43NTZDNDU1LjQ5MiAxNTUuNSA0NjAuMTQzIDE1MC44NTkgNDYwLjE0MyAxNDUuMTMzVjExNC4wMzNDNDYwLjE0MyAxMDguMzA4IDQ2NC43OTMgMTAzLjY2NyA0NzAuNTMgMTAzLjY2N0g0OTkuNjEzQzUwNS4zNSAxMDMuNjY3IDUxMCA5OS4wMjUzIDUxMCA5My4zVjEwLjM2NjdDNTEwIDQuNjQxMzIgNTA1LjM1IDAgNDk5LjYxMyAwSDIwNi43MDFaTTE2OC4yNjkgNDQwLjU4M0MxNjIuNTMyIDQ0MC41ODMgMTU3Ljg4MiA0NDUuMjI1IDE1Ny44ODIgNDUwLjk1VjUwNy45NjdDMTU3Ljg4MiA1MTMuNjkyIDE1My4yMzEgNTE4LjMzMyAxNDcuNDk1IDUxOC4zMzNIMTE4LjQxMUMxMTIuNjc1IDUxOC4zMzMgMTA4LjAyNCA1MjIuOTc1IDEwOC4wMjQgNTI4LjdWNTU5LjhDMTA4LjAyNCA1NjUuNTI1IDExMi42NzUgNTcwLjE2NyAxMTguNDExIDU3MC4xNjdIMTU5Ljk1OVY1MjguN0MxNTkuOTU5IDUyMi45NzUgMTY0LjYxIDUxOC4zMzMgMTcwLjM0NiA1MTguMzMzSDE5OS40M0MyMDUuMTY2IDUxOC4zMzMgMjA5LjgxNyA1MTMuNjkyIDIwOS44MTcgNTA3Ljk2N1Y0NzYuODY3QzIwOS44MTcgNDcxLjE0MSAyMTQuNDY3IDQ2Ni41IDIyMC4yMDQgNDY2LjVIMjQ5LjI4N0MyNTUuMDI0IDQ2Ni41IDI1OS42NzQgNDYxLjg1OSAyNTkuNjc0IDQ1Ni4xMzNWNDI1LjAzM0MyNTkuNjc0IDQxOS4zMDggMjY0LjMyNSA0MTQuNjY3IDI3MC4wNjEgNDE0LjY2N0gyOTkuMTQ1QzMwNC44ODEgNDE0LjY2NyAzMDkuNTMyIDQxMC4wMjUgMzA5LjUzMiA0MDQuM1YzNzMuMkMzMDkuNTMyIDM2Ny40NzUgMzE0LjE4MiAzNjIuODMzIDMxOS45MTkgMzYyLjgzM0gzNDkuMDAyQzM1NC43MzkgMzYyLjgzMyAzNTkuMzg5IDM1OC4xOTIgMzU5LjM4OSAzNTIuNDY3VjMyMS4zNjdDMzU5LjM4OSAzMTUuNjQxIDM2NC4wMzkgMzExIDM2OS43NzYgMzExSDM5OC44NTlDNDA0LjU5NiAzMTEgNDA5LjI0NiAzMDYuMzU5IDQwOS4yNDYgMzAwLjYzM1YyNjkuNTMzQzQwOS4yNDYgMjYzLjgwOCA0MDQuNTk2IDI1OS4xNjcgMzk4Ljg1OSAyNTkuMTY3SDMxOC44OEMzMTMuMTQzIDI1OS4xNjcgMzA4LjQ5MyAyNTQuNTI1IDMwOC40OTMgMjQ4LjhWMjE3LjdDMzA4LjQ5MyAyMTEuOTc1IDMxMy4xNDMgMjA3LjMzMyAzMTguODggMjA3LjMzM0gzNDcuOTYzQzM1My43IDIwNy4zMzMgMzU4LjM1IDIwMi42OTIgMzU4LjM1IDE5Ni45NjdWMTY1Ljg2N0MzNTguMzUgMTYwLjE0MSAzNjMuMDAxIDE1NS41IDM2OC43MzcgMTU1LjVIMzk3LjgyMUM0MDMuNTU3IDE1NS41IDQwOC4yMDggMTUwLjg1OSA0MDguMjA4IDE0NS4xMzNWMTE0LjAzM0M0MDguMjA4IDEwOC4zMDggNDEyLjg1OCAxMDMuNjY3IDQxOC41OTUgMTAzLjY2N0g0NDcuNjc4QzQ1My40MTUgMTAzLjY2NyA0NTguMDY1IDk5LjAyNTMgNDU4LjA2NSA5My4zVjYyLjJDNDU4LjA2NSA1Ni40NzQ2IDQ1My40MTUgNTEuODMzMyA0NDcuNjc4IDUxLjgzMzNIMjA4Ljc3OEMyMDMuMDQxIDUxLjgzMzMgMTk4LjM5MSA1Ni40NzQ2IDE5OC4zOTEgNjIuMlYxNDUuMTMzQzE5OC4zOTEgMTUwLjg1OSAxOTMuNzQxIDE1NS41IDE4OC4wMDQgMTU1LjVIMTU4LjkyMUMxNTMuMTg0IDE1NS41IDE0OC41MzQgMTYwLjE0MSAxNDguNTM0IDE2NS44NjdWMjIyLjg4M0MxNDguNTM0IDIyOC42MDkgMTQzLjg4MyAyMzMuMjUgMTM4LjE0NyAyMzMuMjVIMTA5LjA2M0MxMDMuMzI3IDIzMy4yNSA5OC42NzYyIDIzNy44OTEgOTguNjc2MiAyNDMuNjE3VjMwMC42MzNDOTguNjc2MiAzMDYuMzU5IDEwMy4zMjcgMzExIDEwOS4wNjMgMzExSDE5Ny4zNTJDMjAzLjA4OSAzMTEgMjA3LjczOSAzMTUuNjQxIDIwNy43MzkgMzIxLjM2N1Y0MzAuMjE3QzIwNy43MzkgNDM1Ljk0MiAyMDMuMDg5IDQ0MC41ODMgMTk3LjM1MiA0NDAuNTgzSDE2OC4yNjlaIiBmaWxsPSIjRDdGRjY0Ii8+PC9zdmc+"
/>
<text
aria-hidden="true"
x="355"
y="150"
fill="#010101"
fill-opacity=".3"
transform="scale(.1)"
textLength="230"
>
Ruff
</text>
<text x="355" y="140" transform="scale(.1)" fill="#fff" textLength="230">Ruff</text>
</g>
</svg>
...@@ -2,6 +2,18 @@ ...@@ -2,6 +2,18 @@
Changelog Changelog
========= =========
17.0.1.1.0
----------
User not in the message group, can not:
- access messages related to discuss.channel
- access discuss.channel.
- see the button to display channels/messages.
If a user with discuss send a message to a user without it, the message is blocked.
The UI for that is not very nice, the message appears to be sent but is not.
17.0.1.0.0 17.0.1.0.0
---------- ----------
......
...@@ -17,5 +17,5 @@ ...@@ -17,5 +17,5 @@
|maturity| |license| |ruff| |prettier| |maturity| |license| |ruff| |prettier|
Introduce a new group, messaging, and only member of this group can see the messaging menu. Introduce a new group, messaging, and only member of this group can see the discuss menu.
...@@ -21,1 +21,3 @@ ...@@ -21,1 +21,3 @@
Discussion of internal users is also blocked if they do not belong to this group.
from ._hook import _uninstall_hook, _post_init_hook
from . import models
############################################################################### ###############################################################################
# #
# Messaging Group a module for Odoo # Messaging Group a module for Odoo
# Copyright © 2014, 2018, 2022 XCG Consulting (https://xcg-consulting.fr/) # Copyright © 2014, 2018, 2022, 2025 XCG Consulting (https://xcg-consulting.fr/)
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
"name": "Messaging Group", "name": "Messaging Group",
"license": "AGPL-3", "license": "AGPL-3",
"summary": "New group to access discussions", "summary": "New group to access discussions",
"version": "17.0.1.0.0", "version": "17.0.1.1.0",
"category": "Extra Rights", "category": "Extra Rights",
"author": "XCG Consulting", "author": "XCG Consulting",
"website": "https://orbeet.io/", "website": "https://orbeet.io/",
"depends": ["mail"], "depends": ["mail"],
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
"category": "Extra Rights", "category": "Extra Rights",
"author": "XCG Consulting", "author": "XCG Consulting",
"website": "https://orbeet.io/", "website": "https://orbeet.io/",
"depends": ["mail"], "depends": ["mail"],
"data": ["security/security.xml"], "data": ["security/security.xml", "security/ir.model.access.csv"],
"assets": {
"web.assets_backend": [
"mail_messaging_group/static/src/discuss/**",
],
},
"auto_install": True, "auto_install": True,
...@@ -30,2 +35,4 @@ ...@@ -30,2 +35,4 @@
"auto_install": True, "auto_install": True,
"uninstall_hook": "_uninstall_hook",
"post_init_hook": "_post_init_hook",
} }
_hook.py 0 → 100644
###############################################################################
#
# Messaging Group a module for Odoo
# Copyright © 2025 XCG Consulting (https://xcg-consulting.fr/)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from odoo import Command # type: ignore[import-untyped]
from odoo.api import Environment # type: ignore[import-untyped]
def _uninstall_hook(env: Environment):
"""Revert changes made on other module data"""
env.ref("mail.menu_root_discuss").groups_id = [Command.clear()]
env.ref("mail.access_discuss_channel_user").active = True
env.ref("mail.channel_all_employees").group_ids = [
Command.set(env.ref("base.group_user").id)
]
def _post_init_hook(env: Environment):
"""Change some noupdate data"""
env.ref("mail.channel_all_employees").group_ids = [
Command.set(env.ref("mail_messaging_group.group_messaging").id)
]
from . import mail_message
###############################################################################
#
# Messaging Group a module for Odoo
# Copyright © 2025 XCG Consulting (https://xcg-consulting.fr/)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from odoo import _, models # type: ignore[import-untyped]
from odoo.exceptions import AccessError # type: ignore[import-untyped]
class Message(models.Model):
_inherit = "mail.message"
def create(self, vals_list):
created = super().create(vals_list)
if not self.env.su:
for record in created:
if record.model == "discuss.channel":
channel = self.env["discuss.channel"].browse(record.res_id)
if channel.channel_type == "chat":
# check that all members have messaging group
users = (
self.sudo()
.env["res.users"]
.search(
[
(
"partner_id",
"in",
channel.mapped(
"channel_member_ids.partner_id.id"
),
)
]
)
)
for user in users:
if (
not user.has_group(
"mail_messaging_group.group_messaging"
)
and not user.has_group("base.group_public")
and not user.has_group("base.group_portal")
):
raise AccessError(
_(
"Creating messages to user that can not read "
"them is not allowed."
)
)
return created
py.typed 0 → 100644
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_discuss_channel_user,discuss.channel ,mail.model_discuss_channel,base.group_user,1,0,0,0
access_discuss_channel_messaging,discuss.channel messaging,mail.model_discuss_channel,group_messaging,1,1,1,0
...@@ -14,4 +14,21 @@ ...@@ -14,4 +14,21 @@
<record id="mail.menu_root_discuss" model="ir.ui.menu"> <record id="mail.menu_root_discuss" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('group_messaging')])]" /> <field name="groups_id" eval="[(6, 0, [ref('group_messaging')])]" />
</record> </record>
<record id="mail.access_discuss_channel_user" model="ir.model.access">
<field name="active" eval="False" />
</record>
<record id="message_no_discuss_channel_access" model="ir.rule">
<field name="name">No access to discuss messages to internal users</field>
<field name="model_id" ref="mail.model_mail_message" />
<field name="domain_force">[('model', '!=', 'discuss.channel')]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]" />
</record>
<record id="message" model="ir.rule">
<field name="name">Only messaging users have access</field>
<field name="model_id" ref="mail.model_mail_message" />
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_messaging'))]" />
</record>
</odoo> </odoo>
/** @odoo-module **/
// Adapted from https://www.odoo.com/fr_FR/forum/aide-1/groups-option-on-owl-template-263872
import {patch} from "@web/core/utils/patch";
import {useService} from "@web/core/utils/hooks";
import {useState, onWillStart} from "@odoo/owl";
import {MessagingMenu} from "@mail/core/web/messaging_menu";
patch(MessagingMenu.prototype, {
setup() {
super.setup();
this.user = useService("user");
this.state = useState({
canAccessDiscuss: false, // Initial visibility state
});
// Check if the user belongs to the "mail_messaging_group.group_messaging" group
onWillStart(async () => {
this.state.canAccessDiscuss = await this.user.hasGroup(
"mail_messaging_group.group_messaging"
);
});
},
});
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-inherit="mail.MessagingMenu" t-inherit-mode="extension">
<xpath expr="//Dropdown" position="attributes">
<attribute
name="t-if"
>!env.inDiscussApp &amp; state.canAccessDiscuss</attribute>
</xpath>
<xpath expr="//t[@t-else='']" position="attributes">
<attribute name="t-if">state.canAccessDiscuss</attribute>
</xpath>
</t>
</templates>
from odoo import SUPERUSER_ID, api # type: ignore[import-untyped]
def migrate(cr, _installed_version):
"""Remove user without access to messages from general channel"""
env = api.Environment(cr, SUPERUSER_ID, {})
general_channel = env.ref("mail.channel_all_employees")
if general_channel:
members_to_remove = env["discuss.channel.member"]
for member in env.ref("mail.channel_all_employees").channel_member_ids:
users = env["res.users"].search([("partner_id", "=", member.partner_id.id)])
for user in users:
if not user.has_group("mail_messaging_group.group_messaging"):
members_to_remove |= member
if members_to_remove:
members_to_remove.unlink()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment