2 # -*- coding: utf-8 -*-
4 Outil de partage de fichiers.
6 Copyright : Agence universitaire de la Francophonie — www.auf.org
7 Licence : GNU General Public Licence, version 2
8 Auteur : Jean Christophe André
9 Date de création : 26 août 2010
11 Depends: libapache2-mod-wsgi
13 Attention : le code n'est pas encore “thread-safe”...
20 ROOT_PATH
= '/srv/www/compta'
21 PAGE_TITLE
= u
'Rapport financier du BAP <em>(%s)</em>'
22 BACKGROUND_URL
= 'Bamboo2.png'
23 EXCLUDED_FILES
= [ 'description.txt' ]
24 INVALID_NAME
= u
'%s <span class="alert">(NOM INVALIDE)</span>'
26 html_template_filename
= os
.path
.abspath(__file__
.rstrip('.py') + '.tpl')
27 dir_description_filename
= 'description.txt'
29 dir_link_template
= u
"""%s<li class="dir"><a href="javascript:void(0)" onclick="sw('l%s')">%s</a> <em>(%s) <a href="%s">archive du dossier</a></em> %s</li>"""
30 dir_description_template
= u
""" <em>%s</em>"""
31 begin_content_template
= u
"""%s<div id="l%s" class="hidden"><ul>"""
32 end_content_template
= u
"""%s</ul></div>"""
33 file_link_template
= u
"""%s<li><a href="%s">%s</a> <em>(%s)</em></li>"""
36 if os
.path
.islink('.' + path
):
38 if not os
.path
.isdir('.' + path
):
43 if size
<= 1: return "%s octet" % size
44 if size
< 1024: return "%s octets" % size
46 if size
< 1024: return "%s Kio" % size
48 if size
< 1024: return "%s Mio" % size
50 if size
< 1024: return "%s Gio" % size
52 return "%s Tio" % size
54 def my_cmp(name1
, name2
):
55 m1
= re
.match('[0-9]{1,8}', name1
)
56 m2
= re
.match('[0-9]{1,8}', name2
)
58 return cmp(name1
, name2
)
62 return cmp(name1
[m1
.end():], name2
[m2
.end():])
70 names
= os
.listdir(path
)
77 if not os
.path
.islink(p
):
83 files
.sort(cmp=my_cmp
)
88 for root
, dirs
, files
in os
.walk(path
):
90 files_list
.append(os
.path
.join(root
, a_file
))
96 def dir_content(prefix
, root
, level
=0):
97 dirs
, files
= my_listdir(root
)
98 if not len(dirs
) and not len(files
):
104 path
= root
.rstrip('/') + '/' + d
105 sub_dir_content
, sub_dir_size
= dir_content(prefix
, path
, level
+ 1)
106 file_size_total
+= sub_dir_size
110 name
= d
.replace('_',' ')
112 name
= name
.decode('utf-8')
113 except UnicodeDecodeError:
114 name
= INVALID_NAME
% name
.decode('iso-8859-1')
115 desc_file
= '.' + path
+ '/' + dir_description_filename
116 if os
.path
.isfile(desc_file
):
117 desc
= file(desc_file
).read().strip().replace('\n',' ')
118 desc
= dir_description_template
% desc
.decode('utf-8')
121 archive_path
= (prefix
+ path
+ '.tar').decode('utf-8')
122 archive_size
= human_size(sub_dir_size
)
123 content
.append(dir_link_template
% \
124 (space
, id_number
, name
, archive_size
, archive_path
, desc
))
125 content
.append(begin_content_template
% (space
, id_number
))
126 content
.extend(sub_dir_content
)
127 content
.append(end_content_template
% space
)
129 path
= root
.rstrip('/') + '/' + f
130 file_size
= os
.path
.getsize('.' + path
)
131 file_size_total
+= file_size
132 if file_size
> 0 and f
not in EXCLUDED_FILES
:
133 name
= f
.replace('_',' ')
135 name
= name
.decode('utf-8')
136 except UnicodeDecodeError:
137 name
= INVALID_NAME
% name
.decode('iso-8859-1')
138 content
.append( file_link_template
% (space
,
139 urllib
.quote(prefix
+ path
), name
, human_size(file_size
)) )
140 return content
, file_size_total
147 def write(self
, data
):
148 self
._data
.append(data
)
150 return ''.join(self
._data
)
152 return sum([len(x
) for x
in self
._data
])
154 def tar_size(files
, mode
='w|', bufsize
=65536):
156 buffer = FileBuffer()
157 tar
= tarfile
.open(mode
=mode
, fileobj
=buffer, bufsize
=bufsize
)
159 tar
.add(a_file
, recursive
=False)
160 size
+= buffer.length()
163 size
+= buffer.length()
166 def tar_generator(files
, mode
='w|', bufsize
=65536):
167 buffer = FileBuffer()
168 tar
= tarfile
.open(mode
=mode
, fileobj
=buffer, bufsize
=bufsize
)
170 tar
.add(a_file
, recursive
=False)
176 def application(environ
, start_response
):
180 if False and not environ
.get('HTTP_USER'):
181 headers
= [('Content-Type', 'text/plain; charset=utf-8'), ]
182 start_response('401 Authorization Required', headers
)
183 return ['Authorization Required']
184 path
= environ
['PATH_INFO']
185 if not valid_path(os
.path
.dirname(path
)):
186 headers
= [('Content-Type', 'text/plain; charset=utf-8'), ]
187 start_response('404 Not Found', headers
)
189 if os
.path
.isfile('.' + path
):
190 if path
.endswith('.txt'):
191 mime_type
= 'text/plain; charset=utf-8'
192 elif path
.endswith('.pdf'):
193 mime_type
= 'application/pdf'
195 mime_type
= 'application/octet-stream'
196 length
= str(os
.path
.getsize('.' + path
))
197 headers
= [('Content-Type', mime_type
), ('Content-Length', length
), ]
198 start_response('200 OK', headers
)
199 return file('.' + path
)
200 if path
.endswith('.tar') and os
.path
.isdir('.' + path
[:-4]):
201 files
= find_files('.' + path
[:-4])
202 headers
= [('Content-Type', 'application/octet-stream'),
203 ('Content-Length', str(tar_size(files
)) ), ]
204 start_response('200 OK', headers
)
205 return tar_generator(files
)
206 content
, size
= dir_content(environ
['SCRIPT_NAME'], environ
['PATH_INFO'])
208 'page_title': PAGE_TITLE
% human_size(size
),
209 'background_url': BACKGROUND_URL
,
210 'content': '<ul>\n' + '\n'.join(content
) + '\n</ul>',
212 html_template
= file(html_template_filename
).read().decode('utf-8')
213 content
= (html_template
% environ
).encode('utf-8')
214 headers
= [('Content-Type', 'text/html; charset=utf-8'), ]
215 start_response('200 OK', headers
)
218 if __name__
== '__main__':
219 # this runs when script is started directly from commandline
221 # create a simple WSGI server and run the application
222 from wsgiref
import simple_server
223 print "Running test application - point your browser at http://localhost:8000/ ..."
224 httpd
= simple_server
.WSGIServer(('', 8000), simple_server
.WSGIRequestHandler
)
225 httpd
.set_app(application
)
226 httpd
.serve_forever()
228 # wsgiref not installed, just output html to stdout
229 for content
in application({}, lambda status
, headers
: None):