浏览代码

Merge branch 'master' of github.com:tracim/tracim into integration_v2

Skylsmoi 8 年前
父节点
当前提交
3d2ce79d63

+ 1 - 1
install/requirements.txt 查看文件

47
 sprox==0.9.4
47
 sprox==0.9.4
48
 stevedore==1.1.0
48
 stevedore==1.1.0
49
 tg.devtools==2.3.7
49
 tg.devtools==2.3.7
50
-git+https://github.com/algoo/tgapp-resetpassword.git
50
+git+https://github.com/gasbasd/tgapp-resetpassword.git
51
 tgext.admin==0.6.4
51
 tgext.admin==0.6.4
52
 tgext.crud==0.7.3
52
 tgext.crud==0.7.3
53
 tgext.pluggable==0.6.2
53
 tgext.pluggable==0.6.2

+ 3 - 1
tracim/tracim/config/app_cfg.py 查看文件

173
         :param value:
173
         :param value:
174
         :return:
174
         :return:
175
         """
175
         """
176
-        if 'PASSWORD' not in key and 'URL' not in key and 'CONTENT' not in key:
176
+        if 'PASSWORD' not in key and \
177
+                ('URL' not in key or type(value) == str) and \
178
+                'CONTENT' not in key:
177
             # We do not show PASSWORD for security reason
179
             # We do not show PASSWORD for security reason
178
             # we do not show URL because the associated config uses tg.lurl() which is evaluated when at display time.
180
             # we do not show URL because the associated config uses tg.lurl() which is evaluated when at display time.
179
             # At the time of configuration setup, it can't be evaluated
181
             # At the time of configuration setup, it can't be evaluated

+ 25 - 1
tracim/tracim/controllers/admin/user.py 查看文件

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
 import uuid
2
 import uuid
3
+import random
3
 
4
 
4
 import pytz
5
 import pytz
5
 from tracim import model  as pm
6
 from tracim import model  as pm
7
 from sprox.tablebase import TableBase
8
 from sprox.tablebase import TableBase
8
 from sprox.formbase import EditableForm, AddRecordForm
9
 from sprox.formbase import EditableForm, AddRecordForm
9
 from sprox.fillerbase import TableFiller, EditFormFiller
10
 from sprox.fillerbase import TableFiller, EditFormFiller
11
+from tracim.config.app_cfg import CFG
10
 from tw2 import forms as tw2f
12
 from tw2 import forms as tw2f
11
 import tg
13
 import tg
12
 from tg import predicates
14
 from tg import predicates
273
     profile = UserProfileAdminRestController()
275
     profile = UserProfileAdminRestController()
274
     workspaces = UserWorkspaceRestController()
276
     workspaces = UserWorkspaceRestController()
275
 
277
 
278
+    PASSWORD_LENGTH = 12
279
+    PASSWORD_CHARACTERS = '0123456789' \
280
+                          'abcdefghijklmonpqrstuvwxyz' \
281
+                          'ABCDEFGHIJKLMONPQRSTUVWXYZ'
282
+
276
     @classmethod
283
     @classmethod
277
     def current_item_id_key_in_context(cls):
284
     def current_item_id_key_in_context(cls):
278
         return 'user_id'
285
         return 'user_id'
326
             user.password = password
333
             user.password = password
327
         elif send_email:
334
         elif send_email:
328
             # Setup a random password to send email at user
335
             # Setup a random password to send email at user
329
-            password = str(uuid.uuid4())
336
+            password = self.generate_password()
330
             user.password = password
337
             user.password = password
331
 
338
 
332
         user.webdav_left_digest_response_hash = '%s:/:%s' % (email, password)
339
         user.webdav_left_digest_response_hash = '%s:/:%s' % (email, password)
351
         tg.flash(_('User {} created.').format(user.get_display_name()), CST.STATUS_OK)
358
         tg.flash(_('User {} created.').format(user.get_display_name()), CST.STATUS_OK)
352
         tg.redirect(self.url())
359
         tg.redirect(self.url())
353
 
360
 
361
+    @classmethod
362
+    def generate_password(
363
+            cls,
364
+            password_length = PASSWORD_LENGTH,
365
+            password_chars = PASSWORD_CHARACTERS
366
+            ):
367
+
368
+        # character list that will be contained into the password
369
+        char_list = []
370
+
371
+        for j in range(0, password_length):
372
+            # This puts a random char from the list above inside
373
+            # the list of chars and then merges them into a String
374
+            char_list.append(random.choice(password_chars))
375
+            password = ''.join(char_list)
376
+        return password
377
+
354
     @tg.expose('tracim.templates.admin.user_getone')
378
     @tg.expose('tracim.templates.admin.user_getone')
355
     def get_one(self, user_id):
379
     def get_one(self, user_id):
356
         current_user = tmpl_context.current_user
380
         current_user = tmpl_context.current_user

+ 8 - 0
tracim/tracim/lib/helpers.py 查看文件

82
     current_locale = tg.i18n.get_lang()[0]
82
     current_locale = tg.i18n.get_lang()[0]
83
     return format_time(datetime_object, locale=current_locale)
83
     return format_time(datetime_object, locale=current_locale)
84
 
84
 
85
+def update_date(datetime_object):
86
+    current_locale = tg.i18n.get_lang()[0]
87
+    return format_date(datetime_object, locale=current_locale)
88
+
89
+def update_time(datetime_object):
90
+    current_locale = tg.i18n.get_lang()[0]
91
+    return format_time(datetime_object, locale=current_locale)
92
+
85
 def format_short(datetime_object):
93
 def format_short(datetime_object):
86
     return datetime_object.strftime(format = plag.Globals.SHORT_DATE_FORMAT.__str__())
94
     return datetime_object.strftime(format = plag.Globals.SHORT_DATE_FORMAT.__str__())
87
 
95
 

+ 8 - 0
tracim/tracim/model/data.py 查看文件

1039
         return self.get_current_revision()
1039
         return self.get_current_revision()
1040
 
1040
 
1041
     @property
1041
     @property
1042
+    def first_revision(self) -> ContentRevisionRO:
1043
+        return self.revisions[0]  # FIXME
1044
+
1045
+    @property
1046
+    def last_revision(self) -> ContentRevisionRO:
1047
+        return self.revisions[-1]
1048
+
1049
+    @property
1042
     def is_editable(self) -> bool:
1050
     def is_editable(self) -> bool:
1043
         return not self.is_archived and not self.is_deleted
1051
         return not self.is_archived and not self.is_deleted
1044
 
1052
 

+ 11 - 3
tracim/tracim/model/serializers.py 查看文件

388
             is_new=content.has_new_information_for(context.get_user()),
388
             is_new=content.has_new_information_for(context.get_user()),
389
             content=data_container.description,
389
             content=data_container.description,
390
             created=data_container.created,
390
             created=data_container.created,
391
+            updated=content.last_revision.updated,
391
             label=data_container.label,
392
             label=data_container.label,
392
             icon=ContentType.get_icon(content.type),
393
             icon=ContentType.get_icon(content.type),
393
-            owner=context.toDict(data_container.owner),
394
+            owner=context.toDict(content.first_revision.owner),
395
+            last_modification_author=context.toDict(content.last_revision.owner),
394
             status=context.toDict(data_container.get_status()),
396
             status=context.toDict(data_container.get_status()),
395
             links=[],
397
             links=[],
396
-            revisions=context.toDict(sorted(content.revisions, key=lambda v: v.created, reverse=True)),
398
+            revision_nb = len(content.revisions),
397
             selected_revision='latest' if content.revision_to_serialize<=0 else content.revision_to_serialize,
399
             selected_revision='latest' if content.revision_to_serialize<=0 else content.revision_to_serialize,
398
             history=Context(CTX.CONTENT_HISTORY).toDict(content.get_history()),
400
             history=Context(CTX.CONTENT_HISTORY).toDict(content.get_history()),
399
             is_editable=content.is_editable,
401
             is_editable=content.is_editable,
450
     )
452
     )
451
 
453
 
452
 @pod_serializer(Content, CTX.THREAD)
454
 @pod_serializer(Content, CTX.THREAD)
453
-def serialize_node_for_page(item: Content, context: Context):
455
+def serialize_node_for_thread(item: Content, context: Context):
454
     if item.type==ContentType.Thread:
456
     if item.type==ContentType.Thread:
455
         return DictLikeClass(
457
         return DictLikeClass(
456
             content = item.description,
458
             content = item.description,
457
             created = item.created,
459
             created = item.created,
460
+            updated = item.last_revision.updated,
461
+            revision_nb = len(item.revisions),
458
             icon = ContentType.get_icon(item.type),
462
             icon = ContentType.get_icon(item.type),
459
             id = item.content_id,
463
             id = item.content_id,
460
             label = item.label,
464
             label = item.label,
461
             links=[],
465
             links=[],
462
             owner = context.toDict(item.owner),
466
             owner = context.toDict(item.owner),
467
+            last_modification_author=context.toDict(item.last_revision.owner),
463
             parent = context.toDict(item.parent),
468
             parent = context.toDict(item.parent),
464
             selected_revision = 'latest',
469
             selected_revision = 'latest',
465
             status = context.toDict(item.get_status()),
470
             status = context.toDict(item.get_status()),
595
             id=content.content_id,
600
             id=content.content_id,
596
             label=content.label,
601
             label=content.label,
597
             created=content.created,
602
             created=content.created,
603
+            updated=content.last_revision.updated,
604
+            last_modification_author=context.toDict(content.last_revision.owner),
605
+            revision_nb=len(content.revisions),
598
             workspace=context.toDict(content.workspace),
606
             workspace=context.toDict(content.workspace),
599
             allowed_content=DictLikeClass(content.properties['allowed_content']),
607
             allowed_content=DictLikeClass(content.properties['allowed_content']),
600
             allowed_content_types=context.toDict(content.get_allowed_content_types()),
608
             allowed_content_types=context.toDict(content.get_allowed_content_types()),

+ 8 - 1
tracim/tracim/templates/file/getone.mak 查看文件

50
 
50
 
51
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
51
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
52
                 <% created_localized = h.get_with_timezone(result.file.created) %>
52
                 <% created_localized = h.get_with_timezone(result.file.created) %>
53
-              <p>${_('file created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.file.owner.name)|n}</p>
53
+                <% updated_localized = h.get_with_timezone(result.file.updated) %>
54
+                <% last_modification_author = result.file.last_modification_author.name %>
55
+              <p>${_('file created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.file.owner.name)|n}
56
+                  % if result.file.revision_nb > 1:
57
+                      ${_(' (last modification on {update_date} at {update_time} by {last_modification_author})').format(update_date=h.update_date(updated_localized), update_time=h.update_time(updated_localized), last_modification_author = last_modification_author)|n}
58
+                  % endif
59
+              </p>
60
+
54
             </div>
61
             </div>
55
         </div>
62
         </div>
56
     </div>
63
     </div>

+ 7 - 1
tracim/tracim/templates/folder/getone.mak 查看文件

49
 
49
 
50
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
50
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
51
                 <% created_localized = h.get_with_timezone(result.folder.created) %>
51
                 <% created_localized = h.get_with_timezone(result.folder.created) %>
52
-              <p>${_('folder created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.folder.owner.name)|n}</p>
52
+                <% updated_localized = h.get_with_timezone(result.folder.updated) %>
53
+                <% last_modification_author = result.folder.last_modification_author.name %>
54
+                <p>${_('folder created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.folder.owner.name)|n}
55
+                    % if result.folder.revision_nb > 1:
56
+                      ${_(' (last modification on {update_date} at {update_time} by {last_modification_author})').format(update_date=h.update_date(updated_localized), update_time=h.update_time(updated_localized), last_modification_author = last_modification_author)|n}
57
+                    % endif
58
+                </p>
53
             </div>
59
             </div>
54
         </div>
60
         </div>
55
     </div>
61
     </div>

+ 8 - 1
tracim/tracim/templates/page/getone.mak 查看文件

48
 
48
 
49
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
49
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
50
                 <% created_localized = h.get_with_timezone(result.page.created) %>
50
                 <% created_localized = h.get_with_timezone(result.page.created) %>
51
-              <p>${_('page created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.page.owner.name)|n}</p>
51
+                <% updated_localized = h.get_with_timezone(result.page.updated) %>
52
+                <% last_modification_author = result.page.last_modification_author.name %>
53
+                <p>
54
+                    ${_('page created on {date} at {time} by <b>{author}</b> ').format(date=h.date(created_localized), time=h.time(created_localized), author=result.page.owner.name)|n}
55
+                    % if result.page.revision_nb > 1:
56
+                      ${_('(last modification on {update_date} at {update_time} by {last_modification_author})').format(update_date=h.update_date(updated_localized), update_time=h.update_time(updated_localized), last_modification_author = last_modification_author)|n}
57
+                    % endif
58
+                </p>
52
             </div>
59
             </div>
53
         </div>
60
         </div>
54
     </div>
61
     </div>

+ 8 - 2
tracim/tracim/templates/thread/getone.mak 查看文件

50
 
50
 
51
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
51
             <div style="margin: -1.5em auto -1.5em auto;" class="tracim-less-visible">
52
                 <% created_localized = h.get_with_timezone(result.thread.created) %>
52
                 <% created_localized = h.get_with_timezone(result.thread.created) %>
53
-              <p>${_('page created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.thread.owner.name)|n}</p>
54
-            </div>
53
+                <% updated_localized = h.get_with_timezone(result.thread.updated) %>
54
+                <% last_modification_author = result.thread.last_modification_author.name %>
55
+                <p>${_('page created on {date} at {time} by <b>{author}</b>').format(date=h.date(created_localized), time=h.time(created_localized), author=result.thread.owner.name)|n}
56
+                    % if result.thread.revision_nb > 1:
57
+                      ${_(' (last modification on {update_date} at {update_time} by {last_modification_author})').format(update_date=h.update_date(updated_localized), update_time=h.update_time(updated_localized), last_modification_author = last_modification_author)|n}
58
+                    % endif
59
+                </p>
60
+
55
         </div>
61
         </div>
56
     </div>
62
     </div>
57
 
63