Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dms/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ and their files. Another possibility is to click on "Share" button
inside a directory or a file for obtaining a tokenized link for single
access to that resource, no matter if logged or not.

For any file if you add the portal user or the internal user to
followers mixin, they can read that file.

Known issues / Roadmap
======================

Expand Down
6 changes: 3 additions & 3 deletions dms/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
"template/portal.xml",
# Data
"data/onboarding_data.xml",
# Wizard
"wizards/wizard_dms_file_move_views.xml",
"wizards/wizard_dms_share_views.xml",
# Views
"views/dms_tag.xml",
"views/dms_category.xml",
Expand All @@ -37,9 +40,6 @@
"views/dms_access_groups_views.xml",
"views/res_config_settings.xml",
"views/menu.xml",
# Wizard
"wizards/wizard_dms_file_move_views.xml",
"wizards/wizard_dms_share_views.xml",
],
"assets": {
"web.assets_backend": [
Expand Down
15 changes: 14 additions & 1 deletion dms/controllers/portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ def _get_files(self, access_token, dms_directory_id, search, search_in, sort_br)
file_domain = [
("is_hidden", "=", False),
("directory_id", "=", dms_directory_id),
(
"message_partner_ids",
"child_of",
[request.env.user.commercial_partner_id.id],
),
]
# search
if search and search_in == "name":
Expand Down Expand Up @@ -206,7 +211,15 @@ def _get_directories(
:rtype: tuple[odoo.model.dms_directory, bool|odoo.model.dms_directory]
"""
# domain
domain = [("is_hidden", "=", False), ("parent_id", "=", dms_directory_id)]
domain = [
("is_hidden", "=", False),
("parent_id", "=", dms_directory_id),
(
"file_ids.message_partner_ids",
"child_of",
[request.env.user.commercial_partner_id.id],
),
]
# search
if search and search_in:
domain.append(("name", "ilike", search))
Expand Down
2 changes: 2 additions & 0 deletions dms/readme/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ group in directories, so they will see in the portal such directories
and their files. Another possibility is to click on "Share" button
inside a directory or a file for obtaining a tokenized link for single
access to that resource, no matter if logged or not.

For any file if you add the portal user or the internal user to followers mixin, they can read that file.
6 changes: 3 additions & 3 deletions dms/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink

access_dms_tag_base_user,dms_tag_base_user,model_dms_tag,base.group_user,1,0,0,0
access_dms_tag_user,dms_tag_user,model_dms_tag,group_dms_user,1,1,1,1

access_dms_category_base_user,dms_category_base_user,model_dms_category,base.group_user,1,0,0,0
access_dms_category_user,dms_category_user,model_dms_category,group_dms_user,1,1,1,1

access_dms_storage_base_user,dms_storage_base_user,model_dms_storage,base.group_user,1,0,0,0
access_dms_storage_portal,dms_storage_portal,model_dms_storage,base.group_portal,1,0,0,0
access_dms_storage_user,dms_storage_user,model_dms_storage,group_dms_user,1,0,0,0
access_dms_storage_manager,dms_storage_manager,model_dms_storage,group_dms_manager,1,1,1,1

access_dms_directory_public,dms_directory_public,model_dms_directory,base.group_public,1,0,0,0
access_dms_directory_portal,dms_directory_portal,model_dms_directory,base.group_portal,1,0,0,0
access_dms_directory_base_user,dms_directory_base_user,model_dms_directory,base.group_user,1,0,0,0
access_dms_directory_user,dms_directory_user,model_dms_directory,group_dms_user,1,1,1,1

access_dms_file_public,dms_file_public,model_dms_file,base.group_public,1,0,0,0
access_dms_file_portal,dms_file_portal,model_dms_file,base.group_portal,1,0,0,0
access_dms_file_base_user,dms_file_base_user,model_dms_file,base.group_user,1,0,0,0
access_dms_file_user,dms_file_user,model_dms_file,group_dms_user,1,1,1,1

access_dms_access_group_public,access_dms_access_group_public,model_dms_access_group,base.group_public,1,0,0,0
access_dms_access_group_portal,access_dms_access_group_portal,model_dms_access_group,base.group_portal,1,0,0,0
access_security_access_groups_user,access_security_access_groups_user,model_dms_access_group,base.group_user,1,0,0,0
access_security_access_groups_dms_user,access_security_access_groups_dms_user,model_dms_access_group,group_dms_user,1,1,1,1
Expand Down
196 changes: 112 additions & 84 deletions dms/security/security.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<record id="group_dms_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="category_dms_security" />
<field name="implied_ids" eval="[(4, ref('base.group_user'))]" />
<field name="implied_ids" eval="[(4, ref('base.group_erp_manager'))]" />
</record>
<record id="group_dms_manager" model="res.groups">
<field name="name">Manager</field>
Expand All @@ -29,40 +29,65 @@
<record id="rule_multi_company_storage" model="ir.rule">
<field name="name">DMS Storage multi-company</field>
<field name="model_id" ref="model_dms_storage" />
<field name="global" eval="True" />
<field name="global" eval="False" />
<field name="groups" eval="[(4, ref('group_dms_user'))]" />
<field name="perm_read" eval="1" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id','in',company_ids)]</field>
</record>
<record id="rule_multi_company_directory" model="ir.rule">
<field name="name">DMS Directory multi-company</field>
<field name="model_id" ref="model_dms_directory" />
<field name="global" eval="True" />
<field name="global" eval="False" />
<field name="groups" eval="[(4, ref('group_dms_user'))]" />
<field name="perm_read" eval="1" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id','in',company_ids)]</field>
</record>
<record id="rule_multi_company_file" model="ir.rule">
<field name="name">File multi-company</field>
<field name="model_id" ref="model_dms_file" />
<field name="global" eval="True" />
<field name="global" eval="False" />
<field name="groups" eval="[(4, ref('group_dms_user'))]" />
<field name="perm_read" eval="1" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id','in',company_ids)]</field>
</record>
<record id="rule_file_locked" model="ir.rule">
<field name="name">Locked files are only modified by locker user.</field>
<field name="model_id" ref="model_dms_file" />
<field name="groups" eval="[(4, ref('base.group_user'))]" />
<field name="groups" eval="[(4, ref('dms.group_dms_user'))]" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="1" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1" />
<field
name="domain_force"
>['|', ('locked_by', '=', False), ('locked_by', '=', user.id)]</field>
</record>
<record id="rule_file_locked_exemption" model="ir.rule">
<field name="name">DMS Managers can edit and delete locked files.</field>
<field name="model_id" ref="model_dms_file" />
<field name="groups" eval="[(4, ref('group_dms_manager'))]" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1" />
<field name="domain_force">[(1 ,'=', 1)]</field>
</record>
<record id="rule_security_groups_user" model="ir.rule">
<field name="name">DMS users can only edit and delete their own groups.</field>
<field name="model_id" ref="model_dms_access_group" />
Expand Down Expand Up @@ -107,85 +132,88 @@
<field name="perm_unlink" eval="1" />
<field name="domain_force">[('is_hidden', '=', True)]</field>
</record>
<!-- These rules leverage computed permission management -->
<record id="rule_directory_computed_create" model="ir.rule">
<field name="name">Apply computed create permissions.</field>
<field name="model_id" ref="model_dms_directory" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="1" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field name="domain_force">[('permission_create', '=', user.id)]</field>
</record>
<record id="rule_directory_computed_read" model="ir.rule">
<field name="name">Apply computed read permissions.</field>
<field name="model_id" ref="model_dms_directory" />
<field name="global" eval="True" />
<field name="perm_read" eval="1" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field name="domain_force">[('permission_read', '=', user.id)]</field>
</record>
<record id="rule_directory_computed_unlink" model="ir.rule">
<field name="name">Apply computed unlink permissions.</field>
<field name="model_id" ref="model_dms_directory" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="1" />
<field name="domain_force">[('permission_unlink', '=', user.id)]</field>
</record>
<record id="rule_directory_computed_write" model="ir.rule">
<field name="name">Apply computed write permissions.</field>
<record id="user_rule_category_computed_read" model="ir.rule">
<field name="name">DMS User Categories</field>
<field name="model_id" ref="model_dms_category" />
<field name="domain_force">[(1 ,'=', 1)]</field>
<field name="groups" eval="[Command.link(ref('dms.group_dms_user'))]" />
<field name="perm_unlink" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="True" />
</record>
<record id="user_rule_tag_computed_read" model="ir.rule">
<field name="name">DMS User Tags</field>
<field name="model_id" ref="model_dms_tag" />
<field name="domain_force">[(1 ,'=', 1)]</field>
<field name="groups" eval="[Command.link(ref('dms.group_dms_user'))]" />
<field name="perm_unlink" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="True" />
</record>
<!-- Portal/Base Users Access Rules -->
<record id="portal_rule_directory_computed_read" model="ir.rule">
<field name="name">Portal/Base User Following Directories Read</field>
<field name="model_id" ref="model_dms_directory" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="1" />
<field name="perm_unlink" eval="0" />
<field name="domain_force">[('permission_write', '=', user.id)]</field>
</record>
<record id="rule_file_computed_create" model="ir.rule">
<field name="name">Apply computed create permissions.</field>
<field name="model_id" ref="model_dms_file" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="1" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field name="domain_force">[('permission_create', '=', user.id)]</field>
</record>
<record id="rule_file_computed_read" model="ir.rule">
<field name="name">Apply computed read permissions.</field>
<field name="model_id" ref="model_dms_file" />
<field name="global" eval="True" />
<field name="perm_read" eval="1" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="0" />
<field name="domain_force">[('permission_read', '=', user.id)]</field>
</record>
<record id="rule_file_computed_unlink" model="ir.rule">
<field name="name">Apply computed unlink permissions.</field>
<field name="model_id" ref="model_dms_file" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="0" />
<field name="perm_unlink" eval="1" />
<field name="domain_force">[('permission_unlink', '=', user.id)]</field>
</record>
<record id="rule_file_computed_write" model="ir.rule">
<field name="name">Apply computed write permissions.</field>
<field
name="domain_force"
>[('file_ids.message_partner_ids','child_of',[user.commercial_partner_id.id])]</field>
<field
name="groups"
eval="[Command.link(ref('base.group_portal')), Command.link(ref('base.group_user'))]"
/>
<field name="perm_unlink" eval="False" />
<field name="perm_write" eval="False" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="False" />
</record>
<!-- Portal/Base Users Access Rules -->
<record id="portal_rule_file_computed_read" model="ir.rule">
<field name="name">Portal/Base User Following Files Read</field>
<field name="model_id" ref="model_dms_file" />
<field name="global" eval="True" />
<field name="perm_read" eval="0" />
<field name="perm_create" eval="0" />
<field name="perm_write" eval="1" />
<field name="perm_unlink" eval="0" />
<field name="domain_force">[('permission_write', '=', user.id)]</field>
<field name="global" eval="False" />
<field
name="domain_force"
>[('message_partner_ids','child_of',[user.commercial_partner_id.id])]</field>
<field
name="groups"
eval="[Command.link(ref('base.group_portal')), Command.link(ref('base.group_user'))]"
/>
<field name="perm_unlink" eval="False" />
<field name="perm_write" eval="False" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="False" />
</record>
<!-- Base Users Access Rules -->
<record id="base_user_rule_category_computed_read" model="ir.rule">
<field name="name">Base User Following Categories Read</field>
<field name="model_id" ref="model_dms_category" />
<field name="global" eval="False" />
<field
name="domain_force"
>[('file_ids.message_partner_ids','child_of',[user.commercial_partner_id.id])]</field>
<field name="groups" eval="[Command.link(ref('base.group_user'))]" />
<field name="perm_unlink" eval="False" />
<field name="perm_write" eval="False" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="False" />
</record>
<!-- Base Users Access Rules -->
<record id="base_user_rule_tag_computed_read" model="ir.rule">
<field name="name">Base User Following Tags Read</field>
<field name="model_id" ref="model_dms_tag" />
<field name="global" eval="False" />
<field name="domain_force">
['|',
('file_ids.message_partner_ids', 'child_of', [user.commercial_partner_id.id]),
('directory_ids.file_ids.message_partner_ids', 'child_of', [user.commercial_partner_id.id])
]
</field>
<field name="groups" eval="[Command.link(ref('base.group_user'))]" />
<field name="perm_unlink" eval="False" />
<field name="perm_write" eval="False" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="False" />
</record>
</odoo>
2 changes: 2 additions & 0 deletions dms/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ <h2><a class="toc-backref" href="#toc-entry-11">Portal functionality</a></h2>
and their files. Another possibility is to click on “Share” button
inside a directory or a file for obtaining a tokenized link for single
access to that resource, no matter if logged or not.</p>
<p>For any file if you add the portal user or the internal user to
followers mixin, they can read that file.</p>
</div>
</div>
<div class="section" id="known-issues-roadmap">
Expand Down
11 changes: 11 additions & 0 deletions dms/tests/test_portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ def test_access_portal(self):
)

def test_tour(self):
file_id = self.env.ref("dms.file_11_demo")
follower = self.env["mail.followers"].create(
{
"res_model": "dms.file",
"res_id": file_id.id,
"partner_id": self.portal_user.partner_id.id,
"is_active": True,
}
)

file_id.message_follower_ids = follower
for tour in ("dms_portal_mail_tour", "dms_portal_partners_tour"):
with self.subTest(tour=tour):
self.start_tour("/my", tour, login="portal")
Expand Down
10 changes: 9 additions & 1 deletion dms/views/dms_directory.xml
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,15 @@
<field name="model">dms.directory</field>
<field name="arch" type="xml">
<form>
<header />
<header>
<button
class="oe_highlight"
name="%(dms.wizard_dms_directory_share_action)d"
type="action"
string="Share"
groups="dms.group_dms_manager"
/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button
Expand Down
Loading
Loading