Browse Source

Javascript api base

History and url parser
pull/1/merge
Ruud 14 years ago
parent
commit
e31e8171f9
  1. 1
      couchpotato/__init__.py
  2. 3
      couchpotato/api/__init__.py
  3. 14
      couchpotato/cli.py
  4. 9
      couchpotato/core/settings/__init__.py
  5. 137
      couchpotato/static/scripts/couchpotato.js
  6. 245
      couchpotato/static/scripts/mootools_more.js
  7. 11
      couchpotato/static/scripts/pages.js
  8. 2
      couchpotato/templates/_desktop.html

1
couchpotato/__init__.py

@ -23,7 +23,6 @@ def page_not_found(error):
url = request.path[len(index_url):] url = request.path[len(index_url):]
return redirect(index_url + '#' + url) return redirect(index_url + '#' + url)
@web.route('/exit') @web.route('/exit')
@requires_auth @requires_auth
def exit(): def exit():

3
couchpotato/api/__init__.py

@ -1,7 +1,8 @@
from flask import Module from flask import Module
from flask.helpers import jsonify
api = Module(__name__) api = Module(__name__)
@api.route('/') @api.route('/')
def index(): def index():
return 'api' return jsonify({'test': 'bla'})

14
couchpotato/cli.py

@ -1,7 +1,5 @@
from couchpotato import web from couchpotato import web
from couchpotato.api import api from couchpotato.api import api
from couchpotato.core.logger import CPLog
from couchpotato.core.settings import settings
from libs.daemon import createDaemon from libs.daemon import createDaemon
from logging import handlers from logging import handlers
from optparse import OptionParser from optparse import OptionParser
@ -44,7 +42,10 @@ def cmd_couchpotato(base_path, args):
# Register settings # Register settings
from couchpotato.core.settings import settings
settings.setFile(os.path.join(options.data_dir, 'settings.conf')) settings.setFile(os.path.join(options.data_dir, 'settings.conf'))
# Determine debug
debug = options.debug or settings.get('debug', default = False) debug = options.debug or settings.get('debug', default = False)
@ -70,6 +71,7 @@ def cmd_couchpotato(base_path, args):
server_log.disabled = True server_log.disabled = True
# Start logging # Start logging
from couchpotato.core.logger import CPLog
log = CPLog(__name__) log = CPLog(__name__)
log.debug('Started with options %s' % options) log.debug('Started with options %s' % options)
@ -84,7 +86,7 @@ def cmd_couchpotato(base_path, args):
# Create app # Create app
from couchpotato import app from couchpotato import app
api_key = settings.get('api_key') 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 reloader = debug and not options.daemonize
# Basic config # Basic config
@ -92,7 +94,7 @@ def cmd_couchpotato(base_path, args):
app.port = settings.get('port', default = 5000) app.port = settings.get('port', default = 5000)
app.debug = debug app.debug = debug
app.secret_key = api_key app.secret_key = api_key
app.static_path = url_base + 'static' app.static_path = url_base + '/static'
# Add static url with url_base # Add static url with url_base
app.add_url_rule(app.static_path + '/<path:filename>', app.add_url_rule(app.static_path + '/<path:filename>',
@ -100,8 +102,8 @@ def cmd_couchpotato(base_path, args):
view_func = app.send_static_file) view_func = app.send_static_file)
# Register modules # Register modules
app.register_module(web, url_prefix = url_base) app.register_module(web, url_prefix = '%s/' % url_base)
app.register_module(api, url_prefix = '%s/%s' % (url_base + 'api', api_key)) app.register_module(api, url_prefix = '%s/%s/%s/' % (url_base, 'api', api_key))
# Go go go! # Go go go!
app.run(use_reloader = reloader) app.run(use_reloader = reloader)

9
couchpotato/core/settings/__init__.py

@ -1,11 +1,9 @@
from __future__ import with_statement from __future__ import with_statement
from blinker import signal, Signal from blinker import signal, Signal
from couchpotato.core.logger import CPLog
import ConfigParser import ConfigParser
import os.path import os.path
import time import time
log = CPLog(__name__)
class Settings(): class Settings():
@ -20,6 +18,9 @@ class Settings():
self.p = ConfigParser.RawConfigParser() self.p = ConfigParser.RawConfigParser()
self.p.read(file) self.p.read(file)
from couchpotato.core.logger import CPLog
self.log = CPLog(__name__)
self.connectSignals() self.connectSignals()
def parser(self): def parser(self):
@ -38,7 +39,7 @@ class Settings():
for option, value in options.iteritems(): for option, value in options.iteritems():
self.setDefault(section_name, option, value) 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) self.on_register.send(self)
if save: if save:
@ -66,7 +67,7 @@ class Settings():
with open(self.file, 'wb') as configfile: with open(self.file, 'wb') as configfile:
self.p.write(configfile) self.p.write(configfile)
log.debug('Saved settings') self.log.debug('Saved settings')
self.on_save.send(self) self.on_save.send(self)
def addSection(self, section): def addSection(self, section):

137
couchpotato/static/scripts/couchpotato.js

@ -10,12 +10,12 @@ var CouchPotato = new Class({
pages: [], pages: [],
tabse: [ tabs: [
{'href': 'movie', 'title':'Gimmy gimmy gimmy!', 'label':'Wanted'}, {'href': '/movie/', 'title':'Gimmy gimmy gimmy!', 'label':'Wanted'},
{'href': 'manage', 'title':'Do stuff to your existing movies!', 'label':'Manage'}, {'href': '/manage/', 'title':'Do stuff to your existing movies!', 'label':'Manage'},
{'href': 'feed', 'title':'Which wanted movies are released soon?', 'label':'Soon'}, {'href': '/feed/', 'title':'Which wanted movies are released soon?', 'label':'Soon'},
{'href': 'log', 'title':'Show recent logs.', 'class':'logLink', 'label':'Logs'}, {'href': '/log/', 'title':'Show recent logs.', 'class':'logLink', 'label':'Logs'},
{'href': 'config', 'title':'Change settings.', 'id':'showConfig'} {'href': '/config/', 'title':'Change settings.', 'id':'showConfig'}
], ],
initialize: function(options) { initialize: function(options) {
@ -24,12 +24,39 @@ var CouchPotato = new Class({
self.c = $(document.body) 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.addEvent('change', self.createPage.bind(self));
History.handleInitialState(); History.handleInitialState();
self.createLayout() 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(){ createLayout: function(){
@ -49,17 +76,22 @@ var CouchPotato = new Class({
var self = this; var self = this;
self.route.parse(url); self.route.parse(url);
var page = self.route.getPage().capitalize(); var page_name = self.route.getPage().capitalize();
var action = self.route.getAction(); var action = self.route.getAction();
var params = self.route.getParams(); var params = self.route.getParams();
if(!self.pages[page]){ var pg = self.pages[page_name]
page = new Page[page](); if(!pg){
self.pages[page] = page; pg = new Page[page_name]();
pg.setParent(self)
self.pages[page_name] = pg;
} }
page = self.pages[page] pg.open(action, params)
page.open(action, params)
},
getApi: function(){
return this.api
} }
}); });
@ -73,29 +105,90 @@ var PageBase = new Class({
open: function(action, params){ open: function(action, params){
var self = this; 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(){ getName: function(){
return this.name 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({ var Route = new Class({
defaults: {},
page: '', page: '',
action: 'index', action: 'index',
params: {}, params: {},
parse: function(url){ initialize: function(defaults){
var self = this
self.defaults = defaults
},
parse: function(url_string){
var self = this; var self = this;
url = url.split('/') var current = History.getPath().replace(/^\/+|\/+$/g, '')
self.page = url.shift() var url = current.split('/')
self.action = url.shift()
self.params = {} 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 var key
url.each(function(el, nr){ url.each(function(el, nr){
if(nr%2 == 0) if(nr%2 == 0)
@ -105,6 +198,7 @@ var Route = new Class({
key = null key = null
} }
}) })
}
return self return self
}, },
@ -126,3 +220,8 @@ var Route = new Class({
} }
}); });
var p = function(){
if(typeof(console) !== 'undefined' && console != null)
console.log(arguments)
}

245
couchpotato/static/scripts/mootools_more.js

@ -1,6 +1,6 @@
// MooTools: the javascript framework. // MooTools: the javascript framework.
// Load this file's selection again by visiting: http://mootools.net/more/452f2740e09082a2109bec9f69fbf8dc // Load this file's selection again by visiting: http://mootools.net/more/82d3c4f6ee721f808321f6bf6818d8fb
// Or build this file again with packager using: packager build More/URI More/Element.Delegation More/Element.Shortcuts // Or build this file again with packager using: packager build More/Element.Delegation More/Element.Shortcuts
/* /*
--- ---
@ -38,247 +38,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);
}
});
})();
/*
---
name: Events.Pseudos name: Events.Pseudos
description: Adds the functionallity to add pseudo events description: Adds the functionallity to add pseudo events

11
couchpotato/static/scripts/pages.js

@ -8,6 +8,17 @@ Page.Movie = new Class({
initialize: function(options){ initialize: function(options){
},
indexAction: function(param){
var self = this
self.getMovies()
},
getMovies: function(){
var self = this
this.api().request('movie', {'status': 'wanted'})
} }
}) })

2
couchpotato/templates/_desktop.html

@ -12,7 +12,7 @@
<script type="text/javascript"> <script type="text/javascript">
window.addEvent('domready', function() { window.addEvent('domready', function() {
var cp = new CouchPotato({ var cp = new CouchPotato({
'url': '{{ request.path }}', 'base_url': '{{ request.path }}',
'api_url': '{{ url_for('api.index') }}' 'api_url': '{{ url_for('api.index') }}'
}); });
}) })

Loading…
Cancel
Save