<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Flask-BugzScout
===============

`BugzScout <https://pypi.python.org/pypi/bugzscout>`_ extension for Flask.
"""

import bugzscout
import flask
import functools
import os
import pkg_resources
import pprint
import sys
import traceback

class BugzScout(object):
    """Recording Flask and HTTP errors to FogBugz via BugzScout."""

    def __init__(self, app=None):
        """Initialize a new BugzScout instance."""
        super(BugzScout, self).__init__()
        self.app = app
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        """Initialize BugzScout with Flask app."""

        # Update app extensions.
        if not hasattr(app, 'extensions'):
            app.extensions = {}

        if 'bugzscout' in app.extensions:
            app.logger.warning('Repeated BugzScout initialization attempt.')
            return

        # Configure defaults on app.
        app.config.setdefault('BUGZSCOUT_URL', None)
        app.config.setdefault('BUGZSCOUT_USER', None)
        app.config.setdefault('BUGZSCOUT_PROJECT', None)
        app.config.setdefault('BUGZSCOUT_AREA', None)

        app.config.setdefault('BUGZSCOUT_HTTP_CODES', set(xrange(400, 418)))

        self.url = app.config['BUGZSCOUT_URL']
        self.user = app.config['BUGZSCOUT_USER']
        self.project = app.config['BUGZSCOUT_PROJECT']
        self.area = app.config['BUGZSCOUT_AREA']

        app.handle_exception = self._get_exception_handler(app)
        app.handle_http_exception = self.get_http_exception_handler(app)

        app.extensions['bugzscout'] = self

    def filter(self, resource, resource_type):
        """Filter a dict of data based on the configured filters for its type.

        :type resource: dict
        :arg resource: resource to filter, like headers or cookies

        :type resource_type: str
        :arg resource_type: type of resource to filter

        :rtype: dict
        :returns: filtered resource
        """
        # FIXME: This probably should do something...
        #        (thomasvandoren, 2013-09-19)
        return resource

    def _get_exception_handler(self, app):
        """Create exception handler that wraps app exception handler.

        :type app: Flask app
        :arg app: Flask app to report exceptions to BugzScout
        """
        handle_exception = app.handle_exception

        @functools.wraps(handle_exception)
        def wrapper(exception):
            self._report_error(flask._request_ctx_stack.top)
            return handle_exception(exception)

        return wrapper

    def _get_http_exception_handler(self, app):
        """Create HTTP exception handler that wraps app HTTP exception handler.

        :type app: Flask app
        :arg app: Flask app to report HTTP exceptions to BugzScout
        """
        handle_http_exception = app.handle_http_exception

        @functools.wraps(handle_http_exception)
        def wrapper(exception):
            if exception.code in app.config['BUGZSCOUT_HTTP_CODES']:
                self._report_error(flask._request_ctx_stack.top)
            return handle_http_exception(exception)

        return wrapper

    def _get_app_from_context(self, context):
        """Given a context, which may be None, find and return the current
        flask app.

        :type context: FIXME
        :arg context: FIXME
        """
        if context:
            if isinstance(context, flask.Flask):
                return context
            else:
                return context.app
        else:
            return flask._request_ctx_stack.top.app

    def _report_error(self, context):
        """Report an error to BugzScout!

        :type context: FIXME
        :arg context: FIXME
        """
        app = self._get_app_from_context(context)

        app_data = self._get_app_data(app)
        request_data = self._get_request_data(
            app, context.request, context.session)
        exception_data = self._get_exception_data(*sys.exc_info())

        description = '{method} {url} {summary}'.format(
            request_data['method'],
            request_data['url'],
            exception_data['summary'])

        # FogBugz appears to limit the length of the description (the case
        # title) to ~125 chars, but BugzScout will use the entire description
        # when collating. For now, limit the normalized description to 125
        # chars so the descriptions make sense.
        description = description[:125]

        extra = ''.join([
            '{traceback}',
            '\n\n', '----------', '\n\n',
            'Request:\n'
            '{request_data}',
            '\n\n', '----------', '\n\n',
            'App data:\n',
            '{app_data}',
        ]).format(
            traceback=exception_data['traceback'],
            request_data=pprint.pformat(request_data),
            app_data=pprint.pformat(app_data)
        )

        app.logger.info('Publishing error to BugzScout asynchronously.')
        bugzscout.ext.celery_app.submit_error.delay(
            self.url,
            self.user,
            self.project,
            self.area,
            description,
            extra=extra)

    def _get_exception_data(self, exc_type, exc_value, exc_traceback):
        """Returns dict of exception info, including the full stack trace and a
        summary line.

        :type exc_type: FIXME
        :arg exc_type: FIXME

        :type exc_value: FIXME
        :arg exc_value: FIXME

        :type exc_traceback: FIXME
        :arg exc_traceback: FIXME

        :rtype: dict
        :returns: dict with summary and traceback keys
        """
        tb = traceback.format_exception(
            exc_type, exc_value, exc_traceback)
        summary = '{0}: {1}'.format(str(exc_type.__name__), str(exc_value))
        return {
            'summary': summary,
            'traceback': tb,
        }

    def _get_request_data(self, app, request, session):
        """Returns dict of request data.

        :type app: flask.Flask
        :arg app: Flask application

        :type request: flask.Request
        :arg request: Request instance

        :type session: flask.session
        :arg session: Flask session

        :rtype: dict
        :returns: dict of request data include verb, path, body, etc.
        """
        handler = None
        if hasattr(request, 'blueprint'):
            handler = request.blueprint
        else:
            handler = request.module

        return {
            'method': request.method,
            'url': request.url,
            'headers': self.filter(request.headers, 'headers'),
            'cookies': self.filter(request.cookies, 'cookies'),
            'session': self.filter(session, 'session'),
            'remote_ip': request.remote_addr,
            'body': request.data,
            'handler': handler,
        }

    def _get_app_data(self, app):
        """Returns dict of application data, which may be helpful for
        debugging.

        :type app: flask.Flask
        :arg app: Flask application

        :rtype: dict
        :returns: dict of application, environment, and module data
        """
        # Gather a copy of the app configuration.
        env = app.config.copy()

        # Gather current environment variables, prefix with "os.".
        for key, val in os.environ.iteritems():
            env['os.{0}'.format(key)] = val

        # Gather mapping of module names to versions.
        modules = {}
        for module in pkg_resources.working_set:
            modules[module.name] = module.version

        return {
            'env': self.filter(env, 'configuration'),
            'python_version': sys.version.replace('\n', ''),
            'application_root_directory': app.root_path,
            'loaded_modules': modules,
        }
<commit_msg>Fix python3 bug.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Flask-BugzScout
===============

`BugzScout <https://pypi.python.org/pypi/bugzscout>`_ extension for Flask.
"""

import bugzscout
import flask
import functools
import os
import pkg_resources
import pprint
import sys
import traceback

class BugzScout(object):
    """Recording Flask and HTTP errors to FogBugz via BugzScout."""

    def __init__(self, app=None):
        """Initialize a new BugzScout instance."""
        super(BugzScout, self).__init__()
        self.app = app
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        """Initialize BugzScout with Flask app."""

        # Update app extensions.
        if not hasattr(app, 'extensions'):
            app.extensions = {}

        if 'bugzscout' in app.extensions:
            app.logger.warning('Repeated BugzScout initialization attempt.')
            return

        # Configure defaults on app.
        app.config.setdefault('BUGZSCOUT_URL', None)
        app.config.setdefault('BUGZSCOUT_USER', None)
        app.config.setdefault('BUGZSCOUT_PROJECT', None)
        app.config.setdefault('BUGZSCOUT_AREA', None)

        app.config.setdefault('BUGZSCOUT_HTTP_CODES', set(range(400, 418)))

        self.url = app.config['BUGZSCOUT_URL']
        self.user = app.config['BUGZSCOUT_USER']
        self.project = app.config['BUGZSCOUT_PROJECT']
        self.area = app.config['BUGZSCOUT_AREA']

        app.handle_exception = self._get_exception_handler(app)
        app.handle_http_exception = self.get_http_exception_handler(app)

        app.extensions['bugzscout'] = self

    def filter(self, resource, resource_type):
        """Filter a dict of data based on the configured filters for its type.

        :type resource: dict
        :arg resource: resource to filter, like headers or cookies

        :type resource_type: str
        :arg resource_type: type of resource to filter

        :rtype: dict
        :returns: filtered resource
        """
        # FIXME: This probably should do something...
        #        (thomasvandoren, 2013-09-19)
        return resource

    def _get_exception_handler(self, app):
        """Create exception handler that wraps app exception handler.

        :type app: Flask app
        :arg app: Flask app to report exceptions to BugzScout
        """
        handle_exception = app.handle_exception

        @functools.wraps(handle_exception)
        def wrapper(exception):
            self._report_error(flask._request_ctx_stack.top)
            return handle_exception(exception)

        return wrapper

    def _get_http_exception_handler(self, app):
        """Create HTTP exception handler that wraps app HTTP exception handler.

        :type app: Flask app
        :arg app: Flask app to report HTTP exceptions to BugzScout
        """
        handle_http_exception = app.handle_http_exception

        @functools.wraps(handle_http_exception)
        def wrapper(exception):
            if exception.code in app.config['BUGZSCOUT_HTTP_CODES']:
                self._report_error(flask._request_ctx_stack.top)
            return handle_http_exception(exception)

        return wrapper

    def _get_app_from_context(self, context):
        """Given a context, which may be None, find and return the current
        flask app.

        :type context: FIXME
        :arg context: FIXME
        """
        if context:
            if isinstance(context, flask.Flask):
                return context
            else:
                return context.app
        else:
            return flask._request_ctx_stack.top.app

    def _report_error(self, context):
        """Report an error to BugzScout!

        :type context: FIXME
        :arg context: FIXME
        """
        app = self._get_app_from_context(context)

        app_data = self._get_app_data(app)
        request_data = self._get_request_data(
            app, context.request, context.session)
        exception_data = self._get_exception_data(*sys.exc_info())

        description = '{method} {url} {summary}'.format(
            request_data['method'],
            request_data['url'],
            exception_data['summary'])

        # FogBugz appears to limit the length of the description (the case
        # title) to ~125 chars, but BugzScout will use the entire description
        # when collating. For now, limit the normalized description to 125
        # chars so the descriptions make sense.
        description = description[:125]

        extra = ''.join([
            '{traceback}',
            '\n\n', '----------', '\n\n',
            'Request:\n'
            '{request_data}',
            '\n\n', '----------', '\n\n',
            'App data:\n',
            '{app_data}',
        ]).format(
            traceback=exception_data['traceback'],
            request_data=pprint.pformat(request_data),
            app_data=pprint.pformat(app_data)
        )

        app.logger.info('Publishing error to BugzScout asynchronously.')
        bugzscout.ext.celery_app.submit_error.delay(
            self.url,
            self.user,
            self.project,
            self.area,
            description,
            extra=extra)

    def _get_exception_data(self, exc_type, exc_value, exc_traceback):
        """Returns dict of exception info, including the full stack trace and a
        summary line.

        :type exc_type: FIXME
        :arg exc_type: FIXME

        :type exc_value: FIXME
        :arg exc_value: FIXME

        :type exc_traceback: FIXME
        :arg exc_traceback: FIXME

        :rtype: dict
        :returns: dict with summary and traceback keys
        """
        tb = traceback.format_exception(
            exc_type, exc_value, exc_traceback)
        summary = '{0}: {1}'.format(str(exc_type.__name__), str(exc_value))
        return {
            'summary': summary,
            'traceback': tb,
        }

    def _get_request_data(self, app, request, session):
        """Returns dict of request data.

        :type app: flask.Flask
        :arg app: Flask application

        :type request: flask.Request
        :arg request: Request instance

        :type session: flask.session
        :arg session: Flask session

        :rtype: dict
        :returns: dict of request data include verb, path, body, etc.
        """
        handler = None
        if hasattr(request, 'blueprint'):
            handler = request.blueprint
        else:
            handler = request.module

        return {
            'method': request.method,
            'url': request.url,
            'headers': self.filter(request.headers, 'headers'),
            'cookies': self.filter(request.cookies, 'cookies'),
            'session': self.filter(session, 'session'),
            'remote_ip': request.remote_addr,
            'body': request.data,
            'handler': handler,
        }

    def _get_app_data(self, app):
        """Returns dict of application data, which may be helpful for
        debugging.

        :type app: flask.Flask
        :arg app: Flask application

        :rtype: dict
        :returns: dict of application, environment, and module data
        """
        # Gather a copy of the app configuration.
        env = app.config.copy()

        # Gather current environment variables, prefix with "os.".
        for key, val in os.environ.iteritems():
            env['os.{0}'.format(key)] = val

        # Gather mapping of module names to versions.
        modules = {}
        for module in pkg_resources.working_set:
            modules[module.name] = module.version

        return {
            'env': self.filter(env, 'configuration'),
            'python_version': sys.version.replace('\n', ''),
            'application_root_directory': app.root_path,
            'loaded_modules': modules,
        }
<|endoftext|>


<commit_before>#!/usr/bin/env python3

import sys
import time
import array
import datetime
import requests
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt

NB_HOURS = 23
GRANULOMETRY = 10 # must be a divisor of 60

if len(sys.argv) != 2:
    print('Syntax: %s file.png' % sys.argv[0])
    exit(1)

# Get data
data = requests.get('http://logger.frontend.askplatyp.us/', params={'limit': 10000}).json()

# Convert to datetime
data = [datetime.datetime(*time.strptime(x[1].split('.')[0], "%Y-%m-%d %H:%M:%S")[:6]) for x in data]

# Compute the difference
now = datetime.datetime.now()
data = [now - x for x in data]
max_ = datetime.timedelta(hours=NB_HOURS)

# Shrink and convert to minutes
data = [x.seconds//(60*GRANULOMETRY) for x in data if x <= max_]

# Compute the height of the bars
requests_per_minute = array.array('I', (0 for x in range(0, 60*NB_HOURS//GRANULOMETRY)))
for x in data:
    requests_per_minute[(60*NB_HOURS//GRANULOMETRY) - x - 1] += 1

# Final plot
x = list(map(lambda x:x*GRANULOMETRY, range(-60*NB_HOURS//GRANULOMETRY, 0)))
plt.plot(x, requests_per_minute, label=None)
plt.title("Requests to the PPP in the last %d hours" % NB_HOURS)
plt.xlabel("Time (minutes)")
plt.ylabel("Requests (per slice of %d minutes)" % GRANULOMETRY)
#plt.legend()
plt.savefig(sys.argv[1])
<commit_msg>Human-reable x-axis (first item of GH-2).<commit_after>#!/usr/bin/env python3

import sys
import time
import array
import datetime
import requests
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

NB_HOURS = 48
GRANULOMETRY = 60 # must be a divisor of 60

if len(sys.argv) != 2:
    print('Syntax: %s file.png' % sys.argv[0])
    exit(1)

# Initialize matplotlib
fig, ax = plt.subplots()

# Get data
data = requests.get('http://logger.frontend.askplatyp.us/', params={'limit': 10000}).json()

# Convert to datetime
data = [datetime.datetime(*time.strptime(x[1].split('.')[0], "%Y-%m-%d %H:%M:%S")[:6]) for x in data]

# Compute the difference
datemax = datetime.datetime.now()
data = [datemax - x for x in data]
delta = datetime.timedelta(hours=NB_HOURS)
datemin = datemax - delta
ax.set_xlim(datemin, datemax)

# Shrink and convert to minutes
data = [x.seconds//(60*GRANULOMETRY) for x in data if x <= delta]

# Compute the height of the bars
requests_per_minute = array.array('I', (0 for x in range(0, 60*NB_HOURS//GRANULOMETRY)))
for x in data:
    requests_per_minute[(60*NB_HOURS//GRANULOMETRY) - x - 1] += 1

# Units
hours    = mdates.HourLocator(interval=6) # Show ticks every 6 hour
hoursFmt = mdates.DateFormatter('%H:00')
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(hoursFmt)

# Final plot
x = list(map(lambda x:datemin + datetime.timedelta(minutes=x*GRANULOMETRY), range(0, 60*NB_HOURS//GRANULOMETRY)))
ax.plot(x, requests_per_minute, label=None)

# Titles
plt.title("Requests to the PPP in the last %d hours" % NB_HOURS)
plt.xlabel("Time (hours)")
plt.ylabel("Requests (per slice of %d minutes)" % GRANULOMETRY)
#plt.legend()
plt.savefig(sys.argv[1])
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
    flask.ext.security.datastore
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    This module contains an user datastore classes.

    :copyright: (c) 2012 by Matt Wright.
    :license: MIT, see LICENSE for more details.
"""

from .utils import get_identity_attributes, string_types

class Datastore(object):
    def __init__(self, db):
        self.db = db

    def commit(self):
        pass

    def put(self, model):
        raise NotImplementedError

    def delete(self, model):
        raise NotImplementedError

class SQLAlchemyDatastore(Datastore):
    def commit(self):
        self.db.session.commit()

    def put(self, model):
        self.db.session.add(model)
        return model

    def delete(self, model):
        self.db.session.delete(model)

class MongoEngineDatastore(Datastore):
    def put(self, model):
        model.save()
        return model

    def delete(self, model):
        model.delete()

class PeeweeDatastore(Datastore):
    def put(self, model):
        model.save()
        return model

    def delete(self, model):
        model.delete_instance()

class UserDatastore(object):
    """Abstracted user datastore.

    :param user_model: A user model class definition
    :param role_model: A role model class definition
    """

    def __init__(self, user_model, role_model):
        self.user_model = user_model
        self.role_model = role_model

    def _prepare_role_modify_args(self, user, role):
        if isinstance(user, string_types):
            user = self.find_user(email=user)
        if isinstance(role, string_types):
            role = self.find_role(role)
        return user, role

    def _prepare_create_user_args(self, **kwargs):
        kwargs.setdefault('active', True)
        roles = kwargs.get('roles', [])
        for i, role in enumerate(roles):
            rn = role.name if isinstance(role, self.role_model) else role
            # see if the role exists
            roles[i] = self.find_role(rn)
        kwargs['roles'] = roles
        return kwargs

    def get_user(self, id_or_email):
        """Returns a user matching the specified ID or email address"""
        raise NotImplementedError

    def find_user(self, *args, **kwargs):
        """Returns a user matching the provided parameters."""
        raise NotImplementedError

    def find_role(self, *args, **kwargs):
        """Returns a role matching the provided name."""
        raise NotImplementedError

    def add_role_to_user(self, user, role):
        """Adds a role tp a user

        :param user: The user to manipulate
        :param role: The role to add to the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        if role not in user.roles:
            user.roles.append(role)
            self.put(user)
            return True
        return False

    def remove_role_from_user(self, user, role):
        """Removes a role from a user

        :param user: The user to manipulate
        :param role: The role to remove from the user
        """
        rv = False
        user, role = self._prepare_role_modify_args(user, role)
        if role in user.roles:
            rv = True
            user.roles.remove(role)
        return rv

    def toggle_active(self, user):
        """Toggles a user's active status. Always returns True."""
        user.active = not user.active
        return True

    def deactivate_user(self, user):
        """Deactivates a specified user. Returns `True` if a change was made.

        :param user: The user to deactivate
        """
        if user.active:
            user.active = False
            return True
        return False

    def activate_user(self, user):
        """Activates a specified user. Returns `True` if a change was made.

        :param user: The user to activate
        """
        if not user.active:
            user.active = True
            return True
        return False

    def create_role(self, **kwargs):
        """Creates and returns a new role from the given parameters."""

        role = self.role_model(**kwargs)
        return self.put(role)

    def find_or_create_role(self, name, **kwargs):
        """Returns a role matching the given name or creates it with any
        additionally provided parameters
        """
        kwargs["name"] = name
        return self.find_role(name) or self.create_role(**kwargs)

    def create_user(self, **kwargs):
        """Creates and returns a new user from the given parameters."""
        kwargs = self._prepare_create_user_args(**kwargs)
        user = self.user_model(**kwargs)
        return self.put(user)

    def delete_user(self, user):
        """Delete the specified user

        :param user: The user to delete
        """
        self.delete(user)

class SQLAlchemyUserDatastore(SQLAlchemyDatastore, UserDatastore):
    """A SQLAlchemy datastore implementation for Flask-Security that assumes the
    use of the Flask-SQLAlchemy extension.
    """
    def __init__(self, db, user_model, role_model):
        SQLAlchemyDatastore.__init__(self, db)
        UserDatastore.__init__(self, user_model, role_model)

    def get_user(self, identifier):
        if self._is_numeric(identifier):
            return self.user_model.query.get(identifier)
        for attr in get_identity_attributes():
            query = getattr(self.user_model, attr).ilike(identifier)
            rv = self.user_model.query.filter(query).first()
            if rv is not None:
                return rv

    def _is_numeric(self, value):
        try:
            int(value)
        except ValueError:
            return False
        return True

    def find_user(self, **kwargs):
        return self.user_model.query.filter_by(**kwargs).first()

    def find_role(self, role):
        return self.role_model.query.filter_by(name=role).first()

class MongoEngineUserDatastore(MongoEngineDatastore, UserDatastore):
    """A MongoEngine datastore implementation for Flask-Security that assumes
    the use of the Flask-MongoEngine extension.
    """
    def __init__(self, db, user_model, role_model):
        MongoEngineDatastore.__init__(self, db)
        UserDatastore.__init__(self, user_model, role_model)

    def get_user(self, identifier):
        from mongoengine import ValidationError
        try:
            return self.user_model.objects(id=identifier).first()
        except ValidationError:
            pass
        for attr in get_identity_attributes():
            query_key = '%s__iexact' % attr
            query = {query_key: identifier}
            rv = self.user_model.objects(**query).first()
            if rv is not None:
                return rv

    def find_user(self, **kwargs):
        try:
            from mongoengine.queryset import Q, QCombination
        except ImportError:
            from mongoengine.queryset.visitor import Q, QCombination
        from mongoengine.errors import ValidationError

        queries = map(lambda i: Q(**{i[0]: i[1]}), kwargs.items())
        query = QCombination(QCombination.AND, queries)
        try:
            return self.user_model.objects(query).first()
        except ValidationError:  # pragma: no cover
            return None

    def find_role(self, role):
        return self.role_model.objects(name=role).first()

    # TODO: Not sure why this was added but tests pass without it
    # def add_role_to_user(self, user, role):
    #     rv = super(MongoEngineUserDatastore, self).add_role_to_user(user, role)
    #     if rv:
    #         self.put(user)
    #     return rv

class PeeweeUserDatastore(PeeweeDatastore, UserDatastore):
    """A PeeweeD datastore implementation for Flask-Security that assumes
    the use of the Flask-Peewee extension.

    :param user_model: A user model class definition
    :param role_model: A role model class definition
    :param role_link: A model implementing the many-to-many user-role relation
    """
    def __init__(self, db, user_model, role_model, role_link):
        PeeweeDatastore.__init__(self, db)
        UserDatastore.__init__(self, user_model, role_model)
        self.UserRole = role_link

    def get_user(self, identifier):
        try:
            return self.user_model.get(self.user_model.id == identifier)
        except ValueError:
            pass

        for attr in get_identity_attributes():
            column = getattr(self.user_model, attr)
            try:
                return self.user_model.get(column ** identifier)
            except self.user_model.DoesNotExist:
                pass

    def find_user(self, **kwargs):
        try:
            return self.user_model.filter(**kwargs).get()
        except self.user_model.DoesNotExist:
            return None

    def find_role(self, role):
        try:
            return self.role_model.filter(name=role).get()
        except self.role_model.DoesNotExist:
            return None

    def create_user(self, **kwargs):
        """Creates and returns a new user from the given parameters."""
        roles = kwargs.pop('roles', [])
        user = self.user_model(**self._prepare_create_user_args(**kwargs))
        user = self.put(user)
        for role in roles:
            self.add_role_to_user(user, role)
        self.put(user)
        return user

    def add_role_to_user(self, user, role):
        """Adds a role tp a user

        :param user: The user to manipulate
        :param role: The role to add to the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        result = self.UserRole.select() \
            .where(self.UserRole.user == user.id, self.UserRole.role == role.id)
        if result.count():
            return False
        else:
            self.put(self.UserRole.create(user=user.id, role=role.id))
            return True

    def remove_role_from_user(self, user, role):
        """Removes a role from a user

        :param user: The user to manipulate
        :param role: The role to remove from the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        result = self.UserRole.select() \
            .where(self.UserRole.user == user, self.UserRole.role == role)
        if result.count():
            query = self.UserRole.delete().where(
                self.UserRole.user == user, self.UserRole.role == role)
            query.execute()
            return True
        else:
            return False
<commit_msg>Docs: Fixed typo and made punctuation more consistent.<commit_after># -*- coding: utf-8 -*-
"""
    flask.ext.security.datastore
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    This module contains an user datastore classes.

    :copyright: (c) 2012 by Matt Wright.
    :license: MIT, see LICENSE for more details.
"""

from .utils import get_identity_attributes, string_types

class Datastore(object):
    def __init__(self, db):
        self.db = db

    def commit(self):
        pass

    def put(self, model):
        raise NotImplementedError

    def delete(self, model):
        raise NotImplementedError

class SQLAlchemyDatastore(Datastore):
    def commit(self):
        self.db.session.commit()

    def put(self, model):
        self.db.session.add(model)
        return model

    def delete(self, model):
        self.db.session.delete(model)

class MongoEngineDatastore(Datastore):
    def put(self, model):
        model.save()
        return model

    def delete(self, model):
        model.delete()

class PeeweeDatastore(Datastore):
    def put(self, model):
        model.save()
        return model

    def delete(self, model):
        model.delete_instance()

class UserDatastore(object):
    """Abstracted user datastore.

    :param user_model: A user model class definition
    :param role_model: A role model class definition
    """

    def __init__(self, user_model, role_model):
        self.user_model = user_model
        self.role_model = role_model

    def _prepare_role_modify_args(self, user, role):
        if isinstance(user, string_types):
            user = self.find_user(email=user)
        if isinstance(role, string_types):
            role = self.find_role(role)
        return user, role

    def _prepare_create_user_args(self, **kwargs):
        kwargs.setdefault('active', True)
        roles = kwargs.get('roles', [])
        for i, role in enumerate(roles):
            rn = role.name if isinstance(role, self.role_model) else role
            # see if the role exists
            roles[i] = self.find_role(rn)
        kwargs['roles'] = roles
        return kwargs

    def get_user(self, id_or_email):
        """Returns a user matching the specified ID or email address."""
        raise NotImplementedError

    def find_user(self, *args, **kwargs):
        """Returns a user matching the provided parameters."""
        raise NotImplementedError

    def find_role(self, *args, **kwargs):
        """Returns a role matching the provided name."""
        raise NotImplementedError

    def add_role_to_user(self, user, role):
        """Adds a role to a user.

        :param user: The user to manipulate
        :param role: The role to add to the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        if role not in user.roles:
            user.roles.append(role)
            self.put(user)
            return True
        return False

    def remove_role_from_user(self, user, role):
        """Removes a role from a user.

        :param user: The user to manipulate
        :param role: The role to remove from the user
        """
        rv = False
        user, role = self._prepare_role_modify_args(user, role)
        if role in user.roles:
            rv = True
            user.roles.remove(role)
        return rv

    def toggle_active(self, user):
        """Toggles a user's active status. Always returns True."""
        user.active = not user.active
        return True

    def deactivate_user(self, user):
        """Deactivates a specified user. Returns `True` if a change was made.

        :param user: The user to deactivate
        """
        if user.active:
            user.active = False
            return True
        return False

    def activate_user(self, user):
        """Activates a specified user. Returns `True` if a change was made.

        :param user: The user to activate
        """
        if not user.active:
            user.active = True
            return True
        return False

    def create_role(self, **kwargs):
        """Creates and returns a new role from the given parameters."""

        role = self.role_model(**kwargs)
        return self.put(role)

    def find_or_create_role(self, name, **kwargs):
        """Returns a role matching the given name or creates it with any
        additionally provided parameters.
        """
        kwargs["name"] = name
        return self.find_role(name) or self.create_role(**kwargs)

    def create_user(self, **kwargs):
        """Creates and returns a new user from the given parameters."""
        kwargs = self._prepare_create_user_args(**kwargs)
        user = self.user_model(**kwargs)
        return self.put(user)

    def delete_user(self, user):
        """Deletes the specified user.

        :param user: The user to delete
        """
        self.delete(user)

class SQLAlchemyUserDatastore(SQLAlchemyDatastore, UserDatastore):
    """A SQLAlchemy datastore implementation for Flask-Security that assumes the
    use of the Flask-SQLAlchemy extension.
    """
    def __init__(self, db, user_model, role_model):
        SQLAlchemyDatastore.__init__(self, db)
        UserDatastore.__init__(self, user_model, role_model)

    def get_user(self, identifier):
        if self._is_numeric(identifier):
            return self.user_model.query.get(identifier)
        for attr in get_identity_attributes():
            query = getattr(self.user_model, attr).ilike(identifier)
            rv = self.user_model.query.filter(query).first()
            if rv is not None:
                return rv

    def _is_numeric(self, value):
        try:
            int(value)
        except ValueError:
            return False
        return True

    def find_user(self, **kwargs):
        return self.user_model.query.filter_by(**kwargs).first()

    def find_role(self, role):
        return self.role_model.query.filter_by(name=role).first()

class MongoEngineUserDatastore(MongoEngineDatastore, UserDatastore):
    """A MongoEngine datastore implementation for Flask-Security that assumes
    the use of the Flask-MongoEngine extension.
    """
    def __init__(self, db, user_model, role_model):
        MongoEngineDatastore.__init__(self, db)
        UserDatastore.__init__(self, user_model, role_model)

    def get_user(self, identifier):
        from mongoengine import ValidationError
        try:
            return self.user_model.objects(id=identifier).first()
        except ValidationError:
            pass
        for attr in get_identity_attributes():
            query_key = '%s__iexact' % attr
            query = {query_key: identifier}
            rv = self.user_model.objects(**query).first()
            if rv is not None:
                return rv

    def find_user(self, **kwargs):
        try:
            from mongoengine.queryset import Q, QCombination
        except ImportError:
            from mongoengine.queryset.visitor import Q, QCombination
        from mongoengine.errors import ValidationError

        queries = map(lambda i: Q(**{i[0]: i[1]}), kwargs.items())
        query = QCombination(QCombination.AND, queries)
        try:
            return self.user_model.objects(query).first()
        except ValidationError:  # pragma: no cover
            return None

    def find_role(self, role):
        return self.role_model.objects(name=role).first()

    # TODO: Not sure why this was added but tests pass without it
    # def add_role_to_user(self, user, role):
    #     rv = super(MongoEngineUserDatastore, self).add_role_to_user(user, role)
    #     if rv:
    #         self.put(user)
    #     return rv

class PeeweeUserDatastore(PeeweeDatastore, UserDatastore):
    """A PeeweeD datastore implementation for Flask-Security that assumes
    the use of the Flask-Peewee extension.

    :param user_model: A user model class definition
    :param role_model: A role model class definition
    :param role_link: A model implementing the many-to-many user-role relation
    """
    def __init__(self, db, user_model, role_model, role_link):
        PeeweeDatastore.__init__(self, db)
        UserDatastore.__init__(self, user_model, role_model)
        self.UserRole = role_link

    def get_user(self, identifier):
        try:
            return self.user_model.get(self.user_model.id == identifier)
        except ValueError:
            pass

        for attr in get_identity_attributes():
            column = getattr(self.user_model, attr)
            try:
                return self.user_model.get(column ** identifier)
            except self.user_model.DoesNotExist:
                pass

    def find_user(self, **kwargs):
        try:
            return self.user_model.filter(**kwargs).get()
        except self.user_model.DoesNotExist:
            return None

    def find_role(self, role):
        try:
            return self.role_model.filter(name=role).get()
        except self.role_model.DoesNotExist:
            return None

    def create_user(self, **kwargs):
        """Creates and returns a new user from the given parameters."""
        roles = kwargs.pop('roles', [])
        user = self.user_model(**self._prepare_create_user_args(**kwargs))
        user = self.put(user)
        for role in roles:
            self.add_role_to_user(user, role)
        self.put(user)
        return user

    def add_role_to_user(self, user, role):
        """Adds a role to a user.

        :param user: The user to manipulate
        :param role: The role to add to the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        result = self.UserRole.select() \
            .where(self.UserRole.user == user.id, self.UserRole.role == role.id)
        if result.count():
            return False
        else:
            self.put(self.UserRole.create(user=user.id, role=role.id))
            return True

    def remove_role_from_user(self, user, role):
        """Removes a role from a user.

        :param user: The user to manipulate
        :param role: The role to remove from the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        result = self.UserRole.select() \
            .where(self.UserRole.user == user, self.UserRole.role == role)
        if result.count():
            query = self.UserRole.delete().where(
                self.UserRole.user == user, self.UserRole.role == role)
            query.execute()
            return True
        else:
            return False
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
import config
import pystorage
import subprocess
import os

class GetID:
    def __init__(self, dscli_bin, dscli_profile_path, lss_id):
        """

        :param dscli_bin:
        :param dscli_profile_path:
        :param lss_id:
        :return:
        """

        self.dscli_bin = dscli_bin
        self.dscli_profile_path = dscli_profile_path
        self.lss_id = lss_id

        # test lss_id
        if len(self.lss_id) != 2:
            raise ValueError('lss_id need to have 2 valid characters in hex.\n'
                             'Tip: Between 00 and FF.')

        try:
            int(self.lss_id, 16)
        except:
            raise ValueError(
                'lss_id need to be a string with valid hex value.\n'
                'Tip: Between 00 and FF.')

    def _check_lss(self, lss_list_used, lss_list_reserved):

        code_cmd = 'sh {0}/tools/hexcount.sh {1}00 {1}FF'.format(
            config.stghome, self.lss_id)
        hexa = subprocess.Popen(code_cmd.split(),
                                stderr=subprocess.PIPE,
                                stdout=subprocess.PIPE)
        hexa_out, hexa_err = hexa.communicate()

        if hexa.returncode != 0:
            raise EnvironmentError('ERROR: {0}'.format(hexa_err))

        else:
            lss_list_full = []
            for l_hexa in hexa_out.split('\n'):
                if l_hexa != '':
                    lss_list_full.append(l_hexa)

        for l_reserved in lss_list_reserved:
            lss_list_used.append(l_reserved.split('\n')[0])

        lss_list_free = list(set(lss_list_full) - set(lss_list_used))

        return sorted(lss_list_free)

    def free_lss(self):

        lss_list_used = []
        lss_list_reserved = []
        ds8k = pystorage.DS8K(self.dscli_bin, self.dscli_profile_path)
        lss_list = ds8k.lsfbvol('-lss {0}'.format(self.lss_id))
        if lss_list[0] != 0:
            print ("ERROR: {0}".format(lss_list[1]))

        for l_lss in lss_list[1].split('\n')[3:]:
            try:
                lss_list_used.append(l_lss.split()[1])
            except IndexError:
                pass

        if os.path.isfile(
                '{0}/stgadm/data/reserved_ids.db'.format(config.stghome)):
            lss_reserved_file = open('{0}/stgadm/data/reserved_ids.db'.format(
                config.stghome
            ), 'r')

            for l_lss in lss_reserved_file.readlines():
                if l_lss.startswith('{0}'.format(self.lss_id)[0:2]):
                    lss_list_reserved.append(l_lss)

        return self._check_lss(lss_list_used, lss_list_reserved)
<commit_msg>improve the docstring<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
import config
import pystorage
import subprocess
import os

class GetID:
    def __init__(self, dscli_bin, dscli_profile_path, lss_id):
        """
        Manage the IDs for IBM DS8K

        :param dscli_bin: path of dscli_bin
        :param dscli_profile_path: profile file os dscli
        :param lss_id: LSS ID tat you want to ge the free ids (ex: A6)
        :return:
        """

        self.dscli_bin = dscli_bin
        self.dscli_profile_path = dscli_profile_path
        self.lss_id = lss_id

        # test lss_id
        if len(self.lss_id) != 2:
            raise ValueError('lss_id need to have 2 valid characters in hex.\n'
                             'Tip: Between 00 and FF.')

        try:
            int(self.lss_id, 16)
        except:
            raise ValueError(
                'lss_id need to be a string with valid hex value.\n'
                'Tip: Between 00 and FF.')

    def _check_lss(self, lss_list_used, lss_list_reserved):

        code_cmd = 'sh {0}/tools/hexcount.sh {1}00 {1}FF'.format(
            config.stghome, self.lss_id)
        hexa = subprocess.Popen(code_cmd.split(),
                                stderr=subprocess.PIPE,
                                stdout=subprocess.PIPE)
        hexa_out, hexa_err = hexa.communicate()

        if hexa.returncode != 0:
            raise EnvironmentError('ERROR: {0}'.format(hexa_err))

        else:
            lss_list_full = []
            for l_hexa in hexa_out.split('\n'):
                if l_hexa != '':
                    lss_list_full.append(l_hexa)

        for l_reserved in lss_list_reserved:
            lss_list_used.append(l_reserved.split('\n')[0])

        lss_list_free = list(set(lss_list_full) - set(lss_list_used))

        return sorted(lss_list_free)

    def free_lss(self):

        lss_list_used = []
        lss_list_reserved = []
        ds8k = pystorage.DS8K(self.dscli_bin, self.dscli_profile_path)
        lss_list = ds8k.lsfbvol('-lss {0}'.format(self.lss_id))
        if lss_list[0] != 0:
            print ("ERROR: {0}".format(lss_list[1]))

        for l_lss in lss_list[1].split('\n')[3:]:
            try:
                lss_list_used.append(l_lss.split()[1])
            except IndexError:
                pass

        if os.path.isfile(
                '{0}/stgadm/data/reserved_ids.db'.format(config.stghome)):
            lss_reserved_file = open('{0}/stgadm/data/reserved_ids.db'.format(
                config.stghome
            ), 'r')

            for l_lss in lss_reserved_file.readlines():
                if l_lss.startswith('{0}'.format(self.lss_id)[0:2]):
                    lss_list_reserved.append(l_lss)

        return self._check_lss(lss_list_used, lss_list_reserved)
<|endoftext|>


<commit_before>import os

from django import forms
from django import http
from django.conf import settings
from django.contrib.formtools import preview, wizard, utils
from django.test import TestCase
from django.utils import unittest

success_string = "Done was called!"

class TestFormPreview(preview.FormPreview):
    def get_context(self, request, form):
        context = super(TestFormPreview, self).get_context(request, form)
        context.update({'custom_context': True})
        return context

    def get_initial(self, request):
        return {'field1': 'Works!'}

    def done(self, request, cleaned_data):
        return http.HttpResponse(success_string)

class TestForm(forms.Form):
    field1 = forms.CharField()
    field1_ = forms.CharField()
    bool1 = forms.BooleanField(required=False)

class UserSecuredFormPreview(TestFormPreview):
    """
    FormPreview with a custum security_hash method
    """
    def security_hash(self, request, form):
        return "123"

class PreviewTests(TestCase):
    urls = 'django.contrib.formtools.tests.urls'

    def setUp(self):
        # Create a FormPreview instance to share between tests
        self.preview = preview.FormPreview(TestForm)
        input_template = '<input type="hidden" name="%s" value="%s" />'
        self.input = input_template % (self.preview.unused_name('stage'), "%d")
        self.test_data = {'field1':u'foo', 'field1_':u'asdf'}

    def test_unused_name(self):
        """
        Verifies name mangling to get uniue field name.
        """
        self.assertEqual(self.preview.unused_name('field1'), 'field1__')

    def test_form_get(self):
        """
        Test contrib.formtools.preview form retrieval.

        Use the client library to see if we can sucessfully retrieve
        the form (mostly testing the setup ROOT_URLCONF
        process). Verify that an additional  hidden input field
        is created to manage the stage.

        """
        response = self.client.get('/test1/')
        stage = self.input % 1
        self.assertContains(response, stage, 1)
        self.assertEquals(response.context['custom_context'], True)
        self.assertEquals(response.context['form'].initial, {'field1': 'Works!'})

    def test_form_preview(self):
        """
        Test contrib.formtools.preview form preview rendering.

        Use the client library to POST to the form to see if a preview
        is returned.  If we do get a form back check that the hidden
        value is correctly managing the state of the form.

        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage': 1})
        response = self.client.post('/test1/', self.test_data)
        # Check to confirm stage is set to 2 in output form.
        stage = self.input % 2
        self.assertContains(response, stage, 1)

    def test_form_submit(self):
        """
        Test contrib.formtools.preview form submittal.

        Use the client library to POST to the form with stage set to 3
        to see if our forms done() method is called. Check first
        without the security hash, verify failure, retry with security
        hash and verify sucess.

        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage':2})
        response = self.client.post('/test1/', self.test_data)
        self.failIfEqual(response.content, success_string)
        hash = self.preview.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash': hash})
        response = self.client.post('/test1/', self.test_data)
        self.assertEqual(response.content, success_string)

    def test_bool_submit(self):
        """
        Test contrib.formtools.preview form submittal when form contains:
        BooleanField(required=False)

        Ticket: #6209 - When an unchecked BooleanField is previewed, the preview
        form's hash would be computed with no value for ``bool1``. However, when
        the preview form is rendered, the unchecked hidden BooleanField would be
        rendered with the string value 'False'. So when the preview form is
        resubmitted, the hash would be computed with the value 'False' for
        ``bool1``. We need to make sure the hashes are the same in both cases.

        """
        self.test_data.update({'stage':2})
        hash = self.preview.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash':hash, 'bool1':u'False'})
        response = self.client.post('/test1/', self.test_data)
        self.assertEqual(response.content, success_string)

    def test_form_submit_django12_hash(self):
        """
        Test contrib.formtools.preview form submittal, using the hash function
        used in Django 1.2
        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage':2})
        response = self.client.post('/test1/', self.test_data)
        self.failIfEqual(response.content, success_string)
        hash = utils.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash': hash})
        response = self.client.post('/test1/', self.test_data)
        self.assertEqual(response.content, success_string)

    def test_form_submit_django12_hash_custom_hash(self):
        """
        Test contrib.formtools.preview form submittal, using the hash function
        used in Django 1.2 and a custom security_hash method.
        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage':2})
        response = self.client.post('/test2/', self.test_data)
        self.assertEqual(response.status_code, 200)
        self.failIfEqual(response.content, success_string)
        hash = utils.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash': hash})
        response = self.client.post('/test2/', self.test_data)
        self.failIfEqual(response.content, success_string)

class SecurityHashTests(unittest.TestCase):

    def test_textfield_hash(self):
        """
        Regression test for #10034: the hash generation function should ignore
        leading/trailing whitespace so as to be friendly to broken browsers that
        submit it (usually in textareas).
        """
        f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'})
        f2 = HashTestForm({'name': '  joe', 'bio': 'Nothing notable.  '})
        hash1 = utils.security_hash(None, f1)
        hash2 = utils.security_hash(None, f2)
        self.assertEqual(hash1, hash2)

    def test_empty_permitted(self):
        """
        Regression test for #10643: the security hash should allow forms with
        empty_permitted = True, or forms where data has not changed.
        """
        f1 = HashTestBlankForm({})
        f2 = HashTestForm({}, empty_permitted=True)
        hash1 = utils.security_hash(None, f1)
        hash2 = utils.security_hash(None, f2)
        self.assertEqual(hash1, hash2)

class FormHmacTests(unittest.TestCase):
    """
    Same as SecurityHashTests, but with form_hmac
    """

    def test_textfield_hash(self):
        """
        Regression test for #10034: the hash generation function should ignore
        leading/trailing whitespace so as to be friendly to broken browsers that
        submit it (usually in textareas).
        """
        f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'})
        f2 = HashTestForm({'name': '  joe', 'bio': 'Nothing notable.  '})
        hash1 = utils.form_hmac(f1)
        hash2 = utils.form_hmac(f2)
        self.assertEqual(hash1, hash2)

    def test_empty_permitted(self):
        """
        Regression test for #10643: the security hash should allow forms with
        empty_permitted = True, or forms where data has not changed.
        """
        f1 = HashTestBlankForm({})
        f2 = HashTestForm({}, empty_permitted=True)
        hash1 = utils.form_hmac(f1)
        hash2 = utils.form_hmac(f2)
        self.assertEqual(hash1, hash2)

class HashTestForm(forms.Form):
    name = forms.CharField()
    bio = forms.CharField()

class HashTestBlankForm(forms.Form):
    name = forms.CharField(required=False)
    bio = forms.CharField(required=False)

#
# FormWizard tests
#

class WizardPageOneForm(forms.Form):
    field = forms.CharField()

class WizardPageTwoForm(forms.Form):
    field = forms.CharField()

class WizardPageThreeForm(forms.Form):
    field = forms.CharField()

class WizardClass(wizard.FormWizard):

    def get_template(self, step):
        return 'formwizard/wizard.html'

    def done(self, request, cleaned_data):
        return http.HttpResponse(success_string)

class UserSecuredWizardClass(WizardClass):
    """
    Wizard with a custum security_hash method
    """
    def security_hash(self, request, form):
        return "123"

class DummyRequest(http.HttpRequest):

    def __init__(self, POST=None):
        super(DummyRequest, self).__init__()
        self.method = POST and "POST" or "GET"
        if POST is not None:
            self.POST.update(POST)
        self._dont_enforce_csrf_checks = True

class WizardTests(TestCase):
    urls = 'django.contrib.formtools.tests.urls'

    def setUp(self):
        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
        settings.TEMPLATE_DIRS = (
            os.path.join(
                os.path.dirname(__file__),
                'templates'
            ),
        )
        # Use a known SECRET_KEY to make security_hash tests deterministic
        self.old_SECRET_KEY = settings.SECRET_KEY
        settings.SECRET_KEY = "123"

    def tearDown(self):
        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
        settings.SECRET_KEY = self.old_SECRET_KEY

    def test_step_starts_at_zero(self):
        """
        step should be zero for the first form
        """
        response = self.client.get('/wizard/')
        self.assertEquals(0, response.context['step0'])

    def test_step_increments(self):
        """
        step should be incremented when we go to the next page
        """
        response = self.client.post('/wizard/', {"0-field":"test", "wizard_step":"0"})
        self.assertEquals(1, response.context['step0'])

    def test_bad_hash(self):
        """
        Form should not advance if the hash is missing or bad
        """
        response = self.client.post('/wizard/',
                                    {"0-field":"test",
                                     "1-field":"test2",
                                     "wizard_step": "1"})
        self.assertEquals(0, response.context['step0'])

    def test_good_hash_django12(self):
        """
        Form should advance if the hash is present and good, as calculated using
        django 1.2 method.
        """
        # We are hard-coding a hash value here, but that is OK, since we want to
        # ensure that we don't accidentally change the algorithm.
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        response = self.client.post('/wizard/', data)
        self.assertEquals(2, response.context['step0'])

    def test_good_hash_django12_subclass(self):
        """
        The Django 1.2 method of calulating hashes should *not* be used as a
        fallback if the FormWizard subclass has provided their own method
        of calculating a hash.
        """
        # We are hard-coding a hash value here, but that is OK, since we want to
        # ensure that we don't accidentally change the algorithm.
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        response = self.client.post('/wizard2/', data)
        self.assertEquals(0, response.context['step0'])

    def test_good_hash_current(self):
        """
        Form should advance if the hash is present and good, as calculated using
        current method.
        """
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
                "wizard_step": "1"}
        response = self.client.post('/wizard/', data)
        self.assertEquals(2, response.context['step0'])

    def test_14498(self):
        """
        Regression test for ticket #14498.
        """
        that = self

        class WizardWithProcessStep(WizardClass):
            def process_step(self, request, form, step):
                that.assertTrue(hasattr(form, 'cleaned_data'))

        wizard = WizardWithProcessStep([WizardPageOneForm,
                                        WizardPageTwoForm,
                                        WizardPageThreeForm])
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
                "wizard_step": "1"}
        wizard(DummyRequest(POST=data))

    def test_14576(self):
        """
        Regression test for ticket #14576.

        The form of the last step is not passed to the done method.
        """
        reached = [False]
        that = self

        class Wizard(WizardClass):
            def done(self, request, form_list):
                reached[0] = True
                that.assertTrue(len(form_list) == 2)

        wizard = Wizard([WizardPageOneForm,
                         WizardPageTwoForm])

        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        wizard(DummyRequest(POST=data))
        self.assertTrue(reached[0])

<commit_msg>Removed all usages of deprecated TestCase methods (self.fail*).  This removed most of the Warnings emitted (with -Wall) during the test suite.<commit_after>import os

from django import forms, http
from django.conf import settings
from django.contrib.formtools import preview, wizard, utils
from django.test import TestCase
from django.utils import unittest

success_string = "Done was called!"

class TestFormPreview(preview.FormPreview):
    def get_context(self, request, form):
        context = super(TestFormPreview, self).get_context(request, form)
        context.update({'custom_context': True})
        return context

    def get_initial(self, request):
        return {'field1': 'Works!'}

    def done(self, request, cleaned_data):
        return http.HttpResponse(success_string)

class TestForm(forms.Form):
    field1 = forms.CharField()
    field1_ = forms.CharField()
    bool1 = forms.BooleanField(required=False)

class UserSecuredFormPreview(TestFormPreview):
    """
    FormPreview with a custum security_hash method
    """
    def security_hash(self, request, form):
        return "123"

class PreviewTests(TestCase):
    urls = 'django.contrib.formtools.tests.urls'

    def setUp(self):
        # Create a FormPreview instance to share between tests
        self.preview = preview.FormPreview(TestForm)
        input_template = '<input type="hidden" name="%s" value="%s" />'
        self.input = input_template % (self.preview.unused_name('stage'), "%d")
        self.test_data = {'field1':u'foo', 'field1_':u'asdf'}

    def test_unused_name(self):
        """
        Verifies name mangling to get uniue field name.
        """
        self.assertEqual(self.preview.unused_name('field1'), 'field1__')

    def test_form_get(self):
        """
        Test contrib.formtools.preview form retrieval.

        Use the client library to see if we can sucessfully retrieve
        the form (mostly testing the setup ROOT_URLCONF
        process). Verify that an additional  hidden input field
        is created to manage the stage.

        """
        response = self.client.get('/test1/')
        stage = self.input % 1
        self.assertContains(response, stage, 1)
        self.assertEquals(response.context['custom_context'], True)
        self.assertEquals(response.context['form'].initial, {'field1': 'Works!'})

    def test_form_preview(self):
        """
        Test contrib.formtools.preview form preview rendering.

        Use the client library to POST to the form to see if a preview
        is returned.  If we do get a form back check that the hidden
        value is correctly managing the state of the form.

        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage': 1})
        response = self.client.post('/test1/', self.test_data)
        # Check to confirm stage is set to 2 in output form.
        stage = self.input % 2
        self.assertContains(response, stage, 1)

    def test_form_submit(self):
        """
        Test contrib.formtools.preview form submittal.

        Use the client library to POST to the form with stage set to 3
        to see if our forms done() method is called. Check first
        without the security hash, verify failure, retry with security
        hash and verify sucess.

        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage':2})
        response = self.client.post('/test1/', self.test_data)
        self.assertNotEqual(response.content, success_string)
        hash = self.preview.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash': hash})
        response = self.client.post('/test1/', self.test_data)
        self.assertEqual(response.content, success_string)

    def test_bool_submit(self):
        """
        Test contrib.formtools.preview form submittal when form contains:
        BooleanField(required=False)

        Ticket: #6209 - When an unchecked BooleanField is previewed, the preview
        form's hash would be computed with no value for ``bool1``. However, when
        the preview form is rendered, the unchecked hidden BooleanField would be
        rendered with the string value 'False'. So when the preview form is
        resubmitted, the hash would be computed with the value 'False' for
        ``bool1``. We need to make sure the hashes are the same in both cases.

        """
        self.test_data.update({'stage':2})
        hash = self.preview.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash':hash, 'bool1':u'False'})
        response = self.client.post('/test1/', self.test_data)
        self.assertEqual(response.content, success_string)

    def test_form_submit_django12_hash(self):
        """
        Test contrib.formtools.preview form submittal, using the hash function
        used in Django 1.2
        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage':2})
        response = self.client.post('/test1/', self.test_data)
        self.assertNotEqual(response.content, success_string)
        hash = utils.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash': hash})
        response = self.client.post('/test1/', self.test_data)
        self.assertEqual(response.content, success_string)

    def test_form_submit_django12_hash_custom_hash(self):
        """
        Test contrib.formtools.preview form submittal, using the hash function
        used in Django 1.2 and a custom security_hash method.
        """
        # Pass strings for form submittal and add stage variable to
        # show we previously saw first stage of the form.
        self.test_data.update({'stage':2})
        response = self.client.post('/test2/', self.test_data)
        self.assertEqual(response.status_code, 200)
        self.assertNotEqual(response.content, success_string)
        hash = utils.security_hash(None, TestForm(self.test_data))
        self.test_data.update({'hash': hash})
        response = self.client.post('/test2/', self.test_data)
        self.assertNotEqual(response.content, success_string)

class SecurityHashTests(unittest.TestCase):

    def test_textfield_hash(self):
        """
        Regression test for #10034: the hash generation function should ignore
        leading/trailing whitespace so as to be friendly to broken browsers that
        submit it (usually in textareas).
        """
        f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'})
        f2 = HashTestForm({'name': '  joe', 'bio': 'Nothing notable.  '})
        hash1 = utils.security_hash(None, f1)
        hash2 = utils.security_hash(None, f2)
        self.assertEqual(hash1, hash2)

    def test_empty_permitted(self):
        """
        Regression test for #10643: the security hash should allow forms with
        empty_permitted = True, or forms where data has not changed.
        """
        f1 = HashTestBlankForm({})
        f2 = HashTestForm({}, empty_permitted=True)
        hash1 = utils.security_hash(None, f1)
        hash2 = utils.security_hash(None, f2)
        self.assertEqual(hash1, hash2)

class FormHmacTests(unittest.TestCase):
    """
    Same as SecurityHashTests, but with form_hmac
    """

    def test_textfield_hash(self):
        """
        Regression test for #10034: the hash generation function should ignore
        leading/trailing whitespace so as to be friendly to broken browsers that
        submit it (usually in textareas).
        """
        f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'})
        f2 = HashTestForm({'name': '  joe', 'bio': 'Nothing notable.  '})
        hash1 = utils.form_hmac(f1)
        hash2 = utils.form_hmac(f2)
        self.assertEqual(hash1, hash2)

    def test_empty_permitted(self):
        """
        Regression test for #10643: the security hash should allow forms with
        empty_permitted = True, or forms where data has not changed.
        """
        f1 = HashTestBlankForm({})
        f2 = HashTestForm({}, empty_permitted=True)
        hash1 = utils.form_hmac(f1)
        hash2 = utils.form_hmac(f2)
        self.assertEqual(hash1, hash2)

class HashTestForm(forms.Form):
    name = forms.CharField()
    bio = forms.CharField()

class HashTestBlankForm(forms.Form):
    name = forms.CharField(required=False)
    bio = forms.CharField(required=False)

#
# FormWizard tests
#

class WizardPageOneForm(forms.Form):
    field = forms.CharField()

class WizardPageTwoForm(forms.Form):
    field = forms.CharField()

class WizardPageThreeForm(forms.Form):
    field = forms.CharField()

class WizardClass(wizard.FormWizard):

    def get_template(self, step):
        return 'formwizard/wizard.html'

    def done(self, request, cleaned_data):
        return http.HttpResponse(success_string)

class UserSecuredWizardClass(WizardClass):
    """
    Wizard with a custum security_hash method
    """
    def security_hash(self, request, form):
        return "123"

class DummyRequest(http.HttpRequest):

    def __init__(self, POST=None):
        super(DummyRequest, self).__init__()
        self.method = POST and "POST" or "GET"
        if POST is not None:
            self.POST.update(POST)
        self._dont_enforce_csrf_checks = True

class WizardTests(TestCase):
    urls = 'django.contrib.formtools.tests.urls'

    def setUp(self):
        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
        settings.TEMPLATE_DIRS = (
            os.path.join(
                os.path.dirname(__file__),
                'templates'
            ),
        )
        # Use a known SECRET_KEY to make security_hash tests deterministic
        self.old_SECRET_KEY = settings.SECRET_KEY
        settings.SECRET_KEY = "123"

    def tearDown(self):
        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
        settings.SECRET_KEY = self.old_SECRET_KEY

    def test_step_starts_at_zero(self):
        """
        step should be zero for the first form
        """
        response = self.client.get('/wizard/')
        self.assertEquals(0, response.context['step0'])

    def test_step_increments(self):
        """
        step should be incremented when we go to the next page
        """
        response = self.client.post('/wizard/', {"0-field":"test", "wizard_step":"0"})
        self.assertEquals(1, response.context['step0'])

    def test_bad_hash(self):
        """
        Form should not advance if the hash is missing or bad
        """
        response = self.client.post('/wizard/',
                                    {"0-field":"test",
                                     "1-field":"test2",
                                     "wizard_step": "1"})
        self.assertEquals(0, response.context['step0'])

    def test_good_hash_django12(self):
        """
        Form should advance if the hash is present and good, as calculated using
        django 1.2 method.
        """
        # We are hard-coding a hash value here, but that is OK, since we want to
        # ensure that we don't accidentally change the algorithm.
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        response = self.client.post('/wizard/', data)
        self.assertEquals(2, response.context['step0'])

    def test_good_hash_django12_subclass(self):
        """
        The Django 1.2 method of calulating hashes should *not* be used as a
        fallback if the FormWizard subclass has provided their own method
        of calculating a hash.
        """
        # We are hard-coding a hash value here, but that is OK, since we want to
        # ensure that we don't accidentally change the algorithm.
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        response = self.client.post('/wizard2/', data)
        self.assertEquals(0, response.context['step0'])

    def test_good_hash_current(self):
        """
        Form should advance if the hash is present and good, as calculated using
        current method.
        """
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
                "wizard_step": "1"}
        response = self.client.post('/wizard/', data)
        self.assertEquals(2, response.context['step0'])

    def test_14498(self):
        """
        Regression test for ticket #14498.
        """
        that = self

        class WizardWithProcessStep(WizardClass):
            def process_step(self, request, form, step):
                that.assertTrue(hasattr(form, 'cleaned_data'))

        wizard = WizardWithProcessStep([WizardPageOneForm,
                                        WizardPageTwoForm,
                                        WizardPageThreeForm])
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
                "wizard_step": "1"}
        wizard(DummyRequest(POST=data))

    def test_14576(self):
        """
        Regression test for ticket #14576.

        The form of the last step is not passed to the done method.
        """
        reached = [False]
        that = self

        class Wizard(WizardClass):
            def done(self, request, form_list):
                reached[0] = True
                that.assertTrue(len(form_list) == 2)

        wizard = Wizard([WizardPageOneForm,
                         WizardPageTwoForm])

        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        wizard(DummyRequest(POST=data))
        self.assertTrue(reached[0])
<|endoftext|>


<commit_before># Copyright (C) 2014 Linaro Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import requests

from datetime import date
from flask import current_app
from urlparse import urljoin

def today_date():
    """Return today date as: %a, %d %b %Y

    Date is based on the server, hopefully with the system clock set at UTC.

    :return The date string.
    """
    return date.today().strftime('%a, %d %b %Y')

def _create_url_headers(api_path):
    """Create the complete URL to the API backend.

    Used if we need to set special headers.

    :param api_path: The API path.
    :return A tuple with the full URL, and the headers set.
    """
    backend_token = current_app.config.get('BACKEND_TOKEN')
    backend_url = current_app.config.get('BACKEND_URL')

    backend_url = urljoin(backend_url, api_path)

    headers = {}
    if backend_token:
        headers = {'X-XSRF-Header': backend_token}

    return (backend_url, headers)

def _create_api_path(api_path, other_path=''):
    """Merge two URL tokens together.

    :param api_path: The path to the API endpoint.
    :param other_path: The path to append, defaults to empty string.
    """
    if api_path[-1] != '/':
        api_path += '/'

    if other_path and other_path[-1] == '/':
        other_path = other_path[:-1]

    return api_path + other_path

def get_job(**kwargs):
    """Get a job document from the backend.

    This function is only used for server side processing data.

    :return A `requests.Response` object.
    """
    api_path = current_app.config.get('JOB_API_ENDPOINT')

    if kwargs.get('id', None):
        api_path = _create_api_path(api_path, kwargs['id'])
        kwargs.pop('id')

    url, headers = _create_url_headers(api_path)

    return requests.get(url, params=kwargs, headers=headers)

def get_defconfig(**kwargs):
    """Get a defconfig document from the backend.

    This function is only used for server side processing data.

    :return A `requests.Response` object.
    """
    api_path = current_app.config.get('DEFCONFIG_API_ENDPOINT')

    if kwargs.get('id', None):
        api_path = _create_api_path(api_path, kwargs['id'])
        kwargs.pop('id')

    url, headers = _create_url_headers(api_path)

    return requests.get(url, params=kwargs, headers=headers)

def ajax_count_get(request, api_path, collection):
    """Handle AJAX call from the client to the `count` API.

    :param request: The request performed.
    :param api_path: The API endpoint where to perform the request.
    :param collection: The collection to count.

    :return A tuple with the data, status code and headers of the
        `requests.Response` object.
    """
    params_list = request.args.lists()

    api_path = _create_api_path(api_path)

    if collection:
        api_path = _create_api_path(api_path, collection)

    url, headers = _create_url_headers(api_path)
    r = requests.get(url, headers=headers, params=params_list, stream=True)

    return (r.raw.data, r.status_code, r.headers.items())

def ajax_get(request, api_path):
    """Handle general AJAX calls from the client.

    :param request: The request performed.
    :param api_path: The API endpoint where to perform the request.
    :return A tuple with the data, status code and headers of the
        `requests.Response` object.
    """
    params_list = request.args.lists()

    if 'id' in request.args:
        boot_id = request.args['id']
        api_path = _create_api_path(api_path, boot_id)

        params_list.remove(('id', [boot_id]))

    url, headers = _create_url_headers(api_path)
    r = requests.get(url, headers=headers, params=params_list, stream=True)

    return (r.raw.data, r.status_code, r.headers.items())
<commit_msg>backend: Add metadata extraction function.<commit_after># Copyright (C) 2014 Linaro Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import requests
import urlparse

from bson import json_util
from datetime import date
from flask import current_app as app
from urlparse import urljoin

def extract_response_metadata(response):
    """Extract data from a response object.

    It is used to extract metadata from a backend response, in order to
    translate URLs into real clickable URLs based on the KNOWN_GIT_URLS
    translation rules.

    :param response: A response object as returned by a requests.
    :return A tuple with the metadata from the response, the base_url, the
        commit_url and the response's result.
    """
    metadata = {}
    base_url = ''
    commit_url = ''
    result = {}

    document = json_util.loads(response.content)
    document['result'] = json_util.loads(document['result'])

    if document.get('result', None):
        result = document['result']
        metadata = result.get('metadata', None)

        if metadata:
            git_url = metadata.get('git_url', None)
            commit_id = metadata.get('git_commit', None)

            if git_url and commit_id:
                t_url = urlparse.urlparse(git_url)
                known_git_urls = app.config.get('KNOWN_GIT_URLS')

                if t_url.netloc in known_git_urls.keys():
                    known_git = known_git_urls.get(t_url.netloc)

                    path = t_url.path
                    for replace_rule in known_git[3]:
                        path = path.replace(*replace_rule)

                    base_url = urlparse.urlunparse((
                        known_git[0], t_url.netloc, known_git[1] % path,
                        '', '', ''
                    ))
                    commit_url = urlparse.urlunparse((
                        known_git[0], t_url.netloc,
                        (known_git[2] % path) + commit_id,
                        '', '', ''
                    ))

    return metadata, base_url, commit_url, result

def today_date():
    """Return today date as: %a, %d %b %Y

    Date is based on the server, hopefully with the system clock set at UTC.

    :return The date string.
    """
    return date.today().strftime('%a, %d %b %Y')

def _create_url_headers(api_path):
    """Create the complete URL to the API backend.

    Used if we need to set special headers.

    :param api_path: The API path.
    :return A tuple with the full URL, and the headers set.
    """
    backend_token = app.config.get('BACKEND_TOKEN')
    backend_url = app.config.get('BACKEND_URL')

    backend_url = urljoin(backend_url, api_path)

    headers = {}
    if backend_token:
        headers = {'X-XSRF-Header': backend_token}

    return (backend_url, headers)

def _create_api_path(api_path, other_path=''):
    """Merge two URL tokens together.

    :param api_path: The path to the API endpoint.
    :param other_path: The path to append, defaults to empty string.
    """
    if api_path[-1] != '/':
        api_path += '/'

    if other_path and other_path[-1] == '/':
        other_path = other_path[:-1]

    return api_path + other_path

def get_job(**kwargs):
    """Get a job document from the backend.

    This function is only used for server side processing data.

    :return A `requests.Response` object.
    """
    api_path = app.config.get('JOB_API_ENDPOINT')

    if kwargs.get('id', None):
        api_path = _create_api_path(api_path, kwargs['id'])
        kwargs.pop('id')

    url, headers = _create_url_headers(api_path)

    return requests.get(url, params=kwargs, headers=headers)

def get_defconfig(**kwargs):
    """Get a defconfig document from the backend.

    This function is only used for server side processing data.

    :return A `requests.Response` object.
    """
    api_path = app.config.get('DEFCONFIG_API_ENDPOINT')

    if kwargs.get('id', None):
        api_path = _create_api_path(api_path, kwargs['id'])
        kwargs.pop('id')

    url, headers = _create_url_headers(api_path)

    return requests.get(url, params=kwargs, headers=headers)

def ajax_count_get(request, api_path, collection):
    """Handle AJAX call from the client to the `count` API.

    :param request: The request performed.
    :param api_path: The API endpoint where to perform the request.
    :param collection: The collection to count.

    :return A tuple with the data, status code and headers of the
        `requests.Response` object.
    """
    params_list = request.args.lists()

    api_path = _create_api_path(api_path)

    if collection:
        api_path = _create_api_path(api_path, collection)

    url, headers = _create_url_headers(api_path)
    r = requests.get(url, headers=headers, params=params_list, stream=True)

    return (r.raw.data, r.status_code, r.headers.items())

def ajax_get(request, api_path):
    """Handle general AJAX calls from the client.

    :param request: The request performed.
    :param api_path: The API endpoint where to perform the request.
    :return A tuple with the data, status code and headers of the
        `requests.Response` object.
    """
    params_list = request.args.lists()

    if 'id' in request.args:
        boot_id = request.args['id']
        api_path = _create_api_path(api_path, boot_id)

        params_list.remove(('id', [boot_id]))

    url, headers = _create_url_headers(api_path)
    r = requests.get(url, headers=headers, params=params_list, stream=True)

    return (r.raw.data, r.status_code, r.headers.items())
<|endoftext|>