summaryrefslogtreecommitdiffstats
path: root/module/web
diff options
context:
space:
mode:
Diffstat (limited to 'module/web')
-rw-r--r--module/web/ServerThread.py7
-rw-r--r--module/web/api_app.py12
-rw-r--r--module/web/cnl_app.py2
-rw-r--r--module/web/json_app.py39
-rw-r--r--module/web/media/js/settings.coffee4
-rw-r--r--module/web/media/js/settings.js2
-rw-r--r--module/web/middlewares.py10
-rw-r--r--module/web/pyload_app.py54
-rw-r--r--module/web/templates/default/base.html2
-rw-r--r--module/web/templates/default/queue.html6
-rw-r--r--module/web/templates/default/settings.html32
-rw-r--r--module/web/templates/default/settings_item.html16
12 files changed, 88 insertions, 98 deletions
diff --git a/module/web/ServerThread.py b/module/web/ServerThread.py
index 84667e5f6..8b59ca01b 100644
--- a/module/web/ServerThread.py
+++ b/module/web/ServerThread.py
@@ -93,6 +93,13 @@ class WebServer(threading.Thread):
webinterface.run_threaded(host=self.host, port=self.port, cert=self.cert, key=self.key)
def start_fcgi(self):
+
+ from flup.server.threadedserver import ThreadedServer
+
+ def noop(*args, **kwargs):
+ pass
+
+ ThreadedServer._installSignalHandlers = noop
self.core.log.info(_("Starting fastcgi server: %(host)s:%(port)d") % {"host": self.host, "port": self.port})
webinterface.run_fcgi(host=self.host, port=self.port)
diff --git a/module/web/api_app.py b/module/web/api_app.py
index 1629c1677..affcdb39a 100644
--- a/module/web/api_app.py
+++ b/module/web/api_app.py
@@ -11,6 +11,7 @@ from utils import toDict, set_session
from webinterface import PYLOAD
from module.common.json_layer import json
+from module.utils import remove_chars
from module.lib.SafeEval import const_eval as literal_eval
from module.Api import BaseObject
@@ -24,16 +25,17 @@ class TBaseEncoder(json.JSONEncoder):
# accepting positional arguments, as well as kwargs via post and get
-
-@route("/api/:func:args#[a-zA-Z0-9\-_/\"'\[\]%{}]*#")
-@route("/api/:func:args#[a-zA-Z0-9\-_/\"'\[\]%{}]*#", method="POST")
+# only forbidden path symbol are "?", which is used to seperate GET data and #
+@route("/api/<func><args:re:[^#?]*>")
+@route("/api/<func><args:re:[^#?]*>", method="POST")
def call_api(func, args=""):
response.headers.replace("Content-type", "application/json")
response.headers.append("Cache-Control", "no-cache, must-revalidate")
s = request.environ.get('beaker.session')
if 'session' in request.POST:
- s = s.get_by_id(request.POST['session'])
+ # removes "' so it works on json strings
+ s = s.get_by_id(remove_chars(request.POST['session'], "'\""))
if not s or not s.get("authenticated", False):
return HTTPError(403, json.dumps("Forbidden"))
@@ -63,7 +65,7 @@ def callApi(func, *args, **kwargs):
result = getattr(PYLOAD, func)(*[literal_eval(x) for x in args],
**dict([(x, literal_eval(y)) for x, y in kwargs.iteritems()]))
- # null is invalid json response
+ # null is invalid json response
if result is None: result = True
return json.dumps(result, cls=TBaseEncoder)
diff --git a/module/web/cnl_app.py b/module/web/cnl_app.py
index d8f7c1180..fe308ec04 100644
--- a/module/web/cnl_app.py
+++ b/module/web/cnl_app.py
@@ -18,7 +18,7 @@ except:
def local_check(function):
def _view(*args, **kwargs):
if request.environ.get('REMOTE_ADDR', "0") in ('127.0.0.1', 'localhost') \
- or request.environ.get('HTTP_HOST','0') == '127.0.0.1:9666':
+ or request.environ.get('HTTP_HOST','0') in ('127.0.0.1:9666', 'localhost:9666'):
return function(*args, **kwargs)
else:
return HTTPError(403, "Forbidden")
diff --git a/module/web/json_app.py b/module/web/json_app.py
index f3626405c..5acafe153 100644
--- a/module/web/json_app.py
+++ b/module/web/json_app.py
@@ -179,11 +179,7 @@ def add_package():
links = map(lambda x: x.strip(), links)
links = filter(lambda x: x != "", links)
- pack = PYLOAD.addPackage(name, links, queue)
- if pw:
- pw = pw.decode("utf8", "ignore")
- data = {"password": pw}
- PYLOAD.setPackageData(pack, data)
+ PYLOAD.addPackage(name, links, queue, pw.decode("utf8", "ignore"))
@route("/json/move_package/<dest:int>/<id:int>")
@@ -232,38 +228,23 @@ def set_captcha():
return {'captcha': False}
-@route("/json/load_config/:category/:section")
+@route("/json/load_config/:section")
@login_required("SETTINGS")
-def load_config(category, section):
- conf = None
- if category == "general":
- conf = PYLOAD.getConfigDict()
- elif category == "plugin":
- conf = PYLOAD.getPluginConfigDict()
+def load_config(section):
+ data = PYLOAD.configureSection(section)
+ return render_to_response("settings_item.html", {"section": data})
- for key, option in conf[section].iteritems():
- if key in ("desc","outline"): continue
- if ";" in option["type"]:
- option["list"] = option["type"].split(";")
-
- option["value"] = decode(option["value"])
-
- return render_to_response("settings_item.html", {"skey": section, "section": conf[section]})
-
-
-@route("/json/save_config/:category", method="POST")
+@route("/json/save_config", method="POST")
@login_required("SETTINGS")
-def save_config(category):
+def save_config():
for key, value in request.POST.iteritems():
try:
section, option = key.split("|")
except:
continue
- if category == "general": category = "core"
-
- PYLOAD.setConfigValue(section, option, decode(value), category)
+ PYLOAD.setConfigValue(section, option, decode(value))
@route("/json/add_account", method="POST")
@@ -293,9 +274,9 @@ def update_accounts():
if action == "password":
PYLOAD.updateAccount(plugin, user, value)
elif action == "time" and "-" in value:
- PYLOAD.updateAccount(plugin, user, options={"time": [value]})
+ PYLOAD.updateAccount(plugin, user, options={"time": value})
elif action == "limitdl" and value.isdigit():
- PYLOAD.updateAccount(plugin, user, options={"limitDL": [value]})
+ PYLOAD.updateAccount(plugin, user, options={"limitDL": value})
elif action == "delete":
deleted.append((plugin,user))
PYLOAD.removeAccount(plugin, user)
diff --git a/module/web/media/js/settings.coffee b/module/web/media/js/settings.coffee
index 9205233e3..04d352dae 100644
--- a/module/web/media/js/settings.coffee
+++ b/module/web/media/js/settings.coffee
@@ -51,7 +51,7 @@ class SettingsUI
new Request({
"method" : "get"
- "url" : "/json/load_config/#{category}/#{section}"
+ "url" : "/json/load_config/#{section}"
"onSuccess": (data) =>
target.set "html", data
target.reveal()
@@ -65,7 +65,7 @@ class SettingsUI
form.set "send", {
"method": "post"
- "url": "/json/save_config/#{category}"
+ "url": "/json/save_config"
"onSuccess" : ->
root.notify.alert '{{ _("Settings saved.")}}', {
'className': 'success'
diff --git a/module/web/media/js/settings.js b/module/web/media/js/settings.js
index 9191fac72..3604c38b0 100644
--- a/module/web/media/js/settings.js
+++ b/module/web/media/js/settings.js
@@ -1,3 +1,3 @@
{% autoescape true %}
-var SettingsUI,root;var __bind=function(a,b){return function(){return a.apply(b,arguments)}};root=this;window.addEvent("domready",function(){root.accountDialog=new MooDialog({destroyOnHide:false});root.accountDialog.setContent($("account_box"));new TinyTab($$("#toptabs li a"),$$("#tabs-body > span"));$$("ul.nav").each(function(a){return new MooDropMenu(a,{onOpen:function(b){return b.fade("in")},onClose:function(b){return b.fade("out")},onInitialize:function(b){return b.fade("hide").set("tween",{duration:500})}})});return new SettingsUI()});SettingsUI=(function(){function a(){var c,e,b,d;this.menu=$$("#general-menu li");this.menu.append($$("#plugin-menu li"));this.name=$("tabsback");this.general=$("general_form_content");this.plugin=$("plugin_form_content");d=this.menu;for(e=0,b=d.length;e<b;e++){c=d[e];c.addEvent("click",this.menuClick.bind(this))}$("general|submit").addEvent("click",this.configSubmit.bind(this));$("plugin|submit").addEvent("click",this.configSubmit.bind(this));$("account_add").addEvent("click",function(f){root.accountDialog.open();return f.stop()});$("account_reset").addEvent("click",function(f){return root.accountDialog.close()});$("account_add_button").addEvent("click",this.addAccount.bind(this));$("account_submit").addEvent("click",this.submitAccounts.bind(this))}a.prototype.menuClick=function(h){var c,b,g,f,d;d=h.target.get("id").split("|"),c=d[0],g=d[1];b=h.target.get("text");f=c==="general"?this.general:this.plugin;f.dissolve();return new Request({method:"get",url:"/json/load_config/"+c+"/"+g,onSuccess:__bind(function(e){f.set("html",e);f.reveal();return this.name.set("text",b)},this)}).send()};a.prototype.configSubmit=function(d){var c,b;c=d.target.get("id").split("|")[0];b=$(""+c+"_form");b.set("send",{method:"post",url:"/json/save_config/"+c,onSuccess:function(){return root.notify.alert('{{ _("Settings saved.")}}',{className:"success"})},onFailure:function(){return root.notify.alert('{{ _("Error occured.")}}',{className:"error"})}});b.send();return d.stop()};a.prototype.addAccount=function(c){var b;b=$("add_account_form");b.set("send",{method:"post",onSuccess:function(){return window.location.reload()},onFailure:function(){return root.notify.alert('{{_("Error occured.")}}',{className:"error"})}});b.send();return c.stop()};a.prototype.submitAccounts=function(c){var b;b=$("account_form");b.set("send",{method:"post",onSuccess:function(){return window.location.reload()},onFailure:function(){return root.notify.alert('{{ _("Error occured.") }}',{className:"error"})}});b.send();return c.stop()};return a})();
+var SettingsUI,root;var __bind=function(a,b){return function(){return a.apply(b,arguments)}};root=this;window.addEvent("domready",function(){root.accountDialog=new MooDialog({destroyOnHide:false});root.accountDialog.setContent($("account_box"));new TinyTab($$("#toptabs li a"),$$("#tabs-body > span"));$$("ul.nav").each(function(a){return new MooDropMenu(a,{onOpen:function(b){return b.fade("in")},onClose:function(b){return b.fade("out")},onInitialize:function(b){return b.fade("hide").set("tween",{duration:500})}})});return new SettingsUI()});SettingsUI=(function(){function a(){var c,e,b,d;this.menu=$$("#general-menu li");this.menu.append($$("#plugin-menu li"));this.name=$("tabsback");this.general=$("general_form_content");this.plugin=$("plugin_form_content");d=this.menu;for(e=0,b=d.length;e<b;e++){c=d[e];c.addEvent("click",this.menuClick.bind(this))}$("general|submit").addEvent("click",this.configSubmit.bind(this));$("plugin|submit").addEvent("click",this.configSubmit.bind(this));$("account_add").addEvent("click",function(f){root.accountDialog.open();return f.stop()});$("account_reset").addEvent("click",function(f){return root.accountDialog.close()});$("account_add_button").addEvent("click",this.addAccount.bind(this));$("account_submit").addEvent("click",this.submitAccounts.bind(this))}a.prototype.menuClick=function(h){var c,b,g,f,d;d=h.target.get("id").split("|"),c=d[0],g=d[1];b=h.target.get("text");f=c==="general"?this.general:this.plugin;f.dissolve();return new Request({method:"get",url:"/json/load_config/"+g,onSuccess:__bind(function(e){f.set("html",e);f.reveal();return this.name.set("text",b)},this)}).send()};a.prototype.configSubmit=function(d){var c,b;c=d.target.get("id").split("|")[0];b=$(""+c+"_form");b.set("send",{method:"post",url:"/json/save_config",onSuccess:function(){return root.notify.alert('{{ _("Settings saved.")}}',{className:"success"})},onFailure:function(){return root.notify.alert('{{ _("Error occured.")}}',{className:"error"})}});b.send();return d.stop()};a.prototype.addAccount=function(c){var b;b=$("add_account_form");b.set("send",{method:"post",onSuccess:function(){return window.location.reload()},onFailure:function(){return root.notify.alert('{{_("Error occured.")}}',{className:"error"})}});b.send();return c.stop()};a.prototype.submitAccounts=function(c){var b;b=$("account_form");b.set("send",{method:"post",onSuccess:function(){return window.location.reload()},onFailure:function(){return root.notify.alert('{{ _("Error occured.") }}',{className:"error"})}});b.send();return c.stop()};return a})();
{% endautoescape %} \ No newline at end of file
diff --git a/module/web/middlewares.py b/module/web/middlewares.py
index e0e6c3102..57023dbdb 100644
--- a/module/web/middlewares.py
+++ b/module/web/middlewares.py
@@ -90,14 +90,14 @@ class GzipResponse(object):
cl = int(cl)
else:
cl = 201
- self.compressible = False
- if ct and (ct.startswith('text/') or ct.startswith('application/')) \
- and 'zip' not in ct and cl > 200:
- self.compressible = True
+
if ce:
self.compressible = False
- if self.compressible:
+ elif ct and (ct.startswith('text/') or ct.startswith('application/')) \
+ and 'zip' not in ct and 200 < cl < 1024*1024:
+ self.compressible = True
headers.append(('content-encoding', 'gzip'))
+
remove_header(headers, 'content-length')
self.headers = headers
self.status = status
diff --git a/module/web/pyload_app.py b/module/web/pyload_app.py
index df4a4b3d4..dcfc3266e 100644
--- a/module/web/pyload_app.py
+++ b/module/web/pyload_app.py
@@ -22,7 +22,6 @@ from operator import itemgetter, attrgetter
import time
import os
import sys
-from os import listdir
from os.path import isdir, isfile, join, abspath
from sys import getfilesystemencoding
from urllib import unquote
@@ -36,7 +35,8 @@ from utils import render_to_response, parse_permissions, parse_userdata, \
from filters import relpath, unquotepath
-from module.utils import formatSize, save_join, fs_encode, fs_decode
+from module.utils import formatSize
+from module.utils.fs import save_join, fs_encode, fs_decode, listdir, free_space
# Helper
@@ -189,7 +189,7 @@ def collector():
def downloads():
root = PYLOAD.getConfigValue("general", "download_folder")
- if not isdir(root):
+ if not isdir(fs_encode(root)):
return base([_('Download directory not found.')])
data = {
'folder': [],
@@ -241,45 +241,40 @@ def get_download(path):
@route("/settings")
@login_required('SETTINGS')
def config():
- conf = PYLOAD.getConfig()
- plugin = PYLOAD.getPluginConfig()
+ conf = PYLOAD.getConfigPointer()
conf_menu = []
plugin_menu = []
- for entry in sorted(conf.keys()):
- conf_menu.append((entry, conf[entry].description))
+ for section, data in sorted(conf.getBaseSections()):
+ conf_menu.append((section, data.name))
- for entry in sorted(plugin.keys()):
- plugin_menu.append((entry, plugin[entry].description))
+ for section, data in sorted(conf.getPluginSections()):
+ plugin_menu.append((section, data.name))
accs = PYLOAD.getAccounts(False)
+ # prefix attributes with _, because we would change them directly on the object otherweise
for data in accs:
if data.trafficleft == -1:
- data.trafficleft = _("unlimited")
+ data._trafficleft = _("unlimited")
elif not data.trafficleft:
- data.trafficleft = _("not available")
+ data._trafficleft = _("not available")
else:
- data.trafficleft = formatSize(data.trafficleft * 1024)
+ data._trafficleft = formatSize(data.trafficleft * 1024)
if data.validuntil == -1:
- data.validuntil = _("unlimited")
- elif not data.validuntil :
- data.validuntil = _("not available")
+ data._validuntil = _("unlimited")
+ elif not data.validuntil:
+ data._validuntil = _("not available")
else:
t = time.localtime(data.validuntil)
- data.validuntil = time.strftime("%d.%m.%Y", t)
+ data._validuntil = time.strftime("%d.%m.%Y", t)
- if "time" in data.options:
- try:
- data.options["time"] = data.options["time"][0]
- except:
- data.options["time"] = "0:00-0:00"
+ if not data.options["time"]:
+ data.options["time"] = "0:00-0:00"
- if "limitDL" in data.options:
- data.options["limitdl"] = data.options["limitDL"][0]
- else:
+ if not data.options["limitDL"]:
data.options["limitdl"] = "0"
return render_to_response('settings.html',
@@ -511,9 +506,10 @@ def setup():
return render_to_response('setup.html', {"user": False, "perms": False})
+@login_required("STATUS")
@route("/info")
def info():
- conf = PYLOAD.getConfigDict()
+ conf = PYLOAD.getConfigPointer()
if hasattr(os, "uname"):
extra = os.uname()
@@ -524,10 +520,10 @@ def info():
"os": " ".join((os.name, sys.platform) + extra),
"version": PYLOAD.getServerVersion(),
"folder": abspath(PYLOAD_DIR), "config": abspath(""),
- "download": abspath(conf["general"]["download_folder"]["value"]),
+ "download": abspath(conf["general"]["download_folder"]),
"freespace": formatSize(PYLOAD.freeSpace()),
- "remote": conf["remote"]["port"]["value"],
- "webif": conf["webinterface"]["port"]["value"],
- "language": conf["general"]["language"]["value"]}
+ "remote": conf["remote"]["port"],
+ "webif": conf["webinterface"]["port"],
+ "language": conf["general"]["language"]}
return render_to_response("info.html", data, [pre_processor])
diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html
index 0b20ecdb0..1f77c04ba 100644
--- a/module/web/templates/default/base.html
+++ b/module/web/templates/default/base.html
@@ -162,7 +162,7 @@
<hr style="clear: both;" />
-<div id="foot">&copy; 2008-2011 pyLoad Team
+<div id="foot">&copy; 2008-2012 pyLoad Team
<a href="#top" class="action top" accesskey="x"><span>{{_("Back to top")}}</span></a><br />
<!--<div class="breadcrumbs"></div>-->
diff --git a/module/web/templates/default/queue.html b/module/web/templates/default/queue.html
index c88fa3568..9403a8019 100644
--- a/module/web/templates/default/queue.html
+++ b/module/web/templates/default/queue.html
@@ -50,7 +50,11 @@ document.addEvent("domready", function(){
<img title="{{_("Move Package")}}" style="margin-left: -10px; cursor: pointer" height="12px" src="/media/default/img/package_go.png" />
</span>
</div>
- {% set progress = (package.linksdone * 100) / package.linkstotal %}
+ {% if package.linkstotal %}
+ {% set progress = (package.linksdone * 100) / package.linkstotal %}
+ {% else %}
+ {% set progress = 0 %}
+ {% endif %}
<div id="progress" style="border-radius: 4px; border: 1px solid #AAAAAA; width: 50%; height: 1em">
<div style="width: {{ progress }}%; height: 100%; background-color: #add8e6;"></div>
diff --git a/module/web/templates/default/settings.html b/module/web/templates/default/settings.html
index a4443025a..be320970b 100644
--- a/module/web/templates/default/settings.html
+++ b/module/web/templates/default/settings.html
@@ -102,18 +102,18 @@
{% for account in conf.accs %}
- {% set plugin = account.type %}
+ {% set plugin = account.__name__ %}
<tr>
<td>
<span style="padding:5px">{{ plugin }}</span>
</td>
- <td><label for="{{plugin}}|password;{{account.login}}"
- style="color:#424242;">{{ account.login }}</label></td>
+ <td><label for="{{plugin}}|password;{{account.loginname}}"
+ style="color:#424242;">{{ account.loginname }}</label></td>
<td>
- <input id="{{plugin}}|password;{{account.login}}"
- name="{{plugin}}|password;{{account.login}}"
- type="password" value="{{account.password}}" size="12"/>
+ <input id="{{plugin}}|password;{{account.loginname}}"
+ name="{{plugin}}|password;{{account.loginname}}"
+ type="password" value="" size="12"/>
</td>
<td>
{% if account.valid %}
@@ -137,27 +137,27 @@
</td>
<td>
<span style="font-weight: bold;">
- {{ account.validuntil }}
+ {{ account._validuntil }}
</span>
</td>
<td>
<span style="font-weight: bold;">
- {{ account.trafficleft }}
+ {{ account._trafficleft }}
</span>
</td>
<td>
- <input id="{{plugin}}|time;{{account.login}}"
- name="{{plugin}}|time;{{account.login}}" type="text"
- size="7" value="{{account.time}}"/>
+ <input id="{{plugin}}|time;{{account.loginname}}"
+ name="{{plugin}}|time;{{account.loginname}}" type="text"
+ size="7" value="{{account.options.time}}"/>
</td>
<td>
- <input id="{{plugin}}|limitdl;{{account.login}}"
- name="{{plugin}}|limitdl;{{account.login}}" type="text"
- size="2" value="{{account.limitdl}}"/>
+ <input id="{{plugin}}|limitdl;{{account.loginname}}"
+ name="{{plugin}}|limitdl;{{account.loginname}}" type="text"
+ size="2" value="{{account.options.limitdl}}"/>
</td>
<td>
- <input id="{{plugin}}|delete;{{account.login}}"
- name="{{plugin}}|delete;{{account.login}}" type="checkbox"
+ <input id="{{plugin}}|delete;{{account.loginname}}"
+ name="{{plugin}}|delete;{{account.loginname}}" type="checkbox"
value="True"/>
</td>
</tr>
diff --git a/module/web/templates/default/settings_item.html b/module/web/templates/default/settings_item.html
index 813383343..b3d7fe334 100644
--- a/module/web/templates/default/settings_item.html
+++ b/module/web/templates/default/settings_item.html
@@ -1,12 +1,13 @@
<table class="settable">
- {% if section.outline %}
- <tr><th colspan="2">{{ section.outline }}</th></tr>
+ {% if section.description %}
+ <tr><th colspan="2">{{ section.description }}</th></tr>
{% endif %}
- {% for okey, option in section.iteritems() %}
- {% if okey not in ("desc","outline") %}
+ {% for option in section.items %}
+ {% set okey = option.name %}
+ {% set skey = section.name %}
<tr>
- <td><label for="{{skey}}|{{okey}}"
- style="color:#424242;">{{ option.desc }}:</label></td>
+ <td><label for="{{section.name}}|{{option.name}}"
+ style="color:#424242;">{{ option.long_name }}:</label></td>
<td>
{% if option.type == "bool" %}
<select id="{{skey}}|{{okey}}" name="{{skey}}|{{okey}}">
@@ -17,7 +18,7 @@
</select>
{% elif ";" in option.type %}
<select id="{{skey}}|{{okey}}" name="{{skey}}|{{okey}}">
- {% for entry in option.list %}
+ {% for entry in option.type.split(";") %}
<option {% if option.value == entry %}
selected="selected" {% endif %}>{{ entry }}</option>
{% endfor %}
@@ -43,6 +44,5 @@
{% endif %}
</td>
</tr>
- {% endif %}
{% endfor %}
</table> \ No newline at end of file