|  | @@ -6,7 +6,7 @@ import transaction
 | 
	
		
			
			| 6 | 6 |  from os.path import normpath, dirname, basename
 | 
	
		
			
			| 7 | 7 |  from tracim.lib.content import ContentApi
 | 
	
		
			
			| 8 | 8 |  from tracim.lib.webdav import HistoryType
 | 
	
		
			
			| 9 |  | -from tracim.lib.webdav import MyFileStream, MyFileStream2
 | 
	
		
			
			|  | 9 | +from tracim.lib.webdav import FileStream
 | 
	
		
			
			| 10 | 10 |  from tracim.lib.user import UserApi
 | 
	
		
			
			| 11 | 11 |  from tracim.lib.workspace import WorkspaceApi
 | 
	
		
			
			| 12 | 12 |  from wsgidav import compat
 | 
	
	
		
			
			|  | @@ -26,28 +26,6 @@ _CONTENTS = {
 | 
	
		
			
			| 26 | 26 |      ContentType.Thread: OtherFile
 | 
	
		
			
			| 27 | 27 |  }
 | 
	
		
			
			| 28 | 28 |  
 | 
	
		
			
			| 29 |  | -def create_readable_date(some_date):
 | 
	
		
			
			| 30 |  | -    aff = ''
 | 
	
		
			
			| 31 |  | -
 | 
	
		
			
			| 32 |  | -    delta = datetime.now() - some_date
 | 
	
		
			
			| 33 |  | -
 | 
	
		
			
			| 34 |  | -    if delta.days > 0:
 | 
	
		
			
			| 35 |  | -        if delta.days >= 365:
 | 
	
		
			
			| 36 |  | -            aff = '%d year%s ago' % (delta.days/365, 's' if delta.days/365>=2 else '')
 | 
	
		
			
			| 37 |  | -        elif delta.days >= 30:
 | 
	
		
			
			| 38 |  | -            aff = '%d month%s ago' % (delta.days/30, 's' if delta.days/30>=2 else '')
 | 
	
		
			
			| 39 |  | -        else:
 | 
	
		
			
			| 40 |  | -            aff = '%d day%s ago' % (delta.days, 's' if delta.days>=2 else '')
 | 
	
		
			
			| 41 |  | -    else:
 | 
	
		
			
			| 42 |  | -        if delta.seconds < 60:
 | 
	
		
			
			| 43 |  | -            aff = '%d second%s ago' % (delta.seconds, 's' if delta.seconds>1 else '')
 | 
	
		
			
			| 44 |  | -        elif delta.seconds/60 < 60:
 | 
	
		
			
			| 45 |  | -            aff = '%d minute%s ago' % (delta.seconds/60, 's' if delta.seconds/60>=2 else '')
 | 
	
		
			
			| 46 |  | -        else:
 | 
	
		
			
			| 47 |  | -            aff = '%d hour%s ago' % (delta.seconds/3600, 's' if delta.seconds/3600>=2 else '')
 | 
	
		
			
			| 48 |  | -
 | 
	
		
			
			| 49 |  | -    return aff
 | 
	
		
			
			| 50 |  | -
 | 
	
		
			
			| 51 | 29 |  class Encapsuler(object):
 | 
	
		
			
			| 52 | 30 |      def __init__(self, type: str, api: ContentApi, content: Content):
 | 
	
		
			
			| 53 | 31 |          self._api = api
 | 
	
	
		
			
			|  | @@ -69,31 +47,6 @@ class Encapsuler(object):
 | 
	
		
			
			| 69 | 47 |  
 | 
	
		
			
			| 70 | 48 |          transaction.commit()
 | 
	
		
			
			| 71 | 49 |  
 | 
	
		
			
			| 72 |  | -class DummyResource(object):
 | 
	
		
			
			| 73 |  | -    def __init__(self, file_name: str, content: Content, content_api: ContentApi):
 | 
	
		
			
			| 74 |  | -        self._file_name = file_name
 | 
	
		
			
			| 75 |  | -        self._content = content
 | 
	
		
			
			| 76 |  | -        self._api = content_api
 | 
	
		
			
			| 77 |  | -
 | 
	
		
			
			| 78 |  | -    def beginWrite(self, contentType) -> MyFileStream2:
 | 
	
		
			
			| 79 |  | -        return MyFileStream2(file_name=self._file_name, content=self._content, content_api=self._api)
 | 
	
		
			
			| 80 |  | -
 | 
	
		
			
			| 81 |  | -    def endWrite(self, withErrors):
 | 
	
		
			
			| 82 |  | -        pass
 | 
	
		
			
			| 83 |  | -
 | 
	
		
			
			| 84 |  | -
 | 
	
		
			
			| 85 |  | -class DummyResource2(object):
 | 
	
		
			
			| 86 |  | -    def __init__(self, content: Content, content_api: ContentApi, file_name: str=''):
 | 
	
		
			
			| 87 |  | -        self._content = content
 | 
	
		
			
			| 88 |  | -        self._api = content_api
 | 
	
		
			
			| 89 |  | -        self._file_name = file_name
 | 
	
		
			
			| 90 |  | -
 | 
	
		
			
			| 91 |  | -    def beginWrite(self, contentType) -> MyFileStream:
 | 
	
		
			
			| 92 |  | -        return MyFileStream(content=self._content, content_api=self._api, file_name=self._file_name)
 | 
	
		
			
			| 93 |  | -
 | 
	
		
			
			| 94 |  | -    def endWrite(self, withErrors: bool):
 | 
	
		
			
			| 95 |  | -        pass
 | 
	
		
			
			| 96 |  | -
 | 
	
		
			
			| 97 | 50 |  
 | 
	
		
			
			| 98 | 51 |  class Root(DAVCollection):
 | 
	
		
			
			| 99 | 52 |      def __init__(self, path: str, environ: dict):
 | 
	
	
		
			
			|  | @@ -304,8 +257,13 @@ class Folder(DAVCollection):
 | 
	
		
			
			| 304 | 257 |              environ=self.environ
 | 
	
		
			
			| 305 | 258 |              )
 | 
	
		
			
			| 306 | 259 |  
 | 
	
		
			
			| 307 |  | -    def createEmptyResource(self, file_name: str) -> DummyResource:
 | 
	
		
			
			| 308 |  | -        return DummyResource(file_name=file_name, content=self._content, content_api=self._api)
 | 
	
		
			
			|  | 260 | +    def createEmptyResource(self, file_name: str) -> FileStream:
 | 
	
		
			
			|  | 261 | +        return FileStream(
 | 
	
		
			
			|  | 262 | +            file_name=file_name,
 | 
	
		
			
			|  | 263 | +            content=self._content,
 | 
	
		
			
			|  | 264 | +            content_api=self._api,
 | 
	
		
			
			|  | 265 | +            new_file=True
 | 
	
		
			
			|  | 266 | +            )
 | 
	
		
			
			| 309 | 267 |  
 | 
	
		
			
			| 310 | 268 |      def createCollection(self, label: str) -> Folder:
 | 
	
		
			
			| 311 | 269 |  
 | 
	
	
		
			
			|  | @@ -687,11 +645,17 @@ class HistoryFileFolder(HistoryFolder):
 | 
	
		
			
			| 687 | 645 |      def createCollection(self, name):
 | 
	
		
			
			| 688 | 646 |          raise DAVError(HTTP_FORBIDDEN)
 | 
	
		
			
			| 689 | 647 |  
 | 
	
		
			
			| 690 |  | -    def createEmptyResource(self, name) -> DummyResource2:
 | 
	
		
			
			| 691 |  | -        return DummyResource2(content=self._content, content_api=self._api, file_name=name)
 | 
	
		
			
			|  | 648 | +    def createEmptyResource(self, name) -> FileStream:
 | 
	
		
			
			|  | 649 | +        return FileStream(
 | 
	
		
			
			|  | 650 | +            content=self._content,
 | 
	
		
			
			|  | 651 | +            content_api=self._api,
 | 
	
		
			
			|  | 652 | +            file_name=name,
 | 
	
		
			
			|  | 653 | +            new_file=False
 | 
	
		
			
			|  | 654 | +            )
 | 
	
		
			
			| 692 | 655 |  
 | 
	
		
			
			| 693 | 656 |      def getMemberNames(self) -> [str]:
 | 
	
		
			
			| 694 |  | -        return [content.revision_id for content in self._content.revisions]
 | 
	
		
			
			|  | 657 | +        return [content.revision_id for content in self._content.revisions \
 | 
	
		
			
			|  | 658 | +                if content.revision_type in [ActionDescription.CREATION, ActionDescription.EDITION, ActionDescription.REVISION]]
 | 
	
		
			
			| 695 | 659 |  
 | 
	
		
			
			| 696 | 660 |      def getMember(self, item_id) -> DAVCollection:
 | 
	
		
			
			| 697 | 661 |  
 | 
	
	
		
			
			|  | @@ -883,7 +847,7 @@ class OtherFile(File):
 | 
	
		
			
			| 883 | 847 |          histHTML = '<table class="table table-striped table-hover">'
 | 
	
		
			
			| 884 | 848 |          for event in hist:
 | 
	
		
			
			| 885 | 849 |              if isinstance(event, VirtualEvent):
 | 
	
		
			
			| 886 |  | -                date = create_readable_date(event.created)
 | 
	
		
			
			|  | 850 | +                date = event.create_readable_date()
 | 
	
		
			
			| 887 | 851 |                  _LABELS = {
 | 
	
		
			
			| 888 | 852 |                      'archiving': 'Item archived',
 | 
	
		
			
			| 889 | 853 |                      'content-comment': 'Item commented',
 | 
	
	
		
			
			|  | @@ -995,7 +959,7 @@ class OtherFile(File):
 | 
	
		
			
			| 995 | 959 |                              %s
 | 
	
		
			
			| 996 | 960 |                          </div>
 | 
	
		
			
			| 997 | 961 |                      </div>
 | 
	
		
			
			| 998 |  | -                    ''' % (t.owner.display_name, create_readable_date(t.created), t.description)
 | 
	
		
			
			|  | 962 | +                    ''' % (t.owner.display_name, t.create_readable_date(), t.description)
 | 
	
		
			
			| 999 | 963 |  
 | 
	
		
			
			| 1000 | 964 |                  if t.owner.display_name not in participants:
 | 
	
		
			
			| 1001 | 965 |                      participants[t.owner.display_name] = [1, t.created]
 | 
	
	
		
			
			|  | @@ -1032,19 +996,10 @@ class OtherFile(File):
 | 
	
		
			
			| 1032 | 996 |                      </div>
 | 
	
		
			
			| 1033 | 997 |                      ''' % (t.type.icon,
 | 
	
		
			
			| 1034 | 998 |                             t.owner.display_name,
 | 
	
		
			
			| 1035 |  | -                           create_readable_date(t.created),
 | 
	
		
			
			|  | 999 | +                           t.create_readable_date(),
 | 
	
		
			
			| 1036 | 1000 |                             label,
 | 
	
		
			
			| 1037 | 1001 |                             '''<span><a href="#">(View revision)</a></span>''' if t.type.id == 'revision' else '')
 | 
	
		
			
			| 1038 | 1002 |  
 | 
	
		
			
			| 1039 |  | -        descP = ''
 | 
	
		
			
			| 1040 |  | -        for name, infos in participants.items():
 | 
	
		
			
			| 1041 |  | -            descP = '''
 | 
	
		
			
			| 1042 |  | -            <div><b>%s</b> - %d message%s - last %s</div>
 | 
	
		
			
			| 1043 |  | -            ''' % (name,
 | 
	
		
			
			| 1044 |  | -                 infos[0],
 | 
	
		
			
			| 1045 |  | -                 's' if infos[0]>1 else '',
 | 
	
		
			
			| 1046 |  | -                   create_readable_date(infos[1]))
 | 
	
		
			
			| 1047 |  | -
 | 
	
		
			
			| 1048 | 1003 |          page = '''
 | 
	
		
			
			| 1049 | 1004 |  <html>
 | 
	
		
			
			| 1050 | 1005 |  <head>
 | 
	
	
		
			
			|  | @@ -1055,7 +1010,7 @@ class OtherFile(File):
 | 
	
		
			
			| 1055 | 1010 |  	<script type="text/javascript" src="/home/arnaud/Documents/css/script.js"></script>
 | 
	
		
			
			| 1056 | 1011 |  </head>
 | 
	
		
			
			| 1057 | 1012 |  <body>
 | 
	
		
			
			| 1058 |  | -    <div id="left" class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
 | 
	
		
			
			|  | 1013 | +    <div id="left" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
 | 
	
		
			
			| 1059 | 1014 |          <div class="title thread">
 | 
	
		
			
			| 1060 | 1015 |              <div class="title-text">
 | 
	
		
			
			| 1061 | 1016 |                  <i class="fa fa-comments-o title-icon thread"></i>
 | 
	
	
		
			
			|  | @@ -1080,10 +1035,6 @@ class OtherFile(File):
 | 
	
		
			
			| 1080 | 1035 |              %s
 | 
	
		
			
			| 1081 | 1036 |          </div>
 | 
	
		
			
			| 1082 | 1037 |      </div>
 | 
	
		
			
			| 1083 |  | -    <div id="right" class="col-lg-4 col-md-12 col-sm-12 col-xs-12">
 | 
	
		
			
			| 1084 |  | -        <h4>Participants</h4>
 | 
	
		
			
			| 1085 |  | -        %s
 | 
	
		
			
			| 1086 |  | -    </div>
 | 
	
		
			
			| 1087 | 1038 |  </body>
 | 
	
		
			
			| 1088 | 1039 |  </html>
 | 
	
		
			
			| 1089 | 1040 |          ''' % (content.label,
 | 
	
	
		
			
			|  | @@ -1091,8 +1042,7 @@ class OtherFile(File):
 | 
	
		
			
			| 1091 | 1042 |                 self._content.created.strftime("%B %d, %Y at %H:%m"),
 | 
	
		
			
			| 1092 | 1043 |                 self._content.owner.display_name,
 | 
	
		
			
			| 1093 | 1044 |                 content.description,
 | 
	
		
			
			| 1094 |  | -               disc,
 | 
	
		
			
			| 1095 |  | -               descP)
 | 
	
		
			
			|  | 1045 | +               disc)
 | 
	
		
			
			| 1096 | 1046 |  
 | 
	
		
			
			| 1097 | 1047 |          return page
 | 
	
		
			
			| 1098 | 1048 |  
 |