diff options
| author | sirish bitra <sirish.bitra@gmail.com> | 2011-05-08 17:41:42 +0530 |
|---|---|---|
| committer | sirish bitra <sirish.bitra@gmail.com> | 2011-05-08 17:41:42 +0530 |
| commit | ad0cbd2e763d010d31428393aab9d2bcd787cbe0 (patch) | |
| tree | be2ab246c1105265a0d2e519d643b14a7f63d503 | |
| parent | c32b81baa25c827f72bde67832b2f4e20f09f10c (diff) | |
| download | keystone-ad0cbd2e763d010d31428393aab9d2bcd787cbe0.tar.gz keystone-ad0cbd2e763d010d31428393aab9d2bcd787cbe0.tar.xz keystone-ad0cbd2e763d010d31428393aab9d2bcd787cbe0.zip | |
get version implementation
s Please enter the commit message for your changes. Lines starting
| -rwxr-xr-x | keystone/auth_server.py | 82 | ||||
| -rw-r--r-- | keystone/logic/service.py | 287 |
2 files changed, 363 insertions, 6 deletions
diff --git a/keystone/auth_server.py b/keystone/auth_server.py index 35812f48..5ab8932f 100755 --- a/keystone/auth_server.py +++ b/keystone/auth_server.py @@ -56,7 +56,6 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'keystone', '__init__.py')): sys.path.insert(0, POSSIBLE_TOPDIR) - from queryext import exthandler from keystone.common import wsgi import keystone.logic.service as serv @@ -65,6 +64,7 @@ import keystone.logic.types.auth as auth import keystone.logic.types.fault as fault import keystone.logic.types.user as users + VERSION_STATUS = "ALPHA" VERSION_DATE = "2011-04-23T00:00:00Z" @@ -77,6 +77,10 @@ def is_xml_response(req): return req.content_type == "application/xml" +def get_app_root(): + return os.path.abspath(os.path.dirname(__file__)) + + def get_auth_token(req): auth_token = None if "X-Auth-Token" in req.headers: @@ -113,16 +117,19 @@ def send_result(code, req, result): return return content + class MiscController(wsgi.Controller): def __init__(self, options): self.options = options - def get_version_info(self, req): + def get_version_info(self, req): + if is_xml_response(req): resp_file = os.path.join(POSSIBLE_TOPDIR, "keystone/content/version.xml.tpl") else: + resp_file = os.path.join(POSSIBLE_TOPDIR, "keystone/content/version.json.tpl") @@ -131,11 +138,71 @@ class MiscController(wsgi.Controller): #try: tmplfile=open(resp_file); tmplstring=tmplfile.read() - - send_result(200,req, tmplstring.format(HOST=hostname, PORT=port, + + return serv.template(resp_file, HOST=hostname, PORT=port, + VERSION_STATUS=VERSION_STATUS, + VERSION_DATE=VERSION_DATE) + + def get_pdf_contract(self, req): + resp = Response() + return serv.static_file(resp, req, "content/idmdevguide.pdf", + root=get_app_root(), + mimetype="application/pdf",) + +""" +@bottle.route('/v1.0', method='GET') +@bottle.route('/v1.0/', method='GET') +@wrap_error +def get_version_info(): + if is_xml_response(): + resp_file = os.path.join(POSSIBLE_TOPDIR, "keystone/content/version.xml.tpl") + response.content_type = "application/xml" + else: + resp_file = os.path.join(POSSIBLE_TOPDIR, "keystone/content/version.json.tpl") + response.content_type = "application/json" + hostname = request.environ.get("SERVER_NAME") + port = request.environ.get("SERVER_PORT") + return bottle.template(resp_file, HOST=hostname, PORT=port, VERSION_STATUS=VERSION_STATUS, - VERSION_DATE=VERSION_DATE)) + VERSION_DATE=VERSION_DATE) + +## +## Version links: +## + +@bottle.route('/v1.0/idmdevguide.pdf', method='GET') +@wrap_error +def get_pdf_contract(): + return bottle.static_file("content/idmdevguide.pdf", + root=get_app_root(), + mimetype="application/pdf") + + +@bottle.route('/v1.0/identity.wadl', method='GET') +@wrap_error +def get_wadl_contract(): + return bottle.static_file("identity.wadl", + root=get_app_root(), + mimetype="application/vnd.sun.wadl+xml") + + +@bottle.route('/v1.0/xsd/:xsd', method='GET') +@wrap_error +def get_xsd_contract(xsd): + return bottle.static_file("/xsd/" + xsd, + root=get_app_root(), + mimetype="application/xml") + + +@bottle.route('/v1.0/xsd/atom/:xsd', method='GET') +@wrap_error +def get_xsd_atom_contract(xsd): + return bottle.static_file("/xsd/atom/" + xsd, + root=get_app_root(), + mimetype="application/xml") + +""" class AuthController(wsgi.Controller): @@ -386,7 +453,10 @@ class Auth_API(wsgi.Router): action="get_version_info",conditions=dict(method=["GET"])) mapper.connect("/v1.0", controller=misc_controller, action="get_version_info",conditions=dict(method=["GET"])) - + mapper.connect("/v1.0/idmdevguide.pdf", controller=misc_controller, + action="get_pdf_contract",conditions=dict(method=["GET"])) + + super(Auth_API, self).__init__(mapper) diff --git a/keystone/logic/service.py b/keystone/logic/service.py index cc852af0..9b38b76c 100644 --- a/keystone/logic/service.py +++ b/keystone/logic/service.py @@ -26,6 +26,293 @@ import keystone.db.sqlalchemy.api as db_api import keystone.db.sqlalchemy.models as db_models import uuid +import cgi +import re +import os +import functools +import time +TEMPLATES = {} +DEBUG = False +TEMPLATE_PATH = ['./', './views/'] + + +##""" this part of below code is used from bottle.py """ +class BaseTemplate(object): + """ Base class and minimal API for template adapters """ + extentions = ['tpl','html','thtml','stpl'] + settings = {} #used in prepare() + defaults = {} #used in render() + + def __init__(self, source=None, name=None, lookup=[], encoding='utf8', **settings): + """ Create a new template. + If the source parameter (str or buffer) is missing, the name argument + is used to guess a template filename. Subclasses can assume that + self.source and/or self.filename are set. Both are strings. + The lookup, encoding and settings parameters are stored as instance + variables. + The lookup parameter stores a list containing directory paths. + The encoding parameter should be used to decode byte strings or files. + The settings parameter contains a dict for engine-specific settings. + """ + self.name = name + self.source = source.read() if hasattr(source, 'read') else source + self.filename = source.filename if hasattr(source, 'filename') else None + self.lookup = map(os.path.abspath, lookup) + self.encoding = encoding + self.settings = self.settings.copy() # Copy from class variable + self.settings.update(settings) # Apply + if not self.source and self.name: + self.filename = self.search(self.name, self.lookup) + if not self.filename: + raise TemplateError('Template %s not found.' % repr(name)) + if not self.source and not self.filename: + raise TemplateError('No template specified.') + self.prepare(**self.settings) + + @classmethod + def search(cls, name, lookup=[]): + """ Search name in all directories specified in lookup. + First without, then with common extensions. Return first hit. """ + if os.path.isfile(name): return name + for spath in lookup: + fname = os.path.join(spath, name) + if os.path.isfile(fname): + return fname + for ext in cls.extentions: + if os.path.isfile('%s.%s' % (fname, ext)): + return '%s.%s' % (fname, ext) + + @classmethod + def global_config(cls, key, *args): + ''' This reads or sets the global settings stored in class.settings. ''' + if args: + cls.settings[key] = args[0] + else: + return cls.settings[key] + + def prepare(self, **options): + """ Run preparations (parsing, caching, ...). + It should be possible to call this again to refresh a template or to + update settings. + """ + raise NotImplementedError + + def render(self, **args): + """ Render the template with the specified local variables and return + a single byte or unicode string. If it is a byte string, the encoding + must match self.encoding. This method must be thread-safe! + """ + raise NotImplementedError + + +class SimpleTemplate(BaseTemplate): + blocks = ('if','elif','else','try','except','finally','for','while','with','def','class') + dedent_blocks = ('elif', 'else', 'except', 'finally') + + def prepare(self, escape_func=cgi.escape, noescape=False): + self.cache = {} + if self.source: + self.code = self.translate(self.source) + self.co = compile(self.code, '<string>', 'exec') + else: + self.code = self.translate(open(self.filename).read()) + self.co = compile(self.code, self.filename, 'exec') + enc = self.encoding + touni = functools.partial(unicode, encoding=self.encoding) + self._str = lambda x: touni(x, enc) + self._escape = lambda x: escape_func(touni(x)) + if noescape: + self._str, self._escape = self._escape, self._str + + def translate(self, template): + stack = [] # Current Code indentation + lineno = 0 # Current line of code + ptrbuffer = [] # Buffer for printable strings and token tuple instances + codebuffer = [] # Buffer for generated python code + touni = functools.partial(unicode, encoding=self.encoding) + multiline = dedent = False + + def yield_tokens(line): + for i, part in enumerate(re.split(r'\{\{(.*?)\}\}', line)): + if i % 2: + if part.startswith('!'): yield 'RAW', part[1:] + else: yield 'CMD', part + else: yield 'TXT', part + + def split_comment(codeline): + """ Removes comments from a line of code. """ + line = codeline.splitlines()[0] + try: + tokens = list(tokenize.generate_tokens(iter(line).next)) + except tokenize.TokenError: + return line.rsplit('#',1) if '#' in line else (line, '') + for token in tokens: + if token[0] == tokenize.COMMENT: + start, end = token[2][1], token[3][1] + return codeline[:start] + codeline[end:], codeline[start:end] + return line, '' + + def flush(): # Flush the ptrbuffer + if not ptrbuffer: return + cline = '' + for line in ptrbuffer: + for token, value in line: + if token == 'TXT': cline += repr(value) + elif token == 'RAW': cline += '_str(%s)' % value + elif token == 'CMD': cline += '_escape(%s)' % value + cline += ', ' + cline = cline[:-2] + '\\\n' + cline = cline[:-2] + if cline[:-1].endswith('\\\\\\\\\\n'): + cline = cline[:-7] + cline[-1] # 'nobr\\\\\n' --> 'nobr' + cline = '_printlist([' + cline + '])' + del ptrbuffer[:] # Do this before calling code() again + code(cline) + + def code(stmt): + for line in stmt.splitlines(): + codebuffer.append(' ' * len(stack) + line.strip()) + + for line in template.splitlines(True): + lineno += 1 + line = line if isinstance(line, unicode)\ + else unicode(line, encoding=self.encoding) + if lineno <= 2: + m = re.search(r"%.*coding[:=]\s*([-\w\.]+)", line) + if m: self.encoding = m.group(1) + if m: line = line.replace('coding','coding (removed)') + if line.strip()[:2].count('%') == 1: + line = line.split('%',1)[1].lstrip() # Full line following the % + cline = split_comment(line)[0].strip() + cmd = re.split(r'[^a-zA-Z0-9_]', cline)[0] + flush() ##encodig (TODO: why?) + if cmd in self.blocks or multiline: + cmd = multiline or cmd + dedent = cmd in self.dedent_blocks # "else:" + if dedent and not oneline and not multiline: + cmd = stack.pop() + code(line) + oneline = not cline.endswith(':') # "if 1: pass" + multiline = cmd if cline.endswith('\\') else False + if not oneline and not multiline: + stack.append(cmd) + elif cmd == 'end' and stack: + code('#end(%s) %s' % (stack.pop(), line.strip()[3:])) + elif cmd == 'include': + p = cline.split(None, 2)[1:] + if len(p) == 2: + code("_=_include(%s, _stdout, %s)" % (repr(p[0]), p[1])) + elif p: + code("_=_include(%s, _stdout)" % repr(p[0])) + else: # Empty %include -> reverse of %rebase + code("_printlist(_base)") + elif cmd == 'rebase': + p = cline.split(None, 2)[1:] + if len(p) == 2: + code("globals()['_rebase']=(%s, dict(%s))" % (repr(p[0]), p[1])) + elif p: + code("globals()['_rebase']=(%s, {})" % repr(p[0])) + else: + code(line) + else: # Line starting with text (not '%') or '%%' (escaped) + if line.strip().startswith('%%'): + line = line.replace('%%', '%', 1) + ptrbuffer.append(yield_tokens(line)) + flush() + return '\n'.join(codebuffer) + '\n' + + def subtemplate(self, _name, _stdout, **args): + if _name not in self.cache: + self.cache[_name] = self.__class__(name=_name, lookup=self.lookup) + return self.cache[_name].execute(_stdout, **args) + + def execute(self, _stdout, **args): + env = self.defaults.copy() + env.update({'_stdout': _stdout, '_printlist': _stdout.extend, + '_include': self.subtemplate, '_str': self._str, + '_escape': self._escape}) + env.update(args) + eval(self.co, env) + if '_rebase' in env: + subtpl, rargs = env['_rebase'] + subtpl = self.__class__(name=subtpl, lookup=self.lookup) + rargs['_base'] = _stdout[:] #copy stdout + del _stdout[:] # clear stdout + return subtpl.execute(_stdout, **rargs) + return env + + def render(self, **args): + """ Render the template using keyword arguments as local variables. """ + stdout = [] + self.execute(stdout, **args) + return ''.join(stdout) + +def static_file(resp, req, filename, root, guessmime=True, mimetype=None, download=False): + """ Opens a file in a safe way and returns a HTTPError object with status + code 200, 305, 401 or 404. Sets Content-Type, Content-Length and + Last-Modified header. Obeys If-Modified-Since header and HEAD requests. + """ + root = os.path.abspath(root) + os.sep + filename = os.path.abspath(os.path.join(root, filename.strip('/\\'))) + header = dict() + if not filename.startswith(root): + #return HTTPError(403, "Access denied.") + return ForbiddenFault("Access denied.") + if not os.path.exists(filename) or not os.path.isfile(filename): + #return HTTPError(404, "File does not exist.") + return fault.ItemNotFoundFault("File does not exist.") + if not os.access(filename, os.R_OK): + #return HTTPError(403, "You do not have permission to access this file.") + return ForbiddenFault("You do not have permission to access this file.") + + if not mimetype and guessmime: + resp.headers['Content-Type'] = mimetypes.guess_type(filename)[0] + else: + resp.headers['Content-Type'] = mimetype if mimetype else 'text/plain' + + if download == True: + download = os.path.basename(filename) + if download: + resp.headers['Content-Disposition'] = 'attachment; filename="%s"' % download + + stats = os.stat(filename) + lm = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime)) + resp.headers['Last-Modified'] = lm + ims = req.environ.get('HTTP_IF_MODIFIED_SINCE') + if ims: + ims = ims.split(";")[0].strip() # IE sends "<date>; length=146" + ims = parse_date(ims) + if ims is not None and ims >= int(stats.st_mtime): + resp.headers['Date'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()) + return Response(status=304, header=header) + resp.headers['Content-Length'] = stats.st_size + if req.method == 'HEAD': + return resp('', header=header) + else: + return resp(open(filename, 'rb'), header=header) + + +def template(tpl, template_adapter=SimpleTemplate, **kwargs): + ''' + Get a rendered template as a string iterator. + You can use a name, a filename or a template string as first parameter. + ''' + if tpl not in TEMPLATES or DEBUG: + settings = kwargs.get('template_settings',{}) + lookup = kwargs.get('template_lookup', TEMPLATE_PATH) + if isinstance(tpl, template_adapter): + TEMPLATES[tpl] = tpl + if settings: TEMPLATES[tpl].prepare(**settings) + elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl: + TEMPLATES[tpl] = template_adapter(source=tpl, lookup=lookup, **settings) + else: + TEMPLATES[tpl] = template_adapter(name=tpl, lookup=lookup, **settings) + if not TEMPLATES[tpl]: + abort(500, 'Template (%s) not found' % tpl) + return TEMPLATES[tpl].render(**kwargs) + + +##""" this part of above code is used from bottle.py """ class IDMService(object): |
