浏览代码

correction of some behavior and bugs

Nonolost 8 年前
父节点
当前提交
596e13361c

+ 1 - 0
.gitignore 查看文件

60
 # Site-local config file
60
 # Site-local config file
61
 development.ini
61
 development.ini
62
 track.js
62
 track.js
63
+wsgidav.conf
63
 # Temporary files
64
 # Temporary files
64
 *~
65
 *~

+ 24 - 16
install/requirements.txt 查看文件

1
-Babel==2.2.0
2
-Beaker==1.6.4
3
-CherryPy==3.6.0
4
-FormEncode==1.3.0a1
5
-Genshi==0.7
6
-Mako==1.0.3
7
-MarkupSafe==0.23
8
-PasteDeploy==1.5.2
9
-Radicale==1.1.1
10
-SQLAlchemy==1.0.11
11
-Tempita==0.5.3dev
12
-TurboGears2==2.3.7
13
-Unidecode==0.04.19
14
-WebOb==1.6.0a0
15
-WebTest==1.4.2
16
 alembic==0.8.4
1
 alembic==0.8.4
17
-argparse==1.2.1
2
+Babel==2.2.0
18
 backlash==0.0.7
3
 backlash==0.0.7
4
+Beaker==1.6.4
19
 beautifulsoup4==4.3.2
5
 beautifulsoup4==4.3.2
6
+Brlapi==0.6.2
20
 caldav==0.4.0
7
 caldav==0.4.0
8
+chardet==2.3.0
9
+CherryPy==3.6.0
21
 cliff==1.8.0
10
 cliff==1.8.0
22
 cmd2==0.6.7
11
 cmd2==0.6.7
23
 coverage==4.0b1
12
 coverage==4.0b1
24
 crank==0.7.3
13
 crank==0.7.3
25
 decorator==3.4.0
14
 decorator==3.4.0
15
+FormEncode==1.3.0a1
26
 gearbox==0.0.7
16
 gearbox==0.0.7
17
+Genshi==0.7
27
 icalendar==3.10
18
 icalendar==3.10
28
 itsdangerous==0.24
19
 itsdangerous==0.24
29
 ldap3==1.3.1
20
 ldap3==1.3.1
21
+louis==2.5.3
30
 lxml==3.6.0
22
 lxml==3.6.0
23
+Mako==1.0.3
24
+MarkupSafe==0.23
31
 nose==1.3.4
25
 nose==1.3.4
26
+PasteDeploy==1.5.2
32
 pbr==0.10.0
27
 pbr==0.10.0
33
 prettytable==0.7.2
28
 prettytable==0.7.2
34
 psycopg2==2.5.4
29
 psycopg2==2.5.4
35
 py4j==0.10.1
30
 py4j==0.10.1
36
 pyasn1==0.1.9
31
 pyasn1==0.1.9
32
+pygobject==3.14.0
37
 pyparsing==2.0.3
33
 pyparsing==2.0.3
34
+python-apt==0.9.3.12
38
 python-dateutil==2.5.3
35
 python-dateutil==2.5.3
36
+python-debian==0.1.27
39
 python-editor==1.0.1
37
 python-editor==1.0.1
40
 python-ldap-test==0.2.1
38
 python-ldap-test==0.2.1
41
 pytz==2014.7
39
 pytz==2014.7
40
+pyxdg==0.25
41
+Radicale==1.1.1
42
 repoze.lru==0.6
42
 repoze.lru==0.6
43
 repoze.who==2.2
43
 repoze.who==2.2
44
 requests==2.10.0
44
 requests==2.10.0
45
 six==1.8.0
45
 six==1.8.0
46
 speaklater==1.3
46
 speaklater==1.3
47
 sprox==0.9.4
47
 sprox==0.9.4
48
+SQLAlchemy==1.0.11
48
 stevedore==1.1.0
49
 stevedore==1.1.0
50
+Tempita==0.5.3.dev0
49
 tg.devtools==2.3.7
51
 tg.devtools==2.3.7
50
 tgapp-resetpassword==0.1.8
52
 tgapp-resetpassword==0.1.8
51
 tgext.admin==0.6.4
53
 tgext.admin==0.6.4
53
 tgext.crud==0.7.3
55
 tgext.crud==0.7.3
54
 tgext.pluggable==0.5.5
56
 tgext.pluggable==0.5.5
55
 transaction==1.4.4
57
 transaction==1.4.4
58
+TurboGears2==2.3.7
56
 tw2.core==2.2.2
59
 tw2.core==2.2.2
57
 tw2.forms==2.2.2.1
60
 tw2.forms==2.2.2.1
58
 unicode-slugify==0.1.3
61
 unicode-slugify==0.1.3
62
+Unidecode==0.4.19
63
+virtualenv==1.11.6
59
 vobject==0.9.2
64
 vobject==0.9.2
60
 waitress==0.8.9
65
 waitress==0.8.9
66
+WebOb==1.6.0a0
67
+WebTest==1.4.2
61
 who-ldap==3.1.0
68
 who-ldap==3.1.0
69
+-e git+git@github.com:mar10/wsgidav.git@e233fc4f5f23d1b5326159dfecd39990088f3fbc#egg=WsgiDAV
62
 zope.interface==4.1.3
70
 zope.interface==4.1.3
63
 zope.sqlalchemy==0.7.6
71
 zope.sqlalchemy==0.7.6

+ 2 - 0
tracim/tracim/config/app_cfg.py 查看文件

31
 from tracim.lib.base import logger
31
 from tracim.lib.base import logger
32
 from tracim.lib.daemons import DaemonsManager
32
 from tracim.lib.daemons import DaemonsManager
33
 from tracim.lib.daemons import RadicaleDaemon
33
 from tracim.lib.daemons import RadicaleDaemon
34
+from tracim.lib.daemons import WsgiDavDaemon
34
 from tracim.model.data import ActionDescription
35
 from tracim.model.data import ActionDescription
35
 from tracim.model.data import ContentType
36
 from tracim.model.data import ContentType
36
 
37
 
95
     Sart Tracim daemons
96
     Sart Tracim daemons
96
     """
97
     """
97
     manager.run('radicale', RadicaleDaemon)
98
     manager.run('radicale', RadicaleDaemon)
99
+    manager.run('webdav', WsgiDavDaemon)
98
 
100
 
99
 environment_loaded.register(lambda: start_daemons(daemons))
101
 environment_loaded.register(lambda: start_daemons(daemons))
100
 
102
 

+ 2 - 2
tracim/tracim/lib/content.py 查看文件

402
         if content_type!=ContentType.Any:
402
         if content_type!=ContentType.Any:
403
             resultset = resultset.filter(Content.type==content_type)
403
             resultset = resultset.filter(Content.type==content_type)
404
 
404
 
405
-        if parent_id:
406
-            resultset = resultset.filter(Content.parent_id==parent_id)
405
+        # todo : check utilité if parent_id:
406
+        resultset = resultset.filter(Content.parent_id==parent_id)
407
 
407
 
408
         return resultset.all()
408
         return resultset.all()
409
 
409
 

+ 42 - 20
tracim/tracim/lib/webdav/sql_resources.py 查看文件

123
 
123
 
124
     def getMember(self, content_label):
124
     def getMember(self, content_label):
125
 
125
 
126
+        if content_label=='':
127
+            return None
128
+
126
         content = self._api.get_one_by_label_and_parent(
129
         content = self._api.get_one_by_label_and_parent(
127
             content_label=content_label,
130
             content_label=content_label,
128
             workspace=self._workspace
131
             workspace=self._workspace
129
         )
132
         )
130
 
133
 
134
+        print("ok : ", content_label)
131
         return Folder(self.path + content.get_label(), self.environ, content)
135
         return Folder(self.path + content.get_label(), self.environ, content)
132
 
136
 
133
     def createEmptyResource(self, name):
137
     def createEmptyResource(self, name):
709
         if dirname(destpath).endswith('.deleted') or dirname(destpath).endswith('.archived'):
713
         if dirname(destpath).endswith('.deleted') or dirname(destpath).endswith('.archived'):
710
             if basename(dirname(dirname(destpath))) == self._content.parent.label:
714
             if basename(dirname(dirname(destpath))) == self._content.parent.label:
711
                 if dirname(destpath).endswith('.deleted'):
715
                 if dirname(destpath).endswith('.deleted'):
716
+                    if self._content.label != '':
717
+                        self._content.label += 'deleted now'
718
+                    else:
719
+                        self._content.file_name += 'deleted now'
712
                     Encapsuler(ActionDescription.DELETION, self._api, self._content).action()
720
                     Encapsuler(ActionDescription.DELETION, self._api, self._content).action()
713
                 else:
721
                 else:
714
                     Encapsuler(ActionDescription.ARCHIVING, self._api, self._content).action()
722
                     Encapsuler(ActionDescription.ARCHIVING, self._api, self._content).action()
723
+                    if self._content.label != '':
724
+                        self._content.label += 'archived now'
725
+                    else:
726
+                        self._content.file_name += 'archived now'
715
             else:
727
             else:
716
                 raise DAVError(HTTP_FORBIDDEN)
728
                 raise DAVError(HTTP_FORBIDDEN)
717
         elif (dirname(npath).endswith('.deleted') or dirname(npath).endswith('.archived')):
729
         elif (dirname(npath).endswith('.deleted') or dirname(npath).endswith('.archived')):
718
             if dirname(dirname(npath)) == dirname(destpath):
730
             if dirname(dirname(npath)) == dirname(destpath):
719
                 if dirname(npath).endswith('.deleted'):
731
                 if dirname(npath).endswith('.deleted'):
720
                     Encapsuler(ActionDescription.UNDELETION, self._api, self._content).action()
732
                     Encapsuler(ActionDescription.UNDELETION, self._api, self._content).action()
733
+                    
721
                 else:
734
                 else:
722
                     Encapsuler(ActionDescription.UNARCHIVING, self._api, self._content).action()
735
                     Encapsuler(ActionDescription.UNARCHIVING, self._api, self._content).action()
723
             else:
736
             else:
842
                 label = _LABELS[event.type.id]
855
                 label = _LABELS[event.type.id]
843
 
856
 
844
                 histHTML += '''
857
                 histHTML += '''
845
-                <tr>
858
+                <tr class="%s">
846
                     <td class="my-align"><span class="label label-default"><i class="fa %s"></i> %s</span></td>
859
                     <td class="my-align"><span class="label label-default"><i class="fa %s"></i> %s</span></td>
847
                     <td>%s</td>
860
                     <td>%s</td>
848
                     <td>%s</td>
861
                     <td>%s</td>
849
                     <td>%s</td>
862
                     <td>%s</td>
850
                 </tr>
863
                 </tr>
851
-                ''' % (event.type.icon,
864
+                ''' % ('warning' if event.id == content.revision_id else '',
865
+                       event.type.icon,
852
                        label,
866
                        label,
853
                        date,
867
                        date,
854
                        event.owner.display_name,
868
                        event.owner.display_name,
855
-                       '''<span><a href="#">View revision</a></span>''' if event.type.id == 'revision' else '')
869
+                       '<i class="fa fa-caret-left"></i> shown' if event.id == content.revision_id else '''<span><a class="revision-link" href="/.history/%s/%s-%s">(View revision)</a></span>''' % (self._content.label, event.id, event.ref_object.label) if event.type.id == 'revision' else '')
856
 
870
 
857
         histHTML+='</table>'
871
         histHTML+='</table>'
858
 
872
 
859
-        #pdf = pdfkit.from_string(self._content.description, False)
860
-
861
         file = '''
873
         file = '''
862
 <html>
874
 <html>
863
 <head>
875
 <head>
877
             </div>
889
             </div>
878
             <div class="pull-right">
890
             <div class="pull-right">
879
                 <div class="btn-group btn-group-vertical">
891
                 <div class="btn-group btn-group-vertical">
880
-                    <a class="btn btn-default" onclick="download_pdf()">
881
-                        <i class="fa fa-download"></i> Download as pdf</a>
882
-                    </a>
883
                     <a class="btn btn-default">
892
                     <a class="btn btn-default">
884
-                        <i class="fa fa-external-link"></i> Access webdav</a>
893
+                        <i class="fa fa-external-link"></i> View in tracim</a>
885
                     </a>
894
                     </a>
886
                 </div>
895
                 </div>
887
             </div>
896
             </div>
894
         <h4>History</h4>
903
         <h4>History</h4>
895
         %s
904
         %s
896
     </div>
905
     </div>
897
-    <script>
898
-        function download_pdf() {
899
-            download("%s", "%s.pdf", "application/pdf")
906
+    <script type="text/javascript">
907
+        window.onload = function() {
908
+            elems = document.getElementsByClassName('revision-link');
909
+            for(var i = 0; i<elems.length; i++) {
910
+                test = window.location.href
911
+                test += "/.." + elems[i].href.replace(/file:\/\//, "")
912
+                elems[i].href = test
913
+            }
900
         }
914
         }
901
     </script>
915
     </script>
902
 </body>
916
 </body>
906
                self._content.created.strftime("%B %d, %Y at %H:%m"),
920
                self._content.created.strftime("%B %d, %Y at %H:%m"),
907
                self._content.owner.display_name,
921
                self._content.owner.display_name,
908
                content.description,
922
                content.description,
909
-               histHTML,
910
-               "Meh.",
911
-               self._content.label)
923
+               histHTML)
912
 
924
 
913
         return file
925
         return file
914
 
926
 
976
                            t.owner.display_name,
988
                            t.owner.display_name,
977
                            create_readable_date(t.created),
989
                            create_readable_date(t.created),
978
                            label,
990
                            label,
979
-                           '''<span><a href="#">(View revision)</a></span>''' if t.type.id == 'revision' else '')
991
+                           '''<span><a class="revision-link" href="/.history/%s/%s-%s">(View revision)</a></span>''' % (
992
+                               self._content.label,
993
+                               t.id,
994
+                               t.ref_object.label) if t.type.id == 'revision' else '')
980
 
995
 
981
         descP = ''
996
         descP = ''
982
         for name, infos in participants.items():
997
         for name, infos in participants.items():
1006
             </div>
1021
             </div>
1007
             <div class="pull-right">
1022
             <div class="pull-right">
1008
                 <div class="btn-group btn-group-vertical">
1023
                 <div class="btn-group btn-group-vertical">
1009
-                    <a class="btn btn-default" onclick="download_pdf()">
1010
-                        <i class="fa fa-download"></i> Download as pdf</a>
1011
-                    </a>
1012
                     <a class="btn btn-default">
1024
                     <a class="btn btn-default">
1013
-                        <i class="fa fa-external-link"></i> Access webdav</a>
1025
+                        <i class="fa fa-external-link"></i> View in tracim</a>
1014
                     </a>
1026
                     </a>
1015
                 </div>
1027
                 </div>
1016
             </div>
1028
             </div>
1026
         <h4>Participants</h4>
1038
         <h4>Participants</h4>
1027
         %s
1039
         %s
1028
     </div>
1040
     </div>
1041
+    <script type="text/javascript">
1042
+        window.onload = function() {
1043
+            elems = document.getElementsByClassName('revision-link');
1044
+            for(var i = 0; i<elems.length; i++) {
1045
+                test = window.location.href
1046
+                test += "/.." + elems[i].href.replace(/file:\/\//, "")
1047
+                elems[i].href = test
1048
+            }
1049
+        }
1050
+    </script>
1029
 </body>
1051
 </body>
1030
 </html>
1052
 </html>
1031
         ''' % (content.label,
1053
         ''' % (content.label,

+ 2 - 1
tracim/tracim/model/data.py 查看文件

1203
 
1203
 
1204
         label = content.get_label()
1204
         label = content.get_label()
1205
         if content.type==ContentType.Comment:
1205
         if content.type==ContentType.Comment:
1206
-            label = _('<strong>{}</strong> wrote:').format(content.owner.get_display_name())
1206
+            # todo :voir le _('.... si le _ est utile
1207
+            label = ('<strong>{}</strong> wrote:').format(content.owner.get_display_name())
1207
 
1208
 
1208
         return VirtualEvent(id=content.content_id,
1209
         return VirtualEvent(id=content.content_id,
1209
                             created=content.created,
1210
                             created=content.created,

+ 184 - 0
tracim/wsgidav.conf.sample 查看文件

1
+################################################################################
2
+# Sample WsgiDAV configuration file
3
+# 
4
+# 1. Rename this file to `wsgidav.conf`
5
+# 2. Adjust settings as appropriate
6
+# 3. Run `wsgidav` fro, the same directory.
7
+#
8
+# See
9
+#     doc/annotated_wsgidav.conf
10
+# for a complete, annotated configuration example.
11
+#
12
+################################################################################
13
+
14
+# HELPERS - Do not modify this section
15
+
16
+provider_mapping = {}
17
+user_mapping = {}
18
+
19
+def addShare(shareName, davProvider):
20
+    provider_mapping[shareName] = davProvider
21
+
22
+    
23
+def addUser(realmName, user, password, description, roles=[]):
24
+    realmName = "/" + realmName.strip(r"\/")
25
+    userDict = user_mapping.setdefault(realmName, {}).setdefault(user, {})
26
+    userDict["password"] = password
27
+    userDict["description"] = description
28
+    userDict["roles"] = roles
29
+
30
+        
31
+################################################################################
32
+# SERVER OPTIONS
33
+#===============================================================================
34
+
35
+# host  = "localhost"
36
+# host  = "192.168.0.1"
37
+host  = "0.0.0.0"
38
+
39
+port = 8080
40
+
41
+#===============================================================================
42
+# Enable SSL support
43
+# (The certificate should match the servers hostname, so the bogus certs will not
44
+# work in all scenarios.)
45
+
46
+# ssl_certificate = "wsgidav/server/sample_bogo_server.crt"
47
+# ssl_private_key = "wsgidav/server/sample_bogo_server.key"
48
+# ssl_certificate_chain = None
49
+
50
+
51
+# Add the MS-Author-Via Response Header to OPTIONS command to allow editing
52
+# with Microsoft Office (default: True)
53
+add_header_MS_Author_Via = True	
54
+
55
+#================================================================================
56
+# Misc. setings
57
+#
58
+
59
+# Block size in bytes
60
+#block_size = 8192
61
+
62
+#===============================================================================
63
+# Middlewares
64
+# 
65
+# Use this section to modify the default middleware stack
66
+
67
+#from wsgidav.dir_browser import WsgiDavDirBrowser
68
+#from debug_filter import WsgiDavDebugFilter
69
+#from http_authenticator import HTTPAuthenticator
70
+#from error_printer import ErrorPrinter
71
+#middleware_stack = [ WsgiDavDirBrowser, HTTPAuthenticator, ErrorPrinter, WsgiDavDebugFilter ]
72
+
73
+#===============================================================================
74
+# Debugging
75
+
76
+# verbose = 3
77
+
78
+# Enable specific module loggers
79
+# E.g. ["lock_manager", "property_manager", "http_authenticator", ...]
80
+# enable_loggers = ["http_authenticator", ]
81
+
82
+# Enable max. logging for certain http methods
83
+# E.g. ["COPY", "DELETE", "GET", "HEAD", "LOCK", "MOVE", "OPTIONS", "PROPFIND", "PROPPATCH", "PUT", "UNLOCK"]
84
+debug_methods = []
85
+
86
+# Enable max. logging during  litmus suite tests that contain certain strings
87
+# E.g. ["lock_excl", "notowner_modify", "fail_cond_put_unlocked", ...]
88
+debug_litmus = []
89
+
90
+
91
+################################################################################
92
+# WsgiDavDirBrowser
93
+
94
+dir_browser = {
95
+    "enable": True,          # Render HTML listing for GET requests on collections
96
+    "response_trailer": "",  # Raw HTML code, appended as footer
97
+    "davmount": True,        # Send <dm:mount> response if request URL contains '?davmount'
98
+    "ms_mount": True,        # Add an 'open as webfolder' link (requires Windows)
99
+    "ms_sharepoint_plugin": True, # Invoke MS Offce documents for editing using WebDAV
100
+    "ms_sharepoint_urls": False,  # Prepend 'ms-word:ofe|u|' to URL for MS Offce documents
101
+}
102
+
103
+
104
+################################################################################
105
+# DAV Provider
106
+
107
+#===============================================================================
108
+# Property Manager
109
+
110
+# Example: Use PERSISTENT shelve based property manager
111
+#from wsgidav.property_manager import ShelvePropertyManager
112
+#propsmanager = ShelvePropertyManager("wsgidav-props.shelve")
113
+
114
+### Use in-memory property manager (NOT persistent)
115
+propsmanager = True
116
+
117
+
118
+### Optional additional live property modification
119
+# Enable to allow clients to use e.g. the touch or cp / rsync commands with the
120
+# preserve-timestamp flags in a mounted DAV share (may be RFC4918 incompliant)
121
+#mutable_live_props = ["{DAV:}getlastmodified"]
122
+
123
+
124
+#===============================================================================
125
+# Lock Manager
126
+#
127
+# Example: Use PERSISTENT shelve based lock manager
128
+#from wsgidav.lock_storage import LockStorageShelve
129
+#locksmanager = LockStorageShelve("wsgidav-locks.shelve")
130
+
131
+
132
+#===============================================================================
133
+# SHARES
134
+
135
+addShare("", r"~/davshare")
136
+
137
+
138
+################################################################################
139
+# AUTHENTICATION
140
+#===============================================================================
141
+# HTTP Authentication Options
142
+
143
+acceptbasic = True    # Allow basic authentication, True or False
144
+acceptdigest = True   # Allow digest authentication, True or False
145
+defaultdigest = True  # True (default digest) or False (default basic)
146
+
147
+
148
+#domaincontroller =   # Uncomment this line to specify your own domain controller
149
+                      # Default: wsgidav.domain_controller, which uses the USERS 
150
+                      #          section below
151
+
152
+
153
+# Example: use a domain controller that allows users to authenticate against 
154
+#          a Windows NT domain or a local computer.
155
+#          Note: NTDomainController requires basic authentication:
156
+#                Set acceptbasic=True, acceptdigest=False, defaultdigest=False 
157
+
158
+# from wsgidav.addons.nt_domain_controller import NTDomainController
159
+# domaincontroller = NTDomainController(presetdomain=None, presetserver=None)
160
+# acceptbasic = True
161
+# acceptdigest = False
162
+# defaultdigest = False
163
+
164
+
165
+#===============================================================================
166
+# USERS
167
+#
168
+# This section is ONLY used by the DEFAULT Domain Controller.
169
+#
170
+# Users are defined per realm: 
171
+#     addUser(<realm>, <user>, <password>, <description>)  
172
+#
173
+# Note that the default Domain Controller uses the share name as realm name.   
174
+# 
175
+# If no users are specified for a realm, no authentication is required.
176
+# Thus granting read-write access to anonymous! 
177
+#
178
+# Note: If you wish to use Windows WebDAV support (such as Windows XP's My 
179
+# Network Places), you need to include the domain of the user as part of the 
180
+# username (note the DOUBLE slash), such as:
181
+# addUser("v_root", "domain\\user", "password", "description")
182
+
183
+addUser("", "tester", "secret", "")
184
+#addUser("", "tester2", "secret2", "")