summaryrefslogtreecommitdiffstats
path: root/pyload/web
diff options
context:
space:
mode:
Diffstat (limited to 'pyload/web')
-rw-r--r--pyload/web/api_app.py14
-rw-r--r--pyload/web/app/index.html1
-rw-r--r--pyload/web/app/scripts/default.js18
-rw-r--r--pyload/web/app/scripts/helpers/ifEq.js14
-rw-r--r--pyload/web/app/scripts/models/Setup.js14
-rw-r--r--pyload/web/app/scripts/setup.js33
-rw-r--r--pyload/web/app/scripts/views/setup/setupView.js89
-rw-r--r--pyload/web/app/scripts/views/setup/systemView.js20
-rw-r--r--pyload/web/app/scripts/views/setup/welcomeView.js20
-rw-r--r--pyload/web/app/styles/default/style.less10
-rw-r--r--pyload/web/app/templates/default/setup.html16
-rw-r--r--pyload/web/app/templates/default/setup/actionbar.html24
-rw-r--r--pyload/web/app/templates/default/setup/layout.html7
-rw-r--r--pyload/web/app/templates/default/setup/system.html5
-rw-r--r--pyload/web/app/templates/default/setup/welcome.html16
-rw-r--r--pyload/web/pyload_app.py37
-rw-r--r--pyload/web/setup_app.py7
-rw-r--r--pyload/web/utils.py13
18 files changed, 313 insertions, 45 deletions
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/<func><args:re:[^#?]*>")
@route("/api/<func><args:re:[^#?]*>", 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 %}
- <div class="hero-unit">
- <h1>You did it!</h1>
- <p>pyLoad is running and ready for configuration.</p>
- <p>
- <a class="btn btn-primary btn-large">
- Go on
- </a>
- </p>
- </div>
-{% 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 @@
+<ul class="actionbar nav span8 offset3">
+ <li class="pull-left">
+ <ul class="breadcrumb">
+ {{#each pages}}
+ <li>
+ <a href="#" class="{{#ifEq ../page @index}}active {{/ifEq}}select-page"
+ data-page="{{@index}}">{{this}}</a>
+ {{#ifEq ../max @index}}
+
+ {{else}}
+ <span class="divider">
+ <i class="icon-long-arrow-right"></i>
+ </span>
+ {{/ifEq}}
+ </li>
+ {{/each}}
+ </ul>
+ </li>
+ <li class="pull-right">
+ <select>
+ <option>en</option>
+ </select>
+ </li>
+</ul> \ 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 @@
+<div class="span3">
+ <h1 class="vertical-header">
+ {{ _ "Setup" }}
+ </h1>
+</div>
+<div class="span8 setup-page">
+</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
new file mode 100644
index 000000000..84a217b19
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/system.html
@@ -0,0 +1,5 @@
+<h1>{{ _ "System" }} </h1>
+
+<h2>{{_ "Dependencies" }}</h2>
+
+<h2>{{ _ "Optional" }}</h2> \ 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 @@
+<div class="hero-unit">
+ <h1>{{ _ "Welcome!" }}</h1>
+
+ <p>{{ _ "pyLoad is running and ready for configuration." }}</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
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('/<path:path>')
-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):