summaryrefslogtreecommitdiffstats
path: root/pyload/web
diff options
context:
space:
mode:
Diffstat (limited to 'pyload/web')
-rw-r--r--pyload/web/api_app.py32
-rw-r--r--pyload/web/app/index.html47
-rw-r--r--pyload/web/app/scripts/models/Setup.js20
-rw-r--r--pyload/web/app/scripts/views/linkgrabber/packageView.js12
-rw-r--r--pyload/web/app/scripts/views/setup/finishedView.js25
-rw-r--r--pyload/web/app/scripts/views/setup/setupView.js52
-rw-r--r--pyload/web/app/scripts/views/setup/systemView.js5
-rw-r--r--pyload/web/app/scripts/views/setup/userView.js39
-rw-r--r--pyload/web/app/scripts/views/setup/welcomeView.js5
-rw-r--r--pyload/web/app/styles/default/main.less4
-rw-r--r--pyload/web/app/styles/default/setup.less0
-rw-r--r--pyload/web/app/styles/default/style.less13
-rw-r--r--pyload/web/app/templates/default/setup/error.html14
-rw-r--r--pyload/web/app/templates/default/setup/finished.html23
-rw-r--r--pyload/web/app/templates/default/setup/layout.html5
-rw-r--r--pyload/web/app/templates/default/setup/system.html57
-rw-r--r--pyload/web/app/templates/default/setup/user.html34
-rw-r--r--pyload/web/app/templates/default/setup/welcome.html24
-rw-r--r--pyload/web/bower.json2
-rw-r--r--pyload/web/middlewares.py113
-rw-r--r--pyload/web/pyload_app.py6
-rw-r--r--pyload/web/setup_app.py49
-rw-r--r--pyload/web/utils.py10
23 files changed, 414 insertions, 177 deletions
diff --git a/pyload/web/api_app.py b/pyload/web/api_app.py
index 9370e671f..39747d5ea 100644
--- a/pyload/web/api_app.py
+++ b/pyload/web/api_app.py
@@ -13,6 +13,30 @@ from pyload.Api import ExceptionObject
from pyload.remote.json_converter import loads, dumps, BaseEncoder
from pyload.utils import remove_chars
+# used for gzip compression
+try:
+ import gzip
+ from cStringIO import StringIO
+except ImportError:
+ gzip = None
+ StringIO = None
+
+# gzips response if supported
+def json_response(obj):
+ accept = 'gzip' in request.headers.get('Accept-Encoding', '')
+ result = dumps(obj)
+ # don't compress small string
+ if gzip and accept and len(result) > 500:
+ response.headers['Vary'] = 'Accept-Encoding'
+ response.headers['Content-Encoding'] = 'gzip'
+ zbuf = StringIO()
+ zfile = gzip.GzipFile(mode='wb', compresslevel=6, fileobj=zbuf)
+ zfile.write(result)
+ zfile.close()
+ return zbuf.getvalue()
+
+ return result
+
# returns http error
def error(code, msg):
@@ -78,7 +102,7 @@ def call_api(func, args=""):
result = getattr(api, func)(*args, **kwargs)
# null is invalid json response
if result is None: result = True
- return dumps(result)
+ return json_response(result)
except ExceptionObject, e:
return error(400, e.message)
@@ -98,7 +122,7 @@ def login():
user = PYLOAD.checkAuth(username, password, request.environ.get('REMOTE_ADDR', None))
if not user:
- return dumps(False)
+ return json_response(False)
s = set_session(request, user)
@@ -116,7 +140,7 @@ def login():
if request.params.get('user', None):
return dumps(result)
- return dumps(sid)
+ return json_response(sid)
@route("/api/logout")
@@ -127,4 +151,4 @@ def logout():
s = request.environ.get('beaker.session')
s.delete()
- return dumps(True)
+ return json_response(True)
diff --git a/pyload/web/app/index.html b/pyload/web/app/index.html
index bf75d40ed..98e1bf233 100644
--- a/pyload/web/app/index.html
+++ b/pyload/web/app/index.html
@@ -80,29 +80,52 @@
<a href="http://pyload.org/" target="_blank">The pyLoad Team</a><br>
</div>
</div>
- <div class="span2">
- <h2 class="block-title">Powered by</h2>
+ <div class="span2 block">
+ <h2 class="block-title">
+ <a href="http://pyload.org" target="_blank">
+ Community &nbsp;<i class="icon-comment"></i>
+ </a>
+ </h2>
<hr>
- Bootstrap <br>
+ <a href="http://pyload.org" target="_blank">Homepage</a>&nbsp;&middot;
+ <a href="http://board.pyload.org" target="_blank">Board</a>&nbsp;&middot;
+ <a href="http://pyload.org/chat" target="_blank">Chat</a>
</div>
- <div class="span2">
- <h2 class="block-title">pyLoad</h2>
+ <div class="span2 block">
+ <h2 class="block-title">
+ <a href="https://twitter.com/pyload" target="_blank">
+ Follow us &nbsp;<i class="icon-twitter"></i>
+ </a>
+ </h2>
<hr>
- dsfdsf <br>
+ <a href="https://twitter.com/pyload" target="_blank">Twitter</a>&nbsp;&middot;
+ <a href="http://www.youtube.com/user/pyloadTeam" target="_blank">Youtube</a>
</div>
- <div class="span2">
- <h2 class="block-title">Community</h2>
+ <div class="span2 block">
+ <h2 class="block-title">
+ <a href="https://github.com/pyload" target="_blank">
+ Development &nbsp;<i class="icon-github"></i>
+ </a>
+ </h2>
<hr>
- asd <br>
+ <a href="https://github.com/pyload" target="_blank">Github</a>&nbsp;&middot;
+ <a href="http://docs.pyload.org" target="_blank">Documentation</a>
</div>
- <div class="span2">
- <h2 class="block-title">Development</h2>
+ <div class="span2 block">
+ <h2 class="block-title">
+ <a href="http://pyload.org/donate" target="_blank">
+ Donate &nbsp;<i class="icon-bitcoin">&nbsp;</i>
+ </a>
+ </h2>
<hr>
- asd <br>
+ <a href="http://pyload.org/donate" target="_blank">PayPal</a>&nbsp;&middot;
+ <a href="http://blockchain.info/address/1JvcfSKuzk3VENJm9XtqGp2DCTesgokkG2" target="_blank">Bitcoin</a>&nbsp;&middot;
+ <a href="https://flattr.com/profile/pyload" target="_blank">Flattr</a>
</div>
+
</div>
</div>
</footer>
diff --git a/pyload/web/app/scripts/models/Setup.js b/pyload/web/app/scripts/models/Setup.js
index 82a2978db..424edf452 100644
--- a/pyload/web/app/scripts/models/Setup.js
+++ b/pyload/web/app/scripts/models/Setup.js
@@ -4,10 +4,30 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'],
return Backbone.Model.extend({
+ url: App.apiUrl('setup'),
defaults: {
lang: 'en',
+ system: null,
+ deps: null,
user: null,
password: null
+ },
+
+ fetch: function(options) {
+ options || (options = {});
+ options.url = App.apiUrl('setup');
+ return Backbone.Model.prototype.fetch.call(this, options);
+ },
+
+ // will get a 409 on success
+ submit: function(options) {
+ options || (options = {});
+ options.url = App.apiUrl('setup_done');
+ options.data = {
+ user: this.get('user'),
+ password: this.get('password')
+ };
+ return Backbone.Model.prototype.fetch.call(this, options);
}
});
diff --git a/pyload/web/app/scripts/views/linkgrabber/packageView.js b/pyload/web/app/scripts/views/linkgrabber/packageView.js
index 95c46e3cc..356d39b4b 100644
--- a/pyload/web/app/scripts/views/linkgrabber/packageView.js
+++ b/pyload/web/app/scripts/views/linkgrabber/packageView.js
@@ -39,9 +39,19 @@ define(['jquery', 'underscore', 'backbone', 'app', 'hbs!tpl/linkgrabber/package'
return false;
},
- renamePackage: function() {
+ renamePackage: function(e) {
+ e.stopPropagation();
+
this.ui.name.addClass('edit');
this.ui.name.find('input').focus();
+
+ var self = this;
+ $(document).one('click', function() {
+ self.ui.name.removeClass('edit');
+ self.ui.name.focus();
+ });
+
+ return false;
},
saveName: function(e) {
diff --git a/pyload/web/app/scripts/views/setup/finishedView.js b/pyload/web/app/scripts/views/setup/finishedView.js
new file mode 100644
index 000000000..9f0f8db19
--- /dev/null
+++ b/pyload/web/app/scripts/views/setup/finishedView.js
@@ -0,0 +1,25 @@
+define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/finished'],
+ function($, Backbone, _, App, template) {
+ 'use strict';
+
+ return Backbone.Marionette.ItemView.extend({
+
+ name: 'Finished',
+ template: template,
+
+ events: {
+ 'click .btn-blue': 'confirm'
+ },
+
+ ui: {
+ },
+
+ onRender: function() {
+ },
+
+ confirm: function() {
+ this.model.submit();
+ }
+
+ });
+ }); \ No newline at end of file
diff --git a/pyload/web/app/scripts/views/setup/setupView.js b/pyload/web/app/scripts/views/setup/setupView.js
index 7636a0bc2..8ab6fba51 100644
--- a/pyload/web/app/scripts/views/setup/setupView.js
+++ b/pyload/web/app/scripts/views/setup/setupView.js
@@ -1,6 +1,6 @@
-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) {
+define(['jquery', 'backbone', 'underscore', 'app', 'models/Setup', 'hbs!tpl/setup/layout', 'hbs!tpl/setup/actionbar', 'hbs!tpl/setup/error',
+ './welcomeView', './systemView', './userView', './finishedView'],
+ function($, Backbone, _, App, Setup, template, templateBar, templateError, welcomeView, systemView, userView, finishedView) {
'use strict';
return Backbone.Marionette.ItemView.extend({
@@ -15,11 +15,14 @@ define(['jquery', 'backbone', 'underscore', 'app', 'models/Setup', 'hbs!tpl/setu
pages: [
welcomeView,
- systemView
+ systemView,
+ userView,
+ finishedView
],
page: 0,
view: null,
+ error: null,
initialize: function() {
var self = this;
@@ -52,37 +55,66 @@ define(['jquery', 'backbone', 'underscore', 'app', 'models/Setup', 'hbs!tpl/setu
});
this.listenTo(this.model, 'page:next', function() {
- self.openPage(self.page++);
+ self.openPage(self.page + 1);
});
this.listenTo(this.model, 'page:prev', function() {
- self.openPage(self.page--);
+ self.openPage(self.page - 1);
});
+
+ this.listenTo(this.model, 'error', this.onError);
+ this.model.fetch();
},
openPage: function(page) {
console.log('Change page', page);
// check if number is reasonable
- if (!_.isNumber(page) || !_.isFinite(page))
+ if (!_.isNumber(page) || !_.isFinite(page) || page < 0 || page >= this.pages.length)
return;
if (page === this.page)
return;
+ // Render error directly
+ if (this.error) {
+ this.onRender();
+ return;
+ }
+
this.page = page;
- this.onRender();
+
+ var self = this;
+ this.ui.page.fadeOut({complete: function() {
+ self.onRender();
+ }});
this.model.trigger('page:changed', page);
},
+ onError: function(model, xhr) {
+ console.log('Setup error', xhr);
+ this.error = xhr;
+ this.onRender();
+ },
+
onRender: function() {
+
// close old opened view
if (this.view)
this.view.close();
- // TODO: animation
+ // Render error if occurred
+ if (this.error) {
+ this.ui.page.html(templateError(this.error));
+ return;
+ }
+
this.view = new this.pages[this.page]({model: this.model});
this.ui.page.empty();
- this.ui.page.append(this.view.render().$el);
+
+ var el = this.view.render().el;
+ this.ui.page.append(el);
+
+ this.ui.page.fadeIn();
}
});
diff --git a/pyload/web/app/scripts/views/setup/systemView.js b/pyload/web/app/scripts/views/setup/systemView.js
index 11e50213d..b4c0f7e12 100644
--- a/pyload/web/app/scripts/views/setup/systemView.js
+++ b/pyload/web/app/scripts/views/setup/systemView.js
@@ -8,12 +8,17 @@ define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/system'],
template: template,
events: {
+ 'click .btn-blue': 'nextPage'
},
ui: {
},
onRender: function() {
+ },
+
+ nextPage: function() {
+ this.model.trigger('page:next');
}
});
diff --git a/pyload/web/app/scripts/views/setup/userView.js b/pyload/web/app/scripts/views/setup/userView.js
new file mode 100644
index 000000000..95eaa0dc2
--- /dev/null
+++ b/pyload/web/app/scripts/views/setup/userView.js
@@ -0,0 +1,39 @@
+define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/user'],
+ function($, Backbone, _, App, template) {
+ 'use strict';
+
+ return Backbone.Marionette.ItemView.extend({
+
+ name: 'User',
+ template: template,
+
+ events: {
+ 'click .btn-blue': 'submit'
+ },
+
+ ui: {
+ username: '#username',
+ password: '#password',
+ password2: '#password2'
+ },
+
+ onRender: function() {
+ },
+
+ submit: function() {
+ var pw = this.ui.password.val();
+ var pw2 = this.ui.password2.val();
+
+ // TODO more checks and error messages
+ if (pw !== pw2) {
+ return;
+ }
+
+ this.model.set('user', this.ui.username.val());
+ this.model.set('password', pw);
+
+ this.model.trigger('page:next');
+ }
+
+ });
+ }); \ 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
index 4affc9075..a964e0d42 100644
--- a/pyload/web/app/scripts/views/setup/welcomeView.js
+++ b/pyload/web/app/scripts/views/setup/welcomeView.js
@@ -8,12 +8,17 @@ define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/welcome'],
template: template,
events: {
+ 'click .btn-blue': 'nextPage'
},
ui: {
},
onRender: function() {
+ },
+
+ nextPage: function() {
+ this.model.trigger('page:next');
}
});
diff --git a/pyload/web/app/styles/default/main.less b/pyload/web/app/styles/default/main.less
index 6bf21e80b..6153b576e 100644
--- a/pyload/web/app/styles/default/main.less
+++ b/pyload/web/app/styles/default/main.less
@@ -13,10 +13,10 @@
@import "settings";
@import "accounts";
@import "admin";
+@import "setup";
@ResourcePath: "../..";
@DefaultFont: 'Abel', sans-serif;
// Changed dimensions
-@header-height: 70px;
-@footer-height: 66px; \ No newline at end of file
+@header-height: 70px;; \ No newline at end of file
diff --git a/pyload/web/app/styles/default/setup.less b/pyload/web/app/styles/default/setup.less
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pyload/web/app/styles/default/setup.less
diff --git a/pyload/web/app/styles/default/style.less b/pyload/web/app/styles/default/style.less
index da0e68991..ad60e5b59 100644
--- a/pyload/web/app/styles/default/style.less
+++ b/pyload/web/app/styles/default/style.less
@@ -284,15 +284,4 @@ header { // background-color: @greyDark;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
-}
-
-/*
- Footer
-*/
-footer .copyright {
- background-size: 40px 40px;
- background-position: 12px center;
- height: 40px;
- padding-left: 40px;
- padding-top: 10px;
-}
+} \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/error.html b/pyload/web/app/templates/default/setup/error.html
new file mode 100644
index 000000000..37ce51283
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/error.html
@@ -0,0 +1,14 @@
+{{#ifEq status 410}}
+ <h2 class="text-warning">{{ _ "Setup timed out" }}</h2>
+ <p>{{ _ "Setup was closed due to inactivity. Please restart it to continue configuration." }}</p>
+{{else}}
+{{#ifEq status 409}}
+ <h2 class="text-success">{{ _ "Setup finished" }}</h2>
+ <p>{{ _ "Setup was successful. You can restart pyLoad now." }}</p>
+{{else}}
+ <h2 class="text-error">
+ {{ _ "Setup failed" }}
+ </h2>
+ <p>{{ _ "Try to restart it or open a bug report." }}</p>
+{{/ifEq}}
+{{/ifEq}} \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/finished.html b/pyload/web/app/templates/default/setup/finished.html
new file mode 100644
index 000000000..22a97649b
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/finished.html
@@ -0,0 +1,23 @@
+{{#if user}}
+
+<h2>
+ {{ _ "Nearly Done" }}
+</h2>
+
+<p>
+ {{ _ "Please check your settings." }}
+</p>
+
+<p>
+ <strong>Username:</strong> {{user}}
+</p>
+
+<button class="btn btn-large btn-blue">
+ {{ _ "Confirm" }}
+</button>
+
+{{else}}
+
+<h2>{{ _ "Please add a user first." }}</h2>
+
+{{/if}}
diff --git a/pyload/web/app/templates/default/setup/layout.html b/pyload/web/app/templates/default/setup/layout.html
index 7b75e53b1..2e986173a 100644
--- a/pyload/web/app/templates/default/setup/layout.html
+++ b/pyload/web/app/templates/default/setup/layout.html
@@ -3,5 +3,8 @@
{{ _ "Setup" }}
</h1>
</div>
-<div class="span8 setup-page">
+<div class="span8">
+ <div class="hero-unit setup-page">
+
+ </div>
</div> \ 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
index 84a217b19..0c5023669 100644
--- a/pyload/web/app/templates/default/setup/system.html
+++ b/pyload/web/app/templates/default/setup/system.html
@@ -1,5 +1,56 @@
-<h1>{{ _ "System" }} </h1>
+<h3>{{ _ "System" }} </h3>
-<h2>{{_ "Dependencies" }}</h2>
+<dl class="dl-horizontal">
+ {{#each system}}
+ <dt>{{ @key }}</dt>
+ <dd>{{ this }}</dd>
+ {{/each}}
+</dl>
-<h2>{{ _ "Optional" }}</h2> \ No newline at end of file
+<h3>{{_ "Dependencies" }}</h3>
+<dl class="dl-horizontal">
+ {{#each deps.core}}
+ <dt>{{ name }}</dt>
+ <dd>
+ {{#if avail}}
+ <span class="text-success">
+ <i class="icon-ok"></i>
+ {{#if v}}
+ ({{v}})
+ {{/if}}
+ </span>
+ {{else}}
+ <span class="text-error">
+ <i class="icon-remove"></i>
+ </span>
+ {{/if}}
+ </dd>
+ {{/each}}
+</dl>
+
+
+<h4>{{ _ "Optional" }}</h4>
+<dl class="dl-horizontal">
+ {{#each deps.opt}}
+ <dt>{{ name }}</dt>
+ <dd>
+ {{#if avail}}
+ <span class="text-success">
+ {{ _ "available" }}
+ {{#if v}}
+ ({{v}})
+ {{/if}}
+ </span>
+ {{else}}
+ <span class="text-error">
+ {{ _ "not available" }}
+ </span>
+ {{/if}}
+ </dd>
+ {{/each}}
+</dl>
+
+
+<button class="btn btn-blue">
+ {{ _ "Next" }}
+</button> \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/user.html b/pyload/web/app/templates/default/setup/user.html
new file mode 100644
index 000000000..fe3f2de71
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/user.html
@@ -0,0 +1,34 @@
+<form class="form-horizontal">
+ <div class="control-group">
+ <label class="control-label">
+ Username
+ </label>
+
+ <div class="controls">
+ <input type="text" id="username" placeholder="User">
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label">
+ Password
+ </label>
+
+ <div class="controls">
+ <input type="password" id="password">
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label">
+ Password (again)
+ </label>
+
+ <div class="controls">
+ <input type="password" id="password2">
+ </div>
+ </div>
+ <div class="control-group">
+ <div class="controls">
+ <a class="btn btn-blue">Submit</a>
+ </div>
+ </div>
+</form> \ 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
index f5c5af4d7..5a4f74d9f 100644
--- a/pyload/web/app/templates/default/setup/welcome.html
+++ b/pyload/web/app/templates/default/setup/welcome.html
@@ -1,16 +1,14 @@
-<div class="hero-unit">
- <h1>{{ _ "Welcome!" }}</h1>
+<h1>{{ _ "Welcome!" }}</h1>
- <p>{{ _ "pyLoad is running and ready for configuration." }}</p>
+<p>{{ _ "pyLoad is running and ready for configuration." }}</p>
- <p>
- {{ _ "Select your language:" }}
- <select>
- <option>en</option>
- </select>
- </p>
+<p>
+ {{ _ "Select your language:" }}
+ <select>
+ <option>en</option>
+ </select>
+</p>
- <button class="btn btn-large btn-blue">
- {{ _ "Start configuration" }}
- </button>
-</div> \ No newline at end of file
+<button class="btn btn-large btn-blue">
+ {{ _ "Start configuration" }}
+</button> \ No newline at end of file
diff --git a/pyload/web/bower.json b/pyload/web/bower.json
index b0176a891..4da3634a0 100644
--- a/pyload/web/bower.json
+++ b/pyload/web/bower.json
@@ -11,7 +11,7 @@
"jquery.cookie": "~1.3.1",
"jquery.animate-enhanced": "*",
"flot": "~0.8.1",
- "underscore": "~1.4.4",
+ "underscore": "~1.5.1",
"backbone": "~1.0.0",
"backbone.marionette": "~1.1.0",
"handlebars.js": "1.0.0-rc.3",
diff --git a/pyload/web/middlewares.py b/pyload/web/middlewares.py
index 074681b8f..af355bf11 100644
--- a/pyload/web/middlewares.py
+++ b/pyload/web/middlewares.py
@@ -1,17 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# gzip is optional on some platform
-try:
- import gzip
-except ImportError:
- gzip = None
-
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-
class StripPathMiddleware(object):
def __init__(self, app):
self.app = app
@@ -31,105 +20,3 @@ class PrefixMiddleware(object):
if path.startswith(self.prefix):
e['PATH_INFO'] = path.replace(self.prefix, "", 1)
return self.app(e, h)
-
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-# WSGI middleware
-# Gzip-encodes the response.
-
-# TODO: not in use anymore, because of pre-gzipped resources
-class GZipMiddleWare(object):
-
- def __init__(self, application, compress_level=6):
- self.application = application
- self.compress_level = int(compress_level)
-
- def __call__(self, environ, start_response):
- if 'gzip' not in environ.get('HTTP_ACCEPT_ENCODING', ''):
- # nothing for us to do, so this middleware will
- # be a no-op:
- return self.application(environ, start_response)
- response = GzipResponse(start_response, self.compress_level)
- app_iter = self.application(environ,
- response.gzip_start_response)
- if app_iter is not None:
- response.finish_response(app_iter)
-
- return response.write()
-
-def header_value(headers, key):
- for header, value in headers:
- if key.lower() == header.lower():
- return value
-
-def update_header(headers, key, value):
- remove_header(headers, key)
- headers.append((key, value))
-
-def remove_header(headers, key):
- for header, value in headers:
- if key.lower() == header.lower():
- headers.remove((header, value))
- break
-
-class GzipResponse(object):
-
- def __init__(self, start_response, compress_level):
- self.start_response = start_response
- self.compress_level = compress_level
- self.buffer = StringIO()
- self.compressible = False
- self.content_length = None
- self.headers = ()
-
- def gzip_start_response(self, status, headers, exc_info=None):
- self.headers = headers
- ct = header_value(headers,'content-type')
- ce = header_value(headers,'content-encoding')
- cl = header_value(headers, 'content-length')
-
- # don't compress on unknown size, it may be too huge
- cl = int(cl) if cl else 0
-
- if ce:
- self.compressible = False
- elif gzip is not None and 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'))
- headers.append(('vary', 'Accept-Encoding'))
-
- remove_header(headers, 'content-length')
- self.headers = headers
- self.status = status
- return self.buffer.write
-
- def write(self):
- out = self.buffer
- out.seek(0)
- s = out.getvalue()
- out.close()
- return [s]
-
- def finish_response(self, app_iter):
- if self.compressible:
- output = gzip.GzipFile(mode='wb', compresslevel=self.compress_level,
- fileobj=self.buffer)
- else:
- output = self.buffer
- try:
- for s in app_iter:
- output.write(s)
- if self.compressible:
- output.close()
- finally:
- if hasattr(app_iter, 'close'):
- try:
- app_iter.close()
- except :
- pass
-
- content_length = self.buffer.tell()
- update_header(self.headers, "Content-Length" , str(content_length))
- self.start_response(self.status, self.headers) \ No newline at end of file
diff --git a/pyload/web/pyload_app.py b/pyload/web/pyload_app.py
index 1ec7cf4c9..1c89e2ada 100644
--- a/pyload/web/pyload_app.py
+++ b/pyload/web/pyload_app.py
@@ -70,7 +70,11 @@ def index():
# 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
+ web = None
+ if PYLOAD:
+ web = PYLOAD.getConfigValue('webinterface', 'port')
+ elif SETUP:
+ web = SETUP.config['webinterface']['port']
# Render variables into the html page
if resp.status_code == 200:
diff --git a/pyload/web/setup_app.py b/pyload/web/setup_app.py
index 5163f9cc6..939fcb600 100644
--- a/pyload/web/setup_app.py
+++ b/pyload/web/setup_app.py
@@ -3,26 +3,71 @@
from time import time
+from pyload.utils import json_dumps
+
from bottle import route, request, response, HTTPError, redirect
from webinterface import PROJECT_DIR, SETUP
from utils import add_json_header
+# returns http error
+def error(code, msg):
+ return HTTPError(code, json_dumps(msg), **dict(response.headers))
+
+
def setup_required(func):
def _view(*args, **kwargs):
+ global timestamp
+
# setup needs to be running
if SETUP is None:
- redirect("/nopermission")
+ return error(404, "Not Found")
+
+ # setup finished
+ if timestamp == 0:
+ return error(409, "Done")
+
+ # setup timed out due to inactivity
+ if timestamp + TIMEOUT * 60 < time():
+ return error(410, "Timeout")
+
+ timestamp = time()
return func(*args, **kwargs)
+
return _view
# setup will close after inactivity
TIMEOUT = 15
timestamp = time()
+
@route("/setup")
@setup_required
def setup():
- pass # TODO
+ add_json_header(response)
+
+ return json_dumps({
+ "system": SETUP.check_system(),
+ "deps": SETUP.check_deps()
+ })
+
+
+@route("/setup_done")
+@setup_required
+def setup_done():
+ global timestamp
+ add_json_header(response)
+
+ SETUP.addUser(
+ request.params['user'],
+ request.params['password']
+ )
+
+ SETUP.save()
+
+ # mark setup as finished
+ timestamp = 0
+
+ return error(409, "Done")
diff --git a/pyload/web/utils.py b/pyload/web/utils.py
index e94089185..7e8ee3f13 100644
--- a/pyload/web/utils.py
+++ b/pyload/web/utils.py
@@ -4,14 +4,21 @@
import re
from bottle import request, HTTPError, redirect
+try:
+ import zlib
+except ImportError:
+ zlib = None
+
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')
s["uid"] = user.uid
@@ -58,15 +65,14 @@ def is_mobile():
return True
return False
-def select_language(langs):
+def select_language(langs):
accept = request.headers.get('Accept-Language', '')
# TODO
return langs[0]
-
def login_required(perm=None):
def _dec(func):
def _view(*args, **kwargs):