-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_portal.py
More file actions
180 lines (169 loc) · 7.49 KB
/
Copy pathtest_portal.py
File metadata and controls
180 lines (169 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# Copyright 2021-2025 Tecnativa - Víctor Martínez
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl)
import json
import odoo.tests
from odoo import http
from odoo.exceptions import AccessError
from odoo.tests.common import new_test_user, users
from odoo.tools import mute_logger
from .common import StorageAttachmentBaseCase
@odoo.tests.tagged("post_install", "-at_install")
class TestDmsPortal(odoo.tests.HttpCase, StorageAttachmentBaseCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Name the partner-model root directory "Partners" (the base creates it
# with a uuid name) so the portal tour can navigate to it by name.
cls.directory_model.search(
[
("storage_id", "=", cls.storage.id),
("res_model", "=", "res.partner"),
("is_root_directory", "=", True),
],
limit=1,
).name = "Partners"
cls.portal_user = cls.env["res.users"].search(
[("login", "=", "portal")], limit=1
) or new_test_user(
cls.env, login="portal", password="portal", groups="base.group_portal"
)
cls.partner = cls.portal_user.partner_id
# The partner's directory is named after the partner; set it before
# creating the attachment so the tour finds the "Joel Willis" directory.
cls.partner.name = "Joel Willis"
cls._create_attachment("test.txt")
cls._create_attachment("test2.txt", cls.other_partner)
cls.directory_partner = cls._get_partner_directory()
cls.other_directory_partner = cls._get_partner_directory(cls.other_partner)
cls.file_partner = cls.directory_partner.file_ids[0]
cls.other_file_partner = cls.other_directory_partner.file_ids[0]
# A portal-accessible "Mails" root directory + file, for the mail tour
# (replaces the demo "Mails" directory it relied on).
portal_access = cls.access_group_model.create(
{
"name": "Portal Tour",
"group_ids": [(6, 0, [cls.env.ref("base.group_portal").id])],
}
)
cls.mails_directory = cls.directory_model.create(
{
"name": "Mails",
"is_root_directory": True,
"storage_id": cls.create_storage(save_type="database").id,
"group_ids": [(6, 0, [portal_access.id])],
}
)
cls.file_model.create(
{
"name": "Mail_01.eml",
"directory_id": cls.mails_directory.id,
"content": cls.content_base64(),
}
)
# Flush the computed access relations (dms_*_rel) to the DB so the
# tour's browser requests — which read them via raw SQL in a separate
# env — see the portal user's access to these directories.
cls.env.flush_all()
def test_access_portal(self):
self.authenticate("portal", "portal")
# 404: Incorrect access_token
file_text = self.create_file(directory=self.directory_partner)
url = f"{file_text.access_url}&access_token=abc-def"
response = self.url_open(url, timeout=20)
self.assertEqual(
response.status_code, 404, "Can't access file with incorrect access_token"
)
# 200
response = self.url_open(self.file_partner._get_share_url(), timeout=20)
self.assertEqual(
response.status_code, 200, "Can access file with correct access_token"
)
# 200
response = self.url_open(self.directory_partner._get_share_url(), timeout=20)
self.assertEqual(
response.status_code, 200, "Can access directory with correct access_token"
)
# A direct binary URL must not bypass DMS access checks.
response = self.url_open(
f"/web/content?id={self.other_file_partner.id}&field=content"
"&model=dms.file&filename_field=name&download=true",
timeout=20,
)
self.assertNotEqual(
response.status_code,
200,
"Can't download a restricted file through a direct URL",
)
def test_upload_and_download(self):
upload_directory = self.create_directory(storage=self.create_storage())
self.authenticate("dms-manager", "dms-manager")
response = self.url_open(
"/web/binary/upload_dms_file",
data={
"csrf_token": http.Request.csrf_token(self),
"directory_id": upload_directory.id,
},
files={
"ufile": (
"uploaded.txt",
b"Odoo 19 DMS upload",
"text/plain",
)
},
)
response.raise_for_status()
result = json.loads(response.content)
self.assertFalse(result[0].get("error"))
dms_file = self.file_model.browse(result[0]["id"])
self.assertEqual(dms_file.name, "uploaded.txt")
download = self.url_open(
f"/web/content?id={dms_file.id}&field=content&model=dms.file"
"&filename_field=name&download=true"
)
download.raise_for_status()
self.assertEqual(download.content, b"Odoo 19 DMS upload")
def test_tour(self):
for tour in ("dms_portal_mail_tour", "dms_portal_partners_tour"):
with self.subTest(tour=tour):
self.start_tour("/my/dms", tour, login="portal")
@users("portal")
@mute_logger("odoo.addons.base.models.ir_rule")
def test_permission_portal_user_access_own_attachment(self):
"""
The user can access its own attachments, even if its access group are not set
"""
# Has to manually su=False because the portal user is not a superuser,
# but odoo uses somewhere sudo() internally
file = self.file_partner.with_user(self.env.user).with_env(self.env(su=False))
directory = self.directory_partner.with_user(self.env.user).with_env(
self.env(su=False)
)
# Portal user can only read
file.check_access("read")
# Portal user can't do anything else (each operation checked on its own
# so a single early raise can't mask the others).
with self.assertRaises(AccessError, msg="Portal user should not write"):
file.check_access("write")
with self.assertRaises(AccessError, msg="Portal user should not unlink"):
file.check_access("unlink")
with self.assertRaises(AccessError, msg="Portal user should not create"):
directory.check_access("create")
@users("portal")
@mute_logger("odoo.addons.base.models.ir_rule")
def test_permission_portal_user_access_other_attachment(self):
"""
The user can't access other attachments if its access group are not set
"""
# Has to manually su=False because the portal user is not a superuser,
# but odoo uses somewhere sudo() internally
file = self.other_file_partner.with_user(self.env.user).with_env(
self.env(su=False)
)
# file.invalidate_recordset()
# Portal user can't do anything
with self.assertRaises(AccessError, msg="Portal user should not have access"):
file.check_access("read")
with self.assertRaises(AccessError, msg="Portal user should not have access"):
file.check_access("write")
with self.assertRaises(AccessError, msg="Portal user should not have access"):
file.check_access("unlink")