<commit_before>import warnings

"""
Django settings for refugeedata project.

Generated by 'django-admin startproject' using Django 1.8.

For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
try:
    SECRET_KEY = os.environ["SECRET_KEY"]
except KeyError:
    warnings.warn("SECRET_KEY environment variable not set")

DEBUG = os.environ.get("DEBUG") == "1"
SSLIFY_DISABLE = os.environ.get("SSLIFY_DISABLE", DEBUG and "1") == "1"

#ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django_gulp',
    'django.contrib.contenttypes',
    'grappelli.dashboard',
    'grappelli',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'compressor',
    'raven.contrib.django.raven_compat',
    'foundationform',
    'refugeedata',
)

DEFAULT_DOMAIN = os.environ.get("DEFAULT_DOMAIN", None)
if DEFAULT_DOMAIN:
    INSTALLED_APPS += ('django.contrib.sites',)
    SITE_ID = 1

MIDDLEWARE_CLASSES = (
    'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
    'refugeedata.middleware.EnforceCurrentSiteMiddleware',
    'sslify.middleware.SSLifyMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'refugeedata.distribution.middleware.DistributionUserMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'refugeedata.app.urls'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.media',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

LOCALE_PATHS = ("locale", )

WSGI_APPLICATION = 'refugeedata.app.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
    #'default': {
    #    'ENGINE': 'django.db.backends.sqlite3',
    #    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    #}
}

# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

LANGUAGE_CODE = 'en-us'

# TODO allow this to be specified elsewhere
LANGUAGES = (
    ("tr", "Turkish"),
    ("en", "English"),
)

TIME_ZONE = os.environ.get("TIME_ZONE", "UTC")

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'

# Heroku settings
# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES['default'] = dj_database_url.config()

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers
ALLOWED_HOSTS = ['*']

# Static asset configuration
import os
STATIC_ROOT = 'staticfiles'
MEDIA_ROOT = "uploads"
MEDIA_URL = "/media/"

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'compressor.finders.CompressorFinder',
)

ID_LENGTH = os.environ.get("ID_LENGTH", 4)
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

RAVEN_CONFIG = {
    'dsn': os.environ.get("RAVEN_DSN"),
}

LOGIN_URL = reverse_lazy("auth:login")
LOGOUT_URL = reverse_lazy("auth:logout")
LOGIN_REDIRECT_URL = reverse_lazy("public")

GRAPPELLI_ADMIN_TITLE = _("Admin Interface")
GRAPPELLI_INDEX_DASHBOARD = 'refugeedata.dashboard.CustomIndexDashboard'

# File storage
if not DEBUG:
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
    AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
    AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
    AWS_HEADERS = {
        'ExpiresDefault': 'access plus 6 months',
        'Cache-Control': 'max-age=86400',
    }
<commit_msg>Improve security settings<commit_after>import warnings

"""
Django settings for refugeedata project.

Generated by 'django-admin startproject' using Django 1.8.

For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
try:
    SECRET_KEY = os.environ["SECRET_KEY"]
except KeyError:
    warnings.warn("SECRET_KEY environment variable not set")

DEBUG = os.environ.get("DEBUG") == "1"
SSLIFY_DISABLE = os.environ.get("SSLIFY_DISABLE", DEBUG and "1") == "1"

#ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django_gulp',
    'django.contrib.contenttypes',
    'grappelli.dashboard',
    'grappelli',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'compressor',
    'raven.contrib.django.raven_compat',
    'foundationform',
    'refugeedata',
)

DEFAULT_DOMAIN = os.environ.get("DEFAULT_DOMAIN", None)
if DEFAULT_DOMAIN:
    INSTALLED_APPS += ('django.contrib.sites',)
    SITE_ID = 1
    SECURE_SSL_HOST = DEFAULT_DOMAIN
    SECURE_SSL_REDIRECT = True

MIDDLEWARE_CLASSES = (
    'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
    'refugeedata.middleware.EnforceCurrentSiteMiddleware',
    'sslify.middleware.SSLifyMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'refugeedata.distribution.middleware.DistributionUserMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'refugeedata.app.urls'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.media',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

LOCALE_PATHS = ("locale", )

WSGI_APPLICATION = 'refugeedata.app.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
    #'default': {
    #    'ENGINE': 'django.db.backends.sqlite3',
    #    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    #}
}

# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

LANGUAGE_CODE = 'en-us'

# TODO allow this to be specified elsewhere
LANGUAGES = (
    ("tr", "Turkish"),
    ("en", "English"),
)

TIME_ZONE = os.environ.get("TIME_ZONE", "UTC")

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'

# Heroku settings
# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES['default'] = dj_database_url.config()

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
#SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Extra security settings
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_SECONDS = 3600  # 1 hour - TODO increase this
SECURE_HSTS_INCLUDE_SUBDOMAINS = True

# Allow all host headers
ALLOWED_HOSTS = ['*']

# Static asset configuration
import os
STATIC_ROOT = 'staticfiles'
MEDIA_ROOT = "uploads"
MEDIA_URL = "/media/"

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'compressor.finders.CompressorFinder',
)

ID_LENGTH = os.environ.get("ID_LENGTH", 4)
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

RAVEN_CONFIG = {
    'dsn': os.environ.get("RAVEN_DSN"),
}

LOGIN_URL = reverse_lazy("auth:login")
LOGOUT_URL = reverse_lazy("auth:logout")
LOGIN_REDIRECT_URL = reverse_lazy("public")

GRAPPELLI_ADMIN_TITLE = _("Admin Interface")
GRAPPELLI_INDEX_DASHBOARD = 'refugeedata.dashboard.CustomIndexDashboard'

# File storage
if not DEBUG:
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
    AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
    AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
    AWS_HEADERS = {
        'ExpiresDefault': 'access plus 6 months',
        'Cache-Control': 'max-age=86400',
    }
<|endoftext|>


<commit_before>import inspect
from emcee_functools import func_signature, Fixed, Varying

@func_signature(a=Fixed(), b=Varying(), c=Varying())
def fn(**params):
    return params

def test_parameter_manipulation():
    sig = inspect.signature(fn)
    assert 'p' in sig.parameters

def test_values():
    assert fn([1, 2], a=3) == {'a': 3, 'b': 1, 'c': 2,}
<commit_msg>Tests create wrapped function on the fly<commit_after>import inspect
from emcee_functools import func_signature, Fixed, Varying

def _fn(**params):
    return params

def test_parameter_manipulation():
    fn = func_signature(a=Varying(), b=Fixed())(_fn)
    sig = inspect.signature(fn)
    assert 'p' in sig.parameters

def test_values():
    fn = func_signature(a=Fixed(), b=Varying(), c=Varying())(_fn)
    assert fn([1, 2], a=3) == {'a': 3, 'b': 1, 'c': 2,}
<|endoftext|>


<commit_before>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
from enum import Enum

from sqlalchemy import Column, ForeignKeyConstraint, String, Text, false

from airflow.models.base import Base, StringID
from airflow.utils import timezone
from airflow.utils.session import NEW_SESSION, provide_session
from airflow.utils.sqlalchemy import UtcDateTime

class DagWarning(Base):
    """
    A table to store DAG warnings.

    DAG warnings are problems that don't rise to the level of failing the DAG parse
    but which users should nonetheless be warned about.  These warnings are recorded
    when parsing DAG and displayed on the Webserver in a flash message.
    """

    dag_id = Column(StringID(), primary_key=True)
    warning_type = Column(String(50), primary_key=True)
    message = Column(Text, nullable=False)
    timestamp = Column(UtcDateTime, nullable=False, default=timezone.utcnow)

    __tablename__ = "dag_warning"
    __table_args__ = (
        ForeignKeyConstraint(
            ('dag_id',),
            ['dag.dag_id'],
            name='dcw_dag_id_fkey',
            ondelete='CASCADE',
        ),
    )

    def __init__(self, dag_id, error_type, message, **kwargs):
        super().__init__(**kwargs)
        self.dag_id = dag_id
        self.warning_type = DagWarningType(error_type).value  # make sure valid type
        self.message = message

    def __eq__(self, other):
        return self.dag_id == other.dag_id and self.warning_type == other.warning_type

    def __hash__(self):
        return hash((self.dag_id, self.warning_type))

    @classmethod
    @provide_session
    def purge_inactive_dag_warnings(cls, session=NEW_SESSION):
        """
        Deactivate DagWarning records for inactive dags.

        :return: None
        """
        from airflow.models.dag import DagModel

        if session.get_bind().dialect.name == 'sqlite':
            dag_ids = session.query(DagModel).filter(DagModel.is_active == false()).all()
            session.query(cls).filter(cls.dag_id.in_(dag_ids)).delete(synchronize_session=False)
        else:
            session.query(cls).filter(cls.dag_id == DagModel.dag_id, DagModel.is_active == false()).delete(
                synchronize_session=False
            )
        session.commit()

class DagWarningType(str, Enum):
    """
    Enum for DAG warning types.

    This is the set of allowable values for the ``warning_type`` field
    in the DagWarning model.
    """

    NONEXISTENT_POOL = 'non-existent pool'
<commit_msg>Fix purge_inactive_dag_warnings filter (#24749)<commit_after>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
from enum import Enum

from sqlalchemy import Column, ForeignKeyConstraint, String, Text, false
from sqlalchemy.orm import Session

from airflow.models.base import Base, StringID
from airflow.utils import timezone
from airflow.utils.session import NEW_SESSION, provide_session
from airflow.utils.sqlalchemy import UtcDateTime

class DagWarning(Base):
    """
    A table to store DAG warnings.

    DAG warnings are problems that don't rise to the level of failing the DAG parse
    but which users should nonetheless be warned about.  These warnings are recorded
    when parsing DAG and displayed on the Webserver in a flash message.
    """

    dag_id = Column(StringID(), primary_key=True)
    warning_type = Column(String(50), primary_key=True)
    message = Column(Text, nullable=False)
    timestamp = Column(UtcDateTime, nullable=False, default=timezone.utcnow)

    __tablename__ = "dag_warning"
    __table_args__ = (
        ForeignKeyConstraint(
            ('dag_id',),
            ['dag.dag_id'],
            name='dcw_dag_id_fkey',
            ondelete='CASCADE',
        ),
    )

    def __init__(self, dag_id: str, error_type: str, message: str, **kwargs):
        super().__init__(**kwargs)
        self.dag_id = dag_id
        self.warning_type = DagWarningType(error_type).value  # make sure valid type
        self.message = message

    def __eq__(self, other) -> bool:
        return self.dag_id == other.dag_id and self.warning_type == other.warning_type

    def __hash__(self) -> int:
        return hash((self.dag_id, self.warning_type))

    @classmethod
    @provide_session
    def purge_inactive_dag_warnings(cls, session: Session = NEW_SESSION) -> None:
        """
        Deactivate DagWarning records for inactive dags.

        :return: None
        """
        from airflow.models.dag import DagModel

        if session.get_bind().dialect.name == 'sqlite':
            dag_ids = session.query(DagModel.dag_id).filter(DagModel.is_active == false())
            query = session.query(cls).filter(cls.dag_id.in_(dag_ids))
        else:
            query = session.query(cls).filter(cls.dag_id == DagModel.dag_id, DagModel.is_active == false())
        query.delete(synchronize_session=False)
        session.commit()

class DagWarningType(str, Enum):
    """
    Enum for DAG warning types.

    This is the set of allowable values for the ``warning_type`` field
    in the DagWarning model.
    """

    NONEXISTENT_POOL = 'non-existent pool'
<|endoftext|>


<commit_before># encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models

from cab.models import VERSION_MAPPING
import cab.models

class Migration(DataMigration):

    def forwards(self, orm):
        python = None
        try:
            python = orm['cab.language'].objects.get(name='Python')
        except models.ObjectDoesNotExist, _:
            return

        for snippet in orm['cab.snippet'].objects.all():
            if snippet.language != python:
                continue

            for version, date in VERSION_MAPPING:
                if snippet.pub_date >= date:
                    snippet.django_version = version
                    snippet.save()
                    break

    def backwards(self, orm):
        pass

    models = {
        'auth.group': {
            'Meta': {'object_name': 'Group'},
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
        },
        'auth.permission': {
            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
        },
        'auth.user': {
            'Meta': {'object_name': 'User'},
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
        },
        'cab.bookmark': {
            'Meta': {'object_name': 'Bookmark'},
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'bookmarks'", 'to': "orm['cab.Snippet']"}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'cab_bookmarks'", 'to': "orm['auth.User']"})
        },
        'cab.language': {
            'Meta': {'object_name': 'Language'},
            'file_extension': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'language_code': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
            'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
        },
        'cab.snippet': {
            'Meta': {'object_name': 'Snippet'},
            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
            'bookmark_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
            'code': ('django.db.models.fields.TextField', [], {}),
            'description': ('django.db.models.fields.TextField', [], {}),
            'description_html': ('django.db.models.fields.TextField', [], {}),
            'django_version': ('django.db.models.fields.FloatField', [], {'default': '0'}),
            'highlighted_code': ('django.db.models.fields.TextField', [], {}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'language': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cab.Language']"}),
            'pub_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
            'rating_score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
            'updated_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
        },
        'contenttypes.contenttype': {
            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
        }
    }

    complete_apps = ['cab']
<commit_msg>Removed uncessary import<commit_after># encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models

from cab.models import VERSION_MAPPING

class Migration(DataMigration):

    def forwards(self, orm):
        python = None
        try:
            python = orm['cab.language'].objects.get(name='Python')
        except models.ObjectDoesNotExist, _:
            return

        for snippet in orm['cab.snippet'].objects.all():
            if snippet.language != python:
                continue

            for version, date in VERSION_MAPPING:
                if snippet.pub_date >= date:
                    snippet.django_version = version
                    snippet.save()
                    break

    def backwards(self, orm):
        pass

    models = {
        'auth.group': {
            'Meta': {'object_name': 'Group'},
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
        },
        'auth.permission': {
            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
        },
        'auth.user': {
            'Meta': {'object_name': 'User'},
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
        },
        'cab.bookmark': {
            'Meta': {'object_name': 'Bookmark'},
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'bookmarks'", 'to': "orm['cab.Snippet']"}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'cab_bookmarks'", 'to': "orm['auth.User']"})
        },
        'cab.language': {
            'Meta': {'object_name': 'Language'},
            'file_extension': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'language_code': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
            'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
        },
        'cab.snippet': {
            'Meta': {'object_name': 'Snippet'},
            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
            'bookmark_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
            'code': ('django.db.models.fields.TextField', [], {}),
            'description': ('django.db.models.fields.TextField', [], {}),
            'description_html': ('django.db.models.fields.TextField', [], {}),
            'django_version': ('django.db.models.fields.FloatField', [], {'default': '0'}),
            'highlighted_code': ('django.db.models.fields.TextField', [], {}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'language': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cab.Language']"}),
            'pub_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
            'rating_score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
            'updated_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
        },
        'contenttypes.contenttype': {
            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
        }
    }

    complete_apps = ['cab']
<|endoftext|>


<commit_before>__author__ = 'Calvin Lobo'
__version__ = '1.67'

from .property import Property
from .dictproperty import DictProperty
from .listproperty import ListProperty
from .unitproperty import UnitProperty
from .setproperty import SetProperty
from .limitproperty import LimitProperty
from .stringproperty import StringProperty, _

class BindError(Exception):
    pass

class EventDispatcher(object):
    def __init__(self, **kwargs):
        self.event_dispatcher_event_callbacks = {}
        bindings = {}
        # Walk backwards through the MRO looking for Property attributes in the classes. Then register and bind them to
        # 'on_<prop_name>' if it exists. Walking backwards allows you to override the default value for a superclass.
        for cls in reversed(self.__class__.__mro__):
            for prop_name, prop in cls.__dict__.iteritems():
                if isinstance(prop, Property):
                    prop.name = prop_name
                    prop.register(self, prop_name, prop.default_value)
                    if hasattr(self, 'on_{}'.format(prop_name)):
                        func = getattr(self, 'on_{}'.format(prop_name))
                        bindings.update({prop_name: func})

        self.bind(**bindings)

    def dispatch(self, key, *args):
        for callback in self.event_dispatcher_properties[key]['callbacks']:
            if callback(*args):
                break

    def dispatch_event(self, event, *args):
        for callback in self.event_dispatcher_event_callbacks[event]:
            if callback(*args):
                break

    def register_event(self, name):
        if hasattr(self, 'on_{}'.format(name)):
            self.event_dispatcher_event_callbacks[name] = [getattr(self, 'on_{}'.format(name))]
        else:
            self.event_dispatcher_event_callbacks[name] = []

    def unbind(self, **kwargs):
        all_properties = self.event_dispatcher_properties
        for prop_name, callback in kwargs.iteritems():
            if prop_name in all_properties:
                try:
                    all_properties[prop_name]['callbacks'].remove(callback)
                except ValueError:
                    raise BindError("No binding for {} in property '{}'".format(callback.__name__, prop_name))
            elif prop_name in self.event_dispatcher_event_callbacks:
                try:
                    self.event_dispatcher_event_callbacks[prop_name].remove(callback)
                except ValueError:
                    raise BindError("No binding for {} in event '{}'".format(callback.__name__, prop_name))
            else:
                raise BindError('No property or event by the name of %s' % prop_name)

    def unbind_all(self, *args):
        all_properties = self.event_dispatcher_properties
        for prop_name in args:
            if prop_name in all_properties:
                del all_properties[prop_name]['callbacks'][:]
            elif prop_name in self.event_dispatcher_event_callbacks:
                del self.event_dispatcher_event_callbacks[prop_name][:]
            else:
                raise BindError("No such property or event '%s'" % prop_name)

    def bind(self, **kwargs):
        for prop_name, callback in kwargs.iteritems():
            if prop_name in self.event_dispatcher_properties:
                # Queue the callback into the property
                self.event_dispatcher_properties[prop_name]['callbacks'].append(callback)
            elif prop_name in self.event_dispatcher_event_callbacks:
                # If a property was not found, search in events
                self.event_dispatcher_event_callbacks[prop_name].append(callback)
            else:
                raise BindError("No property or event by the name of '%s'" % prop_name)

    def setter(self, prop_name):
        return lambda inst, value: setattr(self, prop_name, value)

    def get_dispatcher_property(self, prop_name):
        return self.event_dispatcher_properties[prop_name]['property']

<commit_msg>bump to 1.68<commit_after>__author__ = 'Calvin Lobo'
__version__ = '1.68'

from .property import Property
from .dictproperty import DictProperty
from .listproperty import ListProperty
from .unitproperty import UnitProperty
from .setproperty import SetProperty
from .limitproperty import LimitProperty
from .stringproperty import StringProperty, _

class BindError(Exception):
    pass

class EventDispatcher(object):
    def __init__(self, **kwargs):
        self.event_dispatcher_event_callbacks = {}
        bindings = {}
        # Walk backwards through the MRO looking for Property attributes in the classes. Then register and bind them to
        # 'on_<prop_name>' if it exists. Walking backwards allows you to override the default value for a superclass.
        for cls in reversed(self.__class__.__mro__):
            for prop_name, prop in cls.__dict__.iteritems():
                if isinstance(prop, Property):
                    prop.name = prop_name
                    prop.register(self, prop_name, prop.default_value)
                    if hasattr(self, 'on_{}'.format(prop_name)):
                        func = getattr(self, 'on_{}'.format(prop_name))
                        bindings.update({prop_name: func})

        self.bind(**bindings)

    def dispatch(self, key, *args):
        for callback in self.event_dispatcher_properties[key]['callbacks']:
            if callback(*args):
                break

    def dispatch_event(self, event, *args):
        for callback in self.event_dispatcher_event_callbacks[event]:
            if callback(*args):
                break

    def register_event(self, name):
        if hasattr(self, 'on_{}'.format(name)):
            self.event_dispatcher_event_callbacks[name] = [getattr(self, 'on_{}'.format(name))]
        else:
            self.event_dispatcher_event_callbacks[name] = []

    def unbind(self, **kwargs):
        all_properties = self.event_dispatcher_properties
        for prop_name, callback in kwargs.iteritems():
            if prop_name in all_properties:
                try:
                    all_properties[prop_name]['callbacks'].remove(callback)
                except ValueError:
                    raise BindError("No binding for {} in property '{}'".format(callback.__name__, prop_name))
            elif prop_name in self.event_dispatcher_event_callbacks:
                try:
                    self.event_dispatcher_event_callbacks[prop_name].remove(callback)
                except ValueError:
                    raise BindError("No binding for {} in event '{}'".format(callback.__name__, prop_name))
            else:
                raise BindError('No property or event by the name of %s' % prop_name)

    def unbind_all(self, *args):
        all_properties = self.event_dispatcher_properties
        for prop_name in args:
            if prop_name in all_properties:
                del all_properties[prop_name]['callbacks'][:]
            elif prop_name in self.event_dispatcher_event_callbacks:
                del self.event_dispatcher_event_callbacks[prop_name][:]
            else:
                raise BindError("No such property or event '%s'" % prop_name)

    def bind(self, **kwargs):
        for prop_name, callback in kwargs.iteritems():
            if prop_name in self.event_dispatcher_properties:
                # Queue the callback into the property
                self.event_dispatcher_properties[prop_name]['callbacks'].append(callback)
            elif prop_name in self.event_dispatcher_event_callbacks:
                # If a property was not found, search in events
                self.event_dispatcher_event_callbacks[prop_name].append(callback)
            else:
                raise BindError("No property or event by the name of '%s'" % prop_name)

    def setter(self, prop_name):
        return lambda inst, value: setattr(self, prop_name, value)

    def get_dispatcher_property(self, prop_name):
        return self.event_dispatcher_properties[prop_name]['property']

<|endoftext|>


<commit_before>import pytest
from _pytest.config import ExitCode

def test_version(testdir, pytestconfig):
    testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
    result = testdir.runpytest("--version")
    assert result.ret == 0
    # p = py.path.local(py.__file__).dirpath()
    result.stderr.fnmatch_lines(
        ["*pytest*{}*imported from*".format(pytest.__version__)]
    )
    if pytestconfig.pluginmanager.list_plugin_distinfo():
        result.stderr.fnmatch_lines(["*setuptools registered plugins:", "*at*"])

def test_help(testdir):
    result = testdir.runpytest("--help")
    assert result.ret == 0
    result.stdout.fnmatch_lines(
        """
        *-v*verbose*
        *setup.cfg*
        *minversion*
        *to see*markers*pytest --markers*
        *to see*fixtures*pytest --fixtures*
    """
    )

def test_hookvalidation_unknown(testdir):
    testdir.makeconftest(
        """
        def pytest_hello(xyz):
            pass
    """
    )
    result = testdir.runpytest()
    assert result.ret != 0
    result.stdout.fnmatch_lines(["*unknown hook*pytest_hello*"])

def test_hookvalidation_optional(testdir):
    testdir.makeconftest(
        """
        import pytest
        @pytest.hookimpl(optionalhook=True)
        def pytest_hello(xyz):
            pass
    """
    )
    result = testdir.runpytest()
    assert result.ret == ExitCode.NO_TESTS_COLLECTED

def test_traceconfig(testdir):
    result = testdir.runpytest("--traceconfig")
    result.stdout.fnmatch_lines(["*using*pytest*py*", "*active plugins*"])

def test_debug(testdir):
    result = testdir.runpytest_subprocess("--debug")
    assert result.ret == ExitCode.NO_TESTS_COLLECTED
    p = testdir.tmpdir.join("pytestdebug.log")
    assert "pytest_sessionstart" in p.read()

def test_PYTEST_DEBUG(testdir, monkeypatch):
    monkeypatch.setenv("PYTEST_DEBUG", "1")
    result = testdir.runpytest_subprocess()
    assert result.ret == ExitCode.NO_TESTS_COLLECTED
    result.stderr.fnmatch_lines(
        ["*pytest_plugin_registered*", "*manager*PluginManager*"]
    )
<commit_msg>add test<commit_after>import pytest
from _pytest.config import ExitCode

def test_version(testdir, pytestconfig):
    testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
    result = testdir.runpytest("--version")
    assert result.ret == 0
    # p = py.path.local(py.__file__).dirpath()
    result.stderr.fnmatch_lines(
        ["*pytest*{}*imported from*".format(pytest.__version__)]
    )
    if pytestconfig.pluginmanager.list_plugin_distinfo():
        result.stderr.fnmatch_lines(["*setuptools registered plugins:", "*at*"])

def test_help(testdir):
    result = testdir.runpytest("--help")
    assert result.ret == 0
    result.stdout.fnmatch_lines(
        """
          -m MARKEXPR           only run tests matching given mark expression.
                                For example: -m 'mark1 and not mark2'.
        reporting:
          --durations=N *
        *setup.cfg*
        *minversion*
        *to see*markers*pytest --markers*
        *to see*fixtures*pytest --fixtures*
    """
    )

def test_hookvalidation_unknown(testdir):
    testdir.makeconftest(
        """
        def pytest_hello(xyz):
            pass
    """
    )
    result = testdir.runpytest()
    assert result.ret != 0
    result.stdout.fnmatch_lines(["*unknown hook*pytest_hello*"])

def test_hookvalidation_optional(testdir):
    testdir.makeconftest(
        """
        import pytest
        @pytest.hookimpl(optionalhook=True)
        def pytest_hello(xyz):
            pass
    """
    )
    result = testdir.runpytest()
    assert result.ret == ExitCode.NO_TESTS_COLLECTED

def test_traceconfig(testdir):
    result = testdir.runpytest("--traceconfig")
    result.stdout.fnmatch_lines(["*using*pytest*py*", "*active plugins*"])

def test_debug(testdir):
    result = testdir.runpytest_subprocess("--debug")
    assert result.ret == ExitCode.NO_TESTS_COLLECTED
    p = testdir.tmpdir.join("pytestdebug.log")
    assert "pytest_sessionstart" in p.read()

def test_PYTEST_DEBUG(testdir, monkeypatch):
    monkeypatch.setenv("PYTEST_DEBUG", "1")
    result = testdir.runpytest_subprocess()
    assert result.ret == ExitCode.NO_TESTS_COLLECTED
    result.stderr.fnmatch_lines(
        ["*pytest_plugin_registered*", "*manager*PluginManager*"]
    )
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""Akvo RSR is covered by the GNU Affero General Public License.
See more details in the license.txt file located at the root folder of the
Akvo RSR module. For additional details on the GNU license please
see < http://www.gnu.org/licenses/agpl.html >.
"""

from django.conf import settings
from django.db.models import Q
from rest_framework.decorators import api_view
from rest_framework.response import Response

from akvo.codelists.models import Country, Version
from akvo.codelists.store.codelists_v202 import ACTIVITY_STATUS, SECTOR_CATEGORY
from akvo.rest.serializers import (TypeaheadCountrySerializer,
                                   TypeaheadOrganisationSerializer,
                                   TypeaheadProjectSerializer,
                                   TypeaheadProjectUpdateSerializer,
                                   TypeaheadKeywordSerializer,
                                   TypeaheadSectorSerializer,)
from akvo.rsr.filters import location_choices, get_m49_filter
from akvo.rsr.models import Organisation, Project, ProjectUpdate
from akvo.rsr.views.project import _project_directory_coll
from akvo.utils import codelist_choices

def rejig(queryset, serializer):
    """Rearrange & add queryset count to the response data."""
    return {
        'count': queryset.count(),
        'results': serializer.data
    }

@api_view(['GET'])
def typeahead_country(request):
    iati_version = Version.objects.get(code=settings.IATI_VERSION)
    countries = Country.objects.filter(version=iati_version)
    return Response(
        rejig(countries, TypeaheadCountrySerializer(countries, many=True))
    )

@api_view(['GET'])
def typeahead_organisation(request):
    page = request.rsr_page
    if request.GET.get('partners', '0') == '1' and page:
        organisations = page.partners()
    else:
        # Project editor - all organizations
        organisations = Organisation.objects.all()

    return Response(
        rejig(organisations, TypeaheadOrganisationSerializer(organisations,
                                                             many=True))
    )

@api_view(['GET'])
def typeahead_user_organisations(request):
    user = request.user
    is_admin = user.is_active and (user.is_superuser or user.is_admin)
    organisations = user.approved_organisations() if not is_admin else Organisation.objects.all()
    return Response(
        rejig(organisations, TypeaheadOrganisationSerializer(organisations,
                                                             many=True))
    )

@api_view(['GET'])
def typeahead_keyword(request):
    page = request.rsr_page
    keywords = page.keywords.all() if page else None
    if keywords:
        return Response(
            rejig(keywords, TypeaheadKeywordSerializer(keywords, many=True))
        )
    # No keywords on rsr.akvo.org
    return Response({})

@api_view(['GET'])
def typeahead_project(request):
    """Return the typeaheads for projects.

    Without any query parameters, it returns the info for all the projects in
    the current context -- changes depending on whether we are on a partner
    site, or the RSR site.

    If a published query parameter is passed, only projects that have been
    published are returned.

    NOTE: The unauthenticated user gets information about all the projects when
    using this API endpoint.  More permission checking will need to be added,
    if the amount of data being returned is changed.

    """
    if request.GET.get('published', '0') == '0':
        # Project editor - organization projects, all
        page = request.rsr_page
        projects = page.all_projects() if page else Project.objects.all()
    else:
        # Search bar - organization projects, published
        projects = _project_directory_coll(request)

    projects = projects.exclude(title='')
    return Response(
        rejig(projects, TypeaheadProjectSerializer(projects, many=True))
    )

def _int_or_none(value):
    """Return int or None given a value."""
    try:
        return int(value)
    except:
        return None

def _create_filters_query(request):
    """Returns a Q object expression based on query parameters."""
    keyword_param = _int_or_none(request.GET.get('keyword'))
    location_param = _int_or_none(request.GET.get('location'))
    status_param = _int_or_none(request.GET.get('status'))
    organisation_param = _int_or_none(request.GET.get('organisation'))
    sector_param = _int_or_none(request.GET.get('sector'))

    keyword_filter = Q(keywords__id=keyword_param) if keyword_param else None
    location_filter = get_m49_filter(location_param) if location_param else None
    status_filter = Q(iati_status=status_param) if status_param else None
    organisation_filter = Q(partners__id=organisation_param) if organisation_param else None
    sector_filter = (
        Q(sectors__sector_code=sector_param, sectors__vocabulary='2')
        if sector_param else None
    )
    all_filters = [
        keyword_filter, location_filter, status_filter, organisation_filter, sector_filter
    ]
    filters = filter(None, all_filters)
    return reduce(lambda x, y: x & y, filters) if filters else None

@api_view(['GET'])
def typeahead_project_filters(request):
    """Return the values for various project filters.

    Based on the current filters, it returns new options for all the (other)
    filters. This is used to generate dynamic filters.

    """

    # Fetch projects based on whether we are an Akvo site or RSR main site
    page = request.rsr_page
    projects = page.projects() if page else Project.objects.all()
    # FIXME: Can we prefetch things to make this faster???

    # Filter projects based on query parameters
    filter_ = _create_filters_query(request)
    projects = projects.filter(filter_) if filter_ is not None else projects

    # Get the relevant data for typeaheads based on filtered projects.
    keywords = projects.keywords()

    locations = [
        {'id': choice[0], 'name': choice[1]}
        for choice in location_choices(projects)
    ]

    valid_statuses = dict(codelist_choices(ACTIVITY_STATUS))
    status = [
        {'id': status, 'name': valid_statuses[status]}
        for status in set(projects.values_list('iati_status', flat=True))
        if status in valid_statuses
    ]

    organisations = projects.all_partners()

    # FIXME: Currently only vocabulary 2 is supported (as was the case with
    # static filters). This could be extended to other vocabularies, in future.
    valid_sectors = dict(codelist_choices(SECTOR_CATEGORY))
    sectors = projects.sectors().filter(
        vocabulary='2', sector_code__in=valid_sectors
    ).values('sector_code').distinct()

    response = {
        'organisation': TypeaheadOrganisationSerializer(organisations, many=True).data,
        'keyword': TypeaheadKeywordSerializer(keywords, many=True).data,
        'status': sorted(status, key=lambda x: x['id']),
        'sector': TypeaheadSectorSerializer(sectors, many=True).data,
        'location': locations,
    }

    return Response(response)

@api_view(['GET'])
def typeahead_user_projects(request):
    user = request.user
    is_admin = user.is_active and (user.is_superuser or user.is_admin)
    if is_admin:
        projects = Project.objects.all()
    else:
        projects = user.approved_organisations().all_projects()
    projects = projects.exclude(title='')
    return Response(
        rejig(projects, TypeaheadProjectSerializer(projects, many=True))
    )

@api_view(['GET'])
def typeahead_impact_projects(request):
    user = request.user
    projects = Project.objects.all() if user.is_admin or user.is_superuser else user.my_projects()
    projects = projects.published().filter(is_impact_project=True).order_by('title')

    return Response(
        rejig(projects, TypeaheadProjectSerializer(projects, many=True))
    )

@api_view(['GET'])
def typeahead_projectupdate(request):
    updates = ProjectUpdate.objects.all()
    return Response(
        rejig(updates, TypeaheadProjectUpdateSerializer(updates, many=True))
    )
<commit_msg>[#2552] Use only public & published projects for typeaheads<commit_after># -*- coding: utf-8 -*-

"""Akvo RSR is covered by the GNU Affero General Public License.
See more details in the license.txt file located at the root folder of the
Akvo RSR module. For additional details on the GNU license please
see < http://www.gnu.org/licenses/agpl.html >.
"""

from django.conf import settings
from django.db.models import Q
from rest_framework.decorators import api_view
from rest_framework.response import Response

from akvo.codelists.models import Country, Version
from akvo.codelists.store.codelists_v202 import ACTIVITY_STATUS, SECTOR_CATEGORY
from akvo.rest.serializers import (TypeaheadCountrySerializer,
                                   TypeaheadOrganisationSerializer,
                                   TypeaheadProjectSerializer,
                                   TypeaheadProjectUpdateSerializer,
                                   TypeaheadKeywordSerializer,
                                   TypeaheadSectorSerializer,)
from akvo.rsr.filters import location_choices, get_m49_filter
from akvo.rsr.models import Organisation, Project, ProjectUpdate
from akvo.rsr.views.project import _project_directory_coll
from akvo.utils import codelist_choices

def rejig(queryset, serializer):
    """Rearrange & add queryset count to the response data."""
    return {
        'count': queryset.count(),
        'results': serializer.data
    }

@api_view(['GET'])
def typeahead_country(request):
    iati_version = Version.objects.get(code=settings.IATI_VERSION)
    countries = Country.objects.filter(version=iati_version)
    return Response(
        rejig(countries, TypeaheadCountrySerializer(countries, many=True))
    )

@api_view(['GET'])
def typeahead_organisation(request):
    page = request.rsr_page
    if request.GET.get('partners', '0') == '1' and page:
        organisations = page.partners()
    else:
        # Project editor - all organizations
        organisations = Organisation.objects.all()

    return Response(
        rejig(organisations, TypeaheadOrganisationSerializer(organisations,
                                                             many=True))
    )

@api_view(['GET'])
def typeahead_user_organisations(request):
    user = request.user
    is_admin = user.is_active and (user.is_superuser or user.is_admin)
    organisations = user.approved_organisations() if not is_admin else Organisation.objects.all()
    return Response(
        rejig(organisations, TypeaheadOrganisationSerializer(organisations,
                                                             many=True))
    )

@api_view(['GET'])
def typeahead_keyword(request):
    page = request.rsr_page
    keywords = page.keywords.all() if page else None
    if keywords:
        return Response(
            rejig(keywords, TypeaheadKeywordSerializer(keywords, many=True))
        )
    # No keywords on rsr.akvo.org
    return Response({})

@api_view(['GET'])
def typeahead_project(request):
    """Return the typeaheads for projects.

    Without any query parameters, it returns the info for all the projects in
    the current context -- changes depending on whether we are on a partner
    site, or the RSR site.

    If a published query parameter is passed, only projects that have been
    published are returned.

    NOTE: The unauthenticated user gets information about all the projects when
    using this API endpoint.  More permission checking will need to be added,
    if the amount of data being returned is changed.

    """
    if request.GET.get('published', '0') == '0':
        # Project editor - organization projects, all
        page = request.rsr_page
        projects = page.all_projects() if page else Project.objects.all()
    else:
        # Search bar - organization projects, published
        projects = _project_directory_coll(request)

    projects = projects.exclude(title='')
    return Response(
        rejig(projects, TypeaheadProjectSerializer(projects, many=True))
    )

def _int_or_none(value):
    """Return int or None given a value."""
    try:
        return int(value)
    except:
        return None

def _create_filters_query(request):
    """Returns a Q object expression based on query parameters."""
    keyword_param = _int_or_none(request.GET.get('keyword'))
    location_param = _int_or_none(request.GET.get('location'))
    status_param = _int_or_none(request.GET.get('status'))
    organisation_param = _int_or_none(request.GET.get('organisation'))
    sector_param = _int_or_none(request.GET.get('sector'))

    keyword_filter = Q(keywords__id=keyword_param) if keyword_param else None
    location_filter = get_m49_filter(location_param) if location_param else None
    status_filter = Q(iati_status=status_param) if status_param else None
    organisation_filter = Q(partners__id=organisation_param) if organisation_param else None
    sector_filter = (
        Q(sectors__sector_code=sector_param, sectors__vocabulary='2')
        if sector_param else None
    )
    all_filters = [
        keyword_filter, location_filter, status_filter, organisation_filter, sector_filter
    ]
    filters = filter(None, all_filters)
    return reduce(lambda x, y: x & y, filters) if filters else None

@api_view(['GET'])
def typeahead_project_filters(request):
    """Return the values for various project filters.

    Based on the current filters, it returns new options for all the (other)
    filters. This is used to generate dynamic filters.

    """

    # Fetch projects based on whether we are an Akvo site or RSR main site
    page = request.rsr_page
    projects = page.projects() if page else Project.objects.all().public().published()
    # FIXME: Can we prefetch things to make this faster???

    # Filter projects based on query parameters
    filter_ = _create_filters_query(request)
    projects = projects.filter(filter_) if filter_ is not None else projects

    # Get the relevant data for typeaheads based on filtered projects.
    keywords = projects.keywords()

    locations = [
        {'id': choice[0], 'name': choice[1]}
        for choice in location_choices(projects)
    ]

    valid_statuses = dict(codelist_choices(ACTIVITY_STATUS))
    status = [
        {'id': status, 'name': valid_statuses[status]}
        for status in set(projects.values_list('iati_status', flat=True))
        if status in valid_statuses
    ]

    organisations = projects.all_partners()

    # FIXME: Currently only vocabulary 2 is supported (as was the case with
    # static filters). This could be extended to other vocabularies, in future.
    valid_sectors = dict(codelist_choices(SECTOR_CATEGORY))
    sectors = projects.sectors().filter(
        vocabulary='2', sector_code__in=valid_sectors
    ).values('sector_code').distinct()

    response = {
        'organisation': TypeaheadOrganisationSerializer(organisations, many=True).data,
        'keyword': TypeaheadKeywordSerializer(keywords, many=True).data,
        'status': sorted(status, key=lambda x: x['id']),
        'sector': TypeaheadSectorSerializer(sectors, many=True).data,
        'location': locations,
    }

    return Response(response)

@api_view(['GET'])
def typeahead_user_projects(request):
    user = request.user
    is_admin = user.is_active and (user.is_superuser or user.is_admin)
    if is_admin:
        projects = Project.objects.all()
    else:
        projects = user.approved_organisations().all_projects()
    projects = projects.exclude(title='')
    return Response(
        rejig(projects, TypeaheadProjectSerializer(projects, many=True))
    )

@api_view(['GET'])
def typeahead_impact_projects(request):
    user = request.user
    projects = Project.objects.all() if user.is_admin or user.is_superuser else user.my_projects()
    projects = projects.published().filter(is_impact_project=True).order_by('title')

    return Response(
        rejig(projects, TypeaheadProjectSerializer(projects, many=True))
    )

@api_view(['GET'])
def typeahead_projectupdate(request):
    updates = ProjectUpdate.objects.all()
    return Response(
        rejig(updates, TypeaheadProjectUpdateSerializer(updates, many=True))
    )
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# TODO / FIXME
# - lever une exception lorsque nb_lines dépasse 999 (et autres compteurs)

import os
import sys
import tempfile
import datetime
import hashlib
import base64
from datetime import datetime

from batches import build_batches
from transmission_utils import build_mail

OUTPUT_DIRECTORY = '/var/lib/calebasse/B2/'

NORME = 'CP  '

TYPE_EMETTEUR = 'TE'
NUMERO_EMETTEUR = '420788606'
APPLICATION = 'TR'
MESSAGE = 'ENTROUVERT 0143350135 CALEBASSE 1301'
MESSAGE = MESSAGE + ' '*(37-len(MESSAGE))

CATEGORIE = '189'
STATUT = '60'
MODE_TARIF = '05'
NOM = 'CMPP SAINT ETIENNE'
NOM = NOM + ' '*(40-len(NOM))

def filler(n, car=' '):
    return car*n
def filler0(n):
    return filler(n, '0')
def b2date(d):
    return d.strftime('%y%m%d')
def get_control_key(nir):
    try:
        # Corse dpt 2A et 2B
        minus = 0
        if nir[6] in ('A', 'a'):
            nir = [c for c in nir]
            nir[6] = '0'
            nir = ''.join(nir)
            minus = 1000000
        elif nir[6] in ('B', 'b'):
            nir = [c for c in nir]
            nir[6] = '0'
            nir = ''.join(nir)
            minus = 2000000
        nir = int(nir) - minus
        return '%0.2d' % (97 - (nir % 97))
    except Exception, e:
        return '00'

def write128(output_file, line):
    if len(line) != 128:
        raise RuntimeError('length of this B2 line is %d != 128 : <<%s>>' %
                (len(line), line))
    output_file.write(line)

def write_invoice(output_file, invoice):
    invoice_lines = 0
    start_date = invoice.start_date
    start_2 = '2' + NUMERO_EMETTEUR + ' ' + \
            invoice.policy_holder_social_security_id + \
            get_control_key(invoice.policy_holder_social_security_id) + \
            '000' + ('%0.9d' % invoice.number) + \
            '1' + ('%0.9d' % invoice.patient_id) + \
            invoice.policy_holder_healthcenter.large_regime.code + \
            invoice.policy_holder_healthcenter.dest_organism + \
            (invoice.policy_holder_other_health_center or '0000') + \
            '3' + b2date(start_date) + '000000' + \
            invoice.policy_holder_healthcenter.dest_organism + '000' + \
            '10' + '3' +  \
            b2date(start_date) + \
            '000000000' + ' ' + \
            b2date(invoice.patient_birthdate) + \
            ('%d' %  invoice.patient_twinning_rank)[-1:] + \
            b2date(start_date) + b2date(invoice.end_date) + '01' + \
            '00' + filler(10)
    write128(output_file, start_2)
    invoice_lines += 1
    nb_type3 = 0
    kind = invoice.first_tag[0]
    prestation = u'SNS' if kind == 'T' else u'SD'
    for date in invoice.list_dates:
        line_3 = '3' + NUMERO_EMETTEUR + ' ' + \
                invoice.policy_holder_social_security_id + \
                get_control_key(invoice.policy_holder_social_security_id) + \
                '000' + ('%0.9d' % invoice.number) + \
                '19' + '320' + \
                b2date(datetime.strptime(date, "%d/%m/%Y")) + \
                b2date(datetime.strptime(date, "%d/%m/%Y")) + \
                prestation + '001' + \
                ' ' + '00100' +  ' ' + '00000' + \
                ('%0.7d' % invoice.ppa) + \
                ('%0.8d' % invoice.ppa) + \
                '100' + \
                ('%0.8d' % invoice.ppa) + \
                ('%0.8d' % invoice.ppa) + \
                '0000' + '000' + ' ' + filler(2) + ' ' + \
                ' ' + '0000000'
        write128(output_file, line_3)
        invoice_lines += 1
        nb_type3 += 1

    end_5 = '5' + NUMERO_EMETTEUR + ' ' + \
            invoice.policy_holder_social_security_id + \
            get_control_key(invoice.policy_holder_social_security_id) + \
            '000' + ('%0.9d' % invoice.number) + \
            ('%0.3d' % nb_type3) + \
            ('%0.8d' % invoice.amount) + \
            ('%0.8d' % invoice.amount) + \
            '00000000' + '00000000' + '00000000' + '00000000' + '00000000' + \
            filler(17) + \
            ('%0.8d' % invoice.amount) + \
            filler(4+2)
    write128(output_file, end_5)
    invoice_lines += 1

    return invoice_lines

def b2(seq_id, hc, batches):
    to = hc.b2_000()
    total = sum(b.total for b in batches)
    first_batch = min(b.number for b in batches)

    # B2 veut un identifiant de fichier sur 6 caractères alphanum
    hexdigest = hashlib.sha256('%s%s%s%s%s' % (seq_id, first_batch, NUMERO_EMETTEUR, to, total)).hexdigest()
    file_id = base64.encodestring(hexdigest).upper()[0:6]

    utcnow = datetime.datetime.utcnow()
    prefix = '%s-%s-%s-%s-%s.' % (seq_id, NUMERO_EMETTEUR, to, first_batch, file_id)
    output_file = tempfile.NamedTemporaryFile(suffix='.b2tmp',
            prefix=prefix, dir=OUTPUT_DIRECTORY, delete=False)
    nb_lines = 0

    start_000 = '000' +  TYPE_EMETTEUR + '00000' + NUMERO_EMETTEUR + \
            filler(6) + to + filler(6) + APPLICATION + \
            file_id + b2date(utcnow) + NORME + 'B2' + filler(15) + \
            '128' + filler(6) + MESSAGE
    write128(output_file, start_000)
    nb_lines += 1
    nb_batches = 0

    for batch in batches:
        start_1 = '1' + NUMERO_EMETTEUR + filler(6) + \
                batch.health_center.dest_organism[0:3] + \
                ('%0.3d' % batch.number) + CATEGORIE + STATUT + MODE_TARIF + \
                NOM + 'B2' + b2date(utcnow) + ' ' + NORME[0:2] + \
                ' ' + '062007' + 'U' + filler(2+3+1+34)
        write128(output_file, start_1)
        nb_lines += 1

        for i in batch.invoices:
            nb_lines += write_invoice(output_file, i)

        end_6 = '6' + NUMERO_EMETTEUR + \
                ('%0.3d' % batch.number_of_invoices) + \
                ('%0.4d' % batch.number_of_acts) + \
                ('%0.4d' % batch.number_of_invoices) + \
                ('%0.3d' % batch.number_of_invoices) + \
                ('%0.9d' % (batch.total * 100)) + \
                ('%0.9d' % (batch.total * 100)) + \
                '000000000' + ('%0.3d' % batch.number) + \
                filler(1+1+4+12+12+3+9+32)
        write128(output_file, end_6)
        nb_lines += 1
        nb_batches += 1

    if nb_lines > 990:
        # FIXME grouper les lots comme y fo pour que ca n'arrive jamais
        print "[FIXME] TROP DE LIGNES -- ", nb_lines
        raise

    end_999 = '999' +  TYPE_EMETTEUR + '00000' + NUMERO_EMETTEUR + \
            filler(6) + to + filler(6) + APPLICATION + \
            file_id + \
            ('%0.8d' % (nb_lines+1)) + \
            filler(19) + \
            ('%0.3d' % nb_batches) + \
            filler(43)
    write128(output_file, end_999)

    old_filename = output_file.name
    output_file.close()

    b2_filename = os.path.join(OUTPUT_DIRECTORY, prefix + 'b2')
    os.rename(old_filename, b2_filename)

    # create S/MIME mail
    mail_filename = build_mail(hc.large_regime.code, hc.dest_organism, b2_filename)

    return b2_filename, mail_filename

if __name__ == '__main__':
    sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calebasse.settings")
    from calebasse.facturation.models import Invoicing

    try:
        invoicing = Invoicing.objects.filter(seq_id=sys.argv[1])[0]
    except IndexError:
        raise RuntimeError('Facture introuvable')
    print 'Facturation', invoicing.seq_id
    batches = build_batches(invoicing)
    for hc in batches:
        print 'pour', hc
        for b in batches[hc]:
            print '  lot', b
            b2_filename, mail_filename = b2(invoicing.seq_id, hc, [b])
	    print '  B2    :', b2_filename
            print '  smime :', mail_filename
<commit_msg>facturation/b2: fix 2da86cbc9<commit_after># -*- coding: utf-8 -*-

# TODO / FIXME
# - lever une exception lorsque nb_lines dépasse 999 (et autres compteurs)

import os
import sys
import tempfile
import datetime
import hashlib
import base64

from batches import build_batches
from transmission_utils import build_mail

OUTPUT_DIRECTORY = '/var/lib/calebasse/B2/'

NORME = 'CP  '

TYPE_EMETTEUR = 'TE'
NUMERO_EMETTEUR = '420788606'
APPLICATION = 'TR'
MESSAGE = 'ENTROUVERT 0143350135 CALEBASSE 1301'
MESSAGE = MESSAGE + ' '*(37-len(MESSAGE))

CATEGORIE = '189'
STATUT = '60'
MODE_TARIF = '05'
NOM = 'CMPP SAINT ETIENNE'
NOM = NOM + ' '*(40-len(NOM))

def filler(n, car=' '):
    return car*n
def filler0(n):
    return filler(n, '0')
def b2date(d):
    return d.strftime('%y%m%d')
def get_control_key(nir):
    try:
        # Corse dpt 2A et 2B
        minus = 0
        if nir[6] in ('A', 'a'):
            nir = [c for c in nir]
            nir[6] = '0'
            nir = ''.join(nir)
            minus = 1000000
        elif nir[6] in ('B', 'b'):
            nir = [c for c in nir]
            nir[6] = '0'
            nir = ''.join(nir)
            minus = 2000000
        nir = int(nir) - minus
        return '%0.2d' % (97 - (nir % 97))
    except Exception, e:
        return '00'

def write128(output_file, line):
    if len(line) != 128:
        raise RuntimeError('length of this B2 line is %d != 128 : <<%s>>' %
                (len(line), line))
    output_file.write(line)

def write_invoice(output_file, invoice):
    invoice_lines = 0
    start_date = invoice.start_date
    start_2 = '2' + NUMERO_EMETTEUR + ' ' + \
            invoice.policy_holder_social_security_id + \
            get_control_key(invoice.policy_holder_social_security_id) + \
            '000' + ('%0.9d' % invoice.number) + \
            '1' + ('%0.9d' % invoice.patient_id) + \
            invoice.policy_holder_healthcenter.large_regime.code + \
            invoice.policy_holder_healthcenter.dest_organism + \
            (invoice.policy_holder_other_health_center or '0000') + \
            '3' + b2date(start_date) + '000000' + \
            invoice.policy_holder_healthcenter.dest_organism + '000' + \
            '10' + '3' +  \
            b2date(start_date) + \
            '000000000' + ' ' + \
            b2date(invoice.patient_birthdate) + \
            ('%d' %  invoice.patient_twinning_rank)[-1:] + \
            b2date(start_date) + b2date(invoice.end_date) + '01' + \
            '00' + filler(10)
    write128(output_file, start_2)
    invoice_lines += 1
    nb_type3 = 0
    kind = invoice.first_tag[0]
    prestation = u'SNS  ' if kind == 'T' else u'SD   '
    for date in invoice.list_dates.split('$'):
        line_3 = '3' + NUMERO_EMETTEUR + ' ' + \
                invoice.policy_holder_social_security_id + \
                get_control_key(invoice.policy_holder_social_security_id) + \
                '000' + ('%0.9d' % invoice.number) + \
                '19' + '320' + \
                b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
                b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
                prestation + '001' + \
                ' ' + '00100' +  ' ' + '00000' + \
                ('%0.7d' % invoice.ppa) + \
                ('%0.8d' % invoice.ppa) + \
                '100' + \
                ('%0.8d' % invoice.ppa) + \
                ('%0.8d' % invoice.ppa) + \
                '0000' + '000' + ' ' + filler(2) + ' ' + \
                ' ' + '0000000'
        write128(output_file, line_3)
        invoice_lines += 1
        nb_type3 += 1

    end_5 = '5' + NUMERO_EMETTEUR + ' ' + \
            invoice.policy_holder_social_security_id + \
            get_control_key(invoice.policy_holder_social_security_id) + \
            '000' + ('%0.9d' % invoice.number) + \
            ('%0.3d' % nb_type3) + \
            ('%0.8d' % invoice.amount) + \
            ('%0.8d' % invoice.amount) + \
            '00000000' + '00000000' + '00000000' + '00000000' + '00000000' + \
            filler(17) + \
            ('%0.8d' % invoice.amount) + \
            filler(4+2)
    write128(output_file, end_5)
    invoice_lines += 1

    return invoice_lines

def b2(seq_id, hc, batches):
    to = hc.b2_000()
    total = sum(b.total for b in batches)
    first_batch = min(b.number for b in batches)

    # B2 veut un identifiant de fichier sur 6 caractères alphanum
    hexdigest = hashlib.sha256('%s%s%s%s%s' % (seq_id, first_batch, NUMERO_EMETTEUR, to, total)).hexdigest()
    file_id = base64.encodestring(hexdigest).upper()[0:6]

    utcnow = datetime.datetime.utcnow()
    prefix = '%s-%s-%s-%s-%s.' % (seq_id, NUMERO_EMETTEUR, to, first_batch, file_id)
    output_file = tempfile.NamedTemporaryFile(suffix='.b2tmp',
            prefix=prefix, dir=OUTPUT_DIRECTORY, delete=False)
    nb_lines = 0

    start_000 = '000' +  TYPE_EMETTEUR + '00000' + NUMERO_EMETTEUR + \
            filler(6) + to + filler(6) + APPLICATION + \
            file_id + b2date(utcnow) + NORME + 'B2' + filler(15) + \
            '128' + filler(6) + MESSAGE
    write128(output_file, start_000)
    nb_lines += 1
    nb_batches = 0

    for batch in batches:
        start_1 = '1' + NUMERO_EMETTEUR + filler(6) + \
                batch.health_center.dest_organism[0:3] + \
                ('%0.3d' % batch.number) + CATEGORIE + STATUT + MODE_TARIF + \
                NOM + 'B2' + b2date(utcnow) + ' ' + NORME[0:2] + \
                ' ' + '062007' + 'U' + filler(2+3+1+34)
        write128(output_file, start_1)
        nb_lines += 1

        for i in batch.invoices:
            nb_lines += write_invoice(output_file, i)

        end_6 = '6' + NUMERO_EMETTEUR + \
                ('%0.3d' % batch.number_of_invoices) + \
                ('%0.4d' % batch.number_of_acts) + \
                ('%0.4d' % batch.number_of_invoices) + \
                ('%0.3d' % batch.number_of_invoices) + \
                ('%0.9d' % (batch.total * 100)) + \
                ('%0.9d' % (batch.total * 100)) + \
                '000000000' + ('%0.3d' % batch.number) + \
                filler(1+1+4+12+12+3+9+32)
        write128(output_file, end_6)
        nb_lines += 1
        nb_batches += 1

    if nb_lines > 990:
        # FIXME grouper les lots comme y fo pour que ca n'arrive jamais
        print "[FIXME] TROP DE LIGNES -- ", nb_lines
        raise

    end_999 = '999' +  TYPE_EMETTEUR + '00000' + NUMERO_EMETTEUR + \
            filler(6) + to + filler(6) + APPLICATION + \
            file_id + \
            ('%0.8d' % (nb_lines+1)) + \
            filler(19) + \
            ('%0.3d' % nb_batches) + \
            filler(43)
    write128(output_file, end_999)

    old_filename = output_file.name
    output_file.close()

    b2_filename = os.path.join(OUTPUT_DIRECTORY, prefix + 'b2')
    os.rename(old_filename, b2_filename)

    # create S/MIME mail
    mail_filename = build_mail(hc.large_regime.code, hc.dest_organism, b2_filename)

    return b2_filename, mail_filename

if __name__ == '__main__':
    sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calebasse.settings")
    from calebasse.facturation.models import Invoicing

    try:
        invoicing = Invoicing.objects.filter(seq_id=sys.argv[1])[0]
    except IndexError:
        raise RuntimeError('Facture introuvable')
    print 'Facturation', invoicing.seq_id
    batches = build_batches(invoicing)
    for hc in batches:
        print 'pour', hc
        for b in batches[hc]:
            print '  lot', b
            b2_filename, mail_filename = b2(invoicing.seq_id, hc, [b])
	    print '  B2    :', b2_filename
            print '  smime :', mail_filename
<|endoftext|>