Browse Source

Merge pull request #4 from lebouquetin/master

Tracim 10 years ago
parent
commit
2fc0f0c850

+ 16 - 21
tracim/tracim/lib/content.py View File

@@ -150,7 +150,7 @@ class ContentApi(object):
150 150
 
151 151
         if do_save:
152 152
             self.save(item, ActionDescription.COMMENT)
153
-        return content
153
+        return item
154 154
 
155 155
 
156 156
     def get_one_from_revision(self, content_id: int, content_type: str, workspace: Workspace=None, revision_id=None) -> Content:
@@ -174,22 +174,14 @@ class ContentApi(object):
174 174
         return content
175 175
 
176 176
     def get_one(self, content_id: int, content_type: str, workspace: Workspace=None) -> Content:
177
-        assert content_id is None or isinstance(content_id, int) # DYN_REMOVE
178
-        assert content_type is not None # DYN_REMOVE
179
-        assert isinstance(content_type, str) # DYN_REMOVE
180 177
 
181 178
         if not content_id:
182
-            return
179
+            return None
183 180
 
184 181
         if content_type==ContentType.Any:
185
-            return self._base_query(workspace).\
186
-                filter(Content.content_id==content_id).\
187
-                one()
182
+            return self._base_query(workspace).filter(Content.content_id==content_id).one()
188 183
 
189
-        return self._base_query(workspace).\
190
-            filter(Content.content_id==content_id).\
191
-            filter(Content.type==content_type).\
192
-            one()
184
+        return self._base_query(workspace).filter(Content.content_id==content_id).filter(Content.type==content_type).one()
193 185
 
194 186
     def get_all(self, parent_id: int, content_type: str, workspace: Workspace=None) -> Content:
195 187
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
@@ -218,12 +210,6 @@ class ContentApi(object):
218 210
             )
219 211
         :return:
220 212
         """
221
-        assert folder.type==ContentType.Folder
222
-        assert 'file' in allowed_content_dict.keys()
223
-        assert 'folder' in allowed_content_dict.keys()
224
-        assert 'page' in allowed_content_dict.keys()
225
-        assert 'thread' in allowed_content_dict.keys()
226
-
227 213
         properties = dict(allowed_content = allowed_content_dict)
228 214
         folder.properties = properties
229 215
 
@@ -245,32 +231,39 @@ class ContentApi(object):
245 231
         item.revision_type = ActionDescription.EDITION
246 232
 
247 233
 
248
-    def update_content(self, item: Content, new_label: str, new_content: str) -> Content:
234
+    def update_content(self, item: Content, new_label: str, new_content: str=None) -> Content:
235
+        item.owner = self._user
249 236
         item.label = new_label
250
-        item.description = new_content # TODO: convert urls into links
237
+        item.description = new_content if new_content else item.description # TODO: convert urls into links
251 238
         item.revision_type = ActionDescription.EDITION
252 239
         return item
253 240
 
254 241
     def update_file_data(self, item: Content, new_filename: str, new_mimetype: str, new_file_content) -> Content:
242
+        item.owner = self._user
255 243
         item.file_name = new_filename
256 244
         item.file_mimetype = new_mimetype
257 245
         item.file_content = new_file_content
246
+        item.revision_type = ActionDescription.REVISION
258 247
         return item
259 248
 
260 249
     def archive(self, content: Content):
250
+        content.owner = self._user
261 251
         content.is_archived = True
262 252
         content.revision_type = ActionDescription.ARCHIVING
263 253
 
264 254
     def unarchive(self, content: Content):
255
+        content.owner = self._user
265 256
         content.is_archived = False
266 257
         content.revision_type = ActionDescription.UNARCHIVING
267 258
 
268 259
 
269 260
     def delete(self, content: Content):
261
+        content.owner = self._user
270 262
         content.is_deleted = True
271 263
         content.revision_type = ActionDescription.DELETION
272 264
 
273 265
     def undelete(self, content: Content):
266
+        content.owner = self._user
274 267
         content.is_deleted = False
275 268
         content.revision_type = ActionDescription.UNDELETION
276 269
 
@@ -292,7 +285,9 @@ class ContentApi(object):
292 285
                 # The action has not been modified, so we set it to default edition
293 286
                 action_description = ActionDescription.EDITION
294 287
 
295
-        content.revision_type = action_description
288
+        if action_description:
289
+            content.revision_type = action_description
290
+
296 291
 
297 292
         if do_flush:
298 293
             DBSession.flush()

+ 4 - 3
tracim/tracim/lib/notifications.py View File

@@ -32,7 +32,8 @@ class INotifier(object):
32 32
     Interface for Notifier instances
33 33
     """
34 34
     def __init__(self, current_user: User=None):
35
-        raise NotImplementedError
35
+        pass
36
+
36 37
 
37 38
     def notify_content_update(self, content: Content):
38 39
         raise NotImplementedError
@@ -43,7 +44,7 @@ class NotifierFactory(object):
43 44
     @classmethod
44 45
     def create(cls, current_user: User=None) -> INotifier:
45 46
         cfg = CFG.get_instance()
46
-        if cfg.EMAIL_NOTIFICATION_ACTIVATED:
47
+        if not cfg.EMAIL_NOTIFICATION_ACTIVATED:
47 48
             return DummyNotifier(current_user)
48 49
 
49 50
         return RealNotifier(current_user)
@@ -54,7 +55,7 @@ class DummyNotifier(INotifier):
54 55
         logger.info(self, 'Instantiating Dummy Notifier')
55 56
 
56 57
     def notify_content_update(self, content: Content):
57
-        logger.info(self, 'Fake notifier, do not send email-notification for update of content {} by user {}'.format(content.content_id, self._user.user_id))
58
+        logger.info(self, 'Fake notifier, do not send email-notification for update of content {}'.format(content.content_id))
58 59
 
59 60
 
60 61
 class RealNotifier(object):

+ 252 - 2
tracim/tracim/tests/library/test_content_api.py View File

@@ -1,14 +1,20 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3 3
 from nose.tools import eq_
4
+from nose.tools import raises
4 5
 
5 6
 import transaction
6 7
 
7 8
 from tracim.lib.content import compare_content_for_sorting_by_type_and_name
8 9
 from tracim.lib.content import ContentApi
10
+from tracim.lib.user import UserApi
11
+from tracim.lib.user import UserStaticApi
9 12
 
13
+from tracim.model.auth import User
14
+from tracim.model.data import ActionDescription
10 15
 from tracim.model.data import Content
11 16
 from tracim.model.data import ContentType
17
+from tracim.model.data import ContentStatus
12 18
 
13 19
 from tracim.tests import TestStandard
14 20
 
@@ -81,8 +87,6 @@ class TestContentApi(TestStandard):
81 87
         eq_(sorteds[0], c2, 'value is {} instead of {}'.format(sorteds[0].content_id, c2.content_id))
82 88
         eq_(sorteds[1], c1, 'value is {} instead of {}'.format(sorteds[1].content_id, c1.content_id))
83 89
 
84
-class TestContentApiFilteringDeletedItem(TestStandard):
85
-
86 90
     def test_delete(self):
87 91
         api = ContentApi(None)
88 92
         item = api.create(ContentType.Folder, None, None, 'not_deleted', True)
@@ -127,3 +131,249 @@ class TestContentApiFilteringDeletedItem(TestStandard):
127 131
         api = ContentApi(None, show_archived=True)
128 132
         items = api.get_all(None, ContentType.Any, None)
129 133
         eq_(2, len(items))
134
+
135
+    def test_get_all_with_filter(self):
136
+        api = ContentApi(None)
137
+        item = api.create(ContentType.Folder, None, None, 'thefolder', True)
138
+        item2 = api.create(ContentType.File, None, None, 'thefile', True)
139
+        transaction.commit()
140
+
141
+        items = api.get_all(None, ContentType.Any, None)
142
+        eq_(2, len(items))
143
+
144
+        items2 = api.get_all(None, ContentType.File, None)
145
+        eq_(1, len(items2))
146
+        eq_('thefile', items2[0].label)
147
+
148
+        items3 = api.get_all(None, ContentType.Folder, None)
149
+        eq_(1, len(items3))
150
+        eq_('thefolder', items3[0].label)
151
+
152
+    def test_get_all_with_parent_id(self):
153
+        api = ContentApi(None)
154
+        item = api.create(ContentType.Folder, None, None, 'parent', True)
155
+        item2 = api.create(ContentType.File, None, item, 'file1', True)
156
+        item3 = api.create(ContentType.File, None, None, 'file2', True)
157
+        parent_id = item.content_id
158
+        child_id = item2.content_id
159
+        transaction.commit()
160
+
161
+        items = api.get_all(None, ContentType.Any, None)
162
+        eq_(3, len(items))
163
+
164
+        items2 = api.get_all(parent_id, ContentType.File, None)
165
+        eq_(1, len(items2))
166
+        eq_(child_id, items2[0].content_id)
167
+
168
+    @raises(ValueError)
169
+    def test_set_status_unknown_status(self):
170
+        api = ContentApi(None)
171
+        c = api.create(ContentType.Folder, None, None, 'parent', True)
172
+        api.set_status(c, 'unknown-status')
173
+
174
+    def test_set_status_ok(self):
175
+        api = ContentApi(None)
176
+        c = api.create(ContentType.Folder, None, None, 'parent', True)
177
+        for new_status in ['open', 'closed-validated', 'closed-unvalidated', 'closed-deprecated']:
178
+            api.set_status(c, new_status)
179
+            eq_(new_status, c.status)
180
+            eq_(ActionDescription.STATUS_UPDATE, c.revision_type)
181
+
182
+    def test_create_comment_ok(self):
183
+        uapi = UserApi(None)
184
+        user = uapi.create_user()
185
+        user.email = 'this.is@user'
186
+        uapi.save(user)
187
+
188
+        api = ContentApi(user)
189
+        p = api.create(ContentType.Page, None, None, 'this_is_a_page')
190
+        transaction.commit()
191
+
192
+        c = api.create_comment(None, p, 'this is the comment', True)
193
+        transaction.commit()
194
+
195
+        eq_(Content, c.__class__)
196
+        eq_(p.content_id, c.parent_id)
197
+        eq_(user, c.owner)
198
+        eq_(None, c.workspace)
199
+        eq_(ContentType.Comment, c.type)
200
+        eq_('this is the comment', c.description)
201
+        eq_('', c.label)
202
+        eq_(ActionDescription.COMMENT, c.revision_type)
203
+
204
+
205
+    def test_update(self):
206
+        uapi = UserApi(None)
207
+
208
+        user1 = uapi.create_user()
209
+        user1.email = 'this.is@user'
210
+        uapi.save(user1)
211
+
212
+        user2 = uapi.create_user()
213
+        user2.email = 'this.is@another.user'
214
+        uapi.save(user2)
215
+
216
+        api = ContentApi(user1)
217
+        p = api.create(ContentType.Page, None, None, 'this_is_a_page', True)
218
+
219
+        u1id = user1.user_id
220
+        u2id = user2.user_id
221
+        pcid = p.content_id
222
+        poid = p.owner_id
223
+
224
+        transaction.commit()
225
+
226
+        content = api.get_one(pcid, ContentType.Any, None)
227
+        eq_(u1id, content.owner_id)
228
+        eq_(poid, content.owner_id)
229
+
230
+        u2 = UserApi(None).get_one(u2id)
231
+        api2 = ContentApi(u2)
232
+        content2 = api2.get_one(pcid, ContentType.Any, None)
233
+        api2.update_content(content2, 'this is an updated page', 'new content')
234
+        api2.save(content2)
235
+        transaction.commit()
236
+
237
+        updated = api.get_one(pcid, ContentType.Any, None)
238
+        eq_(u2id, updated.owner_id, 'the owner id should be {} (found {})'.format(u2id, updated.owner_id))
239
+        eq_('this is an updated page', updated.label)
240
+        eq_('new content', updated.description)
241
+        eq_(ActionDescription.EDITION, updated.revision_type)
242
+
243
+
244
+    def test_update_file_data(self):
245
+        uapi = UserApi(None)
246
+
247
+        user1 = uapi.create_user()
248
+        user1.email = 'this.is@user'
249
+        uapi.save(user1)
250
+
251
+        user2 = uapi.create_user()
252
+        user2.email = 'this.is@another.user'
253
+        uapi.save(user2)
254
+
255
+        api = ContentApi(user1)
256
+        p = api.create(ContentType.File, None, None, 'this_is_a_page', True)
257
+
258
+        u1id = user1.user_id
259
+        u2id = user2.user_id
260
+        pcid = p.content_id
261
+        poid = p.owner_id
262
+
263
+        transaction.commit()
264
+
265
+        content = api.get_one(pcid, ContentType.Any, None)
266
+        eq_(u1id, content.owner_id)
267
+        eq_(poid, content.owner_id)
268
+
269
+        u2 = UserApi(None).get_one(u2id)
270
+        api2 = ContentApi(u2)
271
+        content2 = api2.get_one(pcid, ContentType.Any, None)
272
+        api2.update_file_data(content2, 'index.html', 'text/html', b'<html>hello world</html>')
273
+        api2.save(content2)
274
+        transaction.commit()
275
+
276
+        updated = api.get_one(pcid, ContentType.Any, None)
277
+        eq_(u2id, updated.owner_id, 'the owner id should be {} (found {})'.format(u2id, updated.owner_id))
278
+        eq_('index.html', updated.file_name)
279
+        eq_('text/html', updated.file_mimetype)
280
+        eq_(b'<html>hello world</html>', updated.file_content)
281
+        eq_(ActionDescription.REVISION, updated.revision_type)
282
+
283
+
284
+    def test_archive_unarchive(self):
285
+        uapi = UserApi(None)
286
+
287
+        user1 = uapi.create_user()
288
+        user1.email = 'this.is@user'
289
+        uapi.save(user1)
290
+
291
+        user2 = uapi.create_user()
292
+        user2.email = 'this.is@another.user'
293
+        uapi.save(user2)
294
+
295
+        api = ContentApi(user1, show_archived=True) # show archived is used at the top end of the test
296
+        p = api.create(ContentType.File, None, None, 'this_is_a_page', True)
297
+
298
+        u1id = user1.user_id
299
+        u2id = user2.user_id
300
+        pcid = p.content_id
301
+        poid = p.owner_id
302
+
303
+        transaction.commit()
304
+
305
+        ####
306
+
307
+        content = api.get_one(pcid, ContentType.Any, None)
308
+        eq_(u1id, content.owner_id)
309
+        eq_(poid, content.owner_id)
310
+
311
+        u2 = UserApi(None).get_one(u2id)
312
+        api2 = ContentApi(u2, show_archived=True)
313
+        content2 = api2.get_one(pcid, ContentType.Any, None)
314
+        api2.archive(content2)
315
+        api2.save(content2)
316
+        transaction.commit()
317
+
318
+        updated = api2.get_one(pcid, ContentType.Any, None)
319
+        eq_(u2id, updated.owner_id, 'the owner id should be {} (found {})'.format(u2id, updated.owner_id))
320
+        eq_(True, updated.is_archived)
321
+        eq_(ActionDescription.ARCHIVING, updated.revision_type)
322
+
323
+        ####
324
+
325
+        updated2 = api.get_one(pcid, ContentType.Any, None)
326
+        api.unarchive(updated)
327
+        api.save(updated2)
328
+        eq_(False, updated2.is_archived)
329
+        eq_(ActionDescription.UNARCHIVING, updated2.revision_type)
330
+        eq_(u1id, updated2.owner_id)
331
+
332
+
333
+    def test_delete_undelete(self):
334
+        uapi = UserApi(None)
335
+
336
+        user1 = uapi.create_user()
337
+        user1.email = 'this.is@user'
338
+        uapi.save(user1)
339
+
340
+        user2 = uapi.create_user()
341
+        user2.email = 'this.is@another.user'
342
+        uapi.save(user2)
343
+
344
+        api = ContentApi(user1, show_deleted=True) # show archived is used at the top end of the test
345
+        p = api.create(ContentType.File, None, None, 'this_is_a_page', True)
346
+
347
+        u1id = user1.user_id
348
+        u2id = user2.user_id
349
+        pcid = p.content_id
350
+        poid = p.owner_id
351
+
352
+        transaction.commit()
353
+
354
+        ####
355
+
356
+        content = api.get_one(pcid, ContentType.Any, None)
357
+        eq_(u1id, content.owner_id)
358
+        eq_(poid, content.owner_id)
359
+
360
+        u2 = UserApi(None).get_one(u2id)
361
+        api2 = ContentApi(u2, show_deleted=True)
362
+        content2 = api2.get_one(pcid, ContentType.Any, None)
363
+        api2.delete(content2)
364
+        api2.save(content2)
365
+        transaction.commit()
366
+
367
+        updated = api2.get_one(pcid, ContentType.Any, None)
368
+        eq_(u2id, updated.owner_id, 'the owner id should be {} (found {})'.format(u2id, updated.owner_id))
369
+        eq_(True, updated.is_deleted)
370
+        eq_(ActionDescription.DELETION, updated.revision_type)
371
+
372
+        ####
373
+
374
+        updated2 = api.get_one(pcid, ContentType.Any, None)
375
+        api.undelete(updated)
376
+        api.save(updated2)
377
+        eq_(False, updated2.is_deleted)
378
+        eq_(ActionDescription.UNDELETION, updated2.revision_type)
379
+        eq_(u1id, updated2.owner_id)

+ 66 - 0
tracim/tracim/tests/library/test_notification.py View File

@@ -0,0 +1,66 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from nose.tools import eq_
4
+from nose.tools import ok_
5
+from nose.tools import raises
6
+
7
+from sqlalchemy.orm.exc import NoResultFound
8
+
9
+import transaction
10
+
11
+from tracim.lib.user import UserApi
12
+from tracim.tests import TestStandard
13
+
14
+
15
+
16
+class TestUserApi(TestStandard):
17
+
18
+    def test_create_and_update_user(self):
19
+        api = UserApi(None)
20
+        u = api.create_user()
21
+        api.update(u, 'bob', 'bob@bob', True)
22
+
23
+        nu = api.get_one_by_email('bob@bob')
24
+        ok_(nu!=None)
25
+        eq_('bob@bob', nu.email)
26
+        eq_('bob', nu.display_name)
27
+
28
+
29
+    def test_user_with_email_exists(self):
30
+        api = UserApi(None)
31
+        u = api.create_user()
32
+        api.update(u, 'bibi', 'bibi@bibi', True)
33
+        transaction.commit()
34
+
35
+        eq_(True, api.user_with_email_exists('bibi@bibi'))
36
+        eq_(False, api.user_with_email_exists('unknown'))
37
+
38
+
39
+    def test_get_one_by_email(self):
40
+        api = UserApi(None)
41
+        u = api.create_user()
42
+        api.update(u, 'bibi', 'bibi@bibi', True)
43
+        uid = u.user_id
44
+        transaction.commit()
45
+
46
+        eq_(uid, api.get_one_by_email('bibi@bibi').user_id)
47
+
48
+    @raises(NoResultFound)
49
+    def test_get_one_by_email_exception(self):
50
+        api = UserApi(None)
51
+        api.get_one_by_email('unknown')
52
+
53
+    def test_get_all(self):
54
+        api = UserApi(None)
55
+        # u1 = api.create_user(True)
56
+        # u2 = api.create_user(True)
57
+
58
+        # users = api.get_all()
59
+        # ok_(2==len(users))
60
+
61
+    def test_get_one(self):
62
+        api = UserApi(None)
63
+        u = api.create_user()
64
+        api.update(u, 'titi', 'titi@titi', True)
65
+        one = api.get_one(u.user_id)
66
+        eq_(u.user_id, one.user_id)