diff --git a/nofussbm/__init__.py b/nofussbm/__init__.py index b3cceb4..d281531 100644 --- a/nofussbm/__init__.py +++ b/nofussbm/__init__.py @@ -15,10 +15,10 @@ # You should have received a copy of the GNU General Public License along with # "No Fuss Bookmarks". If not, see . -from logging import StreamHandler, Formatter, getLogger, DEBUG +from logging import StreamHandler, Formatter, DEBUG from os import environ -from flask import Flask, make_response, request, g, redirect, url_for, abort, render_template +from flask import Flask, make_response, request, redirect, url_for, abort, render_template from flask.ext.pymongo import PyMongo from pymongo.errors import OperationFailure @@ -41,6 +41,9 @@ class Config( object ): from .api import api from .helpers import query_from_dict from .tags import tags +from .json import NofussbmJSONEncoder, NofussbmJSONDecoder +app.json_encoder = NofussbmJSONEncoder +app.json_decoder = NofussbmJSONDecoder # Register APIs blueprint and setup {before,teardown}_request @@ -58,7 +61,7 @@ class Config( object ): stderr_handler = StreamHandler() stderr_handler.setLevel( DEBUG ) -stderr_handler.setFormatter( Formatter( '%(asctime)s [%(process)s] [%(levelname)s] [Flask: %(name)s] %(message)s','%Y-%m-%d %H:%M:%S' ) ) +stderr_handler.setFormatter( Formatter( '%(asctime)s [%(process)s] [%(levelname)s] [Flask: %(name)s] %(message)s', '%Y-%m-%d %H:%M:%S' ) ) app.logger.addHandler( stderr_handler ) app.logger.setLevel( DEBUG ) @@ -136,7 +139,6 @@ def list( ident ): if list_appearance == 'html': for bm in list_query( email, bookmarks_per_page ): date = bm[ 'date-modified' ] - print bm result.append( ( date.strftime( '%Y-%m-%d' ), bm[ 'url' ], bm[ 'title' ], bm[ 'tags' ], bm[ '_id' ] ) ) if content_only: return render_template( 'list-content.html', bookmarks = result ) diff --git a/nofussbm/api.py b/nofussbm/api.py index 50ad097..779a7fa 100644 --- a/nofussbm/api.py +++ b/nofussbm/api.py @@ -15,12 +15,13 @@ # You should have received a copy of the GNU General Public License along with # "No Fuss Bookmarks". If not, see . +import hmac +import re + from base64 import b64encode, b64decode from datetime import datetime from functools import wraps from hashlib import sha1 -import hmac -import re from urlparse import parse_qs from flask import Blueprint, make_response, request, g, json, abort @@ -35,11 +36,6 @@ RANGE_RE = re.compile( r'bookmarks=(\d+)(-(\d+))?' ) -# Hacks (somehow horrible) to personalize decoding in Flask request.json - -from .helpers import setup_json -setup_json( json ) - def myjsonify( data = None, code = 200, headers = None ): data = [] if not data else data response = make_response( json.dumps( data, indent = 4, sort_keys = True, ensure_ascii = False ) + '\n', code ) diff --git a/nofussbm/helpers.py b/nofussbm/helpers.py index 6439ac1..16db03d 100644 --- a/nofussbm/helpers.py +++ b/nofussbm/helpers.py @@ -15,18 +15,13 @@ # You should have received a copy of the GNU General Public License along with # "No Fuss Bookmarks". If not, see . -from datetime import datetime from email.mime.text import MIMEText -from json import JSONEncoder, JSONDecoder from smtplib import SMTP from bson.objectid import ObjectId, InvalidId from . import Config -DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f' - -ALLOWED_KEYS = set(( 'title', 'url', 'id', 'tags', 'date-added', 'date-modified' )) def to_id( id_as_str ): res = None @@ -48,43 +43,6 @@ def query_from_dict( email, dct ): query[ 'title' ] = { '$regex': dct[ 'title' ], '$options': 'i' } return query -def setup_json( json ): - - def object_hook( dct ): - res = {} - for key, value in dct.items(): - if key not in ALLOWED_KEYS: continue - if key == 'id': res[ 'id' ] = to_id( value ) - elif key == 'tags': res[ 'tags' ] = map( lambda _: _.strip(), value.split( ',' ) ) - elif key.startswith( 'date-' ): - try: - res[ key ] = datetime.strptime( value, DATETIME_FORMAT ) - except: - pass - else: - res[ key ] = value - return res - - class Encoder( JSONEncoder ): - def default(self, obj): - if isinstance( obj, datetime ): - return datetime.strftime( obj, DATETIME_FORMAT ) - if isinstance( obj, ObjectId ): - return str( obj ) - return JSONEncoder.default( self, obj ) - - prev_dumps = json.dumps - prev_loads = json.loads - - def _dumps( *args, **kwargs ): - kwargs.update( { 'cls': Encoder } ) - return prev_dumps( *args, **kwargs ) - def _loads( *args, **kwargs ): - return prev_loads( *args, object_hook = object_hook, **kwargs ) - - json.dumps = _dumps - json.loads = _loads - # Utility functions diff --git a/nofussbm/json.py b/nofussbm/json.py new file mode 100644 index 0000000..73106c9 --- /dev/null +++ b/nofussbm/json.py @@ -0,0 +1,59 @@ +# Copyright 2011, Massimo Santini +# +# This file is part of "No Fuss Bookmarks". +# +# "No Fuss Bookmarks" is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# "No Fuss Bookmarks" is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# "No Fuss Bookmarks". If not, see . + +from flask.json import JSONEncoder, JSONDecoder +from datetime import datetime +from bson.objectid import ObjectId +from .helpers import to_id + +DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f' + + +class NofussbmJSONEncoder(JSONEncoder): + + def default(self, obj): + if isinstance(obj, datetime): + return datetime.strftime(obj, DATETIME_FORMAT) + if isinstance(obj, ObjectId): + return str(obj) + return JSONEncoder.default(self, obj) + + +class NofussbmJSONDecoder(JSONDecoder): + + def __init__(self, *args, **kwargs): + self.ALLOWED_KEYS = set(['title', 'url', 'id', 'tags', 'date-added', 'date-modified']) + self.orig_object_hook = kwargs.pop("object_hook", None) + super(NofussbmJSONDecoder, self).__init__(*args, object_hook=self.custom_object_hook, **kwargs) + + def custom_object_hook(self, dct): + res = dict() + for key, value in dct.items(): + if key not in self.ALLOWED_KEYS: + continue + if key == 'id': + res['id'] = to_id(value) + elif key == 'tags': + res['tags'] = [_.strip() for _ in value.split(',')] + elif key.startswith('date-'): + try: + res[key] = datetime.strptime(value, DATETIME_FORMAT) + except: + pass + else: + res[key] = value + return res