From e31e8171f941c55c8f7b17e77b25814fe25074a2 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 14 Feb 2011 23:56:36 +0100 Subject: [PATCH] Javascript api base History and url parser --- couchpotato/__init__.py | 1 - couchpotato/api/__init__.py | 3 +- couchpotato/cli.py | 14 +- couchpotato/core/settings/__init__.py | 9 +- couchpotato/static/scripts/couchpotato.js | 167 ++++++++++--- couchpotato/static/scripts/mootools_more.js | 245 +------------------- couchpotato/static/scripts/pages.js | 11 + couchpotato/templates/_desktop.html | 2 +- 8 files changed, 162 insertions(+), 290 deletions(-) diff --git a/couchpotato/__init__.py b/couchpotato/__init__.py index 85f4097b..8ce29933 100644 --- a/couchpotato/__init__.py +++ b/couchpotato/__init__.py @@ -23,7 +23,6 @@ def page_not_found(error): url = request.path[len(index_url):] return redirect(index_url + '#' + url) - @web.route('/exit') @requires_auth def exit(): diff --git a/couchpotato/api/__init__.py b/couchpotato/api/__init__.py index bf04eb8b..a4f14c3e 100644 --- a/couchpotato/api/__init__.py +++ b/couchpotato/api/__init__.py @@ -1,7 +1,8 @@ from flask import Module +from flask.helpers import jsonify api = Module(__name__) @api.route('/') def index(): - return 'api' + return jsonify({'test': 'bla'}) diff --git a/couchpotato/cli.py b/couchpotato/cli.py index cbbd6692..1961987f 100644 --- a/couchpotato/cli.py +++ b/couchpotato/cli.py @@ -1,7 +1,5 @@ from couchpotato import web from couchpotato.api import api -from couchpotato.core.logger import CPLog -from couchpotato.core.settings import settings from libs.daemon import createDaemon from logging import handlers from optparse import OptionParser @@ -44,7 +42,10 @@ def cmd_couchpotato(base_path, args): # Register settings + from couchpotato.core.settings import settings settings.setFile(os.path.join(options.data_dir, 'settings.conf')) + + # Determine debug debug = options.debug or settings.get('debug', default = False) @@ -70,6 +71,7 @@ def cmd_couchpotato(base_path, args): server_log.disabled = True # Start logging + from couchpotato.core.logger import CPLog log = CPLog(__name__) log.debug('Started with options %s' % options) @@ -84,7 +86,7 @@ def cmd_couchpotato(base_path, args): # Create app from couchpotato import app api_key = settings.get('api_key') - url_base = '/%s/' % settings.get('url_base') + url_base = '/' + settings.get('url_base') if settings.get('url_base') else '' reloader = debug and not options.daemonize # Basic config @@ -92,7 +94,7 @@ def cmd_couchpotato(base_path, args): app.port = settings.get('port', default = 5000) app.debug = debug app.secret_key = api_key - app.static_path = url_base + 'static' + app.static_path = url_base + '/static' # Add static url with url_base app.add_url_rule(app.static_path + '/', @@ -100,8 +102,8 @@ def cmd_couchpotato(base_path, args): view_func = app.send_static_file) # Register modules - app.register_module(web, url_prefix = url_base) - app.register_module(api, url_prefix = '%s/%s' % (url_base + 'api', api_key)) + app.register_module(web, url_prefix = '%s/' % url_base) + app.register_module(api, url_prefix = '%s/%s/%s/' % (url_base, 'api', api_key)) # Go go go! app.run(use_reloader = reloader) diff --git a/couchpotato/core/settings/__init__.py b/couchpotato/core/settings/__init__.py index d5efe2e7..e3ac67cf 100644 --- a/couchpotato/core/settings/__init__.py +++ b/couchpotato/core/settings/__init__.py @@ -1,11 +1,9 @@ from __future__ import with_statement from blinker import signal, Signal -from couchpotato.core.logger import CPLog import ConfigParser import os.path import time -log = CPLog(__name__) class Settings(): @@ -20,6 +18,9 @@ class Settings(): self.p = ConfigParser.RawConfigParser() self.p.read(file) + from couchpotato.core.logger import CPLog + self.log = CPLog(__name__) + self.connectSignals() def parser(self): @@ -38,7 +39,7 @@ class Settings(): for option, value in options.iteritems(): self.setDefault(section_name, option, value) - log.debug('Defaults for "%s": %s' % (section_name, options)) + self.log.debug('Defaults for "%s": %s' % (section_name, options)) self.on_register.send(self) if save: @@ -66,7 +67,7 @@ class Settings(): with open(self.file, 'wb') as configfile: self.p.write(configfile) - log.debug('Saved settings') + self.log.debug('Saved settings') self.on_save.send(self) def addSection(self, section): diff --git a/couchpotato/static/scripts/couchpotato.js b/couchpotato/static/scripts/couchpotato.js index 8617eb8e..bc23fd3e 100644 --- a/couchpotato/static/scripts/couchpotato.js +++ b/couchpotato/static/scripts/couchpotato.js @@ -9,32 +9,59 @@ var CouchPotato = new Class({ }, pages: [], - - tabse: [ - {'href': 'movie', 'title':'Gimmy gimmy gimmy!', 'label':'Wanted'}, - {'href': 'manage', 'title':'Do stuff to your existing movies!', 'label':'Manage'}, - {'href': 'feed', 'title':'Which wanted movies are released soon?', 'label':'Soon'}, - {'href': 'log', 'title':'Show recent logs.', 'class':'logLink', 'label':'Logs'}, - {'href': 'config', 'title':'Change settings.', 'id':'showConfig'} + + tabs: [ + {'href': '/movie/', 'title':'Gimmy gimmy gimmy!', 'label':'Wanted'}, + {'href': '/manage/', 'title':'Do stuff to your existing movies!', 'label':'Manage'}, + {'href': '/feed/', 'title':'Which wanted movies are released soon?', 'label':'Soon'}, + {'href': '/log/', 'title':'Show recent logs.', 'class':'logLink', 'label':'Logs'}, + {'href': '/config/', 'title':'Change settings.', 'id':'showConfig'} ], initialize: function(options) { var self = this; self.setOptions(options); - + self.c = $(document.body) - self.route = new Route(); + self.route = new Route(self.defaults); + self.api = new Api(self.options.api_url) History.addEvent('change', self.createPage.bind(self)); History.handleInitialState(); - + self.createLayout() + self.createNavigation() + + self.c.addEvent('click:relay(a)', self.openPage.bind(self)) }, - + + openPage: function(e){ + var self = this; + (e).stop() + + var url = e.target.get('href') + History.push(url) + }, + + createNavigation: function(){ + var self = this + + self.tabs.each(function(tab){ + new Element('li').adopt( + new Element('a', { + 'href': tab.href, + 'title': tab.title, + 'text': tab.label + }) + ).inject(self.navigation) + }) + + }, + createLayout: function(){ var self = this; - + self.c.adopt( self.header = new Element('div.header').adopt( self.navigation = new Element('ul.navigation'), @@ -49,17 +76,22 @@ var CouchPotato = new Class({ var self = this; self.route.parse(url); - var page = self.route.getPage().capitalize(); + var page_name = self.route.getPage().capitalize(); var action = self.route.getAction(); var params = self.route.getParams(); - if(!self.pages[page]){ - page = new Page[page](); - self.pages[page] = page; + var pg = self.pages[page_name] + if(!pg){ + pg = new Page[page_name](); + pg.setParent(self) + self.pages[page_name] = pg; } - page = self.pages[page] - page.open(action, params) + pg.open(action, params) + }, + + getApi: function(){ + return this.api } }); @@ -73,38 +105,100 @@ var PageBase = new Class({ open: function(action, params){ var self = this; - console.log(action, params, self.getName()); + p('Opening: ' +self.getName() + ', ' + action + ', ' + Object.toQueryString(params)); + try { + self[action+'Action'](params) + } + catch (e){ + self.errorAction(e) + } + }, + + errorAction: function(e){ + p('Error, action not found', e); }, getName: function(){ return this.name + }, + + setParent: function(parent){ + this.parent = parent + }, + + getParent: function(){ + return this.parent + }, + + api: function(){ + return this.parent.getApi() } }); +var Api = new Class({ + + url: '', + + initialize: function(url){ + var self = this + + self.url = url + self.req = new Request.JSON({ + 'method': 'get' + }) + + }, + + request: function(type, params, data){ + var self = this; + + self.req.setOptions({ + 'url': self.createUrl(type, params), + 'data': data + }) + self.req.send() + }, + + createUrl: function(action, params){ + return this.url + (action || 'default') + '/?' + Object.toQueryString(params) + } + +}); + var Route = new Class({ + defaults: {}, page: '', action: 'index', params: {}, - parse: function(url){ + initialize: function(defaults){ + var self = this + self.defaults = defaults + }, + + parse: function(url_string){ var self = this; - url = url.split('/') - self.page = url.shift() - self.action = url.shift() - self.params = {} + var current = History.getPath().replace(/^\/+|\/+$/g, '') + var url = current.split('/') - var key - url.each(function(el, nr){ - if(nr%2 == 0) - key = el - else if(key) { - self.params[key] = el - key = null - } - }) + self.page = (url.length > 0) ? url.shift() : self.defaults.page + self.action = (url.length > 0) ? url.shift() : self.defaults.action + + self.params = self.defaults.params + if(url.length > 1){ + var key + url.each(function(el, nr){ + if(nr%2 == 0) + key = el + else if(key) { + self.params[key] = el + key = null + } + }) + } return self }, @@ -125,4 +219,9 @@ var Route = new Class({ return this.params[param] } -}); \ No newline at end of file +}); + +var p = function(){ + if(typeof(console) !== 'undefined' && console != null) + console.log(arguments) +} \ No newline at end of file diff --git a/couchpotato/static/scripts/mootools_more.js b/couchpotato/static/scripts/mootools_more.js index 3dd73af1..8b0b43e8 100644 --- a/couchpotato/static/scripts/mootools_more.js +++ b/couchpotato/static/scripts/mootools_more.js @@ -1,6 +1,6 @@ // MooTools: the javascript framework. -// Load this file's selection again by visiting: http://mootools.net/more/452f2740e09082a2109bec9f69fbf8dc -// Or build this file again with packager using: packager build More/URI More/Element.Delegation More/Element.Shortcuts +// Load this file's selection again by visiting: http://mootools.net/more/82d3c4f6ee721f808321f6bf6818d8fb +// Or build this file again with packager using: packager build More/Element.Delegation More/Element.Shortcuts /* --- @@ -35,247 +35,6 @@ MooTools.More = { }; -/* ---- - -script: String.QueryString.js - -name: String.QueryString - -description: Methods for dealing with URI query strings. - -license: MIT-style license - -authors: - - Sebastian Markbåge - - Aaron Newton - - Lennart Pilon - - Valerio Proietti - -requires: - - Core/Array - - Core/String - - /MooTools.More - -provides: [String.QueryString] - -... -*/ - -String.implement({ - - parseQueryString: function(decodeKeys, decodeValues){ - if (decodeKeys == null) decodeKeys = true; - if (decodeValues == null) decodeValues = true; - - var vars = this.split(/[&;]/), - object = {}; - if (!vars.length) return object; - - vars.each(function(val){ - var index = val.indexOf('='), - value = val.substr(index + 1), - keys = index < 0 ? [''] : val.substr(0, index).match(/([^\]\[]+|(\B)(?=\]))/g), - obj = object; - - if (decodeValues) value = decodeURIComponent(value); - keys.each(function(key, i){ - if (decodeKeys) key = decodeURIComponent(key); - var current = obj[key]; - - if (i < keys.length - 1) obj = obj[key] = current || {}; - else if (typeOf(current) == 'array') current.push(value); - else obj[key] = current != null ? [current, value] : value; - }); - }); - - return object; - }, - - cleanQueryString: function(method){ - return this.split('&').filter(function(val){ - var index = val.indexOf('='), - key = index < 0 ? '' : val.substr(0, index), - value = val.substr(index + 1); - - return method ? method.call(null, key, value) : (value || value === 0); - }).join('&'); - } - -}); - - -/* ---- - -script: URI.js - -name: URI - -description: Provides methods useful in managing the window location and uris. - -license: MIT-style license - -authors: - - Sebastian Markbåge - - Aaron Newton - -requires: - - Core/Object - - Core/Class - - Core/Class.Extras - - Core/Element - - /String.QueryString - -provides: [URI] - -... -*/ - -(function(){ - -var toString = function(){ - return this.get('value'); -}; - -var URI = this.URI = new Class({ - - Implements: Options, - - options: { - /*base: false*/ - }, - - regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/, - parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'], - schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0}, - - initialize: function(uri, options){ - this.setOptions(options); - var base = this.options.base || URI.base; - if (!uri) uri = base; - - if (uri && uri.parsed) this.parsed = Object.clone(uri.parsed); - else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false); - }, - - parse: function(value, base){ - var bits = value.match(this.regex); - if (!bits) return false; - bits.shift(); - return this.merge(bits.associate(this.parts), base); - }, - - merge: function(bits, base){ - if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false; - if (base){ - this.parts.every(function(part){ - if (bits[part]) return false; - bits[part] = base[part] || ''; - return true; - }); - } - bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()]; - bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/'; - return bits; - }, - - parseDirectory: function(directory, baseDirectory){ - directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory; - if (!directory.test(URI.regs.directoryDot)) return directory; - var result = []; - directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){ - if (dir == '..' && result.length > 0) result.pop(); - else if (dir != '.') result.push(dir); - }); - return result.join('/') + '/'; - }, - - combine: function(bits){ - return bits.value || bits.scheme + '://' + - (bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') + - (bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') + - (bits.directory || '/') + (bits.file || '') + - (bits.query ? '?' + bits.query : '') + - (bits.fragment ? '#' + bits.fragment : ''); - }, - - set: function(part, value, base){ - if (part == 'value'){ - var scheme = value.match(URI.regs.scheme); - if (scheme) scheme = scheme[1]; - if (scheme && this.schemes[scheme.toLowerCase()] == null) this.parsed = { scheme: scheme, value: value }; - else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value }); - } else if (part == 'data'){ - this.setData(value); - } else { - this.parsed[part] = value; - } - return this; - }, - - get: function(part, base){ - switch(part){ - case 'value': return this.combine(this.parsed, base ? base.parsed : false); - case 'data' : return this.getData(); - } - return this.parsed[part] || ''; - }, - - go: function(){ - document.location.href = this.toString(); - }, - - toURI: function(){ - return this; - }, - - getData: function(key, part){ - var qs = this.get(part || 'query'); - if (!(qs || qs === 0)) return key ? null : {}; - var obj = qs.parseQueryString(); - return key ? obj[key] : obj; - }, - - setData: function(values, merge, part){ - if (typeof values == 'string'){ - var data = this.getData(); - data[arguments[0]] = arguments[1]; - values = data; - } else if (merge){ - values = Object.merge(this.getData(), values); - } - return this.set(part || 'query', Object.toQueryString(values)); - }, - - clearData: function(part){ - return this.set(part || 'query', ''); - }, - - toString: toString, - valueOf: toString - -}); - -URI.regs = { - endSlash: /\/$/, - scheme: /^(\w+):/, - directoryDot: /\.\/|\.$/ -}; - -URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location}); - -String.implement({ - - toURI: function(options){ - return new URI(this, options); - } - -}); - -})(); - - /* --- diff --git a/couchpotato/static/scripts/pages.js b/couchpotato/static/scripts/pages.js index 0de1e2f0..21920849 100644 --- a/couchpotato/static/scripts/pages.js +++ b/couchpotato/static/scripts/pages.js @@ -8,6 +8,17 @@ Page.Movie = new Class({ initialize: function(options){ + }, + + indexAction: function(param){ + var self = this + self.getMovies() + }, + + getMovies: function(){ + var self = this + + this.api().request('movie', {'status': 'wanted'}) } }) diff --git a/couchpotato/templates/_desktop.html b/couchpotato/templates/_desktop.html index ebdbee3b..b4a313ee 100644 --- a/couchpotato/templates/_desktop.html +++ b/couchpotato/templates/_desktop.html @@ -12,7 +12,7 @@