Skip to content

Commit 6f01ac8

Browse files
authored
Merge pull request joni2back#222 from xiongyihui/master
add python backend
2 parents dd42bfd + f469756 commit 6f01ac8

File tree

1 file changed

+345
-0
lines changed

1 file changed

+345
-0
lines changed

bridges/python/filemanager.py

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
"""
2+
Python backend for angular-filemanager
3+
4+
The MIT License (MIT)
5+
6+
Copyright (c) 2016 Yihui Xiong
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy of
9+
this software and associated documentation files (the "Software"), to deal in
10+
the Software without restriction, including without limitation the rights to
11+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12+
the Software, and to permit persons to whom the Software is furnished to do so,
13+
subject to the following conditions:
14+
15+
The above copyright notice and this permission notice shall be included in all
16+
copies or substantial portions of the Software.
17+
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24+
"""
25+
26+
27+
import datetime
28+
import json
29+
import os
30+
import shutil
31+
import stat
32+
import zipfile
33+
import tornado.web
34+
35+
36+
def timestamp_to_str(timestamp, format_str='%Y-%m-%d %I:%M:%S'):
37+
date = datetime.datetime.fromtimestamp(timestamp)
38+
return date.strftime(format_str)
39+
40+
41+
def filemode(mode):
42+
is_dir = 'd' if stat.S_ISDIR(mode) else '-'
43+
dic = {'7': 'rwx', '6': 'rw-', '5': 'r-x', '4': 'r--', '0': '---'}
44+
perm = str(oct(mode)[-3:])
45+
return is_dir + ''.join(dic.get(x, x) for x in perm)
46+
47+
48+
def get_file_information(path):
49+
fstat = os.stat(path)
50+
if stat.S_ISDIR(fstat.st_mode):
51+
ftype = 'dir'
52+
else:
53+
ftype = 'file'
54+
55+
fsize = fstat.st_size
56+
ftime = timestamp_to_str(fstat.st_mtime)
57+
fmode = filemode(fstat.st_mode)
58+
59+
return ftype, fsize, ftime, fmode
60+
61+
62+
def change_permissions_recursive(path, mode):
63+
for root, dirs, files in os.walk(path, topdown=False):
64+
for d in [os.path.join(root, d) for d in dirs]:
65+
os.chmod(d, mode)
66+
for f in [os.path.join(root, f) for f in files]:
67+
os.chmod(f, mode)
68+
69+
70+
class FileManager:
71+
def __init__(self, root='/', show_dotfiles=True):
72+
self.root = os.path.abspath(root)
73+
self.show_dotfiles = show_dotfiles
74+
75+
def list(self, request):
76+
path = os.path.abspath(self.root + request['path'])
77+
if not os.path.exists(path) or not path.startswith(self.root):
78+
return {'result': ''}
79+
80+
files = []
81+
for fname in sorted(os.listdir(path)):
82+
if fname.startswith('.') and not self.show_dotfiles:
83+
continue
84+
85+
fpath = os.path.join(path, fname)
86+
87+
try:
88+
ftype, fsize, ftime, fmode = get_file_information(fpath)
89+
except Exception as e:
90+
continue
91+
92+
files.append({
93+
'name': fname,
94+
'rights': fmode,
95+
'size': fsize,
96+
'date': ftime,
97+
'type': ftype,
98+
})
99+
100+
return {'result': files}
101+
102+
def rename(self, request):
103+
try:
104+
src = os.path.abspath(self.root + request['item'])
105+
dst = os.path.abspath(self.root + request['newItemPath'])
106+
print('rename {} {}'.format(src, dst))
107+
if not (os.path.exists(src) and src.startswith(self.root) and dst.startswith(self.root)):
108+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
109+
110+
shutil.move(src, dst)
111+
except Exception as e:
112+
return {'result': {'success': 'false', 'error': e.message}}
113+
114+
return {'result': {'success': 'true', 'error': ''}}
115+
116+
def copy(self, request):
117+
try:
118+
items = request['items']
119+
if len(items) == 1 and 'singleFilename' in request:
120+
src = os.path.abspath(self.root + items[0])
121+
dst = os.path.abspath(self.root + request['singleFilename'])
122+
if not (os.path.exists(src) and src.startswith(self.root) and dst.startswith(self.root)):
123+
return {'result': {'success': 'false', 'error': 'File not found'}}
124+
125+
shutil.move(src, dst)
126+
else:
127+
path = os.path.abspath(self.root + request['newPath'])
128+
for item in items:
129+
src = os.path.abspath(self.root + item)
130+
if not (os.path.exists(src) and src.startswith(self.root) and path.startswith(self.root)):
131+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
132+
133+
shutil.move(src, path)
134+
except Exception as e:
135+
return {'result': {'success': 'false', 'error': e.message}}
136+
137+
return {'result': {'success': 'true', 'error': ''}}
138+
139+
def remove(self, request):
140+
try:
141+
items = request['items']
142+
for item in items:
143+
path = os.path.abspath(self.root + item)
144+
if not (os.path.exists(path) and path.startswith(self.root)):
145+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
146+
147+
if os.path.isdir(path):
148+
shutil.rmtree(path)
149+
else:
150+
os.remove(path)
151+
except Exception as e:
152+
return {'result': {'success': 'false', 'error': e.message}}
153+
154+
return {'result': {'success': 'true', 'error': ''}}
155+
156+
def edit(self, request):
157+
try:
158+
path = os.path.abspath(self.root + request['item'])
159+
if not path.startswith(self.root):
160+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
161+
162+
content = request['content']
163+
with open(path, 'w') as f:
164+
f.write(content)
165+
except Exception as e:
166+
return {'result': {'success': 'false', 'error': e.message}}
167+
168+
return {'result': {'success': 'true', 'error': ''}}
169+
170+
def getContent(self, request):
171+
try:
172+
path = os.path.abspath(self.root + request['item'])
173+
if not path.startswith(self.root):
174+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
175+
176+
with open(path, 'r') as f:
177+
content = f.read()
178+
except Exception as e:
179+
content = e.message
180+
181+
return {'result': content}
182+
183+
def createFolder(self, request):
184+
try:
185+
path = os.path.abspath(self.root + request['newPath'])
186+
if not path.startswith(self.root):
187+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
188+
189+
os.makedirs(path)
190+
except Exception as e:
191+
return {'result': {'success': 'false', 'error': e.message}}
192+
193+
return {'result': {'success': 'true', 'error': ''}}
194+
195+
def changePermissions(self, request):
196+
try:
197+
items = request['items']
198+
permissions = int(request['perms'], 8)
199+
recursive = request['recursive']
200+
print('recursive: {}, type: {}'.format(recursive, type(recursive)))
201+
for item in items:
202+
path = os.path.abspath(self.root + item)
203+
if not (os.path.exists(path) and path.startswith(self.root)):
204+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
205+
206+
if recursive == 'true':
207+
change_permissions_recursive(path, permissions)
208+
else:
209+
os.chmod(path, permissions)
210+
except Exception as e:
211+
return {'result': {'success': 'false', 'error': e.message}}
212+
213+
return {'result': {'success': 'true', 'error': ''}}
214+
215+
def compress(self, request):
216+
try:
217+
items = request['items']
218+
path = os.path.abspath(os.path.join(self.root + request['destination'], request['compressedFilename']))
219+
if not path.startswith(self.root):
220+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
221+
222+
zip_file = zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED)
223+
for item in items:
224+
path = os.path.abspath(self.root + item)
225+
if not (os.path.exists(path) and path.startswith(self.root)):
226+
continue
227+
228+
if os.path.isfile(path):
229+
zip_file.write(path)
230+
else:
231+
for root, dirs, files in os.walk(path):
232+
for f in files:
233+
zip_file.write(
234+
f,
235+
os.path.relpath(os.path.join(root, f), os.path.join(path, '..'))
236+
)
237+
238+
zip_file.close()
239+
except Exception as e:
240+
return {'result': {'success': 'false', 'error': e.message}}
241+
242+
return {'result': {'success': 'true', 'error': ''}}
243+
244+
def extract(self, request):
245+
try:
246+
src = os.path.abspath(self.root + request['item'])
247+
dst = os.path.abspath(self.root + request['destination'])
248+
if not (os.path.isfile(src) and src.startswith(self.root) and dst.startswith(self.root)):
249+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
250+
251+
zip_file = zipfile.ZipFile(src, 'r')
252+
zip_file.extractall(dst)
253+
zip_file.close()
254+
except Exception as e:
255+
return {'result': {'success': 'false', 'error': e.message}}
256+
257+
return {'result': {'success': 'true', 'error': ''}}
258+
259+
def upload(self, handler):
260+
try:
261+
destination = handler.get_body_argument('destination', default='/')
262+
for name in handler.request.files:
263+
fileinfo = handler.request.files[name][0]
264+
filename = fileinfo['filename']
265+
path = os.path.abspath(os.path.join(self.root, destination, filename))
266+
if not path.startswith(self.root):
267+
return {'result': {'success': 'false', 'error': 'Invalid path'}}
268+
with open(path, 'wb') as f:
269+
f.write(fileinfo['body'])
270+
except Exception as e:
271+
return {'result': {'success': 'false', 'error': e.message}}
272+
273+
return {'result': {'success': 'true', 'error': ''}}
274+
275+
def download(self, path):
276+
path = os.path.abspath(self.root + path)
277+
print(path)
278+
content = ''
279+
if path.startswith(self.root) and os.path.isfile(path):
280+
print(path)
281+
try:
282+
with open(path, 'rb') as f:
283+
content = f.read()
284+
except Exception as e:
285+
pass
286+
return content
287+
288+
289+
class FileManagerHandler(tornado.web.RequestHandler):
290+
def initialize(self, root='/', show_dotfiles=True):
291+
self.filemanager = FileManager(root, show_dotfiles)
292+
293+
def get(self):
294+
action = self.get_query_argument('action', '')
295+
path = self.get_query_argument('path', '')
296+
if action == 'download' and path:
297+
result = self.filemanager.download(path)
298+
self.write(result)
299+
300+
def post(self):
301+
if self.request.headers.get('Content-Type').find('multipart/form-data') >= 0:
302+
result = self.filemanager.upload(self)
303+
self.write(json.dumps(result))
304+
else:
305+
try:
306+
request = tornado.escape.json_decode(self.request.body)
307+
if 'action' in request and hasattr(self.filemanager, request['action']):
308+
method = getattr(self.filemanager, request['action'])
309+
result = method(request)
310+
self.write(json.dumps(result))
311+
except ValueError:
312+
pass
313+
314+
315+
def main():
316+
import logging
317+
import tornado.ioloop
318+
319+
logging.basicConfig(level=logging.DEBUG)
320+
321+
handlers = [
322+
(r'/bridges/php/handler.php', FileManagerHandler, {'root': os.getcwd(), 'show_dotfiles': True}),
323+
(
324+
r'/(.*)',
325+
tornado.web.StaticFileHandler,
326+
{
327+
'path': os.path.join(os.path.dirname(__file__), '../..'),
328+
'default_filename': 'index.html'
329+
}
330+
),
331+
]
332+
333+
app = tornado.web.Application(handlers, debug=True)
334+
try:
335+
logging.debug('Open http://127.0.0.1:8000 to use the file manager')
336+
app.listen(8000)
337+
tornado.ioloop.IOLoop.instance().start()
338+
except Exception as e:
339+
print(e.message)
340+
341+
tornado.ioloop.IOLoop.instance().stop()
342+
343+
344+
if __name__ == '__main__':
345+
main()

0 commit comments

Comments
 (0)