odoo-addon-dms 16.0.1.8.0.5__py3-none-any.whl → 17.0.1.0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. odoo/addons/dms/README.rst +132 -78
  2. odoo/addons/dms/__manifest__.py +34 -16
  3. odoo/addons/dms/actions/file.xml +1 -3
  4. odoo/addons/dms/controllers/main.py +0 -34
  5. odoo/addons/dms/controllers/portal.py +178 -92
  6. odoo/addons/dms/data/onboarding_data.xml +77 -0
  7. odoo/addons/dms/demo/access_group.xml +3 -9
  8. odoo/addons/dms/i18n/de.po +332 -221
  9. odoo/addons/dms/i18n/dms.pot +137 -174
  10. odoo/addons/dms/i18n/es.po +355 -226
  11. odoo/addons/dms/i18n/fr.po +256 -342
  12. odoo/addons/dms/i18n/he_IL.po +208 -181
  13. odoo/addons/dms/i18n/it.po +369 -248
  14. odoo/addons/dms/i18n/nl.po +140 -168
  15. odoo/addons/dms/i18n/pt.po +352 -223
  16. odoo/addons/dms/i18n/pt_BR.po +358 -256
  17. odoo/addons/dms/i18n/ru.po +138 -172
  18. odoo/addons/dms/models/__init__.py +7 -1
  19. odoo/addons/dms/models/abstract_dms_mixin.py +1 -1
  20. odoo/addons/dms/models/access_groups.py +18 -11
  21. odoo/addons/dms/models/base.py +10 -2
  22. odoo/addons/dms/models/directory.py +46 -75
  23. odoo/addons/dms/models/{category.py → dms_category.py} +10 -42
  24. odoo/addons/dms/models/dms_file.py +125 -147
  25. odoo/addons/dms/models/dms_security_mixin.py +26 -22
  26. odoo/addons/dms/models/ir_attachment.py +0 -1
  27. odoo/addons/dms/models/ir_binary.py +19 -0
  28. odoo/addons/dms/models/mail_thread.py +2 -4
  29. odoo/addons/dms/models/mixins_thumbnail.py +13 -8
  30. odoo/addons/dms/models/onboarding_onboarding.py +16 -0
  31. odoo/addons/dms/models/onboarding_onboarding_step.py +50 -0
  32. odoo/addons/dms/models/res_company.py +22 -47
  33. odoo/addons/dms/models/res_config_settings.py +0 -1
  34. odoo/addons/dms/models/storage.py +4 -24
  35. odoo/addons/dms/models/tag.py +1 -1
  36. odoo/addons/dms/readme/CONFIGURE.md +59 -0
  37. odoo/addons/dms/readme/CONTRIBUTORS.md +14 -0
  38. odoo/addons/dms/readme/CREDITS.md +6 -0
  39. odoo/addons/dms/readme/DESCRIPTION.md +9 -0
  40. odoo/addons/dms/readme/INSTALL.md +4 -0
  41. odoo/addons/dms/readme/ROADMAP.md +19 -0
  42. odoo/addons/dms/readme/USAGE.md +11 -0
  43. odoo/addons/dms/security/security.xml +1 -0
  44. odoo/addons/dms/static/description/icon.png +0 -0
  45. odoo/addons/dms/static/description/icon.svg +4 -1
  46. odoo/addons/dms/static/description/index.html +133 -88
  47. odoo/addons/dms/static/description/portal_icon.svg +12 -0
  48. odoo/addons/dms/static/src/js/fields/{path_owl.esm.js → path_json/path_owl.esm.js} +22 -4
  49. odoo/addons/dms/static/src/js/fields/{path_owl.xml → path_json/path_owl.xml} +7 -4
  50. odoo/addons/dms/static/src/js/fields/preview_binary/preview_record.esm.js +47 -0
  51. odoo/addons/dms/static/src/js/{views/fields/binary → fields/preview_binary}/preview_record.xml +5 -4
  52. odoo/addons/dms/static/src/js/views/dms_file_upload.esm.js +155 -148
  53. odoo/addons/dms/static/src/js/views/file_kanban_controller.xml +0 -1
  54. odoo/addons/dms/static/src/js/views/file_kanban_record.esm.js +26 -27
  55. odoo/addons/dms/static/src/js/views/file_kanban_renderer.esm.js +1 -2
  56. odoo/addons/dms/static/src/js/views/file_kanban_renderer.xml +12 -16
  57. odoo/addons/dms/static/src/js/views/file_kanban_view.esm.js +11 -9
  58. odoo/addons/dms/static/src/js/views/file_list_controller.esm.js +1 -1
  59. odoo/addons/dms/static/src/js/views/file_list_renderer.xml +1 -7
  60. odoo/addons/dms/static/src/js/views/file_list_view.esm.js +11 -9
  61. odoo/addons/dms/static/src/js/views/search_panel.esm.js +9 -10
  62. odoo/addons/dms/static/src/models/attachment.esm.js +83 -82
  63. odoo/addons/dms/static/src/models/attachment_image.esm.js +30 -28
  64. odoo/addons/dms/static/src/models/attachment_viewer_viewable.esm.js +27 -25
  65. odoo/addons/dms/static/src/scss/directory_kanban.scss +28 -73
  66. odoo/addons/dms/static/src/scss/dms_common.scss +69 -0
  67. odoo/addons/dms/static/src/scss/file_kanban.scss +22 -34
  68. odoo/addons/dms/static/src/scss/portal.scss +12 -0
  69. odoo/addons/dms/static/tests/tours/dms_portal_tour.esm.js +46 -0
  70. odoo/addons/dms/{views/dms_portal_templates.xml → template/portal.xml} +13 -3
  71. odoo/addons/dms/tests/common.py +20 -4
  72. odoo/addons/dms/tests/data/mail01.eml +2 -2
  73. odoo/addons/dms/tests/data/mail02.eml +2 -2
  74. odoo/addons/dms/tests/test_benchmark.py +16 -21
  75. odoo/addons/dms/tests/test_directory.py +128 -40
  76. odoo/addons/dms/tests/test_file.py +112 -30
  77. odoo/addons/dms/tests/test_file_database.py +50 -24
  78. odoo/addons/dms/tests/test_portal.py +50 -37
  79. odoo/addons/dms/tests/test_storage_attachment.py +85 -63
  80. odoo/addons/dms/tests/test_storage_database.py +89 -35
  81. odoo/addons/dms/tools/file.py +63 -11
  82. odoo/addons/dms/views/dms_access_groups_views.xml +2 -17
  83. odoo/addons/dms/views/{category.xml → dms_category.xml} +4 -9
  84. odoo/addons/dms/views/{directory.xml → dms_directory.xml} +168 -176
  85. odoo/addons/dms/views/dms_file.xml +170 -191
  86. odoo/addons/dms/views/{tag.xml → dms_tag.xml} +50 -53
  87. odoo/addons/dms/views/menu.xml +52 -21
  88. odoo/addons/dms/views/res_config_settings.xml +31 -82
  89. odoo/addons/dms/views/storage.xml +7 -13
  90. odoo_addon_dms-17.0.1.0.0.3.dist-info/METADATA +257 -0
  91. {odoo_addon_dms-16.0.1.8.0.5.dist-info → odoo_addon_dms-17.0.1.0.0.3.dist-info}/RECORD +93 -95
  92. {odoo_addon_dms-16.0.1.8.0.5.dist-info → odoo_addon_dms-17.0.1.0.0.3.dist-info}/WHEEL +1 -1
  93. odoo_addon_dms-17.0.1.0.0.3.dist-info/top_level.txt +1 -0
  94. odoo/addons/dms/i18n/fa.po +0 -2277
  95. odoo/addons/dms/i18n/fa_IR.po +0 -2277
  96. odoo/addons/dms/readme/CONFIGURE.rst +0 -40
  97. odoo/addons/dms/readme/CONTRIBUTORS.rst +0 -16
  98. odoo/addons/dms/readme/CREDITS.rst +0 -6
  99. odoo/addons/dms/readme/DESCRIPTION.rst +0 -6
  100. odoo/addons/dms/readme/INSTALL.rst +0 -9
  101. odoo/addons/dms/readme/ROADMAP.rst +0 -8
  102. odoo/addons/dms/readme/USAGE.rst +0 -8
  103. odoo/addons/dms/static/src/js/components/path/path.esm.js +0 -0
  104. odoo/addons/dms/static/src/js/dms_portal_tour.js +0 -57
  105. odoo/addons/dms/static/src/js/fields/path.js +0 -81
  106. odoo/addons/dms/static/src/js/views/fields/binary/preview_record.esm.js +0 -35
  107. odoo/addons/dms/static/src/js/views/many_drop_target.js +0 -98
  108. odoo/addons/dms/static/src/scss/variables.scss +0 -9
  109. odoo/addons/dms/static/src/xml/views.xml +0 -72
  110. odoo/addons/dms/template/assets.xml +0 -44
  111. odoo/addons/dms/template/onboarding.xml +0 -97
  112. odoo_addon_dms-16.0.1.8.0.5.dist-info/METADATA +0 -203
  113. odoo_addon_dms-16.0.1.8.0.5.dist-info/top_level.txt +0 -1
@@ -23,78 +23,156 @@ class FileFilestoreTestCase(StorageFileBaseCase):
23
23
  def setUpClass(cls):
24
24
  super().setUpClass()
25
25
  cls.user_a = new_test_user(cls.env, login="user-a", groups="dms.group_dms_user")
26
+ cls.directory_group_a = cls.create_directory(storage=cls.storage)
27
+ cls.inaccessible_directory = cls.create_directory(storage=cls.storage)
28
+ cls.inaccessible_file = cls.create_file(directory=cls.inaccessible_directory)
29
+ cls.inaccessible_group = cls.access_group_model.create(
30
+ {
31
+ "name": "Inaccessible Group. No directory set",
32
+ "perm_create": True,
33
+ "explicit_user_ids": [(6, 0, [cls.user_a.id])],
34
+ }
35
+ )
36
+ cls.sub_directory_x = cls.create_directory(directory=cls.directory_group_a)
26
37
  cls.group_a = cls.access_group_model.create(
27
38
  {
28
39
  "name": "Group A",
29
40
  "perm_create": True,
30
41
  "explicit_user_ids": [(6, 0, [cls.user_a.id])],
42
+ "directory_ids": [
43
+ (4, cls.directory_group_a.id),
44
+ (4, cls.sub_directory_x.id),
45
+ ],
31
46
  }
32
47
  )
33
- cls.directory_group_a = cls.create_directory(storage=cls.storage)
34
48
  cls.directory_group_a.group_ids = [(4, cls.group_a.id)]
35
- cls.sub_directory_x = cls.create_directory(directory=cls.directory_group_a)
36
49
  cls.file2 = cls.create_file(directory=cls.sub_directory_x)
37
50
 
51
+ @users("user-a")
52
+ def test_unaccessible_file(self):
53
+ dms_files = self.file_model.with_user(self.env.user).search(
54
+ [("storage_id", "=", self.storage.id)]
55
+ )
56
+ self.assertNotIn(
57
+ self.inaccessible_file.id,
58
+ dms_files.ids,
59
+ msg="User A should not see the unaccessible file since it "
60
+ "was not granted access to the directory",
61
+ )
62
+ self.assertIn(
63
+ self.file2.id,
64
+ dms_files.ids,
65
+ msg="User A should see the file2 since it was granted access to "
66
+ "the directory",
67
+ )
68
+
69
+ @users("user-a")
70
+ def test_inaccessible_directory(self):
71
+ dms_directories = self.directory_model.with_user(self.env.user).search(
72
+ [("storage_id", "=", self.storage.id)]
73
+ )
74
+ self.assertNotIn(
75
+ self.inaccessible_directory.id,
76
+ dms_directories.ids,
77
+ msg="User A should not see the inaccessible directory since "
78
+ "it was not granted access to the directory",
79
+ )
80
+ self.assertIn(
81
+ self.sub_directory_x.id,
82
+ dms_directories.ids,
83
+ msg="User A should see the sub_directory_x since it was granted "
84
+ "access to the directory",
85
+ )
86
+
38
87
  @users("user-a")
39
88
  def test_file_access(self):
40
89
  dms_files = self.file_model.with_user(self.env.user).search(
41
90
  [("storage_id", "=", self.storage.id)]
42
91
  )
43
- self.assertNotIn(self.file.id, dms_files.ids)
44
- self.assertIn(self.file2.id, dms_files.ids)
92
+ self.assertNotIn(self.file.id, dms_files.ids, msg="User A should not see file")
93
+ self.assertIn(self.file2.id, dms_files.ids, msg="User A should see file2")
45
94
  dms_directories = self.directory_model.with_user(self.env.user).search(
46
95
  [("storage_id", "=", self.storage.id)]
47
96
  )
48
- self.assertNotIn(self.directory.id, dms_directories.ids)
49
- self.assertIn(self.sub_directory_x.id, dms_directories.ids)
97
+ self.assertNotIn(
98
+ self.directory.id,
99
+ dms_directories.ids,
100
+ msg="User A should not see directory",
101
+ )
102
+ self.assertIn(
103
+ self.sub_directory_x.id,
104
+ dms_directories.ids,
105
+ msg="User A should see sub_directory_x",
106
+ )
50
107
 
51
108
  @users("dms-manager", "dms-user")
52
109
  @mute_logger("odoo.models.unlink")
53
110
  def test_content_file(self):
54
- lobject_file = self.create_file(directory=self.directory)
55
- self.assertTrue(lobject_file.content)
56
- self.assertTrue(lobject_file.content_file)
57
- self.assertTrue(lobject_file.with_context(bin_size=True).content)
58
- self.assertTrue(lobject_file.with_context(bin_size=True).content_file)
59
- self.assertTrue(lobject_file.with_context(human_size=True).content_file)
60
- self.assertTrue(lobject_file.with_context(base64=True).content_file)
61
- self.assertTrue(lobject_file.with_context(stream=True).content_file)
62
- oid = lobject_file.with_context(oid=True).content_file
63
- self.assertTrue(oid)
64
- lobject_file.with_context(**{"show_content": True}).write(
111
+ object_file = self.create_file(directory=self.directory)
112
+ self.assertTrue(object_file.content, msg="Content is not empty")
113
+ self.assertTrue(object_file.content_file, msg="Content file is not empty")
114
+ self.assertTrue(
115
+ object_file.with_context(bin_size=True).content,
116
+ msg="Content is not empty (with bin_size)",
117
+ )
118
+ self.assertTrue(
119
+ object_file.with_context(bin_size=True).content_file,
120
+ msg="Content file is not empty (with bin_size)",
121
+ )
122
+ self.assertTrue(
123
+ object_file.with_context(human_size=True).content_file,
124
+ msg="Content file is not empty (with human_size)",
125
+ )
126
+ self.assertTrue(
127
+ object_file.with_context(base64=True).content_file,
128
+ msg="Content file is not empty (with base64)",
129
+ )
130
+ self.assertTrue(
131
+ object_file.with_context(stream=True).content_file,
132
+ msg="Content file is not empty (with stream)",
133
+ )
134
+ oid = object_file.with_context(oid=True).content_file
135
+ self.assertTrue(oid, msg="Content file is not empty (with oid)")
136
+ object_file.with_context(**{"show_content": True}).write(
65
137
  {"content": base64.b64encode(b"\xff new content")}
66
138
  )
67
139
  self.assertNotEqual(
68
- oid, lobject_file.with_context(**{"oid": True}).content_file
140
+ oid,
141
+ object_file.with_context(**{"oid": True}).content_file,
142
+ msg="Content file has changed",
69
143
  )
70
- self.assertTrue(lobject_file.export_data(["content"]))
71
- lobject_file.unlink()
144
+ self.assertTrue(object_file.export_data(["content"]))
145
+ object_file.unlink()
72
146
 
73
147
  def test_content_file_mimetype(self):
74
148
  file_svg = self.env.ref("dms.file_05_demo")
75
- self.assertEqual(file_svg.mimetype, "image/svg+xml")
149
+ self.assertEqual(file_svg.mimetype, "image/svg+xml", msg="SVG mimetype")
76
150
  file_logo = self.env.ref("dms.file_02_demo")
77
- self.assertEqual(file_logo.mimetype, "image/jpeg")
151
+ self.assertEqual(file_logo.mimetype, "image/jpeg", msg="JPEG mimetype")
78
152
 
79
153
  def test_content_file_mimetype_magic_library(self):
80
154
  if not magic:
81
155
  self.skipTest("Without python-magic library installed")
82
156
  file_video = self.env.ref("dms.file_10_demo")
83
- self.assertEqual(file_video.mimetype, "video/mp4")
157
+ self.assertEqual(file_video.mimetype, "video/mp4", msg="MP4 mimetype")
84
158
 
85
159
  def test_content_file_extension(self):
86
160
  file_pdf = self.env.ref("dms.file_27_demo")
87
- self.assertEqual(file_pdf.extension, "pdf")
161
+ self.assertEqual(file_pdf.extension, "pdf", msg="PDF extension")
88
162
  file_pdf.name = "Document_05"
89
- self.assertEqual(file_pdf.extension, "pdf")
163
+ self.assertEqual(
164
+ file_pdf.extension, "pdf", msg="PDF extension without extension"
165
+ )
90
166
  file_pdf.name = "Document_05.pdf"
91
- self.assertEqual(file_pdf.extension, "pdf")
167
+ self.assertEqual(file_pdf.extension, "pdf", msg="PDF extension with extension")
92
168
 
93
169
  def test_wizard_dms_file_move(self):
94
170
  file3 = self.create_file(directory=self.sub_directory_x)
95
171
  all_files = self.file + self.file2 + file3
96
172
  # Error: All files must have the same root directory
97
- with self.assertRaises(UserError):
173
+ with self.assertRaises(
174
+ UserError, msg="All files must have the same root directory"
175
+ ):
98
176
  self.file_model.with_context(
99
177
  active_ids=all_files.ids
100
178
  ).action_wizard_dms_file_move()
@@ -105,7 +183,11 @@ class FileFilestoreTestCase(StorageFileBaseCase):
105
183
  ).action_wizard_dms_file_move()
106
184
  wizard_model = self.env[res["res_model"]].with_context(**res["context"])
107
185
  wizard = wizard_model.create({"directory_id": self.directory.id})
108
- self.assertEqual(wizard.count_files, 2)
186
+ self.assertEqual(wizard.count_files, 2, msg="Wizard has 2 files")
109
187
  wizard.process()
110
- self.assertEqual(self.file2.directory_id, self.directory)
111
- self.assertEqual(file3.directory_id, self.directory)
188
+ self.assertEqual(
189
+ self.file2.directory_id, self.directory, msg="File2 has a new directory"
190
+ )
191
+ self.assertEqual(
192
+ file3.directory_id, self.directory, msg="File3 has a new directory"
193
+ )
@@ -25,29 +25,35 @@ class FileDatabaseTestCase(StorageDatabaseBaseCase):
25
25
  self.create_file(directory=root_directory)
26
26
  sub_directory = self.create_directory(directory=root_directory)
27
27
  self.create_file(sub_directory)
28
- self.assertEqual(root_directory.count_total_files, 2)
29
- self.assertEqual(sub_directory.count_files, 1)
28
+ self.assertEqual(root_directory.count_total_files, 2, "Total files should be 2")
29
+ self.assertEqual(
30
+ sub_directory.count_files, 1, "Subdirectory total files should be 1"
31
+ )
30
32
 
31
33
  @users("dms-manager", "dms-user")
32
34
  def test_lock_file(self):
33
35
  file = self.create_file(directory=self.directory)
34
36
  file.lock()
35
- self.assertTrue(file.is_locked)
37
+ self.assertTrue(file.is_locked, "File should be locked")
36
38
  file.unlock()
37
- self.assertFalse(file.is_locked)
39
+ self.assertFalse(file.is_locked, "File should be unlocked")
38
40
 
39
41
  @users("dms-manager", "dms-user")
40
42
  def test_copy_file(self):
41
43
  copy_file = self.file.copy()
42
- self.assertEqual(self.file.storage_id, copy_file.storage_id)
43
- self.assertEqual(self.file.content, copy_file.content)
44
+ self.assertEqual(
45
+ self.file.storage_id, copy_file.storage_id, "Storage should be the same"
46
+ )
47
+ self.assertEqual(
48
+ self.file.content, copy_file.content, "Content should be the same"
49
+ )
44
50
 
45
51
  @users("dms-manager", "dms-user")
46
52
  def test_rename_file(self):
47
53
  file = self.create_file(directory=self.directory)
48
54
  extension = file.extension
49
55
  file.write({"name": "test-%s.jpg" % self.env.user.login})
50
- self.assertNotEqual(file.extension, extension)
56
+ self.assertNotEqual(file.extension, extension, "Extension should be different")
51
57
 
52
58
  @users("dms-manager", "dms-user")
53
59
  def test_move_file(self):
@@ -55,11 +61,15 @@ class FileDatabaseTestCase(StorageDatabaseBaseCase):
55
61
  path_names = file.path_names
56
62
  file.write({"directory_id": self.directory2.id})
57
63
  file.flush_recordset()
58
- self.assertNotEqual(path_names, file.path_names)
64
+ self.assertNotEqual(
65
+ path_names, file.path_names, "Path names should be different"
66
+ )
59
67
 
60
68
  @users("dms-manager", "dms-user")
61
69
  def test_move_directory(self):
62
- with self.assertRaises(UserError):
70
+ with self.assertRaises(
71
+ UserError, msg="Directory can't have any parent, because it is " "root"
72
+ ):
63
73
  self.directory.write(
64
74
  {
65
75
  "is_root_directory": False,
@@ -72,57 +82,73 @@ class FileDatabaseTestCase(StorageDatabaseBaseCase):
72
82
  def test_unlink_file(self):
73
83
  file = self.create_file(directory=self.directory)
74
84
  file.unlink()
75
- self.assertFalse(file.exists())
85
+ self.assertFalse(file.exists(), "File should not exist")
76
86
 
77
87
  @users("dms-manager", "dms-user")
78
88
  def test_compute_thumbnail(self):
79
- self.assertTrue(self.file_demo_01.image_128)
89
+ self.assertTrue(self.file_demo_01.image_128, "Thumbnail should be computed")
80
90
 
81
91
  @users("dms-manager", "dms-user")
82
92
  def test_compute_path_names(self):
83
- self.assertTrue(self.file.path_names)
93
+ self.assertTrue(self.file.path_names, "Path names should be computed")
84
94
 
85
95
  @users("dms-manager", "dms-user")
86
96
  def test_compute_path_json(self):
87
- self.assertTrue(self.file.path_json)
97
+ self.assertTrue(self.file.path_json, "Path json should be computed")
88
98
 
89
99
  @users("dms-manager", "dms-user")
90
100
  def test_compute_mimetype(self):
91
- self.assertTrue(self.file.mimetype)
101
+ self.assertTrue(self.file.mimetype, "Mimetype should be computed")
92
102
 
93
103
  @users("dms-manager", "dms-user")
94
104
  def test_compute_extension(self):
95
- self.assertTrue(self.file.extension)
105
+ self.assertTrue(self.file.extension, "Extension should be computed")
96
106
 
97
107
  @users("dms-manager", "dms-user")
98
108
  def test_size_calculation(self):
99
- self.assertTrue(self.file.size)
109
+ self.assertTrue(self.file.size, "Size should be computed")
100
110
 
101
111
  @users("dms-manager", "dms-user")
102
112
  def test_checksum_calculation(self):
103
- self.assertTrue(self.file.checksum)
113
+ self.assertTrue(self.file.checksum, "Checksum should be computed")
104
114
 
105
115
  @users("dms-manager", "dms-user")
106
116
  def test_compute_content(self):
107
- self.assertTrue(self.file.with_context(bin_size=True).content)
108
- self.assertTrue(self.file.with_context(bin_size=False).content)
117
+ self.assertTrue(
118
+ self.file.with_context(bin_size=True).content,
119
+ "Content should be computed (with bin_size)",
120
+ )
121
+ self.assertTrue(
122
+ self.file.with_context(bin_size=False).content,
123
+ "Content should be computed (without bin_size)",
124
+ )
109
125
  self.assertNotEqual(
110
126
  self.file.with_context(bin_size=False).content,
111
127
  self.file.with_context(bin_size=True).content,
128
+ "Content should be different",
112
129
  )
113
130
 
114
131
  @users("dms-manager", "dms-user")
115
132
  def test_compute_save_type(self):
116
- self.assertTrue(self.file.save_type)
133
+ self.assertTrue(self.file.save_type, "Save type should be computed")
117
134
 
118
135
  @users("dms-manager", "dms-user")
119
136
  def test_compute_migration(self):
120
- self.assertTrue(self.file.migration)
137
+ self.assertTrue(self.file.migration, "Migration should be computed")
121
138
 
122
139
  @users("dms-manager", "dms-user")
123
140
  def test_search_panel(self):
124
- self.assertTrue(self.file.search_panel_select_range("directory_id"))
125
- self.assertTrue(self.file.search_panel_select_multi_range("directory_id"))
126
- self.assertTrue(self.file.search_panel_select_multi_range("tag_ids"))
141
+ self.assertTrue(
142
+ self.file.search_panel_select_range("directory_id"),
143
+ "Directory should be selected",
144
+ )
145
+ self.assertTrue(
146
+ self.file.search_panel_select_multi_range("directory_id"),
147
+ "Directory should be selected",
148
+ )
149
+ self.assertTrue(
150
+ self.file.search_panel_select_multi_range("tag_ids"),
151
+ "Tag should be selected",
152
+ )
127
153
  res = self.file.search_panel_select_range("directory_id", enable_counters=True)
128
154
  self.assertTrue(self.directory2.id == x["id"] for x in res["values"])
@@ -2,6 +2,7 @@
2
2
  # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl)
3
3
 
4
4
  import odoo.tests
5
+ from odoo.exceptions import AccessError
5
6
  from odoo.tests.common import users
6
7
 
7
8
  from .common import StorageAttachmentBaseCase
@@ -14,10 +15,15 @@ class TestDmsPortal(odoo.tests.HttpCase, StorageAttachmentBaseCase):
14
15
  super().setUpClass()
15
16
  cls.partner = cls.env.ref("base.partner_demo_portal")
16
17
  cls.portal_user = cls.partner.user_ids
18
+ cls.other_portal_user = cls.other_partner.user_ids
17
19
  cls.portal_user.login = "portal"
20
+ cls.other_portal_user.login = "other_portal"
18
21
  cls._create_attachment("test.txt")
22
+ cls._create_attachment("test2.txt", cls.other_partner)
19
23
  cls.directory_partner = cls._get_partner_directory()
24
+ cls.other_directory_partner = cls._get_partner_directory(cls.other_partner)
20
25
  cls.file_partner = cls.directory_partner.file_ids[0]
26
+ cls.other_file_partner = cls.other_directory_partner.file_ids[0]
21
27
 
22
28
  def test_access_portal(self):
23
29
  self.authenticate("portal", "portal")
@@ -25,54 +31,61 @@ class TestDmsPortal(odoo.tests.HttpCase, StorageAttachmentBaseCase):
25
31
  file_text = self.create_file(directory=self.directory_partner)
26
32
  url = "%s&access_token=abc-def" % (file_text.access_url)
27
33
  response = self.url_open(url, timeout=20)
28
- self.assertEqual(response.status_code, 404)
34
+ self.assertEqual(
35
+ response.status_code, 404, "Can't access file with incorrect access_token"
36
+ )
29
37
  # 200
30
38
  response = self.url_open(self.file_partner._get_share_url(), timeout=20)
31
- self.assertEqual(response.status_code, 200)
39
+ self.assertEqual(
40
+ response.status_code, 200, "Can access file with correct access_token"
41
+ )
32
42
  # 200
33
43
  response = self.url_open(self.directory_partner._get_share_url(), timeout=20)
34
- self.assertEqual(response.status_code, 200)
44
+ self.assertEqual(
45
+ response.status_code, 200, "Can access directory with correct access_token"
46
+ )
35
47
 
36
48
  def test_tour(self):
37
49
  for tour in ("dms_portal_mail_tour", "dms_portal_partners_tour"):
38
50
  with self.subTest(tour=tour):
39
- self.start_tour("/", tour, login="portal")
51
+ self.start_tour("/my", tour, login="portal")
40
52
 
41
- def test_permission_flag(self):
42
- """Assert portal partner directory and files permissions."""
43
- # Superuser can read everything
44
- self.assertTrue(self.directory_partner.permission_read)
45
- self.assertTrue(self.directory_partner.parent_id.permission_read)
46
- self.assertTrue(self.file_partner.permission_read)
47
- self.assertEqual(
48
- self.directory_partner.parent_id.child_directory_ids, self.directory_partner
49
- )
50
- # Public user can access only the empty res.partner folder
51
- self.directory_partner.with_user(self.public_user).invalidate_recordset()
52
- self.assertFalse(
53
- self.directory_partner.with_user(self.public_user).permission_read
54
- )
55
- self.directory_partner.parent_id.with_user(
56
- self.public_user
57
- ).invalidate_recordset()
58
- self.assertTrue(
59
- self.directory_partner.parent_id.with_user(self.public_user).permission_read
53
+ @users("portal")
54
+ def test_permission_portal_user_access_own_attachment(self):
55
+ """
56
+ The user can access its own attachments, even if its access group are not set
57
+ """
58
+ # Has to manually su=False because the portal user is not a superuser,
59
+ # but odoo uses somewhere sudo() internally
60
+ file = self.file_partner.with_user(self.portal_user).with_env(
61
+ self.env(su=False)
60
62
  )
61
- self.file_partner.with_user(self.public_user).invalidate_recordset()
62
- self.assertFalse(self.file_partner.with_user(self.public_user).permission_read)
63
- self.assertFalse(
64
- self.directory_partner.parent_id.with_user(
65
- self.public_user
66
- ).child_directory_ids
63
+ directory = self.directory_partner.with_user(self.portal_user).with_env(
64
+ self.env(su=False)
67
65
  )
66
+ # Portal user can only read
67
+ file.check_access_rule("read")
68
+
69
+ # Portal user can't do anything else
70
+ with self.assertRaises(AccessError, msg="Portal user should not have access"):
71
+ file.check_access_rule("write")
72
+ file.check_access_rule("unlink")
73
+ directory.check_access_rule("create")
68
74
 
69
75
  @users("portal")
70
- def test_permission_flag_portal_user(self):
71
- # Portal user can read everything (because it belongs to him)
72
- self.assertTrue(self.directory_partner.permission_read)
73
- self.assertTrue(self.directory_partner.parent_id.permission_read)
74
- self.assertTrue(self.file_partner.permission_read)
75
- self.assertEqual(
76
- self.directory_partner.parent_id.child_directory_ids,
77
- self.directory_partner,
76
+ def test_permission_portal_user_access_other_attachment(self):
77
+ """
78
+ The user can't access other attachments if its access group are not set
79
+ """
80
+ # Has to manually su=False because the portal user is not a superuser,
81
+ # but odoo uses somewhere sudo() internally
82
+ file = self.other_file_partner.with_user(self.portal_user).with_env(
83
+ self.env(su=False)
78
84
  )
85
+ # Portal user can't do anything
86
+ with self.assertRaises(AccessError, msg="Portal user should not have access"):
87
+ file.check_access_rule("read")
88
+ with self.assertRaises(AccessError, msg="Portal user should not have access"):
89
+ file.check_access_rule("write")
90
+ with self.assertRaises(AccessError, msg="Portal user should not have access"):
91
+ file.check_access_rule("unlink")