diff options
Diffstat (limited to 'module/web')
-rw-r--r-- | module/web/ServerThread.py | 7 | ||||
-rw-r--r-- | module/web/api_app.py | 12 | ||||
-rw-r--r-- | module/web/cnl_app.py | 2 | ||||
-rw-r--r-- | module/web/json_app.py | 39 | ||||
-rw-r--r-- | module/web/media/js/settings.coffee | 4 | ||||
-rw-r--r-- | module/web/media/js/settings.js | 2 | ||||
-rw-r--r-- | module/web/middlewares.py | 10 | ||||
-rw-r--r-- | module/web/pyload_app.py | 54 | ||||
-rw-r--r-- | module/web/templates/default/base.html | 2 | ||||
-rw-r--r-- | module/web/templates/default/queue.html | 6 | ||||
-rw-r--r-- | module/web/templates/default/settings.html | 32 | ||||
-rw-r--r-- | module/web/templates/default/settings_item.html | 16 |
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">© 2008-2011 pyLoad Team
+<div id="foot">© 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 |