From 6a997661dc5c259f844531382a90a4ca120f1233 Mon Sep 17 00:00:00 2001 From: RaNaN Date: Sun, 29 Sep 2013 13:03:17 +0200 Subject: basics for web setup --- pyload/Core.py | 6 +- pyload/Setup.py | 418 --------------------- pyload/datatypes/OnlineCheck.py | 5 + pyload/setup/Setup.py | 398 ++++++++++++++++++++ pyload/setup/System_Checks.py | 126 ------- pyload/setup/__init__.py | 0 pyload/setup/dependencies.py | 84 +++++ pyload/setup/system.py | 28 ++ pyload/threads/BaseThread.py | 9 +- pyload/threads/ThreadManager.py | 7 +- pyload/utils/JsEngine.py | 2 +- pyload/utils/fs.py | 1 - pyload/web/api_app.py | 14 +- pyload/web/app/index.html | 1 + pyload/web/app/scripts/default.js | 18 +- pyload/web/app/scripts/helpers/ifEq.js | 14 + pyload/web/app/scripts/models/Setup.js | 14 + pyload/web/app/scripts/setup.js | 33 ++ pyload/web/app/scripts/views/setup/setupView.js | 89 +++++ pyload/web/app/scripts/views/setup/systemView.js | 20 + pyload/web/app/scripts/views/setup/welcomeView.js | 20 + pyload/web/app/styles/default/style.less | 10 +- pyload/web/app/templates/default/setup.html | 16 - .../web/app/templates/default/setup/actionbar.html | 24 ++ pyload/web/app/templates/default/setup/layout.html | 7 + pyload/web/app/templates/default/setup/system.html | 5 + .../web/app/templates/default/setup/welcome.html | 16 + pyload/web/pyload_app.py | 37 +- pyload/web/setup_app.py | 7 + pyload/web/utils.py | 13 + 30 files changed, 841 insertions(+), 601 deletions(-) delete mode 100644 pyload/Setup.py create mode 100644 pyload/setup/Setup.py delete mode 100644 pyload/setup/System_Checks.py create mode 100644 pyload/setup/__init__.py create mode 100644 pyload/setup/dependencies.py create mode 100644 pyload/setup/system.py create mode 100644 pyload/web/app/scripts/helpers/ifEq.js create mode 100644 pyload/web/app/scripts/models/Setup.js create mode 100644 pyload/web/app/scripts/setup.js create mode 100644 pyload/web/app/scripts/views/setup/setupView.js create mode 100644 pyload/web/app/scripts/views/setup/systemView.js create mode 100644 pyload/web/app/scripts/views/setup/welcomeView.js delete mode 100644 pyload/web/app/templates/default/setup.html create mode 100644 pyload/web/app/templates/default/setup/actionbar.html create mode 100644 pyload/web/app/templates/default/setup/layout.html create mode 100644 pyload/web/app/templates/default/setup/system.html create mode 100644 pyload/web/app/templates/default/setup/welcome.html diff --git a/pyload/Core.py b/pyload/Core.py index f97cfcf3b..5e083a14e 100644 --- a/pyload/Core.py +++ b/pyload/Core.py @@ -120,21 +120,21 @@ class Core(object): elif option in ("-d", "--debug"): self.doDebug = True elif option in ("-u", "--user"): - from Setup import Setup + from setup.Setup import Setup self.config = ConfigParser() s = Setup(pypath, self.config) s.set_user() exit() elif option in ("-s", "--setup"): - from Setup import Setup + from setup.Setup import Setup self.config = ConfigParser() s = Setup(pypath, self.config) s.start() exit() elif option == "--changedir": - from Setup import Setup + from setup.Setup import Setup self.config = ConfigParser() s = Setup(pypath, self.config) diff --git a/pyload/Setup.py b/pyload/Setup.py deleted file mode 100644 index d2ec3731f..000000000 --- a/pyload/Setup.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -############################################################################### -# Copyright(c) 2008-2012 pyLoad Team -# http://www.pyload.org -# -# This file is part of pyLoad. -# pyLoad is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# Subjected to the terms and conditions in LICENSE -# -# @author: RaNaN -############################################################################### - -import pyload.utils.pylgettext as gettext -import os -import sys -import socket -import webbrowser - -from getpass import getpass -from time import time -from sys import exit - -from pyload.utils.fs import abspath, dirname, exists, join, makedirs -from pyload.utils import get_console_encoding -from pyload.web.ServerThread import WebServer - - -class Setup(): - """ - pyLoads initial setup configuration assistant - """ - - def __init__(self, path, config): - self.path = path - self.config = config - self.stdin_encoding = get_console_encoding(sys.stdin.encoding) - self.lang = None - # We will create a timestamp so that the setup will be completed in a specific interval - self.timestamp = time() - - # TODO: probably unneeded - self.yes = "yes" - self.no = "no" - - - def start(self): - web = WebServer(pysetup=self) - web.start() - - error = web.check_error() - if error: #todo errno 44 port already in use - print error - - url = "http://%s:%d/" % (socket.gethostbyname(socket.gethostname()), web.port) - - print "Setup is started" - - opened = webbrowser.open_new_tab(url) - if not opened: - print "Please point your browser to %s" % url - - - self.ask_lang() - - print "" - print _("Would you like to configure pyLoad via Webinterface?") - print _("You need a Browser and a connection to this PC for it.") - print _("Url would be: http://hostname:8000/") - viaweb = self.ask(_("Start initial webinterface for configuration?"), self.yes, bool=True) - if viaweb: - self.start_web() - else: - self.start_cli() - - - - def start_cli(self): - - - print _("Welcome to the pyLoad Configuration Assistent.") - print _("It will check your system and make a basic setup in order to run pyLoad.") - print "" - print _("The value in brackets [] always is the default value,") - print _("in case you don't want to change it or you are unsure what to choose, just hit enter.") - print _( - "Don't forget: You can always rerun this assistent with --setup or -s parameter, when you start pyLoadCore.") - print _("If you have any problems with this assistent hit CTRL+C,") - print _("to abort and don't let him start with pyLoadCore automatically anymore.") - print "" - print _("When you are ready for system check, hit enter.") - raw_input() - - #self.get_page_next() - - - if len(avail) < 5: - print _("Features missing: ") - print - - if not self.check_module("Crypto"): - print _("no py-crypto available") - print _("You need this if you want to decrypt container files.") - print "" - - if not ssl: - print _("no SSL available") - print _("This is needed if you want to establish a secure connection to core or webinterface.") - print _("If you only want to access locally to pyLoad ssl is not useful.") - print "" - - if not captcha: - print _("no Captcha Recognition available") - print _("Only needed for some hosters and as freeuser.") - print "" - - if not js: - print _("no JavaScript engine found") - print _("You will need this for some Click'N'Load links. Install Spidermonkey, ossp-js, pyv8 or rhino") - - print _("You can abort the setup now and fix some dependencies if you want.") - - con = self.ask(_("Continue with setup?"), self.yes, bool=True) - - if not con: - return False - - print "" - print _("Do you want to change the config path? Current is %s") % abspath("") - print _( - "If you use pyLoad on a server or the home partition lives on an internal flash it may be a good idea to change it.") - path = self.ask(_("Change config path?"), self.no, bool=True) - if path: - self.conf_path() - #calls exit when changed - - print "" - print _("Do you want to configure login data and basic settings?") - print _("This is recommend for first run.") - con = self.ask(_("Make basic setup?"), self.yes, bool=True) - - if con: - self.conf_basic() - - if ssl: - print "" - print _("Do you want to configure ssl?") - ssl = self.ask(_("Configure ssl?"), self.no, bool=True) - if ssl: - self.conf_ssl() - - if web: - print "" - print _("Do you want to configure webinterface?") - web = self.ask(_("Configure webinterface?"), self.yes, bool=True) - if web: - self.conf_web() - - print "" - print _("Setup finished successfully.") - print _("Hit enter to exit and restart pyLoad") - raw_input() - return True - - - def start_web(self): - print "" - print _("Webinterface running for setup.") - # TODO start browser? - try: - from pyload.web import ServerThread - ServerThread.setup = self - from pyload.web import webinterface - webinterface.run_simple() - self.web = True - return True - except Exception, e: - print "Webinterface failed with this error: ", e - print "Falling back to commandline setup." - self.start_cli() - - - def conf_basic(self): - print "" - print _("## Basic Setup ##") - - print "" - print _("The following logindata is valid for CLI, GUI and webinterface.") - - from pyload.database import DatabaseBackend - - db = DatabaseBackend(None) - db.setup() - username = self.ask(_("Username"), "User") - password = self.ask("", "", password=True) - db.addUser(username, password) - db.shutdown() - - print "" - print _("External clients (GUI, CLI or other) need remote access to work over the network.") - print _("However, if you only want to use the webinterface you may disable it to save ram.") - self.config["remote"]["activated"] = self.ask(_("Enable remote access"), self.yes, bool=True) - - print "" - langs = self.config.getMetaData("general", "language") - self.config["general"]["language"] = self.ask(_("Language"), "en", langs.type.split(";")) - - self.config["general"]["download_folder"] = self.ask(_("Download folder"), "Downloads") - self.config["download"]["max_downloads"] = self.ask(_("Max parallel downloads"), "3") - #print _("You should disable checksum proofing, if you have low hardware requirements.") - #self.config["general"]["checksum"] = self.ask(_("Proof checksum?"), "y", bool=True) - - reconnect = self.ask(_("Use Reconnect?"), self.no, bool=True) - self.config["reconnect"]["activated"] = reconnect - if reconnect: - self.config["reconnect"]["method"] = self.ask(_("Reconnect script location"), "./reconnect.sh") - - - def conf_web(self): - print "" - print _("## Webinterface Setup ##") - - print "" - self.config["webinterface"]["activated"] = self.ask(_("Activate webinterface?"), self.yes, bool=True) - print "" - print _("Listen address, if you use 127.0.0.1 or localhost, the webinterface will only accessible locally.") - self.config["webinterface"]["host"] = self.ask(_("Address"), "0.0.0.0") - self.config["webinterface"]["port"] = self.ask(_("Port"), "8000") - print "" - print _("pyLoad offers several server backends, now following a short explanation.") - print "threaded:", _("Default server, this server offers SSL and is a good alternative to builtin.") - print "fastcgi:", _( - "Can be used by apache, lighttpd, requires you to configure them, which is not too easy job.") - print "lightweight:", _("Very fast alternative written in C, requires libev and linux knowledge.") - print "\t", _("Get it from here: https://github.com/jonashaag/bjoern, compile it") - print "\t", _("and copy bjoern.so to pyload/lib") - - print - print _( - "Attention: In some rare cases the builtin server is not working, if you notice problems with the webinterface") - print _("come back here and change the builtin server to the threaded one here.") - - self.config["webinterface"]["server"] = self.ask(_("Server"), "threaded", - ["builtin", "threaded", "fastcgi", "lightweight"]) - - def conf_ssl(self): - print "" - print _("## SSL Setup ##") - print "" - print _("Execute these commands from pyLoad config folder to make ssl certificates:") - print "" - print "openssl genrsa -out ssl.key 1024" - print "openssl req -new -key ssl.key -out ssl.csr" - print "openssl req -days 36500 -x509 -key ssl.key -in ssl.csr > ssl.crt " - print "" - print _("If you're done and everything went fine, you can activate ssl now.") - self.config["ssl"]["activated"] = self.ask(_("Activate SSL?"), self.yes, bool=True) - - def set_user(self): - gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) - translation = gettext.translation("setup", join(self.path, "locale"), - languages=[self.config["general"]["language"], "en"], fallback=True) - translation.install(True) - - from pyload.database import DatabaseBackend - - db = DatabaseBackend(None) - db.setup() - - noaction = True - try: - while True: - print _("Select action") - print _("1 - Create/Edit user") - print _("2 - List users") - print _("3 - Remove user") - print _("4 - Quit") - action = raw_input("[1]/2/3/4: ") - if not action in ("1", "2", "3", "4"): - continue - elif action == "1": - print "" - username = self.ask(_("Username"), "User") - password = self.ask("", "", password=True) - db.addUser(username, password) - noaction = False - elif action == "2": - print "" - print _("Users") - print "-----" - users = db.getAllUserData() - noaction = False - for user in users.itervalues(): - print user.name - print "-----" - print "" - elif action == "3": - print "" - username = self.ask(_("Username"), "") - if username: - db.removeUserByName(username) - noaction = False - elif action == "4": - db.syncSave() - break - finally: - if not noaction: - db.shutdown() - - def conf_path(self, trans=False): - if trans: - gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) - translation = gettext.translation("setup", join(self.path, "locale"), - languages=[self.config["general"]["language"], "en"], fallback=True) - translation.install(True) - - print _("Setting new configpath, current configuration will not be transferred!") - path = self.ask(_("Config path"), abspath("")) - try: - path = join(pypath, path) - if not exists(path): - makedirs(path) - f = open(join(pypath, "pyload", "config", "configdir"), "wb") - f.write(path) - f.close() - print _("Config path changed, setup will now close, please restart to go on.") - print _("Press Enter to exit.") - raw_input() - exit() - except Exception, e: - print _("Setting config path failed: %s") % str(e) - - - def ask_lang(self): - langs = self.config.getMetaData("general", "language").type.split(";") - self.lang = self.ask(u"Choose your Language / Wähle deine Sprache", "en", langs) - gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) - translation = gettext.translation("setup", join(self.path, "locale"), languages=[self.lang, "en"], fallback=True) - translation.install(True) - - #l10n Input shorthand for yes - self.yes = _("y") - #l10n Input shorthand for no - self.no = _("n") - - def ask(self, qst, default, answers=[], bool=False, password=False): - """ Generate dialog on command line """ - - if answers: - info = "(" - for i, answer in enumerate(answers): - info += (", " if i != 0 else "") + str((answer == default and "[%s]" % answer) or answer) - - info += ")" - elif bool: - if default == self.yes: - info = "([%s]/%s)" % (self.yes, self.no) - else: - info = "(%s/[%s])" % (self.yes, self.no) - else: - info = "[%s]" % default - - if password: - p1 = True - p2 = False - while p1 != p2: - # getpass(_("Password: ")) will crash on systems with broken locales (Win, NAS) - sys.stdout.write(_("Password: ")) - p1 = getpass("") - - if len(p1) < 4: - print _("Password too short. Use at least 4 symbols.") - continue - - sys.stdout.write(_("Password (again): ")) - p2 = getpass("") - - if p1 == p2: - return p1 - else: - print _("Passwords did not match.") - - while True: - input = raw_input(qst + " %s: " % info) - input = input.decode(self.stdin_encoding) - - if input.strip() == "": - input = default - - if bool: - #l10n yes, true,t are inputs for booleans with value true - if input.lower().strip() in [self.yes, _("yes"), _("true"), _("t"), "yes"]: - return True - #l10n no, false,f are inputs for booleans with value false - elif input.lower().strip() in [self.no, _("no"), _("false"), _("f"), "no"]: - return False - else: - print _("Invalid Input") - continue - - if not answers: - return input - - else: - if input in answers: - return input - else: - print _("Invalid Input") - - -if __name__ == "__main__": - test = Setup(join(abspath(dirname(__file__)), ".."), None) - test.start() diff --git a/pyload/datatypes/OnlineCheck.py b/pyload/datatypes/OnlineCheck.py index 2797828bf..b0b19cf76 100644 --- a/pyload/datatypes/OnlineCheck.py +++ b/pyload/datatypes/OnlineCheck.py @@ -5,6 +5,7 @@ from time import time from pyload.Api import OnlineCheck as OC + class OnlineCheck: """ Helper class that holds result of an initiated online check """ @@ -16,6 +17,10 @@ class OnlineCheck: self.timestamp = time() + def isStale(self, timeout=5): + """ checks if the data was updated or accessed recently """ + return self.timestamp + timeout * 60 < time() + def update(self, result): self.timestamp = time() self.result.update(result) diff --git a/pyload/setup/Setup.py b/pyload/setup/Setup.py new file mode 100644 index 000000000..78afb7fcc --- /dev/null +++ b/pyload/setup/Setup.py @@ -0,0 +1,398 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +############################################################################### +# Copyright(c) 2008-2013 pyLoad Team +# http://www.pyload.org +# +# This file is part of pyLoad. +# pyLoad is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Subjected to the terms and conditions in LICENSE +# +# @author: RaNaN +############################################################################### + +import os +import sys +import socket +import webbrowser + +from getpass import getpass +from time import time +from sys import exit + +from pyload.utils import pylgettext as gettext +from pyload.utils.fs import abspath, dirname, exists, join, makedirs +from pyload.utils import get_console_encoding +from pyload.web.ServerThread import WebServer + + +class Setup(): + """ + pyLoads initial setup configuration assistant + """ + + def __init__(self, path, config): + self.path = path + self.config = config + self.stdin_encoding = get_console_encoding(sys.stdin.encoding) + self.lang = None + # We will create a timestamp so that the setup will be completed in a specific interval + self.timestamp = time() + + # TODO: probably unneeded + self.yes = "yes" + self.no = "no" + + def start(self): + import __builtin__ + # set the gettext translation + __builtin__._ = lambda x: x + + web = WebServer(pysetup=self) + web.start() + + error = web.check_error() + + # TODO: start cli in this case + if error: #todo errno 44 port already in use + print error + + url = "http://%s:%d/" % (socket.gethostbyname(socket.gethostname()), web.port) + + print "Setup is running at %s" % url + + opened = webbrowser.open_new_tab(url) + if not opened: + print "Please point your browser to the url above." + + cli = self.ask("Use commandline for configuration instead?", self.no, bool=True) + if cli: + self.start_cli() + else: + raw_input() + + def start_cli(self): + + self.ask_lang() + + print _("Welcome to the pyLoad Configuration Assistent.") + print _("It will check your system and make a basic setup in order to run pyLoad.") + print "" + print _("The value in brackets [] always is the default value,") + print _("in case you don't want to change it or you are unsure what to choose, just hit enter.") + print _( + "Don't forget: You can always rerun this assistent with --setup or -s parameter, when you start pyLoadCore.") + print _("If you have any problems with this assistent hit CTRL+C,") + print _("to abort and don't let him start with pyLoadCore automatically anymore.") + print "" + print _("When you are ready for system check, hit enter.") + raw_input() + + #self.get_page_next() + + + if len(avail) < 5: + print _("Features missing: ") + print + + if not self.check_module("Crypto"): + print _("no py-crypto available") + print _("You need this if you want to decrypt container files.") + print "" + + if not ssl: + print _("no SSL available") + print _("This is needed if you want to establish a secure connection to core or webinterface.") + print _("If you only want to access locally to pyLoad ssl is not useful.") + print "" + + if not captcha: + print _("no Captcha Recognition available") + print _("Only needed for some hosters and as freeuser.") + print "" + + if not js: + print _("no JavaScript engine found") + print _("You will need this for some Click'N'Load links. Install Spidermonkey, ossp-js, pyv8 or rhino") + + print _("You can abort the setup now and fix some dependencies if you want.") + + con = self.ask(_("Continue with setup?"), self.yes, bool=True) + + if not con: + return False + + print "" + print _("Do you want to change the config path? Current is %s") % abspath("") + print _( + "If you use pyLoad on a server or the home partition lives on an internal flash it may be a good idea to change it.") + path = self.ask(_("Change config path?"), self.no, bool=True) + if path: + self.conf_path() + #calls exit when changed + + print "" + print _("Do you want to configure login data and basic settings?") + print _("This is recommend for first run.") + con = self.ask(_("Make basic setup?"), self.yes, bool=True) + + if con: + self.conf_basic() + + if ssl: + print "" + print _("Do you want to configure ssl?") + ssl = self.ask(_("Configure ssl?"), self.no, bool=True) + if ssl: + self.conf_ssl() + + if web: + print "" + print _("Do you want to configure webinterface?") + web = self.ask(_("Configure webinterface?"), self.yes, bool=True) + if web: + self.conf_web() + + print "" + print _("Setup finished successfully.") + print _("Hit enter to exit and restart pyLoad") + raw_input() + return True + + + def conf_basic(self): + print "" + print _("## Basic Setup ##") + + print "" + print _("The following logindata is valid for CLI, GUI and webinterface.") + + from pyload.database import DatabaseBackend + + db = DatabaseBackend(None) + db.setup() + username = self.ask(_("Username"), "User") + password = self.ask("", "", password=True) + db.addUser(username, password) + db.shutdown() + + print "" + print _("External clients (GUI, CLI or other) need remote access to work over the network.") + print _("However, if you only want to use the webinterface you may disable it to save ram.") + self.config["remote"]["activated"] = self.ask(_("Enable remote access"), self.yes, bool=True) + + print "" + langs = self.config.getMetaData("general", "language") + self.config["general"]["language"] = self.ask(_("Language"), "en", langs.type.split(";")) + + self.config["general"]["download_folder"] = self.ask(_("Download folder"), "Downloads") + self.config["download"]["max_downloads"] = self.ask(_("Max parallel downloads"), "3") + #print _("You should disable checksum proofing, if you have low hardware requirements.") + #self.config["general"]["checksum"] = self.ask(_("Proof checksum?"), "y", bool=True) + + reconnect = self.ask(_("Use Reconnect?"), self.no, bool=True) + self.config["reconnect"]["activated"] = reconnect + if reconnect: + self.config["reconnect"]["method"] = self.ask(_("Reconnect script location"), "./reconnect.sh") + + + def conf_web(self): + print "" + print _("## Webinterface Setup ##") + + print "" + self.config["webinterface"]["activated"] = self.ask(_("Activate webinterface?"), self.yes, bool=True) + print "" + print _("Listen address, if you use 127.0.0.1 or localhost, the webinterface will only accessible locally.") + self.config["webinterface"]["host"] = self.ask(_("Address"), "0.0.0.0") + self.config["webinterface"]["port"] = self.ask(_("Port"), "8000") + print "" + print _("pyLoad offers several server backends, now following a short explanation.") + print "threaded:", _("Default server, this server offers SSL and is a good alternative to builtin.") + print "fastcgi:", _( + "Can be used by apache, lighttpd, requires you to configure them, which is not too easy job.") + print "lightweight:", _("Very fast alternative written in C, requires libev and linux knowledge.") + print "\t", _("Get it from here: https://github.com/jonashaag/bjoern, compile it") + print "\t", _("and copy bjoern.so to pyload/lib") + + print + print _( + "Attention: In some rare cases the builtin server is not working, if you notice problems with the webinterface") + print _("come back here and change the builtin server to the threaded one here.") + + self.config["webinterface"]["server"] = self.ask(_("Server"), "threaded", + ["builtin", "threaded", "fastcgi", "lightweight"]) + + def conf_ssl(self): + print "" + print _("## SSL Setup ##") + print "" + print _("Execute these commands from pyLoad config folder to make ssl certificates:") + print "" + print "openssl genrsa -out ssl.key 1024" + print "openssl req -new -key ssl.key -out ssl.csr" + print "openssl req -days 36500 -x509 -key ssl.key -in ssl.csr > ssl.crt " + print "" + print _("If you're done and everything went fine, you can activate ssl now.") + self.config["ssl"]["activated"] = self.ask(_("Activate SSL?"), self.yes, bool=True) + + def set_user(self): + gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) + translation = gettext.translation("setup", join(self.path, "locale"), + languages=[self.config["general"]["language"], "en"], fallback=True) + translation.install(True) + + from pyload.database import DatabaseBackend + + db = DatabaseBackend(None) + db.setup() + + noaction = True + try: + while True: + print _("Select action") + print _("1 - Create/Edit user") + print _("2 - List users") + print _("3 - Remove user") + print _("4 - Quit") + action = raw_input("[1]/2/3/4: ") + if not action in ("1", "2", "3", "4"): + continue + elif action == "1": + print "" + username = self.ask(_("Username"), "User") + password = self.ask("", "", password=True) + db.addUser(username, password) + noaction = False + elif action == "2": + print "" + print _("Users") + print "-----" + users = db.getAllUserData() + noaction = False + for user in users.itervalues(): + print user.name + print "-----" + print "" + elif action == "3": + print "" + username = self.ask(_("Username"), "") + if username: + db.removeUserByName(username) + noaction = False + elif action == "4": + db.syncSave() + break + finally: + if not noaction: + db.shutdown() + + def conf_path(self, trans=False): + if trans: + gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) + translation = gettext.translation("setup", join(self.path, "locale"), + languages=[self.config["general"]["language"], "en"], fallback=True) + translation.install(True) + + print _("Setting new configpath, current configuration will not be transferred!") + path = self.ask(_("Config path"), abspath("")) + try: + path = join(pypath, path) + if not exists(path): + makedirs(path) + f = open(join(pypath, "pyload", "config", "configdir"), "wb") + f.write(path) + f.close() + print _("Config path changed, setup will now close, please restart to go on.") + print _("Press Enter to exit.") + raw_input() + exit() + except Exception, e: + print _("Setting config path failed: %s") % str(e) + + + def ask_lang(self): + langs = self.config.getMetaData("general", "language").type.split(";") + self.lang = self.ask(u"Choose your Language / Wähle deine Sprache", "en", langs) + gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) + translation = gettext.translation("setup", join(self.path, "locale"), languages=[self.lang, "en"], fallback=True) + translation.install(True) + + #l10n Input shorthand for yes + self.yes = _("y") + #l10n Input shorthand for no + self.no = _("n") + + def ask(self, qst, default, answers=[], bool=False, password=False): + """ Generate dialog on command line """ + + if answers: + info = "(" + for i, answer in enumerate(answers): + info += (", " if i != 0 else "") + str((answer == default and "[%s]" % answer) or answer) + + info += ")" + elif bool: + if default == self.yes: + info = "([%s]/%s)" % (self.yes, self.no) + else: + info = "(%s/[%s])" % (self.yes, self.no) + else: + info = "[%s]" % default + + if password: + p1 = True + p2 = False + while p1 != p2: + # getpass(_("Password: ")) will crash on systems with broken locales (Win, NAS) + sys.stdout.write(_("Password: ")) + p1 = getpass("") + + if len(p1) < 4: + print _("Password too short. Use at least 4 symbols.") + continue + + sys.stdout.write(_("Password (again): ")) + p2 = getpass("") + + if p1 == p2: + return p1 + else: + print _("Passwords did not match.") + + while True: + input = raw_input(qst + " %s: " % info) + input = input.decode(self.stdin_encoding) + + if input.strip() == "": + input = default + + if bool: + #l10n yes, true,t are inputs for booleans with value true + if input.lower().strip() in [self.yes, _("yes"), _("true"), _("t"), "yes"]: + return True + #l10n no, false,f are inputs for booleans with value false + elif input.lower().strip() in [self.no, _("no"), _("false"), _("f"), "no"]: + return False + else: + print _("Invalid Input") + continue + + if not answers: + return input + + else: + if input in answers: + return input + else: + print _("Invalid Input") + + +if __name__ == "__main__": + test = Setup(join(abspath(dirname(__file__)), ".."), None) + test.start() diff --git a/pyload/setup/System_Checks.py b/pyload/setup/System_Checks.py deleted file mode 100644 index cef46956b..000000000 --- a/pyload/setup/System_Checks.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - @author: RaNaN -""" -from getpass import getpass -import module.common.pylgettext as gettext -import os -from os import makedirs -from os.path import abspath, dirname, exists, join -from subprocess import PIPE, call -import sys -from sys import exit -from module.utils import get_console_encoding - -class System_Checks(): - def __init__(self): - self.result = "" - - def print_str(self, text, translate = True): - if translate: - self.result += _(text) + "\n" - else: - self.result += text + "\n" - - def print_dep(self, name, value): - """Print Status of dependency""" - if value: - self.print_str(name + ": OK", False) - else: - self.print_str(name + ": missing", False) - - def check_basic(self): - self.result = "" #clear result - python = False - if sys.version_info[:2] > (2, 7): - self.print_str("Your python version is to new, Please use Python 2.6/2.7") - elif sys.version_info[:2] < (2, 5): - self.print_str("Your python version is to old, Please use at least Python 2.5") - else: - self.print_str("Python Version: OK") - python = True - - curl = self.check_module("pycurl") - self.print_dep("pycurl", curl) - - sqlite = self.check_module("sqlite3") - self.print_dep("sqlite3", sqlite) - - beaker = self.check_module("beaker") - self.print_dep("beaker", beaker) - - jinja = True - try: - import jinja2 - v = jinja2.__version__ - if v and "unknown" not in v: - if not v.startswith("2.5") and not v.startswith("2.6"): - self.print_str("Your installed jinja2 version %s seems too old.") % jinja2.__version__ - self.print_str("You can safely continue but if the webinterface is not working,") - self.print_str("please upgrade or deinstall it, pyLoad includes a sufficient jinja2 library.") - jinja = False - except: - pass - self.print_dep("jinja2", jinja) - - return self.result, (python and curl and sqlite and (beaker or jinja)) - - def check_ssl(self): - self.result = "" #clear result - ssl = self.check_module("OpenSSL") - self.print_dep("py-OpenSSL", ssl) - return self.result, ssl - - def check_crypto(self): - self.result = "" #clear result - crypto = self.check_module("Crypto") - self.print_dep("pycrypto", crypto) - return self.result, crypto - - def check_captcha(self): - self.result = "" #clear result - pil = self.check_module("Image") - self.print_dep("py-imaging", pil) - if os.name == "nt": - tesser = self.check_prog([join(pypath, "tesseract", "tesseract.exe"), "-v"]) - else: - tesser = self.check_prog(["tesseract", "-v"]) - self.print_dep("tesseract", tesser) - return self.result, pil and tesser - - def check_js(self): - self.result = "" #clear result - from module.common import JsEngine - js = True if JsEngine.ENGINE else False - self.print_dep(_("JS engine"), js) - return self.result, pil and tesser - - def check_module(self, module): - try: - __import__(module) - return True - except: - return False - - def check_prog(self, command): - pipe = PIPE - try: - call(command, stdout=pipe, stderr=pipe) - return True - except: - return False - diff --git a/pyload/setup/__init__.py b/pyload/setup/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyload/setup/dependencies.py b/pyload/setup/dependencies.py new file mode 100644 index 000000000..53457de93 --- /dev/null +++ b/pyload/setup/dependencies.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# Provide gettext marker +_ = lambda x: x + + +def find_module(name): + from imp import find_module + + try: + f, pathname, desc = find_module(name) + if f is not None: + f.close() + return True + except: + return False + + +class Dependency(object): + name = None + optional = True + desc = None + + @classmethod + def check(cls): + """ Returns (availability, version) as tuple """ + inst = cls() + avail = inst.isStatisfied() + v = None + if avail: + v = inst.getVersion() + + return avail, v + + def isStatisfied(self): + raise NotImplementedError + + def getVersion(self): + return None + + +class Python(Dependency): + name = "Python" + optional = False + + def isStatisfied(self): + # obviously + return True + + def getVersion(self): + import sys + + ".".join(str(v) for v in sys.version_info[:3]) + + +class JSON(Dependency): + name = "json" + optional = False + + def isStatisfied(self): + # TODO + return True + + +class PyCurl(Dependency): + name = "pycurl" + optional = False + + def isStatisfied(self): + # TODO + return True + + +class Sqlite(Dependency): + name = "sqlite" + optional = False + + def isStatisfied(self): + # TODO + return True + +# TODO: ssl, crypto, image, tesseract, js + +deps = [x for x in locals().itervalues() if issubclass(x, Dependency) and x is not Dependency] \ No newline at end of file diff --git a/pyload/setup/system.py b/pyload/setup/system.py new file mode 100644 index 000000000..6e7039331 --- /dev/null +++ b/pyload/setup/system.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +import sys +import os + +# gettext decorator, translated only when needed +_ = lambda x: x + +# platform usually don't change at runtime +info = None + + +def get_system_info(): + """ Returns system information as dict """ + global info + + if info is None: + import platform + + info = { + _("Platform"): platform.platform(), + _("Version"): sys.version, + _("Path"): os.path.abspath(""), + _("Encoding"): sys.getdefaultencoding(), + _("FS-Encoding"): sys.getfilesystemencoding() + } + + return info \ No newline at end of file diff --git a/pyload/threads/BaseThread.py b/pyload/threads/BaseThread.py index b7912e924..3655480dd 100644 --- a/pyload/threads/BaseThread.py +++ b/pyload/threads/BaseThread.py @@ -10,6 +10,7 @@ from traceback import format_exc from pyload.utils import primary_uid from pyload.utils.fs import listdir, join, save_join, stat, exists +from pyload.setup.system import get_system_info class BaseThread(Thread): @@ -137,9 +138,7 @@ class BaseThread(Thread): def getSystemDump(self): dump = "SYSTEM:\n\n" - dump += """Platform: %s -Version: %s -Encoding: %s -FS-Encoding: %s - """ % (sys.platform, sys.version, sys.getdefaultencoding(), sys.getfilesystemencoding()) + for k,v in get_system_info().iteritems(): + dump += "%s: %s\n" % (k, v) + return dump diff --git a/pyload/threads/ThreadManager.py b/pyload/threads/ThreadManager.py index ff8bfe8d7..07b0cd6e9 100644 --- a/pyload/threads/ThreadManager.py +++ b/pyload/threads/ThreadManager.py @@ -167,11 +167,14 @@ class ThreadManager: self.assignJob() #it may be failed non critical so we try it again - if (self.infoCache or self.infoResults) and self.timestamp < time(): + if self.infoCache and self.timestamp < time(): self.infoCache.clear() - self.infoResults.clear() self.log.debug("Cleared Result cache") + for rid in self.infoResults.keys(): + if self.infoResults[rid].isStale(): + del self.infoResults[rid] + def tryReconnect(self): """checks if reconnect needed""" diff --git a/pyload/utils/JsEngine.py b/pyload/utils/JsEngine.py index ef7494d16..3318ffb2a 100644 --- a/pyload/utils/JsEngine.py +++ b/pyload/utils/JsEngine.py @@ -48,7 +48,7 @@ if not ENGINE: if not ENGINE or DEBUG: try: - find_module("PyV8") + import PyV8 ENGINE = "pyv8" PYV8 = True except: diff --git a/pyload/utils/fs.py b/pyload/utils/fs.py index 92cc605e7..52bf0bd51 100644 --- a/pyload/utils/fs.py +++ b/pyload/utils/fs.py @@ -44,7 +44,6 @@ def exists(path): def makedirs(path, mode=0755): return os.makedirs(fs_encode(path), mode) -# fs_decode? def listdir(path): return [fs_decode(x) for x in os.listdir(fs_encode(path))] diff --git a/pyload/web/api_app.py b/pyload/web/api_app.py index d0a41b4d0..9370e671f 100644 --- a/pyload/web/api_app.py +++ b/pyload/web/api_app.py @@ -6,7 +6,7 @@ from traceback import format_exc, print_exc from bottle import route, request, response, HTTPError, parse_auth -from utils import set_session, get_user_api +from utils import set_session, get_user_api, add_json_header from webinterface import PYLOAD, session from pyload.Api import ExceptionObject @@ -14,12 +14,6 @@ from pyload.remote.json_converter import loads, dumps, BaseEncoder from pyload.utils import remove_chars -def add_header(r): - r.headers.replace("Content-type", "application/json") - r.headers.append("Cache-Control", "no-cache, must-revalidate") - r.headers.append("Access-Control-Allow-Origin", request.get_header('Origin', '*')) - r.headers.append("Access-Control-Allow-Credentials", "true") - # returns http error def error(code, msg): return HTTPError(code, dumps(msg), **dict(response.headers)) @@ -29,7 +23,7 @@ def error(code, msg): @route("/api/") @route("/api/", method="POST") def call_api(func, args=""): - add_header(response) + add_json_header(response) s = request.environ.get('beaker.session') # Accepts standard http auth @@ -96,7 +90,7 @@ def call_api(func, args=""): @route("/api/login") @route("/api/login", method="POST") def login(): - add_header(response) + add_json_header(response) username = request.params.get("username") password = request.params.get("password") @@ -128,7 +122,7 @@ def login(): @route("/api/logout") @route("/api/logout", method="POST") def logout(): - add_header(response) + add_json_header(response) s = request.environ.get('beaker.session') s.delete() diff --git a/pyload/web/app/index.html b/pyload/web/app/index.html index 4a4195b13..bf75d40ed 100644 --- a/pyload/web/app/index.html +++ b/pyload/web/app/index.html @@ -41,6 +41,7 @@ // TODO window.pathPrefix = '/'; window.wsAddress = configValue('{{ws}}', 'ws://%s:7227'); + window.setup = configValue('{{setup}}', 'false'); require(['config'], function(Config) { require(['default'], function(App) { diff --git a/pyload/web/app/scripts/default.js b/pyload/web/app/scripts/default.js index 428ec2b28..91b46715e 100644 --- a/pyload/web/app/scripts/default.js +++ b/pyload/web/app/scripts/default.js @@ -1,5 +1,5 @@ -define('default', ['backbone', 'jquery', 'app', 'router', 'models/UserSession'], - function(Backbone, $, App, Router, UserSession) { +define('default', ['require', 'backbone', 'jquery', 'app', 'router', 'models/UserSession'], + function(require, Backbone, $, App, Router, UserSession) { 'use strict'; // Global ajax options @@ -21,9 +21,17 @@ define('default', ['backbone', 'jquery', 'app', 'router', 'models/UserSession'], }; $(function() { - App.user = new UserSession(); - App.router = new Router(); - App.start(); + // load setup async + if (window.setup === 'true') { + require(['setup'], function(SetupRouter) { + App.router = new SetupRouter(); + App.start(); + }); + } else { + App.user = new UserSession(); + App.router = new Router(); + App.start(); + } }); return App; diff --git a/pyload/web/app/scripts/helpers/ifEq.js b/pyload/web/app/scripts/helpers/ifEq.js new file mode 100644 index 000000000..1c8a71b61 --- /dev/null +++ b/pyload/web/app/scripts/helpers/ifEq.js @@ -0,0 +1,14 @@ +define('helpers/ifEq', ['underscore', 'handlebars'], + function(_, Handlebars) { + /*jshint validthis:true */ + 'use strict'; + function ifEq(v1, v2, options) { + if (v1 === v2) { + return options.fn(this); + } + return options.inverse(this); + } + + Handlebars.registerHelper('ifEq', ifEq); + return ifEq; + }); diff --git a/pyload/web/app/scripts/models/Setup.js b/pyload/web/app/scripts/models/Setup.js new file mode 100644 index 000000000..82a2978db --- /dev/null +++ b/pyload/web/app/scripts/models/Setup.js @@ -0,0 +1,14 @@ +define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], + function($, Backbone, _, App, Api) { + 'use strict'; + + return Backbone.Model.extend({ + + defaults: { + lang: 'en', + user: null, + password: null + } + + }); + }); \ No newline at end of file diff --git a/pyload/web/app/scripts/setup.js b/pyload/web/app/scripts/setup.js new file mode 100644 index 000000000..94d370078 --- /dev/null +++ b/pyload/web/app/scripts/setup.js @@ -0,0 +1,33 @@ +/** + * Router and controller used in setup mode + */ +define([ + // Libraries + 'backbone', + 'marionette', + 'app', + + // Views + 'views/setup/setupView' +], + function(Backbone, Marionette, App, SetupView) { + 'use strict'; + + return Backbone.Marionette.AppRouter.extend({ + + appRoutes: { + '': 'setup' + }, + + controller: { + + setup: function() { + + var view = new SetupView(); + App.actionbar.show(new view.actionbar()); + App.content.show(view); + } + + } + }); + }); diff --git a/pyload/web/app/scripts/views/setup/setupView.js b/pyload/web/app/scripts/views/setup/setupView.js new file mode 100644 index 000000000..7636a0bc2 --- /dev/null +++ b/pyload/web/app/scripts/views/setup/setupView.js @@ -0,0 +1,89 @@ +define(['jquery', 'backbone', 'underscore', 'app', 'models/Setup', 'hbs!tpl/setup/layout', 'hbs!tpl/setup/actionbar', + './welcomeView', './systemView'], + function($, Backbone, _, App, Setup, template, templateBar, welcomeView, systemView) { + 'use strict'; + + return Backbone.Marionette.ItemView.extend({ + template: template, + + events: { + }, + + ui: { + page: '.setup-page' + }, + + pages: [ + welcomeView, + systemView + ], + + page: 0, + view: null, + + initialize: function() { + var self = this; + this.model = new Setup(); + + this.actionbar = Backbone.Marionette.ItemView.extend({ + template: templateBar, + view: this, + events: { + 'click .select-page': 'selectPage' + }, + + initialize: function() { + this.listenTo(self.model, 'page:changed', this.render); + }, + + serializeData: function() { + return { + page: this.view.page, + max: this.view.pages.length - 1, + pages: _.map(this.view.pages, function(p) { + return p.prototype.name; + }) + }; + }, + + selectPage: function(e) { + this.view.openPage(parseInt($(e.target).data('page'), 10)); + } + + }); + this.listenTo(this.model, 'page:next', function() { + self.openPage(self.page++); + }); + this.listenTo(this.model, 'page:prev', function() { + self.openPage(self.page--); + }); + }, + + openPage: function(page) { + console.log('Change page', page); + // check if number is reasonable + if (!_.isNumber(page) || !_.isFinite(page)) + return; + + if (page === this.page) + return; + + this.page = page; + this.onRender(); + + this.model.trigger('page:changed', page); + }, + + onRender: function() { + // close old opened view + if (this.view) + this.view.close(); + + // TODO: animation + this.view = new this.pages[this.page]({model: this.model}); + this.ui.page.empty(); + this.ui.page.append(this.view.render().$el); + } + + }); + }); \ No newline at end of file diff --git a/pyload/web/app/scripts/views/setup/systemView.js b/pyload/web/app/scripts/views/setup/systemView.js new file mode 100644 index 000000000..11e50213d --- /dev/null +++ b/pyload/web/app/scripts/views/setup/systemView.js @@ -0,0 +1,20 @@ +define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/system'], + function($, Backbone, _, App, template) { + 'use strict'; + + return Backbone.Marionette.ItemView.extend({ + + name: 'System', + template: template, + + events: { + }, + + ui: { + }, + + onRender: function() { + } + + }); + }); \ No newline at end of file diff --git a/pyload/web/app/scripts/views/setup/welcomeView.js b/pyload/web/app/scripts/views/setup/welcomeView.js new file mode 100644 index 000000000..4affc9075 --- /dev/null +++ b/pyload/web/app/scripts/views/setup/welcomeView.js @@ -0,0 +1,20 @@ +define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/welcome'], + function($, Backbone, _, App, template) { + 'use strict'; + + return Backbone.Marionette.ItemView.extend({ + + name: 'Language', + template: template, + + events: { + }, + + ui: { + }, + + onRender: function() { + } + + }); + }); \ No newline at end of file diff --git a/pyload/web/app/styles/default/style.less b/pyload/web/app/styles/default/style.less index b24e5ff21..da0e68991 100644 --- a/pyload/web/app/styles/default/style.less +++ b/pyload/web/app/styles/default/style.less @@ -231,15 +231,13 @@ header { // background-color: @greyDark; } .actionbar { + padding-top: 2px; padding-bottom: 3px; - margin-bottom: 0; + margin-bottom: 5px; border-bottom: 1px dashed @grey; height: @actionbar-height; - padding-top: 2px; - margin-bottom: 5px; - & > li > a, & > li > button { margin-top: 4px; } @@ -259,6 +257,10 @@ header { // background-color: @greyDark; margin-bottom: 0; } + select { + margin: 2px 0 0; + } + input, button { padding-top: 2px; padding-bottom: 2px; diff --git a/pyload/web/app/templates/default/setup.html b/pyload/web/app/templates/default/setup.html deleted file mode 100644 index e5c9f4b8c..000000000 --- a/pyload/web/app/templates/default/setup.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends 'default/base.html' %} -{% block title %} - {{_("Setup")}} - {{ super()}} -{% endblock %} - -{% block content %} -
-

You did it!

-

pyLoad is running and ready for configuration.

-

- - Go on - -

-
-{% endblock %} \ No newline at end of file diff --git a/pyload/web/app/templates/default/setup/actionbar.html b/pyload/web/app/templates/default/setup/actionbar.html new file mode 100644 index 000000000..b109025b7 --- /dev/null +++ b/pyload/web/app/templates/default/setup/actionbar.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/pyload/web/app/templates/default/setup/layout.html b/pyload/web/app/templates/default/setup/layout.html new file mode 100644 index 000000000..7b75e53b1 --- /dev/null +++ b/pyload/web/app/templates/default/setup/layout.html @@ -0,0 +1,7 @@ +
+

+ {{ _ "Setup" }} +

+
+
+
\ No newline at end of file diff --git a/pyload/web/app/templates/default/setup/system.html b/pyload/web/app/templates/default/setup/system.html new file mode 100644 index 000000000..84a217b19 --- /dev/null +++ b/pyload/web/app/templates/default/setup/system.html @@ -0,0 +1,5 @@ +

{{ _ "System" }}

+ +

{{_ "Dependencies" }}

+ +

{{ _ "Optional" }}

\ No newline at end of file diff --git a/pyload/web/app/templates/default/setup/welcome.html b/pyload/web/app/templates/default/setup/welcome.html new file mode 100644 index 000000000..f5c5af4d7 --- /dev/null +++ b/pyload/web/app/templates/default/setup/welcome.html @@ -0,0 +1,16 @@ +
+

{{ _ "Welcome!" }}

+ +

{{ _ "pyLoad is running and ready for configuration." }}

+ +

+ {{ _ "Select your language:" }} + +

+ + +
\ No newline at end of file diff --git a/pyload/web/pyload_app.py b/pyload/web/pyload_app.py index b182816c2..1ec7cf4c9 100644 --- a/pyload/web/pyload_app.py +++ b/pyload/web/pyload_app.py @@ -23,7 +23,9 @@ from bottle import route, static_file, response, request, redirect, template from webinterface import PYLOAD, PROJECT_DIR, SETUP, APP_PATH, UNAVAILALBE -from utils import login_required +from utils import login_required, add_json_header, select_language + +from pyload.utils import json_dumps APP_ROOT = join(PROJECT_DIR, APP_PATH) @@ -45,27 +47,42 @@ def download(fid, api): return static_file(name, path, download=True) +@route("/i18n") +@route("/i18n/:lang") +def i18n(lang=None): + add_json_header(response) + + if lang is None: + pass + # TODO use lang from PYLOAD.config or setup + else: + # TODO auto choose language + lang = select_language(["en"]) + + return json_dumps({}) + @route('/') def index(): if UNAVAILALBE: - return server_static("unavailable.html") - - if SETUP: - # TODO show different page - pass + return serve_static("unavailable.html") - resp = server_static('index.html') + resp = serve_static('index.html') + # set variable depending on setup mode + setup = 'false' if SETUP is None else 'true' + ws = PYLOAD.getWSAddress() if PYLOAD else False + web = PYLOAD.getConfigValue('webinterface', 'port') if PYLOAD else False # Render variables into the html page if resp.status_code == 200: content = resp.body.read() - resp.body = template(content, ws=PYLOAD.getWSAddress(), web=PYLOAD.getConfigValue('webinterface', 'port')) + resp.body = template(content, ws=ws, web=web, setup=setup) + resp.content_length = len(resp.body) return resp # Very last route that is registered, could match all uris @route('/') -def server_static(path): +def serve_static(path): 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" @@ -76,7 +93,7 @@ def server_static(path): # gzipped and clients accepts it # TODO: index.html is not gzipped, because of template processing - if GZIPPED[path] and "gzip" in request.get_header("Accept-Encoding", "") and path != "index.html": + if GZIPPED[path] and "gzip" in request.get_header("Accept-Encoding", "") and path != "index.html": response.headers['Vary'] = 'Accept-Encoding' response.headers['Content-Encoding'] = 'gzip' path += ".gz" diff --git a/pyload/web/setup_app.py b/pyload/web/setup_app.py index cd44ad08e..5163f9cc6 100644 --- a/pyload/web/setup_app.py +++ b/pyload/web/setup_app.py @@ -1,10 +1,14 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from time import time + from bottle import route, request, response, HTTPError, redirect from webinterface import PROJECT_DIR, SETUP +from utils import add_json_header + def setup_required(func): def _view(*args, **kwargs): # setup needs to be running @@ -14,6 +18,9 @@ def setup_required(func): return func(*args, **kwargs) return _view +# setup will close after inactivity +TIMEOUT = 15 +timestamp = time() @route("/setup") @setup_required diff --git a/pyload/web/utils.py b/pyload/web/utils.py index dae987f84..e94089185 100644 --- a/pyload/web/utils.py +++ b/pyload/web/utils.py @@ -6,6 +6,11 @@ from bottle import request, HTTPError, redirect from webinterface import PYLOAD, SETUP +def add_json_header(r): + r.headers.replace("Content-type", "application/json") + r.headers.append("Cache-Control", "no-cache, must-revalidate") + r.headers.append("Access-Control-Allow-Origin", request.get_header('Origin', '*')) + r.headers.append("Access-Control-Allow-Credentials", "true") def set_session(request, user): s = request.environ.get('beaker.session') @@ -53,6 +58,14 @@ def is_mobile(): return True return False +def select_language(langs): + + accept = request.headers.get('Accept-Language', '') + # TODO + + return langs[0] + + def login_required(perm=None): def _dec(func): -- cgit v1.2.3