Changeset - c2659d40ee53
[Not reviewed]
default
0 3 0
Dennis Fink - 9 years ago 2016-10-24 14:46:46
dennis.fink@c3l.lu
Added logging
3 files changed with 59 insertions and 1 deletions:
0 comments (0 inline, 0 general)
setup.py
Show inline comments
 
from pprint import pprint
 

	
 
from setuptools import setup, find_packages
 

	
 
packages = find_packages()
 
packages.append('spaceapi.templates')
 
packages.append('spaceapi.static')
 
packages.append('spaceapi.schema')
 

	
 
setup(
 
    name='c3l_spaceapi',
 
    version='0.0.7',
 
    version='0.0.8',
 
    url=None,
 
    license='GPLv3+',
 
    author='Dennis Fink',
 
    author_email='dennis.fink@c3l.lu',
 
    description='spaceapi endpoint for c3l.lu',
 
    packages=packages,
 
    package_data={
 
        'spaceapi.templates': ['*'],
 
        'spaceapi.static': ['*'],
 
        'spaceapi.schema': ['*'],
 
    },
 
    install_requires=[
 
        'Flask',
 
        'Flask-HTTPAuth',
 
        'Flask-Bootstrap',
 
        'jsonschema',
 
        'tweepy',
 
    ]
 
)
spaceapi/__init__.py
Show inline comments
 
import json
 
import os
 
import os.path
 
import base64
 

	
 
import logging
 
import logging.handlers
 

	
 
from flask import Flask
 
from flask_bootstrap import Bootstrap
 

	
 
config_file = os.path.abspath('config.json')
 
bootstrap = Bootstrap()
 

	
 
logging_debug_string = ('%(levelname)s:%(name)s:%(asctime)s:%(filename)s'
 
                        ':%(lineno)d: %(message)s')
 
logging_string = '%(levelname)s - %(name)s - %(asctime)s - %(message)s'
 
logging_debug_formatter = logging.Formatter(logging_debug_string)
 
logging_formatter = logging.Formatter(logging_string)
 

	
 

	
 
def create_app():
 
    app = Flask(__name__)
 

	
 
    _default_secret_key = base64.b64encode(os.urandom(32)).decode('utf-8')
 
    app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY',
 
                                              _default_secret_key)
 

	
 
    if not hasattr(app.config, 'from_json'):
 
        def from_json(file, silent=True):
 
            try:
 
                with open(file, encoding='utf-8') as json_file:
 
                    obj = json.load(json_file)
 
            except IOError:
 
                if silent:
 
                    return False
 
                raise
 

	
 
            for key in obj:
 
                if key.isupper():
 
                    app.config[key] = obj[key]
 

	
 
            return True
 

	
 
        app.config.from_json = from_json
 

	
 
    app.config.from_json(config_file, silent=True)
 
    app.config.setdefault('BOOTSTRAP_SERVE_LOCAL', True)
 

	
 
    bootstrap.init_app(app)
 

	
 
    app.logger.setLevel(logging.DEBUG)
 
    stream_handler = logging.StreamHandler()
 
    stream_handler.setLevel(logging.DEBUG)
 
    stream_handler.setFormatter(logging_debug_formatter)
 

	
 
    if not os.path.exists('spaceapi.log'):
 
        open('spaceapi.log', mode='a').close()
 

	
 
    rotating_file_handler = logging.handlers.RotatingFileHandler(
 
        'spaceapi.log',
 
        maxBytes=1300000,
 
        backupCount=10,
 
        encoding='utf-8')
 
    rotating_file_handler.setLevel(logging.INFO)
 
    rotating_file_handler.setFormatter(logging_formatter)
 

	
 
    if app.debug or ('ENABLE_DEBUG_LOG' in app.config and
 
                     app.config['ENABLE_DEBUG_LOG']):
 

	
 
        if not os.path.exists('spaceapi_debug.log'):
 
            open('spaceapi_debug.log', mode='a').close()
 

	
 
        second_rotating_file_handler = logging.handlers.RotatingFileHandler(
 
            'spaceapi_debug.log',
 
            maxBytes=1300000,
 
            backupCount=20,
 
            encoding='utf-8')
 
        second_rotating_file_handler.setLevel(logging.DEBUG)
 
        second_rotating_file_handler.setFormatter(logging_debug_formatter)
 
        app.logger.addHandler(second_rotating_file_handler)
 

	
 
    app.logger.addHandler(stream_handler)
 
    app.logger.addHandler(rotating_file_handler)
 

	
 
    @app.after_request
 
    def add_headers(response):
 
        response.headers.setdefault('Access-Control-Allow-Origin', '*')
 
        response.headers.setdefault('Cache-Control', 'no-cache')
 

	
 
        return response
 

	
 
    from .views import root_views
 
    app.register_blueprint(root_views)
 

	
 
    from .state import state_views
 
    app.register_blueprint(state_views, url_prefix='/state')
 

	
 
    from .sensors import sensors_views
 
    app.register_blueprint(sensors_views, url_prefix='/sensors')
 

	
 
    from .utils import ActiveStatus
 
    ActiveStatus().reload()
 

	
 
    return app
spaceapi/utils.py
Show inline comments
 
import json
 
import os.path
 
from time import time
 
import random
 
from functools import wraps
 

	
 
from flask import request, current_app
 

	
 
import tweepy
 

	
 

	
 
default_json_file = os.path.abspath('default.json')
 
last_state_file = os.path.abspath('laststate.json')
 

	
 
if not os.path.exists(default_json_file):
 
    raise RuntimeError('default.json does not exists!')
 
elif not os.path.isfile(default_json_file):
 
    raise RuntimeError('default.json is not a file!')
 

	
 
possible_open_tweets = {
 
    'The space is now open!',
 
    'The space is open! Come in and hack something!',
 
    'Yes, we\'re open! Come in and create something!',
 
}
 

	
 
possible_closed_tweets = {
 
    'The space is now closed!',
 
    'We\'re closed now! See you soon.',
 
}
 

	
 

	
 
def send_tweet(tweet):
 
    if 'TWITTER_CONSUMER_KEY' in current_app.config:
 
        auth = tweepy.OAuthHandler(
 
            current_app.config['TWITTER_CONSUMER_KEY'],
 
            current_app.config['TWITTER_CONSUMER_SECRET']
 
        )
 
        auth.set_access_token(
 
            current_app.config['TWITTER_ACCESS_TOKEN_KEY'],
 
            current_app.config['TWITTER_ACCESS_TOKEN_SECRET']
 
        )
 
        api = tweepy.API(auth)
 
        api.update_status(tweet)
 

	
 

	
 
class Singleton:
 

	
 
    def __new__(cls, *args, **kwargs):
 
        key = str(hash(cls))
 

	
 
        if not hasattr(cls, '_instance_dict'):
 
            cls._instance_dict = {}
 

	
 
@@ -84,96 +85,110 @@ class ActiveStatus(Singleton, dict):
 
                self['sensors']['people_now_present'] = [{'value': 0}]
 

	
 
            people_now_present = self['sensors']['people_now_present'][0]
 

	
 
            if 'names' in people_now_present and username not in people_now_present['names']:
 
                people_now_present['value'] += 1
 

	
 
                if username in current_app.config['PEOPLE_NOW_PRESENT_ALLOWED']:
 
                    people_now_present['names'].append(username)
 

	
 
            elif 'names' not in people_now_present:
 
                people_now_present['value'] += 1
 

	
 
                if username in current_app.config['PEOPLE_NOW_PRESENT_ALLOWED']:
 
                    people_now_present['names'] = [username]
 

	
 
            self['sensors']['people_now_present'][0] = people_now_present
 
        else:
 
            pass
 

	
 
    def remove_user_present(self, username):
 
        if self['state']['open'] and 'people_now_present' in self['sensors']:
 
            people_now_present = self['sensors']['people_now_present'][0]
 

	
 
            if people_now_present['value'] > 0:
 
                people_now_present['value'] -= 1
 

	
 
            if 'names' in people_now_present:
 

	
 
                if username in people_now_present['names']:
 
                    people_now_present['names'].remove(username)
 

	
 
                if not people_now_present['names'] or people_now_present['value'] == 0:
 
                    del people_now_present['names']
 

	
 
            self['sensors']['people_now_present'][0] = people_now_present
 
        else:
 
            pass
 

	
 
    def set_new_state(self, value=None, trigger_person=None, message=None):
 

	
 
        if value is not None:
 
            self['state']['open'] = value
 

	
 
            if value:
 
                tweet = random.choice(possible_open_tweets)
 
            else:
 
                tweet = random.choice(possible_closed_tweets)
 
            try:
 
            send_tweet(tweet)
 
            except Exception as e:
 
                current_app.logger.error('Sending tweet failed! %s' % e,
 
                                         exc_info=True)
 

	
 
            if not value:
 
                if 'people_now_present' in self['sensors']:
 
                    self['sensors']['people_now_present'][0]['value'] = 0
 
                    if 'names' in self['sensors']['people_now_present'][0]:
 
                        del self['sensors']['people_now_present'][0]['names']
 

	
 
                if 'message' in self['state']:
 
                    del self['state']['message']
 

	
 
            if trigger_person is None:
 
                del self['state']['trigger_person']
 

	
 
        if trigger_person is not None:
 
            self['state']['trigger_person'] = trigger_person
 

	
 
        if message is not None:
 
            self['state']['message'] = message
 

	
 
        if value is not None or trigger_person is not None or message is not None:
 
            self['state']['lastchange'] = int(time())
 

	
 

	
 
def request_wants_json():
 
    best = request.accept_mimetypes.best_match(
 
        ['application/json', 'text/html']
 
    )
 
    return best == 'application/json' and \
 
        request.accept_mimetypes[best] > \
 
        request.accept_mimetypes['text/html']
 

	
 

	
 
def fuzzy_list_find(lst, key, value):
 

	
 
    for i, dic in enumerate(lst):
 
        if dic[key] == value:
 
            return i
 

	
 
    raise ValueError
 

	
 

	
 
def first(iterable, keys):
 
    for key in keys:
 
        if key in iterable:
 
            return key
 

	
 
    raise ValueError
 

	
 

	
 
def pass_active_status(f):
 
    @wraps(f)
 
    def wrapper(*args, **kwargs):
 
        status = ActiveStatus()
 
        rv = f(status, *args, **kwargs)
 
        status.save_last_state()
 
        return rv
 
    return wrapper
0 comments (0 inline, 0 general)