summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-05-11 20:09:27 +0200
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-05-11 20:09:27 +0200
commit6534294c48df5cb89cfff278e4040c0b8f718659 (patch)
tree370e7b9e5f9d4d331c55a713396dee47672a67eb
parentfix cli (diff)
downloadpyload-6534294c48df5cb89cfff278e4040c0b8f718659.tar.xz
whites filemanager
-rw-r--r--module/database/UserDatabase.py1
-rw-r--r--module/web/json_app.py126
-rw-r--r--module/web/media/default/css/window.css21
-rw-r--r--module/web/media/default/img/add_folder.pngbin0 -> 571 bytes
-rw-r--r--module/web/pyload_app.py98
-rw-r--r--module/web/templates/default/admin.html4
-rw-r--r--module/web/templates/default/base.html28
-rw-r--r--module/web/templates/default/collector.html28
-rw-r--r--module/web/templates/default/downloads.html21
-rw-r--r--module/web/templates/default/filemanager.html80
-rw-r--r--module/web/templates/default/filemanager_ui.js296
-rw-r--r--module/web/templates/default/folder.html15
-rw-r--r--module/web/templates/default/home.html24
-rw-r--r--module/web/templates/default/info.html7
-rw-r--r--module/web/templates/default/logs.html20
-rw-r--r--module/web/templates/default/queue.html30
-rw-r--r--module/web/templates/default/rename_directory.html28
-rw-r--r--module/web/templates/default/settings.html25
-rw-r--r--module/web/utils.py4
19 files changed, 716 insertions, 140 deletions
diff --git a/module/database/UserDatabase.py b/module/database/UserDatabase.py
index 4367b1292..11bdbabc0 100644
--- a/module/database/UserDatabase.py
+++ b/module/database/UserDatabase.py
@@ -29,6 +29,7 @@ class PERMS:
SEE_DOWNLOADS = 16 # see queue and collector
DOWNLOAD = 32 # can download from webinterface
SETTINGS = 64 # can access settings
+ FILEMANAGER = 128 # can manage files and folders trough webinterface
class ROLE:
ADMIN = 0 #admin has all permissions implicit
diff --git a/module/web/json_app.py b/module/web/json_app.py
index df58238ec..5b3b9f1fd 100644
--- a/module/web/json_app.py
+++ b/module/web/json_app.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
import base64
-from os.path import join
+#from os.path import join, exists
from traceback import print_exc
from shutil import copyfileobj
@@ -14,6 +14,10 @@ from utils import login_required, render_to_response
from module.utils import decode
+import os
+import shutil
+import os.path
+
def format_time(seconds):
seconds = int(seconds)
@@ -384,3 +388,123 @@ def update_accounts():
elif action == "delete" and value:
PYLOAD.remove_account(plugin, user)
+@route("/json/filemanager/rename", method="POST")
+@login_required('filemanager')
+def rename_dir():
+ try:
+ path = request.forms.get("path").decode("utf8", "ignore")
+ old_name = path + "/" + request.forms.get("old_name").decode("utf8", "ignore")
+ new_name = path + "/" + request.forms.get("new_name").decode("utf8", "ignore")
+
+ try:
+ #check if file exists
+ os.rename(old_name, new_name);
+ except Exception as (errno, strerror):
+ return { "response": "fail", "error" : strerror + "\n" + old_name + " => " + new_name }
+
+ return {"response" : "success"}
+
+ except:
+ return HTTPError()
+
+@route("/json/filemanager/delete", method="POST")
+@login_required('filemanager')
+def rename_dir():
+ try:
+
+ try:
+ path = request.forms.get("path").decode("utf8", "ignore")
+ name = request.forms.get("name").decode("utf8", "ignore")
+
+ shutil.rmtree(path + "/" + name)
+ except Exception as (errno, strerror):
+ return { "response": "fail", "error": strerror + "\n" + path + "/" + name }
+
+ return {"response" : "success"}
+
+ except:
+ return HTTPError()
+
+@route("/json/filemanager/mkdir", method="POST")
+@login_required('filemanager')
+def make_dir():
+ try:
+ path = request.forms.get("path").decode("utf8", "ignore")
+ name = request.forms.get("name").decode("utf8", "ignore")
+ try:
+ #i = 1
+ #full_name = path + "/" + name
+ #while os.path.exists(full_name)
+ # full_name = full_name + i
+ # i = i + 1
+ #
+ #os.mkdir(full_name)
+
+ os.mkdir(path + "/" + name)
+ except Exception as (errno, strerror):
+ return { "response": "fail", "error": strerror + "\nUnable to create directory: " + path + "/" + name }
+
+ return {"response" : "success", "path": path, "name": name}
+
+ except:
+ return HTTPError()
+@route("/json/filemanager/rename", method="POST")
+@login_required('filemanager')
+def rename_dir():
+ try:
+ path = request.forms.get("path").decode("utf8", "ignore")
+ old_name = path + "/" + request.forms.get("old_name").decode("utf8", "ignore")
+ new_name = path + "/" + request.forms.get("new_name").decode("utf8", "ignore")
+
+ try:
+ #check if file exists
+ os.rename(old_name, new_name);
+ except Exception as (errno, strerror):
+ return { "response": "fail", "error" : strerror + "\n" + old_name + " => " + new_name }
+
+ return {"response" : "success"}
+
+ except:
+ return HTTPError()
+
+@route("/json/filemanager/delete", method="POST")
+@login_required('filemanager')
+def rename_dir():
+ try:
+
+ try:
+ path = request.forms.get("path").decode("utf8", "ignore")
+ name = request.forms.get("name").decode("utf8", "ignore")
+
+ shutil.rmtree(path + "/" + name)
+ except Exception as (errno, strerror):
+ return { "response": "fail", "error": strerror + "\n" + path + "/" + name }
+
+ return {"response" : "success"}
+
+ except:
+ return HTTPError()
+
+@route("/json/filemanager/mkdir", method="POST")
+@login_required('filemanager')
+def make_dir():
+ try:
+ path = request.forms.get("path").decode("utf8", "ignore")
+ name = request.forms.get("name").decode("utf8", "ignore")
+ try:
+ #i = 1
+ #full_name = path + "/" + name
+ #while os.path.exists(full_name)
+ # full_name = full_name + i
+ # i = i + 1
+ #
+ #os.mkdir(full_name)
+
+ os.mkdir(path + "/" + name)
+ except Exception as (errno, strerror):
+ return { "response": "fail", "error": strerror + "\nUnable to create directory: " + path + "/" + name }
+
+ return {"response" : "success", "path": path, "name": name}
+
+ except:
+ return HTTPError() \ No newline at end of file
diff --git a/module/web/media/default/css/window.css b/module/web/media/default/css/window.css
index a2f2dcef5..6841c5315 100644
--- a/module/web/media/default/css/window.css
+++ b/module/web/media/default/css/window.css
@@ -86,4 +86,23 @@
.styled_button {
margin-left: 15px;
-} \ No newline at end of file
+}
+#directories-list {
+ padding-left:5px;
+ margin-top:-30px;
+}
+#directories-list ul {
+ padding-left:0px;
+ margin-left:0;
+}
+
+#directories-list li {
+ list-style:none;
+}
+
+#directories-list li.folder { background:url(../img/folder.png) no-repeat top left; padding-left:22px;}
+#directories-list li.file { background:url(../img/images.png) no-repeat top left; padding-left:22px;}
+
+#directories-list li.folder span { cursor:pointer; }
+
+/*#directories-list li span input { width:200px; float:left; }*/
diff --git a/module/web/media/default/img/add_folder.png b/module/web/media/default/img/add_folder.png
new file mode 100644
index 000000000..8acbc411b
--- /dev/null
+++ b/module/web/media/default/img/add_folder.png
Binary files differ
diff --git a/module/web/pyload_app.py b/module/web/pyload_app.py
index fc2302809..693d08d06 100644
--- a/module/web/pyload_app.py
+++ b/module/web/pyload_app.py
@@ -20,12 +20,11 @@ from copy import deepcopy
from datetime import datetime
from operator import itemgetter
-
import time
import os
import sys
from os import listdir
-from os.path import isdir, isfile, join ,abspath
+from os.path import isdir, isfile, join, abspath
from sys import getfilesystemencoding
from hashlib import sha1
from urllib import unquote
@@ -54,7 +53,8 @@ def pre_processor():
return {"user": user,
'status': status,
'captcha': captcha,
- 'perms': perms}
+ 'perms': perms,
+ 'url': request.url}
def get_sort_key(item):
@@ -68,11 +68,10 @@ def base(messages):
## Views
@error(500)
def error500(error):
-
print "An error occured while processing the request."
if error.traceback:
print error.traceback
-
+
return base(["An Error occured, please enable debug mode to get more details.", error,
error.traceback.replace("\n", "<br>") if error.traceback else "No Traceback"])
@@ -84,10 +83,12 @@ def server_static(path):
response.headers['Cache-control'] = "public"
return static_file(path, root=join(PROJECT_DIR, "media"))
+
@route('/favicon.ico')
def favicon():
return static_file("favicon.ico", root=join(PROJECT_DIR, "media", "img"))
+
@route('/login', method="GET")
def login():
if not PYLOAD and SETUP:
@@ -95,10 +96,12 @@ def login():
else:
return render_to_response("login.html", proc=[pre_processor])
+
@route('/nopermission')
def nopermission():
return base([_("You dont have permission to access this page.")])
+
@route("/login", method="POST")
def login_post():
user = request.forms.get("username")
@@ -120,6 +123,7 @@ def login_post():
return redirect("/")
+
@route("/logout")
def logout():
s = request.environ.get('beaker.session')
@@ -155,6 +159,7 @@ def queue():
return render_to_response('queue.html', {'content': data}, [pre_processor])
+
@route("/collector")
@login_required('see_downloads')
def collector():
@@ -165,6 +170,7 @@ def collector():
return render_to_response('collector.html', {'content': data}, [pre_processor])
+
@route("/downloads")
@login_required('download')
def downloads():
@@ -197,6 +203,7 @@ def downloads():
return render_to_response('downloads.html', {'files': data}, [pre_processor])
+
@route("/downloads/get/:path#.+#")
@login_required("download")
def get_download(path):
@@ -213,6 +220,63 @@ def get_download(path):
print e
return HTTPError(404, "File not Found.")
+
+@route("/filemanager")
+@login_required('filemanager')
+def filemanager():
+ root = PYLOAD.get_conf_val("general", "download_folder")
+
+ if not isdir(root):
+ return base([_('Download directory not found.')])
+
+ root_node = {'name': '/',
+ 'path': root,
+ 'files': [],
+ 'folders': []
+ }
+
+ for item in sorted(listdir(root)):
+ if isdir(join(root, item)):
+ root_node['folders'].append(iterate_over_dir(root, item))
+ elif isfile(join(root, item)):
+ f = {
+ 'name': decode(item),
+ 'path': root
+ }
+ root_node['files'].append(f)
+
+ return render_to_response('filemanager.html', {'root': root_node}, [pre_processor])
+
+
+def iterate_over_dir(root, dir):
+ out = {
+ 'name': decode(dir),
+ 'path': root,
+ 'files': [],
+ 'folders': []
+ }
+ for item in sorted(listdir(join(root, dir))):
+ subroot = join(root, dir)
+ if isdir(join(subroot, item)):
+ out['folders'].append(iterate_over_dir(subroot, item))
+ elif isfile(join(subroot, item)):
+ f = {
+ 'name': decode(item),
+ 'path': subroot
+ }
+ out['files'].append(f)
+
+ return out
+
+
+@route("/filemanager/get_dir", "POST")
+@login_required('filemanager')
+def folder():
+ path = request.forms.get("path").decode("utf8", "ignore")
+ name = request.forms.get("name").decode("utf8", "ignore")
+ return render_to_response('folder.html', {'path': path, 'name': name}, [pre_processor])
+
+
@route("/settings")
@login_required('settings')
def config():
@@ -257,6 +321,7 @@ def config():
{'conf': {'plugin': plugin_menu, 'general': conf_menu, 'accs': accs}},
[pre_processor])
+
@route("/package_ui.js")
@login_required('see_downloads')
def package_ui():
@@ -266,6 +331,15 @@ def package_ui():
return render_to_response('package_ui.js')
+@route("/filemanager_ui.js")
+@login_required('see_downloads')
+def package_ui():
+ response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
+ time.gmtime(time.time() + 60 * 60 * 24 * 7))
+ response.headers['Cache-control'] = "public"
+ return render_to_response('filemanager_ui.js')
+
+
@route("/filechooser")
@route("/pathchooser")
@route("/filechooser/:file#.+#")
@@ -357,6 +431,7 @@ def path(file="", path=""):
{'cwd': cwd, 'files': files, 'parentdir': parentdir, 'type': type, 'oldfile': oldfile,
'absolute': abs}, [])
+
@route("/logs")
@route("/logs", method="POST")
@route("/logs/:item")
@@ -443,11 +518,11 @@ def logs(item=-1):
'inext': (item + perpage) if item + perpage < len(log) else item},
[pre_processor])
+
@route("/admin")
@route("/admin", method="POST")
@login_required("is_admin")
def admin():
-
user = PYLOAD.get_user_data()
for data in user.itervalues():
data["perms"] = {}
@@ -494,13 +569,16 @@ def admin():
else:
user[name]["perms"]["settings"] = False
+ if request.POST.get("%s|filemanager" % name, False):
+ user[name]["perms"]["filemanager"] = True
+ else:
+ user[name]["perms"]["filemanager"] = False
user[name]["permission"] = set_permission(user[name]["perms"])
PYLOAD.set_user_permission(name, user[name]["permission"], user[name]["role"])
-
- return render_to_response("admin.html", {"users": user} ,[pre_processor])
+ return render_to_response("admin.html", {"users": user}, [pre_processor])
@route("/setup")
@@ -508,11 +586,11 @@ def setup():
if PYLOAD or not SETUP:
return base([_("Run pyLoadCore.py -s to access the setup.")])
- return render_to_response('setup.html', {"user" : False, "perms": False})
+ return render_to_response('setup.html', {"user": False, "perms": False})
+
@route("/info")
def info():
-
conf = PYLOAD.get_config()
data = {"python": sys.version,
diff --git a/module/web/templates/default/admin.html b/module/web/templates/default/admin.html
index 5be649de7..365e9b7bc 100644
--- a/module/web/templates/default/admin.html
+++ b/module/web/templates/default/admin.html
@@ -36,6 +36,9 @@
<th>
{{ _("Change settings") }}
</th>
+ <th>
+ {{ _("Filemanager") }}
+ </th>
</thead>
{% for name, data in users.iteritems() %}
@@ -48,6 +51,7 @@
<td><input name="{{ name }}|see_downloads" type="checkbox" {% if data.perms.see_downloads %} checked="True" {% endif %}"></td>
<td><input name="{{ name }}|download" type="checkbox" {% if data.perms.download %} checked="True" {% endif %}"></td>
<td><input name="{{ name }}|settings" type="checkbox" {% if data.perms.settings %} checked="True" {% endif %}"></td>
+ <td><input name="{{ name }}|filemanager" type="checkbox" {% if data.perms.filemanager %} checked="True" {% endif %}"></td>
</tr>
{% endfor %}
diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html
index 7f7db2610..fd22abbd4 100644
--- a/module/web/templates/default/base.html
+++ b/module/web/templates/default/base.html
@@ -245,24 +245,33 @@ function AddBox()
<div id="head-menu">
<ul>
-
+
+ {% macro selected(name, right=False) -%}
+ {% if name in url -%}class="{% if right -%}right {% endif %}selected"{%- endif %}
+ {% if not name in url and right -%}class="right"{%- endif %}
+ {%- endmacro %}
+
+
{% block menu %}
- <li class="selected">
+ <li>
<a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt="" /> {{_("Home")}}</a>
</li>
- <li>
+ <li {{ selected('queue') }}>
<a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt="" /> {{_("Queue")}}</a>
</li>
- <li>
+ <li {{ selected('collector') }}>
<a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png" alt="" /> {{_("Collector")}}</a>
</li>
- <li>
+ <li {{ selected('downloads') }}>
<a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png" alt="" /> {{_("Downloads")}}</a>
</li>
- <li class="right">
+ <li {{ selected('filemanager') }}>
+ <a href="/filemanager/" title=""><img src="/media/default/img/head-menu-download.png" alt="" /> {{_("FileManager")}}</a>
+ </li>
+ <li {{ selected('logs', True) }}>
<a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-index.png" alt="" />{{_("Logs")}}</a>
</li>
- <li class="right">
+ <li {{ selected('settings', True) }}>
<a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-config.png" alt="" />{{_("Config")}}</a>
</li>
{% endblock %}
@@ -316,6 +325,11 @@ function AddBox()
<b><p>{{message}}</p></b>
{% endfor %}
+<div id="load-indicator" style="opacity: 0; float: right; margin-top: -10px;">
+ <img src="/media/default/img/ajax-loader.gif" alt="" style="padding-right: 5px"/>
+ {{_("loading")}}
+</div>
+
{% block content %}
{% endblock content %}
diff --git a/module/web/templates/default/collector.html b/module/web/templates/default/collector.html
index 3e6b47234..2683d8ee5 100644
--- a/module/web/templates/default/collector.html
+++ b/module/web/templates/default/collector.html
@@ -14,26 +14,6 @@ document.addEvent("domready", function(){
{% block title %}{{_("Collector")}} - {{super()}} {% endblock %}
{% block subtitle %}{{_("Collector")}}{% endblock %}
-{% block menu %}
-<li>
- <a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt="" /> {{_("Home")}}</a>
-</li>
-<li>
- <a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt="" /> {{_("Queue")}}</a>
-</li>
-<li class="selected">
- <a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png" alt="" /> {{_("Collector")}}</a>
-</li>
-<li>
- <a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png" alt="" /> {{_("Downloads")}}</a>
-</li>
-<li class="right">
- <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-index.png" alt="" />{{_("Logs")}}</a>
-</li>
-<li class="right">
- <a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-config.png" alt="" />{{_("Config")}}</a>
-</li>{% endblock %}
-
{% block pageactions %}
<ul id="page-actions-more">
<li id="del_finished"><a style="padding: 0; font-weight: bold;" href="#">{{_("Delete Finished")}}</a></li>
@@ -42,12 +22,6 @@ document.addEvent("domready", function(){
{% endblock %}
{% block content %}
-<div id="load-success" style="opacity: 0; float: right; color: white; background-color: #90ee90; padding: 4px; -moz-border-radius: 5px; border-radius: 5px; font-weight: bold; margin-left: -100%; margin-top: -10px;">{{_("success")}}</div>
-<div id="load-failure" style="opacity: 0; float: right; color: white; background-color: #f08080; padding: 4px; -moz-border-radius: 5px; border-radius: 5px; font-weight: bold; margin-left: -100%; margin-top: -10px;">{{_("failure")}}</div>
-<div id="load-indicator" style="opacity: 0; float: right; margin-top: -10px;">
- <img src="/media/default/img/ajax-loader.gif" alt="" style="padding-right: 5px"/>
- {{_("loading")}}
-</div>
<ul id="package-list" style="list-style: none; padding-left: 0; margin-top: -10px;">
{% for id, package in content %}
@@ -81,4 +55,4 @@ document.addEvent("domready", function(){
{% include "default/edit_package.html" %}
-{% endblock %} \ No newline at end of file
+{% endblock %}
diff --git a/module/web/templates/default/downloads.html b/module/web/templates/default/downloads.html
index 813dc8d06..450b8a102 100644
--- a/module/web/templates/default/downloads.html
+++ b/module/web/templates/default/downloads.html
@@ -2,27 +2,6 @@
{% block title %}Downloads - {{super()}} {% endblock %}
-{% block menu %}
-<li>
- <a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt="" /> {{_("Home")}}</a>
-</li>
-<li>
- <a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt="" /> {{_("Queue")}}</a>
-</li>
-<li>
- <a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png" alt="" /> {{_("Collector")}}</a>
-</li>
-<li class="selected">
- <a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png" alt="" /> {{_("Downloads")}}</a>
-</li>
-<li class="right">
- <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-index.png" alt="" />{{_("Logs")}}</a>
-</li>
-<li class="right">
- <a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-config.png" alt="" />{{_("Config")}}</a>
-</li>
-{% endblock %}
-
{% block subtitle %}
{{_("Downloads")}}
{% endblock %}
diff --git a/module/web/templates/default/filemanager.html b/module/web/templates/default/filemanager.html
new file mode 100644
index 000000000..97095c13e
--- /dev/null
+++ b/module/web/templates/default/filemanager.html
@@ -0,0 +1,80 @@
+{% extends 'default/base.html' %}
+
+{% block head %}
+
+<script type="text/javascript" src="/filemanager_ui.js"></script>
+
+<script type="text/javascript">
+
+document.addEvent("domready", function(){
+ var fmUI = new FilemanagerUI("url",1);
+});
+</script>
+{% endblock %}
+
+{% block title %}Downloads - {{super()}} {% endblock %}
+
+
+{% block subtitle %}
+{{_("FileManager")}}
+{% endblock %}
+
+{% macro display_file(file) %}
+ <li class="file">
+ <input type="hidden" name="path" class="path" value="{{ file.path }}" />
+ <input type="hidden" name="name" class="name" value="{{ file.name }}" />
+ <span>
+ <b>{{ file.name }}</b>
+ <span class="buttons" style="opacity:0">
+ <img title="{{_("Rename Directory")}}" class="rename" style="cursor: pointer" height="12px" src="/media/default/img/pencil.png" />
+ &nbsp;&nbsp;
+ <img title="{{_("Delete Directory")}}" class="delete" style="margin-left: -10px; cursor: pointer" width="12px" height="12px" src="/media/default/img/delete.png" />
+ </span>
+ </span>
+ </li>
+{%- endmacro %}
+
+{% macro display_folder(fld, open = false) -%}
+ <li class="folder">
+ <input type="hidden" name="path" class="path" value="{{ fld.path }}" />
+ <input type="hidden" name="name" class="name" value="{{ fld.name }}" />
+ <span>
+ <b>{{ fld.name }}</b>
+ <span class="buttons" style="opacity:0">
+ <img title="{{_("Rename Directory")}}" class="rename" style="cursor: pointer" height="12px" src="/media/default/img/pencil.png" />
+ &nbsp;&nbsp;
+ <img title="{{_("Delete Directory")}}" class="delete" style="margin-left: -10px; cursor: pointer" width="12px" height="12px" src="/media/default/img/delete.png" />
+ &nbsp;&nbsp;
+ <img title="{{_("Add subdirectory")}}" class="mkdir" style="margin-left: -10px; cursor: pointer" width="12px" height="12px" src="/media/default/img/add_folder.png" />
+ </span>
+ </span>
+ {% if (fld.folders|length + fld.files|length) > 0 %}
+ {% if open %}
+ <ul>
+ {% else %}
+ <ul style="display:none">
+ {% endif %}
+ {% for child in fld.folders %}
+ {{ display_folder(child) }}
+ {% endfor %}
+ {% for child in fld.files %}
+ {{ display_file(child) }}
+ {% endfor %}
+ </ul>
+ {% else %}
+ <div style="display:none">{{ _("Folder is empty") }}</div>
+ {% endif %}
+ </li>
+{%- endmacro %}
+
+{% block content %}
+
+<div style="clear:both"><!-- --></div>
+
+<ul id="directories-list">
+{{ display_folder(root, true) }}
+</ul>
+
+{% include "default/rename_directory.html" %}
+
+{% endblock %}
diff --git a/module/web/templates/default/filemanager_ui.js b/module/web/templates/default/filemanager_ui.js
new file mode 100644
index 000000000..2808317be
--- /dev/null
+++ b/module/web/templates/default/filemanager_ui.js
@@ -0,0 +1,296 @@
+var load, success, fail, rename_box, confirm_box;
+
+document.addEvent("domready", function() {
+ load = new Fx.Tween($("load-indicator"), {link: "cancel"});
+ success = new Fx.Tween($("load-success"), {link: "chain"});
+ fail = new Fx.Tween($("load-failure"), {link: "chain"});
+
+ [load,success,fail].each(function(fx) {
+ fx.set("opacity", 0)
+ });
+
+ rename_box = new Fx.Tween($('rename_box'));
+ confirm_box = new Fx.Tween($('confirm_box'));
+ $('rename_reset').addEvent('click', function() {
+ hide_rename_box()
+ });
+ $('delete_reset').addEvent('click', function() {
+ hide_confirm_box()
+ });
+
+ /*$('filemanager_actions_list').getChildren("li").each(function(action) {
+ var action_name = action.className;
+ if(functions[action.className] != undefined)
+ {
+ action.addEvent('click', functions[action.className]);
+ }
+ });*/
+});
+
+function indicateLoad() {
+ //$("load-indicator").reveal();
+ load.start("opacity", 1)
+}
+
+function indicateFinish() {
+ load.start("opacity", 0)
+}
+
+function indicateSuccess() {
+ indicateFinish();
+ notify.alert('{{_("Success")}}.', {
+ 'className': 'success'
+ });
+}
+
+function indicateFail() {
+ indicateFinish();
+ notify.alert('{{_("Failed")}}.', {
+ 'className': 'error'
+ });
+}
+
+function show_rename_box() {
+ bg_show();
+ $("rename_box").setStyle('display', 'block');
+ rename_box.start('opacity', 1)
+}
+
+function hide_rename_box() {
+ bg_hide();
+ rename_box.start('opacity', 0).chain(function() {
+ $('rename_box').setStyle('display', 'none');
+ });
+}
+
+function show_confirm_box() {
+ bg_show();
+ $("confirm_box").setStyle('display', 'block');
+ confirm_box.start('opacity', 1)
+}
+
+function hide_confirm_box() {
+ bg_hide();
+ confirm_box.start('opacity', 0).chain(function() {
+ $('confirm_box').setStyle('display', 'none');
+ });
+}
+
+var FilemanagerUI = new Class({
+ initialize: function(url, type) {
+ this.url = url;
+ this.type = type;
+ this.directories = [];
+ this.files = [];
+ this.parseChildren();
+ },
+
+ parseChildren: function() {
+ $("directories-list").getChildren("li.folder").each(function(ele) {
+ var path = ele.getElements("input.path")[0].get("value");
+ var name = ele.getElements("input.name")[0].get("value");
+ this.directories.push(new Item(this, path, name, ele))
+ }.bind(this));
+
+ $("directories-list").getChildren("li.file").each(function(ele) {
+ var path = ele.getElements("input.path")[0].get("value");
+ var name = ele.getElements("input.name")[0].get("value");
+ this.files.push(new Item(this, path, name, ele))
+ }.bind(this));
+ }
+});
+
+var Item = new Class({
+ initialize: function(ui, path, name, ele) {
+ this.ui = ui;
+ this.path = path;
+ this.name = name;
+ this.ele = ele;
+ this.directories = [];
+ this.files = [];
+ this.actions = new Array();
+ this.actions["delete"] = this.delete;
+ this.actions["rename"] = this.rename;
+ this.actions["mkdir"] = this.mkdir;
+ this.parseElement();
+
+ var pname = this.ele.getElements("span")[0];
+ this.buttons = new Fx.Tween(this.ele.getElements(".buttons")[0], {link: "cancel"});
+ this.buttons.set("opacity", 0);
+
+ pname.addEvent("mouseenter", function(e) {
+ this.buttons.start("opacity", 1)
+ }.bind(this));
+
+ pname.addEvent("mouseleave", function(e) {
+ this.buttons.start("opacity", 0)
+ }.bind(this));
+
+ },
+
+ parseElement: function() {
+ this.ele.getChildren('span span.buttons img').each(function(img) {
+ img.addEvent('click', this.actions[img.className].bind(this));
+ }, this);
+
+ //click on the directory name must open the directory itself
+ this.ele.getElements('b')[0].addEvent('click', this.toggle.bind(this));
+
+ //iterate over child directories
+ var uls = this.ele.getElements('ul');
+ if(uls.length > 0)
+ {
+ uls[0].getChildren("li.folder").each(function(fld) {
+ var path = fld.getElements("input.path")[0].get("value");
+ var name = fld.getElements("input.name")[0].get("value");
+ this.directories.push(new Item(this, path, name, fld));
+ }.bind(this));
+ uls[0].getChildren("li.file").each(function(fld) {
+ var path = fld.getElements("input.path")[0].get("value");
+ var name = fld.getElements("input.name")[0].get("value");
+ this.files.push(new Item(this, path, name, fld));
+ }.bind(this));
+ }
+ },
+
+ reorderElements: function() {
+ //TODO sort the main ul again (to keep data ordered after renaming something)
+ },
+
+ delete: function(event) {
+ $("confirm_form").removeEvents("submit");
+ $("confirm_form").addEvent("submit", this.deleteDirectory.bind(this));
+
+ $$("#confirm_form p").set('html', '{{_(("Are you sure you want to delete the selected item?"))}}');
+
+ show_confirm_box();
+ event.stop();
+ },
+
+ deleteDirectory: function(event) {
+ hide_confirm_box();
+ new Request.JSON({
+ method: 'POST',
+ url: "/json/filemanager/delete",
+ data: {"path": this.path, "name": this.name},
+ onSuccess: function(data) {
+ if(data.response == "success")
+ {
+ new Fx.Tween(this.ele).start('opacity', 0);
+ var ul = this.ele.parentNode;
+ this.ele.dispose();
+ //if this was the only child, add a "empty folder" div
+ if(!ul.getChildren('li')[0])
+ {
+ var div = new Element("div", { 'html': '{{ _("Folder is empty") }}' });
+ div.replaces(ul);
+ }
+
+ indicateSuccess();
+ } else
+ {
+ //error from json code...
+ indicateFail();
+ }
+ }.bind(this),
+ onFailure: indicateFail
+ }).send();
+
+ event.stop();
+ },
+
+ rename: function(event) {
+ $("rename_form").removeEvents("submit");
+ $("rename_form").addEvent("submit", this.renameDirectory.bind(this));
+
+ $("path").set("value", this.path);
+ $("old_name").set("value", this.name);
+ $("new_name").set("value", this.name);
+
+ show_rename_box();
+ event.stop();
+ },
+
+ renameDirectory: function(event) {
+ hide_rename_box();
+ new Request.JSON({
+ method: 'POST',
+ url: "/json/filemanager/rename",
+ onSuccess: function(data) {
+ if(data.response == "success")
+ {
+ this.name = $("new_name").get("value");
+ this.ele.getElements("b")[0].set('html', $("new_name").get("value"));
+ this.reorderElements();
+ indicateSuccess();
+ } else
+ {
+ //error from json code...
+ indicateFail();
+ }
+ }.bind(this),
+ onFailure: indicateFail
+ }).send($("rename_form").toQueryString());
+
+ event.stop();
+ },
+
+ mkdir: function(event) {
+ new Request.JSON({
+ method: 'POST',
+ url: "/json/filemanager/mkdir",
+ data: {"path": this.path + "/" + this.name, "name": '{{_("New folder")}}'},
+ onSuccess: function(data) {
+ if(data.response == "success")
+ {
+ new Request.HTML({
+ method: 'POST',
+ url: "/filemanager/get_dir",
+ data: {"path": data.path, "name": data.name},
+ onSuccess: function(li) {
+ //add node as first child of ul
+ var ul = this.ele.getChildren('ul')[0];
+ if(!ul)
+ {
+ //remove the "Folder Empty" div
+ this.ele.getChildren('div').dispose();
+
+ //create new ul to contain subfolder
+ ul = new Element("ul");
+ ul.inject(this.ele, 'bottom');
+ }
+ li[0].inject(ul, 'top');
+
+ //add directory as a subdirectory of the current item
+ this.directories.push(new Item(this.ui, data.path, data.name, ul.firstChild));
+ }.bind(this),
+ onFailure: indicateFail
+ }).send();
+ indicateSuccess();
+ } else
+ {
+ //error from json code...
+ indicateFail();
+ }
+ }.bind(this),
+ onFailure: indicateFail
+ }).send();
+
+ event.stop();
+ },
+
+ toggle: function() {
+ var child = this.ele.getElement('ul');
+ if(child == null)
+ child = this.ele.getElement('div');
+
+ if(child != null)
+ {
+ if (child.getStyle('display') == "block") {
+ child.dissolve();
+ } else {
+ child.reveal();
+ }
+ }
+ }
+});
diff --git a/module/web/templates/default/folder.html b/module/web/templates/default/folder.html
new file mode 100644
index 000000000..b385e80cb
--- /dev/null
+++ b/module/web/templates/default/folder.html
@@ -0,0 +1,15 @@
+<li class="folder">
+ <input type="hidden" name="path" class="path" value="{{ path }}" />
+ <input type="hidden" name="name" class="name" value="{{ name }}" />
+ <span>
+ <b>{{ name }}</b>
+ <span class="buttons" style="opacity:0">
+ <img title="{{_("Rename Directory")}}" class="rename" style="cursor: pointer" height="12px" src="/media/default/img/pencil.png" />
+ &nbsp;&nbsp;
+ <img title="{{_("Delete Directory")}}" class="delete" style="margin-left: -10px; cursor: pointer" width="12px" height="12px" src="/media/default/img/delete.png" />
+ &nbsp;&nbsp;
+ <img title="{{_("Add subdirectory")}}" class="mkdir" style="margin-left: -10px; cursor: pointer" width="12px" height="12px" src="/media/default/img/add_folder.png" />
+ </span>
+ </span>
+ <div style="display:none">{{ _("Folder is empty") }}</div>
+</li> \ No newline at end of file
diff --git a/module/web/templates/default/home.html b/module/web/templates/default/home.html
index b2cef2cb7..927287dfc 100644
--- a/module/web/templates/default/home.html
+++ b/module/web/templates/default/home.html
@@ -205,6 +205,30 @@ var LinkEntry = new Class({
{{_("Active Downloads")}}
{% endblock %}
+{% block menu %}
+<li class="selected">
+ <a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt="" /> {{_("Home")}}</a>
+</li>
+<li>
+ <a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt="" /> {{_("Queue")}}</a>
+</li>
+<li>
+ <a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png" alt="" /> {{_("Collector")}}</a>
+</li>
+<li>
+ <a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png" alt="" /> {{_("Downloads")}}</a>
+</li>
+<li>
+ <a href="/filemanager/" title=""><img src="/media/default/img/head-menu-download.png" alt="" /> {{_("FileManager")}}</a>
+</li>
+<li class="right">
+ <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-index.png" alt="" />{{_("Logs")}}</a>
+</li>
+<li class="right">
+ <a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-config.png" alt="" />{{_("Config")}}</a>
+</li>
+{% endblock %}
+
{% block content %}
<table width="100%" class="queue">
<thead>
diff --git a/module/web/templates/default/info.html b/module/web/templates/default/info.html
index b9ee3b1bd..fabe7aea1 100644
--- a/module/web/templates/default/info.html
+++ b/module/web/templates/default/info.html
@@ -18,6 +18,13 @@
<h3>{{ _("News") }}</h3>
<div id="twitter"></div>
+ <h3>{{ _("Support") }}</h3>
+
+ <ul>
+ <li style="font-weight:bold;"><a href="http://forum.pyload.org/" target="_blank">Forum</a></li>
+ <li style="font-weight:bold;"><a href="http://pyload.org/irc/" target="_blank">Chat</a></li>
+ </ul>
+
<h3>{{ _("System") }}</h3>
<table class="system">
<tr>
diff --git a/module/web/templates/default/logs.html b/module/web/templates/default/logs.html
index 7a95b4364..d6288df0e 100644
--- a/module/web/templates/default/logs.html
+++ b/module/web/templates/default/logs.html
@@ -5,26 +5,6 @@
{% block head %}
<link rel="stylesheet" type="text/css" href="/media/default/css/log.css"/>
{% endblock %}
-{% block menu %}
-<li>
- <a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt="" /> {{_("Home")}}</a>
-</li>
-<li>
- <a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt="" /> {{_("Queue")}}</a>
-</li>
-<li>
- <a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png" alt="" /> {{_("Collector")}}</a>
-</li>
-<li>
- <a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png" alt="" /> {{_("Downloads")}}</a>
-</li>
-<li class="right selected">
- <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-index.png" alt="" />{{_("Logs")}}</a>
-</li>
-<li class="right">
- <a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-config.png" alt="" />{{_("Config")}}</a>
-</li>
-{% endblock %}
{% block content %}
<div style="clear: both;"></div>
diff --git a/module/web/templates/default/queue.html b/module/web/templates/default/queue.html
index e72871873..104369c11 100644
--- a/module/web/templates/default/queue.html
+++ b/module/web/templates/default/queue.html
@@ -14,27 +14,6 @@ document.addEvent("domready", function(){
{% block title %}{{_("Queue")}} - {{super()}} {% endblock %}
{% block subtitle %}{{_("Queue")}}{% endblock %}
-{% block menu %}
-<li>
- <a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt="" /> {{_("Home")}}</a>
-</li>
-<li class="selected">
- <a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt="" /> {{_("Queue")}}</a>
-</li>
-<li>
- <a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png" alt="" /> {{_("Collector")}}</a>
-</li>
-<li>
- <a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png" alt="" /> {{_("Downloads")}}</a>
-</li>
-<li class="right">
- <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-index.png" alt="" />{{_("Logs")}}</a>
-</li>
-<li class="right">
- <a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img src="/media/default/img/head-menu-config.png" alt="" />{{_("Config")}}</a>
-</li>
-{% endblock %}
-
{% block pageactions %}
<ul id="page-actions-more">
<li id="del_finished"><a style="padding: 0; font-weight: bold;" href="#">{{_("Delete Finished")}}</a></li>
@@ -43,12 +22,7 @@ document.addEvent("domready", function(){
{% endblock %}
{% block content %}
-<div id="load-success" style="opacity: 0; float: right; color: white; background-color: #90ee90; padding: 4px; -moz-border-radius: 5px; border-radius: 5px; font-weight: bold; margin-left: -100%; margin-top: -10px;">{{_("success")}}</div>
-<div id="load-failure" style="opacity: 0; float: right; color: white; background-color: #f08080; padding: 4px; -moz-border-radius: 5px; border-radius: 5px; font-weight: bold; margin-left: -100%; margin-top: -10px;">{{_("failure")}}</div>
-<div id="load-indicator" style="opacity: 0; float: right; margin-top: -10px;">
- <img src="/media/default/img/ajax-loader.gif" alt="" style="padding-right: 5px"/>
- {{_("loading")}}
-</div>
+
<ul id="package-list" style="list-style: none; padding-left: 0; margin-top: -10px;">
{% for id, package in content %}
@@ -82,4 +56,4 @@ document.addEvent("domready", function(){
{% include "default/edit_package.html" %}
-{% endblock %} \ No newline at end of file
+{% endblock %}
diff --git a/module/web/templates/default/rename_directory.html b/module/web/templates/default/rename_directory.html
new file mode 100644
index 000000000..606573554
--- /dev/null
+++ b/module/web/templates/default/rename_directory.html
@@ -0,0 +1,28 @@
+<div id="rename_box" class="myform window_box" style="z-index: 2">
+ <form id="rename_form" action="/json/filemanager/rename" method="POST" enctype="multipart/form-data">
+ <h1>{{_("Rename directory")}}</h1>
+ <input name="path" id="path" type="hidden" value=""/>
+ <input name="old_name" id="old_name" type="hidden" value=""/>
+
+ <label for="new_name">{{_("New Name")}}
+ <span class="small">{{_("Name the selected item must be renamed to.")}}</span>
+ </label>
+ <input id="new_name" name="new_name" type="text" size="20" />
+
+ <button type="submit">{{_("Submit")}}</button>
+ <button id="rename_reset" style="margin-left: 0" type="reset">{{_("Reset")}}</button>
+ <div class="spacer"></div>
+ </form>
+</div>
+
+<div id="confirm_box" class="myform window_box" style="z-index: 2">
+ <form id="confirm_form" action="/json/filemanager/delete" method="POST" enctype="multipart/form-data">
+ <h1>{{_("Delete directory")}}</h1>
+
+ <p>{{_(("Are you sure?"))}}</p>
+
+ <button type="submit">{{_("Yes")}}</button>
+ <button id="delete_reset" style="margin-left: 0" type="reset">{{_("No")}}</button>
+ <div class="spacer"></div>
+ </form>
+</div> \ No newline at end of file
diff --git a/module/web/templates/default/settings.html b/module/web/templates/default/settings.html
index df6616e42..fc33ca64a 100644
--- a/module/web/templates/default/settings.html
+++ b/module/web/templates/default/settings.html
@@ -41,31 +41,6 @@
{% endblock %}
-{% block menu %}
- <li>
- <a href="/" title=""><img src="/media/default/img/head-menu-home.png" alt=""/> {{ _("Home") }}</a>
- </li>
- <li>
- <a href="/queue/" title=""><img src="/media/default/img/head-menu-queue.png" alt=""/> {{ _("Queue") }}</a>
- </li>
- <li>
- <a href="/collector/" title=""><img src="/media/default/img/head-menu-collector.png"
- alt=""/> {{ _("Collector") }}</a>
- </li>
- <li>
- <a href="/downloads/" title=""><img src="/media/default/img/head-menu-development.png"
- alt=""/> {{ _("Downloads") }}</a>
- </li>
- <li class="right">
- <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img
- src="/media/default/img/head-menu-index.png" alt=""/>{{ _("Logs") }}</a>
- </li>
- <li class="right selected">
- <a href="/settings/" class="action index" accesskey="x" rel="nofollow"><img
- src="/media/default/img/head-menu-config.png" alt=""/>{{ _("Config") }}</a>
- </li>
-{% endblock %}
-
{% block content %}
<ul id="toptabs" class="tabs">
diff --git a/module/web/utils.py b/module/web/utils.py
index afe5ac60c..fccfb78d6 100644
--- a/module/web/utils.py
+++ b/module/web/utils.py
@@ -35,6 +35,7 @@ def parse_permissions(session):
"status": False,
"see_downloads": False,
"download" : False,
+ "filemanager" : False,
"settings": False,
"is_admin": False}
@@ -58,6 +59,7 @@ def get_permission(perms, p):
perms["see_downloads"] = has_permission(p, PERMS.SEE_DOWNLOADS)
perms["download"] = has_permission(p, PERMS.DOWNLOAD)
perms["settings"] = has_permission(p, PERMS.SETTINGS)
+ perms["filemanager"] = has_permission(p, PERMS.FILEMANAGER)
def set_permission(perms):
permission = 0
@@ -73,6 +75,8 @@ def set_permission(perms):
permission |= PERMS.DOWNLOAD
if perms["settings"]:
permission |= PERMS.SETTINGS
+ if perms["filemanager"]:
+ permission |= PERMS.FILEMANAGER
return permission