diff --git a/gui/slick/css/style.css b/gui/slick/css/style.css
index 2100c582..75b963be 100644
--- a/gui/slick/css/style.css
+++ b/gui/slick/css/style.css
@@ -3133,4 +3133,74 @@ pnotify.css
.ui-pnotify-closer {
margin-top: -12px;
margin-right: -10px;
-}
\ No newline at end of file
+}
+
+/* =======================================================================
+login.css
+========================================================================== */
+
+.login {
+ display: block;
+}
+
+ .login h1 {
+ padding: 0 0 10px;
+ font-size: 60px;
+ font-family: Lobster;
+ font-weight: normal;
+ }
+
+ .login form {
+ padding: 0;
+ height: 300px;
+ width: 400px;
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ margin: -200px 0 0 -200px;
+ }
+ @media all and (max-width: 480px) {
+
+ .login form {
+ padding: 0;
+ height: 300px;
+ width: 90%;
+ position: absolute;
+ left: 5%;
+ top: 10px;
+ margin: 0;
+ }
+
+ }
+
+ .login .ctrlHolder {
+ padding: 0;
+ margin: 0 0 20px;
+ }
+ .login .ctrlHolder:hover {
+ background: none;
+ }
+
+ .login input[type=text],
+ .login input[type=password] {
+ width: 100% !important;
+ font-size: 25px;
+ padding: 14px !important;
+ }
+
+ .login .remember_me {
+ font-size: 15px;
+ float: left;
+ width: 150px;
+ padding: 20px 0;
+ }
+
+ .login .remember_me .check {
+ margin: 5px 5px 0 0;
+ }
+
+ .login .button {
+ font-size: 25px;
+ padding: 20px;
+ float: right;
+ }
\ No newline at end of file
diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl
index 81f78bf1..a923b175 100644
--- a/gui/slick/interfaces/default/inc_top.tmpl
+++ b/gui/slick/interfaces/default/inc_top.tmpl
@@ -140,6 +140,7 @@
+ #if $sbLogin:
-
+ #end if
diff --git a/gui/slick/interfaces/default/login.tmpl b/gui/slick/interfaces/default/login.tmpl
new file mode 100644
index 00000000..4bf40394
--- /dev/null
+++ b/gui/slick/interfaces/default/login.tmpl
@@ -0,0 +1,21 @@
+#import sickbeard
+
+#set global $title="Login"
+
+#set global $sbPath = ".."
+
+#set global $topmenu="login"#
+#import os.path
+#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_top.tmpl")
+
+
\ No newline at end of file
diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py
index b134d84d..41265843 100644
--- a/sickbeard/webapi.py
+++ b/sickbeard/webapi.py
@@ -25,9 +25,10 @@ import urllib
import datetime
import re
import traceback
-import sickbeard
-import webserve
+import sickbeard
+
+from sickbeard.webserve import PageTemplate
from sickbeard import db, logger, exceptions, history, ui, helpers
from sickbeard import encodingKludge as ek
from sickbeard import search_queue
@@ -46,6 +47,9 @@ except ImportError:
from lib import subliminal
+from tornado.web import RequestHandler
+from tornado.routes import route
+
indexer_ids = ["indexerid", "tvdbid", "tvrageid"]
dateFormat = "%Y-%m-%d"
@@ -67,7 +71,8 @@ result_type_map = {RESULT_SUCCESS: "success",
}
# basically everything except RESULT_SUCCESS / success is bad
-class Api(webserve.MainHandler):
+@route('/api/(.*)(/?)')
+class ApiHandler(RequestHandler):
""" api class that returns json results """
version = 4 # use an int since float-point is unpredictible
intent = 4
@@ -123,7 +128,7 @@ class Api(webserve.MainHandler):
def builder(self):
""" expose the api-builder template """
- t = webserve.PageTemplate(headers=self.request.headers, file="apiBuilder.tmpl")
+ t = PageTemplate(headers=self.request.headers, file="apiBuilder.tmpl")
def titler(x):
if not x or sickbeard.SORT_ARTICLE:
@@ -159,7 +164,7 @@ class Api(webserve.MainHandler):
else:
t.apikey = "api key not generated"
- return webserve._munge(t)
+ return t
def _out_as_json(self, dict):
self.set_header("Content-Type", "application/json;charset=UTF-8'")
@@ -298,7 +303,7 @@ def filter_params(cmd, args, kwargs):
return curArgs, curKwargs
-class ApiCall(object):
+class ApiCall(ApiHandler):
_help = {"desc": "No help message available. Please tell the devs that a help msg is missing for this cmd"}
def __init__(self, handler, args, kwargs):
@@ -1440,7 +1445,7 @@ class CMD_SickBeard(ApiCall):
def run(self):
""" display misc sickrage related information """
- data = {"sb_version": sickbeard.BRANCH, "api_version": Api.version,
+ data = {"sb_version": sickbeard.BRANCH, "api_version": self.version,
"api_commands": sorted(_functionMaper.keys())}
return _responds(RESULT_SUCCESS, data)
@@ -2425,9 +2430,6 @@ class CMD_ShowPause(ApiCall):
showObj.paused = 0
return _responds(RESULT_SUCCESS, msg=str(showObj.name) + " has been unpaused")
- return _responds(RESULT_FAILURE, msg=str(showObj.name) + " was unable to be paused")
-
-
class CMD_ShowRefresh(ApiCall):
_help = {"desc": "refresh a show in sickrage",
"requiredParameters": {
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 24831e75..14c4a1b9 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -18,8 +18,6 @@
from __future__ import with_statement
-import base64
-import functools
import traceback
import os
import time
@@ -77,8 +75,9 @@ except ImportError:
from Cheetah.Template import Template
+import tornado.escape
from tornado.routes import route
-from tornado.web import RequestHandler
+from tornado.web import RequestHandler, authenticated
from bug_tracker import BugTracker
@@ -87,38 +86,6 @@ def check_basic_auth(username, password):
if username == sickbeard.WEB_USERNAME and password == sickbeard.WEB_PASSWORD:
return True
-def basic_auth(checkfunc, realm="Authentication Required!"):
- def wrap(method):
- def request_auth(self):
- self.set_header('WWW-Authenticate', 'Basic realm=%s' % realm)
- self.set_status(401)
- self.finish()
- return False
-
- @functools.wraps(method)
- def wrapper(self, *args, **kwargs):
- if not (sickbeard.WEB_USERNAME and sickbeard.WEB_PASSWORD):
- return method(self, *args, **kwargs)
-
- auth = self.request.headers.get('Authorization')
- if auth is None or not auth.startswith('Basic '):
- return request_auth(self)
- auth = auth[6:]
- try:
- username, password = base64.decodestring(auth).split(':', 2)
- except:
- return request_auth(self)
-
- if checkfunc(username, password):
- self.request.basic_auth = (username, password)
- return method(self, *args, **kwargs)
- else:
- return request_auth(self)
-
- return wrapper
-
- return wrap
-
def page_not_found(rh):
index_url = sickbeard.WEB_ROOT
url = rh.request.uri[len(index_url):]
@@ -221,7 +188,7 @@ class Menus:
return menu
class PageTemplate(Template):
- def __init__(self, headers, *args, **kwargs):
+ def __init__(self, rh, *args, **kwargs):
kwargs['file'] = os.path.join(sickbeard.PROG_DIR, "gui/" + sickbeard.GUI_NAME + "/interfaces/default/", kwargs['file'])
super(PageTemplate, self).__init__(*args, **kwargs)
@@ -231,19 +198,20 @@ class PageTemplate(Template):
self.sbHttpsEnabled = sickbeard.ENABLE_HTTPS
self.sbHandleReverseProxy = sickbeard.HANDLE_REVERSE_PROXY
self.sbThemeName = sickbeard.THEME_NAME
+ self.sbLogin = rh.get_current_user()
- if headers['Host'][0] == '[':
- self.sbHost = re.match("^\[.*\]", headers['Host'], re.X | re.M | re.S).group(0)
+ if rh.request.headers['Host'][0] == '[':
+ self.sbHost = re.match("^\[.*\]", rh.request.headers['Host'], re.X | re.M | re.S).group(0)
else:
- self.sbHost = re.match("^[^:]+", headers['Host'], re.X | re.M | re.S).group(0)
+ self.sbHost = re.match("^[^:]+", rh.request.headers['Host'], re.X | re.M | re.S).group(0)
- if "X-Forwarded-Host" in headers:
- self.sbHost = headers['X-Forwarded-Host']
- if "X-Forwarded-Port" in headers:
- sbHttpPort = headers['X-Forwarded-Port']
+ if "X-Forwarded-Host" in rh.request.headers:
+ self.sbHost = rh.request.headers['X-Forwarded-Host']
+ if "X-Forwarded-Port" in rh.request.headers:
+ sbHttpPort = rh.request.headers['X-Forwarded-Port']
self.sbHttpsPort = sbHttpPort
- if "X-Forwarded-Proto" in headers:
- self.sbHttpsEnabled = True if headers['X-Forwarded-Proto'] == 'https' else False
+ if "X-Forwarded-Proto" in rh.request.headers:
+ self.sbHttpsEnabled = True if rh.request.headers['X-Forwarded-Proto'] == 'https' else False
logPageTitle = 'Logs & Errors'
if len(classes.ErrorViewer.errors):
@@ -268,8 +236,14 @@ class PageTemplate(Template):
return super(PageTemplate, self).compile(*args, **kwargs)
class BaseHandler(RequestHandler):
+ def get_current_user(self):
+ if sickbeard.WEB_USERNAME and sickbeard.WEB_PASSWORD:
+ return self.get_secure_cookie('user')
+ else:
+ return True
+
def _genericMessage(self, subject, message):
- t = PageTemplate(headers=self.request.headers, file="genericMessage.tmpl")
+ t = PageTemplate(rh=self, file="genericMessage.tmpl")
t.submenu = Menus().HomeMenu()
t.subject = subject
t.message = message
@@ -296,7 +270,7 @@ class KeyHandler(RequestHandler):
logger.log('Failed doing key request: %s' % (traceback.format_exc()), logger.ERROR)
self.write({'success': False, 'error': 'Failed returning results'})
-class UI(RequestHandler):
+class UIHandler(RequestHandler):
def add_message(self):
ui.notifications.message('Test 1', 'This is test number 1')
ui.notifications.error('Test 2', 'This is test number 2')
@@ -338,8 +312,7 @@ class WebHandler(BaseHandler):