<commit_before>from itertools import groupby
from collections import defaultdict, namedtuple
from couchdbkit import SchemaListProperty, SchemaProperty

from corehq.apps.userreports.expressions.getters import NestedDictGetter
from corehq.apps.app_manager.dbaccessors import get_built_app_ids_for_app_id
from corehq.apps.app_manager.models import Application
from dimagi.utils.couch.database import iter_docs
from dimagi.ext.couchdbkit import (
    Document,
    DocumentSchema,
    ListProperty,
    StringProperty,
    IntegerProperty,
)

Question = namedtuple('Question', [
    'type',
    'label',
    'value',
    'repeat',
    'group',
    'relevant',
    'required',
    'tag',
    'options',
    'translations',
    'calculate',
])
Question.__new__.__defaults__ = (None,) * len(Question._fields)  # Defaults all fields to None

class ExportItem(DocumentSchema):
    """
    An item for export.
    path is a question path like ["my_group", "q1"] or a case property name
    like ["date_of_birth"].
    """
    path = ListProperty()
    label = StringProperty()
    last_occurrence = IntegerProperty()

    @classmethod
    def create_from_question(cls, question, appVersion):
        return cls(
            path=_string_path_to_list(question.value),
            label=question.label,
            last_occurrence=appVersion,
        )

    @classmethod
    def merge(cls, one, two):
        item = cls(one.to_json())
        item.last_occurrence = max(one.last_occurrence, two.last_occurrence)
        return item

class ExportColumn(DocumentSchema):
    item = SchemaProperty(ExportItem)
    label = StringProperty()

    def get_value(self, doc, base_path):
        """
        Get the value of self.item of the given doc.
        When base_path is [], doc is a form submission or case,
        when base_path is non empty, doc is a repeat group from a form submission.
        :param doc: A form submission or instance of a repeat group in a submission or case
        :param base_path:
        :return:
        """
        # Confirm the ExportItem's path starts with the base_path
        assert base_path == self.item.path[:len(base_path)]
        # Get the path from the doc root to the desired ExportItem
        path = self.item.path[len(base_path):]
        return NestedDictGetter(path)(doc)

class TableConfiguration(DocumentSchema):

    name = StringProperty()
    repeat_path = StringProperty()
    columns = ListProperty(ExportColumn)

    def get_rows(self, document):
        """
        Return a list of ExportRows generated for the given document.
        :param document: dictionary representation of a form submission or case
        :return: List of ExportRows
        """
        # Note that repeat_items will be [document] if self.repeat_path is []
        repeat_items = self._get_items_for_repeat(self.repeat_path, [document])
        rows = []
        for item in repeat_items:
            row = ExportRow(data=[
                col.get_value(item, self.repeat_path) for col in self.columns
            ])
            rows.append(row)
        return rows

    def _get_items_for_repeat(self, path, docs):
        """
        Return each instance of a repeat group at the path from the given docs.
        If path is [], just return the docs

        >>> TableConfiguration()._get_items_for_repeat(['foo'], [{'foo': {'bar': 'a'}}, {'foo': {'bar': 'b'}}])
        [{'bar': 'a'}, {'bar': 'b'}]
        >>> TableConfiguration()._get_items_for_repeat(['foo', 'bar'], [{'foo': [{'bar': {'baz': 'a'}}, {'bar': {'baz': 'b'}},]}]
        [{'baz': 'a'}, {'baz': 'b'}]

        :param path: A list of a strings
        :param docs: A list of dicts representing form submissions
        :return:
        """
        if len(path) == 0:
            return docs

        new_docs = []
        for doc in docs:
            next_doc = doc.get(path[0], {})
            if type(next_doc) == list:
                new_docs.extend(next_doc)
            else:
                new_docs.append(next_doc)
        return self._get_items_for_repeat(path[1:], new_docs)

class ExportInstance(Document):

    class Meta:
        app_label = 'export'

class ExportRow(object):
    def __init__(self, data):
        self.data = data

class ScalarItem(ExportItem):
    """
    A text, numeric, date, etc. question or case property
    """

class Option(DocumentSchema):
    """
    This object represents a multiple choice question option.

    last_occurrence is an app build number representing the last version of the app in
    which this option was present.
    """
    last_occurrence = IntegerProperty()
    value = StringProperty()

class MultipleChoiceItem(ExportItem):
    """
    A multiple choice question or case property
    Choices is the union of choices for the question in each of the builds with
    this question.
    """
    options = SchemaListProperty(Option)

    @classmethod
    def create_from_question(cls, question, appVersion):
        item = super(MultipleChoiceItem, cls).create_from_question(question, appVersion)

        for option in question.options:
            item.options.append(Option(
                last_occurrence=appVersion,
                value=option['value']
            ))
        return item

    @classmethod
    def merge(cls, one, two):
        item = super(MultipleChoiceItem, cls).merge(one, two)
        options = _merge_lists(one.options, two.options,
            keyfn=lambda i: i.value,
            resolvefn=lambda option1, option2:
                Option(
                    value=option1.value,
                    last_occurrence=max(option1.last_occurrence, option2.last_occurrence)
                ),
            copyfn=lambda option: Option(option.to_json())
        )

        item.options = options
        return item

class ExportGroupSchema(DocumentSchema):
    """
    An object that represents a logical group of questions in the form
    """
    path = ListProperty()
    items = SchemaListProperty(ExportItem)
    last_occurrence = IntegerProperty()

class ExportDataSchema(DocumentSchema):
    """
    An object representing the things that can be exported for a particular
    form xmlns or case type.
    Each item in the list is uniquely identified by its path and doc_type.
    repeats is a list of RepeatGroups, present at any level of the question hierarchy
    """
    group_schemas = SchemaListProperty(ExportGroupSchema)
    datatype_mapping = defaultdict(lambda: ScalarItem, {
        'MSelect': MultipleChoiceItem,
    })

    @staticmethod
    def generate_schema_from_builds(domain, app_id, unique_form_id):
        app_build_ids = get_built_app_ids_for_app_id(domain, app_id)
        all_xform_conf = TableConfiguration()

        for app in iter_docs(Application.get_db(), app_build_ids):
            xform = app.get_form(unique_form_id).wrapped_xform()
            xform_conf = ExportDataSchema._generate_schema_from_xform(xform, app.langs, app.version)
            all_xform_conf = ExportDataSchema._merge_schema(all_xform_conf, xform_conf)

        return all_xform_conf

    @staticmethod
    def _generate_schema_from_xform(xform, langs, appVersion):
        questions = xform.get_questions(langs)
        schema = ExportDataSchema()

        for group_path, group_questions in groupby(questions, lambda q: q['repeat']):
            # If group_path is None, that means the questions are part of the form and not a repeat group
            # inside of the form
            group_schema = ExportGroupSchema(
                path=_string_path_to_list(group_path),
                last_occurrence=appVersion,
            )
            for question in group_questions:
                wrapped_question = Question(**question)

                # Create ExportItem based on the question type
                item = ExportDataSchema.datatype_mapping[wrapped_question.type].create_from_question(
                    wrapped_question,
                    appVersion,
                )
                group_schema.items.append(item)

            schema.group_schemas.append(group_schema)

        return schema

    @staticmethod
    def _merge_schema(schema1, schema2):
        """Merges two ExportDataSchemas together

        :param schema1: The first ExportDataSchema
        :param schema2: The second ExportDataSchema
        :returns: The merged ExportDataSchema
        """

        schema = ExportDataSchema()

        def resolvefn(group_schema1, group_schema2):
            group_schema = ExportGroupSchema(
                path=group_schema1.path,
                last_occurrence=max(group_schema1.last_occurrence, group_schema2.last_occurrence),
            )
            items = _merge_lists(
                group_schema1.items,
                group_schema2.items,
                keyfn=lambda item: '{}:{}'.format(_list_path_to_string(item.path), item.doc_type),
                resolvefn=lambda item1, item2: item1.__class__.merge(item1, item2),
                copyfn=lambda item: item.__class__(item.to_json()),
            )
            group_schema.items = items
            return group_schema

        group_schemas = _merge_lists(
            schema1.group_schemas,
            schema2.group_schemas,
            keyfn=lambda group_schema: _list_path_to_string(group_schema.path),
            resolvefn=resolvefn,
            copyfn=lambda group_schema: ExportGroupSchema(group_schema.to_json())
        )

        schema.group_schemas = group_schemas

        return schema

def _string_path_to_list(path):
    return path if path is None else path[1:].split('/')

def _list_path_to_string(path, separator='.'):
    if not path or (len(path) == 1 and path[0] is None):
        return ''
    return separator.join(path)

def _merge_lists(one, two, keyfn, resolvefn, copyfn):
    """Merges two lists. The alogorithm is to first iterate over the first list. If the item in the first list
    does not exist in the second list, add that item to the merged list. If the item does exist in the second
    list, resolve the conflict using the resolvefn. After the first list has been iterated over, simply append
    any items in the second list that have not already been added.

    :param one: The first list to be merged.
    :param two: The second list to be merged.
    :param keyfn: A function that takes an element from the list as an argument and returns a unique
        identifier for that item.
    :param resolvefn: A function that takes two elements that resolve to the same key and returns a single
        element that has resolved the conflict between the two elements.
    :param copyfn: A function that takes an element as its argument and returns a copy of it.
    :returns: A list of the merged elements
    """

    merged = []
    two_keys = set(map(lambda obj: keyfn(obj), two))

    for obj in one:

        if keyfn(obj) in two_keys:
            # If obj exists in both list, must merge
            two_keys.remove(keyfn(obj))
            new_obj = resolvefn(
                obj,
                filter(lambda other: keyfn(other) == keyfn(obj), two)[0],
            )
        else:
            new_obj = copyfn(obj)

        merged.append(new_obj)

    # Filter any objects we've already added by merging
    filtered = filter(lambda obj: keyfn(obj) in two_keys, two)
    merged.extend(
        # Map objects to new object
        map(lambda obj: copyfn(obj), filtered)
    )
    return merged
<commit_msg>Update doc strings<commit_after>from itertools import groupby
from collections import defaultdict, namedtuple
from couchdbkit import SchemaListProperty, SchemaProperty

from corehq.apps.userreports.expressions.getters import NestedDictGetter
from corehq.apps.app_manager.dbaccessors import get_built_app_ids_for_app_id
from corehq.apps.app_manager.models import Application
from dimagi.utils.couch.database import iter_docs
from dimagi.ext.couchdbkit import (
    Document,
    DocumentSchema,
    ListProperty,
    StringProperty,
    IntegerProperty,
)

Question = namedtuple('Question', [
    'type',
    'label',
    'value',
    'repeat',
    'group',
    'relevant',
    'required',
    'tag',
    'options',
    'translations',
    'calculate',
])
Question.__new__.__defaults__ = (None,) * len(Question._fields)  # Defaults all fields to None

class ExportItem(DocumentSchema):
    """
    An item for export.
    path is a question path like ["my_group", "q1"] or a case property name
    like ["date_of_birth"].
    """
    path = ListProperty()
    label = StringProperty()
    last_occurrence = IntegerProperty()

    @classmethod
    def create_from_question(cls, question, appVersion):
        return cls(
            path=_string_path_to_list(question.value),
            label=question.label,
            last_occurrence=appVersion,
        )

    @classmethod
    def merge(cls, one, two):
        item = cls(one.to_json())
        item.last_occurrence = max(one.last_occurrence, two.last_occurrence)
        return item

class ExportColumn(DocumentSchema):
    item = SchemaProperty(ExportItem)
    label = StringProperty()

    def get_value(self, doc, base_path):
        """
        Get the value of self.item of the given doc.
        When base_path is [], doc is a form submission or case,
        when base_path is non empty, doc is a repeat group from a form submission.
        :param doc: A form submission or instance of a repeat group in a submission or case
        :param base_path:
        :return:
        """
        # Confirm the ExportItem's path starts with the base_path
        assert base_path == self.item.path[:len(base_path)]
        # Get the path from the doc root to the desired ExportItem
        path = self.item.path[len(base_path):]
        return NestedDictGetter(path)(doc)

class TableConfiguration(DocumentSchema):

    name = StringProperty()
    repeat_path = StringProperty()
    columns = ListProperty(ExportColumn)

    def get_rows(self, document):
        """
        Return a list of ExportRows generated for the given document.
        :param document: dictionary representation of a form submission or case
        :return: List of ExportRows
        """
        # Note that repeat_items will be [document] if self.repeat_path is []
        repeat_items = self._get_items_for_repeat(self.repeat_path, [document])
        rows = []
        for item in repeat_items:
            row = ExportRow(data=[
                col.get_value(item, self.repeat_path) for col in self.columns
            ])
            rows.append(row)
        return rows

    def _get_items_for_repeat(self, path, docs):
        """
        Return each instance of a repeat group at the path from the given docs.
        If path is [], just return the docs

        >>> TableConfiguration()._get_items_for_repeat(['foo'], [{'foo': {'bar': 'a'}}, {'foo': {'bar': 'b'}}])
        [{'bar': 'a'}, {'bar': 'b'}]
        >>> TableConfiguration()._get_items_for_repeat(['foo', 'bar'], [{'foo': [{'bar': {'baz': 'a'}}, {'bar': {'baz': 'b'}},]}]
        [{'baz': 'a'}, {'baz': 'b'}]

        :param path: A list of a strings
        :param docs: A list of dicts representing form submissions
        :return:
        """
        if len(path) == 0:
            return docs

        new_docs = []
        for doc in docs:
            next_doc = doc.get(path[0], {})
            if type(next_doc) == list:
                new_docs.extend(next_doc)
            else:
                new_docs.append(next_doc)
        return self._get_items_for_repeat(path[1:], new_docs)

class ExportInstance(Document):

    class Meta:
        app_label = 'export'

class ExportRow(object):
    def __init__(self, data):
        self.data = data

class ScalarItem(ExportItem):
    """
    A text, numeric, date, etc. question or case property
    """

class Option(DocumentSchema):
    """
    This object represents a multiple choice question option.

    last_occurrence is an app build number representing the last version of the app in
    which this option was present.
    """
    last_occurrence = IntegerProperty()
    value = StringProperty()

class MultipleChoiceItem(ExportItem):
    """
    A multiple choice question or case property
    Choices is the union of choices for the question in each of the builds with
    this question.
    """
    options = SchemaListProperty(Option)

    @classmethod
    def create_from_question(cls, question, appVersion):
        item = super(MultipleChoiceItem, cls).create_from_question(question, appVersion)

        for option in question.options:
            item.options.append(Option(
                last_occurrence=appVersion,
                value=option['value']
            ))
        return item

    @classmethod
    def merge(cls, one, two):
        item = super(MultipleChoiceItem, cls).merge(one, two)
        options = _merge_lists(one.options, two.options,
            keyfn=lambda i: i.value,
            resolvefn=lambda option1, option2:
                Option(
                    value=option1.value,
                    last_occurrence=max(option1.last_occurrence, option2.last_occurrence)
                ),
            copyfn=lambda option: Option(option.to_json())
        )

        item.options = options
        return item

class ExportGroupSchema(DocumentSchema):
    """
    An object representing the `ExportItem`s that would appear in a single export table, such as all the
    questions in a particular repeat group, or all the questions not in any repeat group.
    """
    path = ListProperty()
    items = SchemaListProperty(ExportItem)
    last_occurrence = IntegerProperty()

class ExportDataSchema(DocumentSchema):
    """
    An object representing the things that can be exported for a particular
    form xmlns or case type. It contains a list of ExportGroupSchema.
    """
    group_schemas = SchemaListProperty(ExportGroupSchema)
    datatype_mapping = defaultdict(lambda: ScalarItem, {
        'MSelect': MultipleChoiceItem,
    })

    @staticmethod
    def generate_schema_from_builds(domain, app_id, unique_form_id):
        app_build_ids = get_built_app_ids_for_app_id(domain, app_id)
        all_xform_conf = TableConfiguration()

        for app in iter_docs(Application.get_db(), app_build_ids):
            xform = app.get_form(unique_form_id).wrapped_xform()
            xform_conf = ExportDataSchema._generate_schema_from_xform(xform, app.langs, app.version)
            all_xform_conf = ExportDataSchema._merge_schema(all_xform_conf, xform_conf)

        return all_xform_conf

    @staticmethod
    def _generate_schema_from_xform(xform, langs, appVersion):
        questions = xform.get_questions(langs)
        schema = ExportDataSchema()

        for group_path, group_questions in groupby(questions, lambda q: q['repeat']):
            # If group_path is None, that means the questions are part of the form and not a repeat group
            # inside of the form
            group_schema = ExportGroupSchema(
                path=_string_path_to_list(group_path),
                last_occurrence=appVersion,
            )
            for question in group_questions:
                wrapped_question = Question(**question)

                # Create ExportItem based on the question type
                item = ExportDataSchema.datatype_mapping[wrapped_question.type].create_from_question(
                    wrapped_question,
                    appVersion,
                )
                group_schema.items.append(item)

            schema.group_schemas.append(group_schema)

        return schema

    @staticmethod
    def _merge_schema(schema1, schema2):
        """Merges two ExportDataSchemas together

        :param schema1: The first ExportDataSchema
        :param schema2: The second ExportDataSchema
        :returns: The merged ExportDataSchema
        """

        schema = ExportDataSchema()

        def resolvefn(group_schema1, group_schema2):
            group_schema = ExportGroupSchema(
                path=group_schema1.path,
                last_occurrence=max(group_schema1.last_occurrence, group_schema2.last_occurrence),
            )
            items = _merge_lists(
                group_schema1.items,
                group_schema2.items,
                keyfn=lambda item: '{}:{}'.format(_list_path_to_string(item.path), item.doc_type),
                resolvefn=lambda item1, item2: item1.__class__.merge(item1, item2),
                copyfn=lambda item: item.__class__(item.to_json()),
            )
            group_schema.items = items
            return group_schema

        group_schemas = _merge_lists(
            schema1.group_schemas,
            schema2.group_schemas,
            keyfn=lambda group_schema: _list_path_to_string(group_schema.path),
            resolvefn=resolvefn,
            copyfn=lambda group_schema: ExportGroupSchema(group_schema.to_json())
        )

        schema.group_schemas = group_schemas

        return schema

def _string_path_to_list(path):
    return path if path is None else path[1:].split('/')

def _list_path_to_string(path, separator='.'):
    if not path or (len(path) == 1 and path[0] is None):
        return ''
    return separator.join(path)

def _merge_lists(one, two, keyfn, resolvefn, copyfn):
    """Merges two lists. The alogorithm is to first iterate over the first list. If the item in the first list
    does not exist in the second list, add that item to the merged list. If the item does exist in the second
    list, resolve the conflict using the resolvefn. After the first list has been iterated over, simply append
    any items in the second list that have not already been added.

    :param one: The first list to be merged.
    :param two: The second list to be merged.
    :param keyfn: A function that takes an element from the list as an argument and returns a unique
        identifier for that item.
    :param resolvefn: A function that takes two elements that resolve to the same key and returns a single
        element that has resolved the conflict between the two elements.
    :param copyfn: A function that takes an element as its argument and returns a copy of it.
    :returns: A list of the merged elements
    """

    merged = []
    two_keys = set(map(lambda obj: keyfn(obj), two))

    for obj in one:

        if keyfn(obj) in two_keys:
            # If obj exists in both list, must merge
            two_keys.remove(keyfn(obj))
            new_obj = resolvefn(
                obj,
                filter(lambda other: keyfn(other) == keyfn(obj), two)[0],
            )
        else:
            new_obj = copyfn(obj)

        merged.append(new_obj)

    # Filter any objects we've already added by merging
    filtered = filter(lambda obj: keyfn(obj) in two_keys, two)
    merged.extend(
        # Map objects to new object
        map(lambda obj: copyfn(obj), filtered)
    )
    return merged
<|endoftext|>


<commit_before>from collections import namedtuple

from corehq import privileges, toggles
from corehq.apps.accounting.utils import domain_has_privilege

FORM_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.ExcelExportReport'
DEID_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.DeidExportReport'
CASE_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.CaseExportReport'
ODATA_FEED_PERMISSION = 'corehq.apps.reports.standard.export.ODataFeedListView'
SMS_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.SMSExportReport'

EXPORT_PERMISSIONS = {
    FORM_EXPORT_PERMISSION,
    DEID_EXPORT_PERMISSION,
    CASE_EXPORT_PERMISSION,
    ODATA_FEED_PERMISSION,
}

ReportPermission = namedtuple('ReportPermission', ['slug', 'title', 'is_visible'])

def get_extra_permissions():
    from corehq.apps.export.views.list import (
        FormExportListView,
        DeIdFormExportListView,
        CaseExportListView,
        ODataFeedListView,
    )
    from corehq.apps.export.views.download import DownloadNewSmsExportView
    yield ReportPermission(
        FORM_EXPORT_PERMISSION, FormExportListView.page_title, lambda domain: True)
    yield ReportPermission(
        DEID_EXPORT_PERMISSION, DeIdFormExportListView.page_title,
        lambda domain: domain_has_privilege(domain, privileges.DEIDENTIFIED_DATA))
    yield ReportPermission(
        CASE_EXPORT_PERMISSION, CaseExportListView.page_title, lambda domain: True)
    yield ReportPermission(
        SMS_EXPORT_PERMISSION, DownloadNewSmsExportView.page_title, lambda domain: True)
    yield ReportPermission(
        ODATA_FEED_PERMISSION, ODataFeedListView.page_title,
        lambda domain: domain_has_privilege(domain, privileges.ODATA_FEED)
    )

def can_download_data_files(domain, couch_user):
    return _has_data_file_permission(domain, couch_user, read_only=True)

def can_upload_data_files(domain, couch_user):
    return _has_data_file_permission(domain, couch_user, read_only=False)

def _has_data_file_permission(domain, couch_user, read_only=True):
    from corehq.apps.users.models import DomainMembershipError
    try:
        role = couch_user.get_role(domain)
    except DomainMembershipError:
        return False

    if not (role and toggles.DATA_FILE_DOWNLOAD.enabled(domain)):
        return False

    return role.permissions.edit_file_dropzone or (read_only and role.permissions.view_file_dropzone)

def can_view_sms_exports(couch_user, domain):
    return has_permission_to_view_report(
        couch_user, domain, SMS_EXPORT_PERMISSION
    )

def has_permission_to_view_report(couch_user, domain, report_to_check):
    from corehq.apps.users.decorators import get_permission_name
    from corehq.apps.users.models import Permissions
    return (
        couch_user.can_view_reports(domain) or
        couch_user.has_permission(
            domain,
            get_permission_name(Permissions.view_report),
            data=report_to_check
        )
    )

def can_manage_releases(couch_user, domain, app_id):
    if _can_manage_releases_for_all_apps(couch_user, domain):
        return True
    role = couch_user.get_role(domain)
    return app_id in role.permissions.manage_releases_list

def _can_manage_releases_for_all_apps(couch_user, domain):
    from corehq.apps.users.decorators import get_permission_name
    from corehq.apps.users.models import Permissions
    restricted_app_release = toggles.RESTRICT_APP_RELEASE.enabled(domain)
    if not restricted_app_release:
        return True
    return couch_user.has_permission(
        domain, get_permission_name(Permissions.manage_releases),
        restrict_global_admin=True
    )
<commit_msg>rename de-id export permission<commit_after>from collections import namedtuple

from django.utils.translation import ugettext_noop

from corehq import privileges, toggles
from corehq.apps.accounting.utils import domain_has_privilege

FORM_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.ExcelExportReport'
DEID_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.DeidExportReport'
CASE_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.CaseExportReport'
ODATA_FEED_PERMISSION = 'corehq.apps.reports.standard.export.ODataFeedListView'
SMS_EXPORT_PERMISSION = 'corehq.apps.reports.standard.export.SMSExportReport'

EXPORT_PERMISSIONS = {
    FORM_EXPORT_PERMISSION,
    DEID_EXPORT_PERMISSION,
    CASE_EXPORT_PERMISSION,
    ODATA_FEED_PERMISSION,
}

ReportPermission = namedtuple('ReportPermission', ['slug', 'title', 'is_visible'])

def get_extra_permissions():
    from corehq.apps.export.views.list import (
        FormExportListView,
        CaseExportListView,
        ODataFeedListView,
    )
    from corehq.apps.export.views.download import DownloadNewSmsExportView
    yield ReportPermission(
        FORM_EXPORT_PERMISSION, FormExportListView.page_title, lambda domain: True)
    yield ReportPermission(
        DEID_EXPORT_PERMISSION, ugettext_noop("Export De-Identified Data"),
        lambda domain: domain_has_privilege(domain, privileges.DEIDENTIFIED_DATA))
    yield ReportPermission(
        CASE_EXPORT_PERMISSION, CaseExportListView.page_title, lambda domain: True)
    yield ReportPermission(
        SMS_EXPORT_PERMISSION, DownloadNewSmsExportView.page_title, lambda domain: True)
    yield ReportPermission(
        ODATA_FEED_PERMISSION, ODataFeedListView.page_title,
        lambda domain: domain_has_privilege(domain, privileges.ODATA_FEED)
    )

def can_download_data_files(domain, couch_user):
    return _has_data_file_permission(domain, couch_user, read_only=True)

def can_upload_data_files(domain, couch_user):
    return _has_data_file_permission(domain, couch_user, read_only=False)

def _has_data_file_permission(domain, couch_user, read_only=True):
    from corehq.apps.users.models import DomainMembershipError
    try:
        role = couch_user.get_role(domain)
    except DomainMembershipError:
        return False

    if not (role and toggles.DATA_FILE_DOWNLOAD.enabled(domain)):
        return False

    return role.permissions.edit_file_dropzone or (read_only and role.permissions.view_file_dropzone)

def can_view_sms_exports(couch_user, domain):
    return has_permission_to_view_report(
        couch_user, domain, SMS_EXPORT_PERMISSION
    )

def has_permission_to_view_report(couch_user, domain, report_to_check):
    from corehq.apps.users.decorators import get_permission_name
    from corehq.apps.users.models import Permissions
    return (
        couch_user.can_view_reports(domain) or
        couch_user.has_permission(
            domain,
            get_permission_name(Permissions.view_report),
            data=report_to_check
        )
    )

def can_manage_releases(couch_user, domain, app_id):
    if _can_manage_releases_for_all_apps(couch_user, domain):
        return True
    role = couch_user.get_role(domain)
    return app_id in role.permissions.manage_releases_list

def _can_manage_releases_for_all_apps(couch_user, domain):
    from corehq.apps.users.decorators import get_permission_name
    from corehq.apps.users.models import Permissions
    restricted_app_release = toggles.RESTRICT_APP_RELEASE.enabled(domain)
    if not restricted_app_release:
        return True
    return couch_user.has_permission(
        domain, get_permission_name(Permissions.manage_releases),
        restrict_global_admin=True
    )
<|endoftext|>


<commit_before># Added Fortran compiler support to config. Currently useful only for
# try_compile call. try_run works but is untested for most of Fortran
# compilers (they must define linker_exe first).
# Pearu Peterson

import os, signal
from distutils.command.config import config as old_config
from distutils.command.config import LANG_EXT
from distutils import log
from numpy.distutils.exec_command import exec_command

LANG_EXT['f77'] = '.f'
LANG_EXT['f90'] = '.f90'

class config(old_config):
    old_config.user_options += [
        ('fcompiler=', None,
         "specify the Fortran compiler type"),
        ]

    def initialize_options(self):
        self.fcompiler = None
        old_config.initialize_options(self)
        return

    def finalize_options(self):
        old_config.finalize_options(self)
        f = self.distribution.get_command_obj('config_fc')
        self.set_undefined_options('config_fc',
                                   ('fcompiler', 'fcompiler'))
        return

    def _check_compiler (self):
        old_config._check_compiler(self)
        from numpy.distutils.fcompiler import FCompiler, new_fcompiler
        if not isinstance(self.fcompiler, FCompiler):
            self.fcompiler = new_fcompiler(compiler=self.fcompiler,
                                           dry_run=self.dry_run, force=1)
            self.fcompiler.customize(self.distribution)
            self.fcompiler.customize_cmd(self)
            self.fcompiler.show_customization()
        return

    def _wrap_method(self,mth,lang,args):
        from distutils.ccompiler import CompileError
        from distutils.errors import DistutilsExecError
        save_compiler = self.compiler
        if lang in ['f77','f90']:
            self.compiler = self.fcompiler
        try:
            ret = mth(*((self,)+args))
        except (DistutilsExecError,CompileError),msg:
            self.compiler = save_compiler
            raise CompileError
        self.compiler = save_compiler
        return ret

    def _compile (self, body, headers, include_dirs, lang):
        return self._wrap_method(old_config._compile,lang,
                                 (body, headers, include_dirs, lang))

    def _link (self, body,
               headers, include_dirs,
               libraries, library_dirs, lang):
        return self._wrap_method(old_config._link,lang,
                                 (body, headers, include_dirs,
                                  libraries, library_dirs, lang))

    def check_func(self, func,
                   headers=None, include_dirs=None,
                   libraries=None, library_dirs=None,
                   decl=False, call=False, call_args=None):
        # clean up distutils's config a bit: add void to main(), and
        # return a value.
        self._check_compiler()
        body = []
        if decl:
            body.append("int %s ();" % func)
        body.append("int main (void) {")
        if call:
            if call_args is None:
                call_args = ''
            body.append("  %s(%s);" % (func, call_args))
        else:
            body.append("  %s;" % func)
        body.append("  return 0;")
        body.append("}")
        body = '\n'.join(body) + "\n"

        return self.try_link(body, headers, include_dirs,
                             libraries, library_dirs)

    def get_output(self, body, headers=None, include_dirs=None,
                   libraries=None, library_dirs=None,
                   lang="c"):
        """Try to compile, link to an executable, and run a program
        built from 'body' and 'headers'. Returns the exit status code
        of the program and its output.
        """
        from distutils.ccompiler import CompileError, LinkError
        self._check_compiler()
        exitcode, output = 255, ''
        try:
            src, obj, exe = self._link(body, headers, include_dirs,
                                       libraries, library_dirs, lang)
            exe = os.path.join('.', exe)
            exitstatus, output = exec_command(exe, execute_in='.')
            exitcode = os.WEXITSTATUS(exitstatus)
            if os.WIFSIGNALED(exitstatus):
                sig = os.WTERMSIG(exitstatus)
                log.error('subprocess exited with signal %d' % (sig,))
                if sig == signal.SIGINT:
                    # control-C
                    raise KeyboardInterrupt
            ok = exitstatus == 0
            ok = 1
        except (CompileError, LinkError):
            ok = 0

        log.info(ok and "success!" or "failure.")
        self._clean()
        return exitcode, output

<commit_msg>Fix use of os.WEXITSTATUS and friends: only use if they exist<commit_after># Added Fortran compiler support to config. Currently useful only for
# try_compile call. try_run works but is untested for most of Fortran
# compilers (they must define linker_exe first).
# Pearu Peterson

import os, signal
from distutils.command.config import config as old_config
from distutils.command.config import LANG_EXT
from distutils import log
from numpy.distutils.exec_command import exec_command

LANG_EXT['f77'] = '.f'
LANG_EXT['f90'] = '.f90'

class config(old_config):
    old_config.user_options += [
        ('fcompiler=', None,
         "specify the Fortran compiler type"),
        ]

    def initialize_options(self):
        self.fcompiler = None
        old_config.initialize_options(self)
        return

    def finalize_options(self):
        old_config.finalize_options(self)
        f = self.distribution.get_command_obj('config_fc')
        self.set_undefined_options('config_fc',
                                   ('fcompiler', 'fcompiler'))
        return

    def _check_compiler (self):
        old_config._check_compiler(self)
        from numpy.distutils.fcompiler import FCompiler, new_fcompiler
        if not isinstance(self.fcompiler, FCompiler):
            self.fcompiler = new_fcompiler(compiler=self.fcompiler,
                                           dry_run=self.dry_run, force=1)
            self.fcompiler.customize(self.distribution)
            self.fcompiler.customize_cmd(self)
            self.fcompiler.show_customization()
        return

    def _wrap_method(self,mth,lang,args):
        from distutils.ccompiler import CompileError
        from distutils.errors import DistutilsExecError
        save_compiler = self.compiler
        if lang in ['f77','f90']:
            self.compiler = self.fcompiler
        try:
            ret = mth(*((self,)+args))
        except (DistutilsExecError,CompileError),msg:
            self.compiler = save_compiler
            raise CompileError
        self.compiler = save_compiler
        return ret

    def _compile (self, body, headers, include_dirs, lang):
        return self._wrap_method(old_config._compile,lang,
                                 (body, headers, include_dirs, lang))

    def _link (self, body,
               headers, include_dirs,
               libraries, library_dirs, lang):
        return self._wrap_method(old_config._link,lang,
                                 (body, headers, include_dirs,
                                  libraries, library_dirs, lang))

    def check_func(self, func,
                   headers=None, include_dirs=None,
                   libraries=None, library_dirs=None,
                   decl=False, call=False, call_args=None):
        # clean up distutils's config a bit: add void to main(), and
        # return a value.
        self._check_compiler()
        body = []
        if decl:
            body.append("int %s ();" % func)
        body.append("int main (void) {")
        if call:
            if call_args is None:
                call_args = ''
            body.append("  %s(%s);" % (func, call_args))
        else:
            body.append("  %s;" % func)
        body.append("  return 0;")
        body.append("}")
        body = '\n'.join(body) + "\n"

        return self.try_link(body, headers, include_dirs,
                             libraries, library_dirs)

    def get_output(self, body, headers=None, include_dirs=None,
                   libraries=None, library_dirs=None,
                   lang="c"):
        """Try to compile, link to an executable, and run a program
        built from 'body' and 'headers'. Returns the exit status code
        of the program and its output.
        """
        from distutils.ccompiler import CompileError, LinkError
        self._check_compiler()
        exitcode, output = 255, ''
        try:
            src, obj, exe = self._link(body, headers, include_dirs,
                                       libraries, library_dirs, lang)
            exe = os.path.join('.', exe)
            exitstatus, output = exec_command(exe, execute_in='.')
            if hasattr(os, 'WEXITSTATUS'):
                exitcode = os.WEXITSTATUS(exitstatus)
                if os.WIFSIGNALED(exitstatus):
                    sig = os.WTERMSIG(exitstatus)
                    log.error('subprocess exited with signal %d' % (sig,))
                    if sig == signal.SIGINT:
                        # control-C
                        raise KeyboardInterrupt
            else:
                exitcode = exitstatus
            log.info("success!")
        except (CompileError, LinkError):
            log.info("failure.")

        self._clean()
        return exitcode, output

<|endoftext|>


<commit_before>#!/usr/bin/python

# takes templated file .xxx.src and produces .xxx file  where .xxx is .i or .c or .h
#  using the following template rules

# /**begin repeat     on a line by itself marks the beginning of a segment of code to be repeated
# /**end repeat**/    on a line by itself marks it's end

# after the /**begin repeat and before the */
#  all the named templates are placed
#  these should all have the same number of replacements

#  in the main body, the names are used.
#  Each replace will use one entry from the list of named replacements

#  Note that all #..# forms in a block must have the same number of
#    comma-separated entries.

__all__ = ['process_str', 'process_file']

import os
import sys
import re

def parse_structure(astr):
    spanlist = []
    # subroutines
    ind = 0
    line = 1
    while 1:
        start = astr.find("/**begin repeat", ind)
        if start == -1:
            break
        start2 = astr.find("*/",start)
        start2 = astr.find("\n",start2)
        fini1 = astr.find("/**end repeat**/",start2)
        fini2 = astr.find("\n",fini1)
        line += astr.count("\n", ind, start2+1)
        spanlist.append((start, start2+1, fini1, fini2+1, line))
        line += astr.count("\n", start2+1, fini2)
        ind = fini2
    spanlist.sort()
    return spanlist

# return n copies of substr with template replacement
_special_names = {}

template_re = re.compile(r"@([\w]+)@")
named_re = re.compile(r"#([\w]*)=([^#]*?)#")

parenrep = re.compile(r"[(]([^)]*?)[)]\*(\d+)")
def paren_repl(obj):
    torep = obj.group(1)
    numrep = obj.group(2)
    return ','.join([torep]*int(numrep))

plainrep = re.compile(r"([^*]+)\*(\d+)")

def conv(astr):
    # replaces all occurrences of '(a,b,c)*4' in astr
    #  with 'a,b,c,a,b,c,a,b,c,a,b,c'
    astr = parenrep.sub(paren_repl,astr)
    # replaces occurences of xxx*3 with xxx, xxx, xxx
    astr = ','.join([plainrep.sub(paren_repl,x.strip())
                     for x in astr.split(',')])
    return astr

def unique_key(adict):
    # this obtains a unique key given a dictionary
    # currently it works by appending together n of the letters of the
    #   current keys and increasing n until a unique key is found
    # -- not particularly quick
    allkeys = adict.keys()
    done = False
    n = 1
    while not done:
        newkey = "".join([x[:n] for x in allkeys])
        if newkey in allkeys:
            n += 1
        else:
            done = True
    return newkey

def expand_sub(substr, namestr, line):
    # find all named replacements
    reps = named_re.findall(namestr)
    names = {}
    names.update(_special_names)
    numsubs = None
    for rep in reps:
        name = rep[0].strip()
        thelist = conv(rep[1])
        names[name] = thelist

    # make lists out of string entries in name dictionary
    for name in names.keys():
        entry = names[name]
        entrylist = entry.split(',')
        names[name] = entrylist
        num = len(entrylist)
        if numsubs is None:
            numsubs = num
        elif numsubs != num:
            print namestr
            print substr
            raise ValueError, "Mismatch in number to replace"

    # now replace all keys for each of the lists
    mystr = ''
    thissub = [None]
    def namerepl(match):
        name = match.group(1)
        return names[name][thissub[0]]
    for k in range(numsubs):
        thissub[0] = k
        mystr += ("#line %d\n%s\n\n"
                  % (line, template_re.sub(namerepl, substr)))
    return mystr

_head = \
"""/*  This file was autogenerated from a template  DO NOT EDIT!!!!
       Changes should be made to the original source (.src) file
*/

"""

def get_line_header(str,beg):
    extra = []
    ind = beg-1
    char = str[ind]
    while (ind > 0) and (char != '\n'):
        extra.insert(0,char)
        ind = ind - 1
        char = str[ind]
    return ''.join(extra)

def process_str(allstr):
    newstr = allstr
    writestr = _head

    struct = parse_structure(newstr)
    #  return a (sorted) list of tuples for each begin repeat section
    #  each tuple is the start and end of a region to be template repeated

    oldend = 0
    for sub in struct:
        writestr += newstr[oldend:sub[0]]
        expanded = expand_sub(newstr[sub[1]:sub[2]],
                              newstr[sub[0]:sub[1]], sub[4])
        writestr += expanded
        oldend =  sub[3]

    writestr += newstr[oldend:]
    return writestr

include_src_re = re.compile(r"(\n|\A)#include\s*['\"]"
                            r"(?P<name>[\w\d./\\]+[.]src)['\"]", re.I)

def resolve_includes(source):
    d = os.path.dirname(source)
    fid = open(source)
    lines = []
    for line in fid.readlines():
        m = include_src_re.match(line)
        if m:
            fn = m.group('name')
            if not os.path.isabs(fn):
                fn = os.path.join(d,fn)
            if os.path.isfile(fn):
                print 'Including file',fn
                lines.extend(resolve_includes(fn))
            else:
                lines.append(line)
        else:
            lines.append(line)
    fid.close()
    return lines

def process_file(source):
    lines = resolve_includes(source)
    sourcefile = os.path.normcase(source).replace("\\","\\\\")
    return ('#line 1 "%s"\n%s'
            % (sourcefile, process_str(''.join(lines))))

if __name__ == "__main__":

    try:
        file = sys.argv[1]
    except IndexError:
        fid = sys.stdin
        outfile = sys.stdout
    else:
        fid = open(file,'r')
        (base, ext) = os.path.splitext(file)
        newname = base
        outfile = open(newname,'w')

    allstr = fid.read()
    writestr = process_str(allstr)
    outfile.write(writestr)
<commit_msg>Update conv_template file.<commit_after>#!/usr/bin/python
"""
takes templated file .xxx.src and produces .xxx file  where .xxx is
.i or .c or .h, using the following template rules

/**begin repeat  -- on a line by itself marks the start of a repeated code
                    segment
/**end repeat**/ -- on a line by itself marks it's end

After the /**begin repeat and before the */, all the named templates are placed
these should all have the same number of replacements

Repeat blocks can be nested, with each nested block labeled with its depth,
i.e.
/**begin repeat1
 *....
 */
/**end repeat1**/

In the main body each replace will use one entry from the list of named replacements

 Note that all #..# forms in a block must have the same number of
   comma-separated entries.

Example:

    An input file containing

        /**begin repeat
         * #a = 1,2,3#
         * #b = 1,2,3#
         */

        /**begin repeat1
         * #c = ted, jim#
         */
        @a@, @b@, @c@
        /**end repeat1**/

        /**end repeat**/

    produces

        line 1 "template.c.src"

        /*
         *********************************************************************
         **       This file was autogenerated from a template  DO NOT EDIT!!**
         **       Changes should be made to the original source (.src) file **
         *********************************************************************
         */

        #line 9
        1, 1, ted

        #line 9
        1, 1, jim

        #line 9
        2, 2, ted

        #line 9
        2, 2, jim

        #line 9
        3, 3, ted

        #line 9
        3, 3, jim

"""

__all__ = ['process_str', 'process_file']

import os
import sys
import re

# names for replacement that are already global.
global_names = {}

# header placed at the front of head processed file
header =\
"""
/*
 *****************************************************************************
 **       This file was autogenerated from a template  DO NOT EDIT!!!!      **
 **       Changes should be made to the original source (.src) file         **
 *****************************************************************************
 */

"""
# Parse string for repeat loops
def parse_structure(astr, level):
    """
    The returned line number is from the beginning of the string, starting
    at zero. Returns an empty list if no loops found.

    """
    if level == 0 :
        loopbeg = "/**begin repeat"
        loopend = "/**end repeat**/"
    else :
        loopbeg = "/**begin repeat%d" % level
        loopend = "/**end repeat%d**/" % level

    ind = 0
    line = 0
    spanlist = []
    while 1:
        start = astr.find(loopbeg, ind)
        if start == -1:
            break
        start2 = astr.find("*/",start)
        start2 = astr.find("\n",start2)
        fini1 = astr.find(loopend,start2)
        fini2 = astr.find("\n",fini1)
        line += astr.count("\n", ind, start2+1)
        spanlist.append((start, start2+1, fini1, fini2+1, line))
        line += astr.count("\n", start2+1, fini2)
        ind = fini2
    spanlist.sort()
    return spanlist

def paren_repl(obj):
    torep = obj.group(1)
    numrep = obj.group(2)
    return ','.join([torep]*int(numrep))

parenrep = re.compile(r"[(]([^)]*?)[)]\*(\d+)")
plainrep = re.compile(r"([^*]+)\*(\d+)")
def conv(astr):
    # replaces all occurrences of '(a,b,c)*4' in astr
    #  with 'a,b,c,a,b,c,a,b,c,a,b,c'. The result is
    # split at ',' and a list of values returned.
    astr = parenrep.sub(paren_repl,astr)
    # replaces occurences of xxx*3 with xxx, xxx, xxx
    astr = ','.join([plainrep.sub(paren_repl,x.strip())
                     for x in astr.split(',')])
    return astr.split(',')

named_re = re.compile(r"#\s*([\w]*)\s*=\s*([^#]*)#")
def parse_loop_header(loophead) :
    """Find all named replacements in the header

    Returns a list of dictionaries, one for each loop iteration,
    where each key is a name to be substituted and the corresponding
    value is the replacement string.

    """
    # parse out the names and lists of values
    names = []
    reps = named_re.findall(loophead)
    nsub = None
    for rep in reps:
        name = rep[0].strip()
        vals = conv(rep[1])
        size = len(vals)
        if nsub is None :
            nsub = size
        elif nsub != size :
            msg = "Mismatch in number: %s - %s" % (name, vals)
            raise ValueError, msg
        names.append((name,vals))

    # generate list of dictionaries, one for each template iteration
    dlist = []
    for i in range(nsub) :
        tmp = {}
        for name,vals in names :
            tmp[name] = vals[i]
        dlist.append(tmp)
    return dlist

replace_re = re.compile(r"@([\w]+)@")
def parse_string(astr, env, level, line) :
    lineno = "#line %d\n" % line

    # local function for string replacement, uses env
    def replace(match):
        name = match.group(1)
        try :
            val = env[name]
        except KeyError, e :
            msg = '%s: %s'%(lineno, e)
            raise KeyError, msg
        return val

    code = [lineno]
    struct = parse_structure(astr, level)
    if struct :
        # recurse over inner loops
        oldend = 0
        newlevel = level + 1
        for sub in struct:
            pref = astr[oldend:sub[0]]
            head = astr[sub[0]:sub[1]]
            text = astr[sub[1]:sub[2]]
            oldend = sub[3]
            newline = line + sub[4]
            code.append(replace_re.sub(replace, pref))
            try :
                envlist = parse_loop_header(head)
            except ValueError, e :
                msg = "%s: %s" % (lineno, e)
                raise ValueError, msg
            for newenv in envlist :
                newenv.update(env)
                newcode = parse_string(text, newenv, newlevel, newline)
                code.extend(newcode)
        suff = astr[oldend:]
        code.append(replace_re.sub(replace, suff))
    else :
        # replace keys
        code.append(replace_re.sub(replace, astr))
    code.append('\n')
    return ''.join(code)

def process_str(astr):
    code = [header]
    code.extend(parse_string(astr, global_names, 0, 1))
    return ''.join(code)

include_src_re = re.compile(r"(\n|\A)#include\s*['\"]"
                            r"(?P<name>[\w\d./\\]+[.]src)['\"]", re.I)

def resolve_includes(source):
    d = os.path.dirname(source)
    fid = open(source)
    lines = []
    for line in fid.readlines():
        m = include_src_re.match(line)
        if m:
            fn = m.group('name')
            if not os.path.isabs(fn):
                fn = os.path.join(d,fn)
            if os.path.isfile(fn):
                print 'Including file',fn
                lines.extend(resolve_includes(fn))
            else:
                lines.append(line)
        else:
            lines.append(line)
    fid.close()
    return lines

def process_file(source):
    lines = resolve_includes(source)
    sourcefile = os.path.normcase(source).replace("\\","\\\\")
    code = process_str(''.join(lines))
    return '#line 1 "%s"\n%s' % (sourcefile, code)

def unique_key(adict):
    # this obtains a unique key given a dictionary
    # currently it works by appending together n of the letters of the
    #   current keys and increasing n until a unique key is found
    # -- not particularly quick
    allkeys = adict.keys()
    done = False
    n = 1
    while not done:
        newkey = "".join([x[:n] for x in allkeys])
        if newkey in allkeys:
            n += 1
        else:
            done = True
    return newkey

if __name__ == "__main__":

    try:
        file = sys.argv[1]
    except IndexError:
        fid = sys.stdin
        outfile = sys.stdout
    else:
        fid = open(file,'r')
        (base, ext) = os.path.splitext(file)
        newname = base
        outfile = open(newname,'w')

    allstr = fid.read()
    writestr = process_str(allstr)
    outfile.write(writestr)

<|endoftext|>


<commit_before>"""
yubistack.wsgi
~~~~~~~~~~~~~~

WSGI wrappers around the yubistack functions
to support backward compatibility.
"""

import logging
import re

from yubistack.config import settings
from yubistack.utils import parse_querystring, wsgi_response
from yubistack.ykauth import YKAuthError, Client
from yubistack.ykksm import YKKSMError, Decryptor
from yubistack.ykval import (
    YKSyncError,
    YKValError,
    Sync,
    Verifyer,
)

logger = logging.getLogger(__name__)

URI_REGEX = re.compile(r"""
    ^/?                     # Leading slash might not be present
    (                       # Intersection: yubiauth and yubikey-val + yubikey-ksm differences
        wsapi(/\d+\.\d+)?   # YKVal and YKKsm uses wsapi prefix + protocol version
      | yubiauth/client     # Yubiclient authentication URI
    )
    /
    (?P<resource>           # The resource should map to a function name
        (
            decrypt
          | verify
          | sync
          | resync
          | authenticate
        )
    )
    /?                      # Trailing clash might not be present
""", re.VERBOSE)

def authenticate(environ, start_response):
    """
    Handle authentications
    """
    REQUIRED_PARAMS = ['username', 'password', 'otp']
    try:
        # Parse POST request
        try:
            request_body_size = int(environ.get('CONTENT_LENGTH', 0))
        except ValueError:
            request_body_size = 0
        request_body = environ['wsgi.input'].read(request_body_size)
        params = parse_querystring(request_body.decode())
        _params = params.copy()
        _params['password'] = '********'
        logger.debug('PROCESSED QUERYSTRING: %s', _params)
        for req_param in REQUIRED_PARAMS:
            if req_param not in params:
                raise YKAuthError("Missing parameter: '%s'" % req_param)
        client = Client()
        output = client.authenticate(params['username'], params['password'], params['otp'])
    except YKAuthError as err:
        logger.exception('Authentication error: %s', err)
        output = False
    except Exception as err:
        logger.exception('Backend error: %s', err)
        output = None
        raise
    finally:
        if output == True:
            resp = (200, 'true')
        elif output == False:
            resp = (400, 'false')
        else:
            resp = (500, 'false')
        start_response('%s OK' % resp[0], [('Content-Type', 'text/plain')])
        return [resp[1].encode()]

def decrypt(environ, start_response):
    """
    Handle OTP decryptions
    """
    try:
        params = parse_querystring(environ['QUERY_STRING'])
        logger.debug('PROCESSED QUERYSTRING: %s', params)
        decryptor = Decryptor()
        output = decryptor.decrypt(params.get('otp'))
        output = 'OK counter=%(counter)s low=%(low)s high=%(high)s use=%(use)s\n' % output
    except YKKSMError as err:
        logger.exception('Decryption error: %s', err)
        output = '%s\n' % err
    except Exception as err:
        logger.exception('Backend error: %s', err)
        output = 'ERR Backend failure\n'
    finally:
        start_response('200 OK', [('Content-Type', 'text/plain')])
        return [output.encode()]

def verify(environ, start_response):
    """
    Handle OTP Validation
    """
    apikey = ''.encode()
    try:
        params = parse_querystring(environ['QUERY_STRING'])
        logger.debug('PROCESSED QUERYSTRING: %s', params)
        verifyer = Verifyer()
        kwargs = params.copy()
        if 'id' in kwargs:
            kwargs.pop('id')
        if 'otp' in kwargs:
            kwargs.pop('otp')
        apikey = verifyer.get_client_apikey(params.get('id'))
        output = verifyer.verify(params.get('id'), params.get('otp'), **kwargs)
    except YKValError as err:
        logger.exception('Validation error: %s', err)
        output = '%s' % err
    except Exception as err:
        logger.exception('Backend error: %s', err)
        output = 'BACKEND_ERROR'
    finally:
        return wsgi_response(output, start_response, apikey=apikey, extra=None)

def sync(environ, start_response):
    """
    Handle Sync requests
    """
    local_params = None
    try:
        # Validate caller address
        logger.debug('Received request from %(REMOTE_ADDR)s', environ)
        if environ['REMOTE_ADDR'] not in settings['SYNC_POOL']:
            logger.info('Operation not permitted from IP %(REMOTE_ADDR)s', environ)
            logger.debug('Remote IP %s is not in allowed sync pool: %s',
                         environ['REMOTE_ADDR'], settings['SYNC_POOL'])
            raise YKSyncError('ERROR Authorization failed for %(REMOTE_ADDR)s)' % environ)
        sync_params = parse_querystring(environ['QUERY_STRING'])
        logger.info('Received: %s', sync_params)
        synclib = Sync()
        local_params = synclib.sync_local(sync_params)
        output = 'OK'
    except YKSyncError as err:
        output = str(err)
    except Exception as err:
        logger.exception('ERROR: %s', err)
        output = 'BACKEND_ERROR'
    finally:
        return wsgi_response(output, start_response, apikey=''.encode(), extra=local_params)

def resync(environ, start_response):
    """
    Handle Re-sync requests
    """
    try:
        # Validate caller address
        if environ['REMOTE_ADDR'] not in settings['SYNC_POOL']:
            logger.info('Operation not permitted from IP %(REMOTE_ADDR)s', environ)
            raise YKSyncError('ERROR Authorization failed for %(REMOTE_ADDR)s)' % environ)
        # Parse query and check values
        resync_params = parse_querystring(environ['QUERY_STRING'])
        synclib = Sync()
        output = synclib.resync_local(resync_params)
    except YKSyncError as err:
        output = str(err)
    except Exception as err:
        logger.exception('ERROR: %s', err)
        output = ''
    finally:
        start_response('200 OK', [('Content-Type', 'text/plain')])
        return [output.encode()]

def router(environ, start_response):
    """ Simple WSGI router """
    path = environ.get('PATH_INFO', '')
    match = re.match(URI_REGEX, path)
    if not match:
        start_response('500 Error', [('Content-Type', 'text/plain')])
        return ['Invalid URI'.encode()]
    request = match.groupdict()
    if not request['resource']:
        start_response('500 Error', [('Content-Type', 'text/plain')])
        return ['Invalid URI'.encode()]
    func = globals()[request['resource']]
    return func(environ, start_response)

def main():
    """ Run a web server to test the application """
    from wsgiref.simple_server import make_server
    logging.basicConfig(format='%(asctime)s %(levelname)s %(module)s %(funcName)s: %(message)s',
                        level=logging.DEBUG)
    srv = make_server('0.0.0.0', 8080, router)
    srv.serve_forever()

if __name__ == '__main__':
    main()
<commit_msg>Using proper HTTP status codes for failures<commit_after>"""
yubistack.wsgi
~~~~~~~~~~~~~~

WSGI wrappers around the yubistack functions
to support backward compatibility.
"""

import logging
import re

from yubistack.config import settings
from yubistack.utils import parse_querystring, wsgi_response
from yubistack.ykauth import YKAuthError, Client
from yubistack.ykksm import YKKSMError, Decryptor
from yubistack.ykval import (
    YKSyncError,
    YKValError,
    Sync,
    Verifyer,
)

logger = logging.getLogger(__name__)

URI_REGEX = re.compile(r"""
    ^/?                     # Leading slash might not be present
    (                       # Intersection: yubiauth and yubikey-val + yubikey-ksm differences
        wsapi(/\d+\.\d+)?   # YKVal and YKKsm uses wsapi prefix + protocol version
      | yubiauth/client     # Yubiclient authentication URI
    )
    /
    (?P<resource>           # The resource should map to a function name
        (
            decrypt
          | verify
          | sync
          | resync
          | authenticate
        )
    )
    /?                      # Trailing clash might not be present
""", re.VERBOSE)

def authenticate(environ, start_response):
    """
    Handle authentications
    """
    REQUIRED_PARAMS = ['username', 'password', 'otp']
    try:
        # Parse POST request
        try:
            request_body_size = int(environ.get('CONTENT_LENGTH', 0))
        except ValueError:
            request_body_size = 0
        request_body = environ['wsgi.input'].read(request_body_size)
        params = parse_querystring(request_body.decode())
        _params = params.copy()
        _params['password'] = '********'
        logger.debug('PROCESSED QUERYSTRING: %s', _params)
        for req_param in REQUIRED_PARAMS:
            if req_param not in params:
                raise YKAuthError("Missing parameter: '%s'" % req_param)
        client = Client()
        output = client.authenticate(params['username'], params['password'], params['otp'])
    except YKAuthError as err:
        logger.exception('Authentication error: %s', err)
        output = False
    except Exception as err:
        logger.exception('Backend error: %s', err)
        output = None
        raise
    finally:
        if output == True:
            resp = (200, 'true')
        elif output == False:
            resp = (400, 'false')
        else:
            resp = (500, 'false')
        start_response('%s OK' % resp[0], [('Content-Type', 'text/plain')])
        return [resp[1].encode()]

def decrypt(environ, start_response):
    """
    Handle OTP decryptions
    """
    try:
        params = parse_querystring(environ['QUERY_STRING'])
        logger.debug('PROCESSED QUERYSTRING: %s', params)
        decryptor = Decryptor()
        output = decryptor.decrypt(params.get('otp'))
        output = 'OK counter=%(counter)s low=%(low)s high=%(high)s use=%(use)s\n' % output
    except YKKSMError as err:
        logger.exception('Decryption error: %s', err)
        output = '%s\n' % err
    except Exception as err:
        logger.exception('Backend error: %s', err)
        output = 'ERR Backend failure\n'
    finally:
        start_response('200 OK', [('Content-Type', 'text/plain')])
        return [output.encode()]

def verify(environ, start_response):
    """
    Handle OTP Validation
    """
    apikey = ''.encode()
    try:
        params = parse_querystring(environ['QUERY_STRING'])
        logger.debug('PROCESSED QUERYSTRING: %s', params)
        verifyer = Verifyer()
        kwargs = params.copy()
        if 'id' in kwargs:
            kwargs.pop('id')
        if 'otp' in kwargs:
            kwargs.pop('otp')
        apikey = verifyer.get_client_apikey(params.get('id'))
        output = verifyer.verify(params.get('id'), params.get('otp'), **kwargs)
    except YKValError as err:
        logger.exception('Validation error: %s', err)
        output = '%s' % err
    except Exception as err:
        logger.exception('Backend error: %s', err)
        output = 'BACKEND_ERROR'
    finally:
        return wsgi_response(output, start_response, apikey=apikey, extra=None)

def sync(environ, start_response):
    """
    Handle Sync requests
    """
    local_params = None
    try:
        # Validate caller address
        logger.debug('Received request from %(REMOTE_ADDR)s', environ)
        if environ['REMOTE_ADDR'] not in settings['SYNC_POOL']:
            logger.info('Operation not permitted from IP %(REMOTE_ADDR)s', environ)
            logger.debug('Remote IP %s is not in allowed sync pool: %s',
                         environ['REMOTE_ADDR'], settings['SYNC_POOL'])
            raise YKSyncError('ERROR Authorization failed for %(REMOTE_ADDR)s)' % environ)
        sync_params = parse_querystring(environ['QUERY_STRING'])
        logger.info('Received: %s', sync_params)
        synclib = Sync()
        local_params = synclib.sync_local(sync_params)
        output = 'OK'
        status_code = 200
    except YKSyncError as err:
        output = str(err)
        status_code = 401
    except Exception as err:
        logger.exception('ERROR: %s', err)
        output = 'BACKEND_ERROR'
        status_code = 500
    finally:
        return wsgi_response(output, start_response, apikey=''.encode(),
                             extra=local_params, status=status_code)

def resync(environ, start_response):
    """
    Handle Re-sync requests
    """
    try:
        # Validate caller address
        if environ['REMOTE_ADDR'] not in settings['SYNC_POOL']:
            logger.info('Operation not permitted from IP %(REMOTE_ADDR)s', environ)
            raise YKSyncError('ERROR Authorization failed for %(REMOTE_ADDR)s)' % environ)
        # Parse query and check values
        resync_params = parse_querystring(environ['QUERY_STRING'])
        synclib = Sync()
        output = synclib.resync_local(resync_params)
        status_code = 200
    except YKSyncError as err:
        output = str(err)
        status_code = 401
    except Exception as err:
        logger.exception('ERROR: %s', err)
        output = ''
        status_code = 500
    finally:
        start_response('%d OK' % status_code, [('Content-Type', 'text/plain')])
        return [output.encode()]

def router(environ, start_response):
    """ Simple WSGI router """
    path = environ.get('PATH_INFO', '')
    match = re.match(URI_REGEX, path)
    if not match or not match.groupdict()['resource']:
        start_response('500 Error', [('Content-Type', 'text/plain')])
        return ['Invalid URI'.encode()]
    func = globals()[match.groupdict()['resource']]
    return func(environ, start_response)

def main():
    """ Run a web server to test the application """
    from wsgiref.simple_server import make_server
    logging.basicConfig(format='%(asctime)s %(levelname)s %(module)s %(funcName)s: %(message)s',
                        level=logging.DEBUG)
    srv = make_server('0.0.0.0', 8080, router)
    srv.serve_forever()

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before># imports here

def main():
    basenum_length, largest = 3, 0
    maxnum = 10 ** basenum_length - 1
    maxprod = maxnum ** 2

    print("Maximum number is %d." % maxprod)
    for a in range(maxprod, 1, -1):
        for b in range(maxprod, a, -1):
            if isPalindrome(a * b) and a * b > largest:
                largest = a * b
    print("%d is the product of %d and %d." % (a * b, a, b))

def isPalindrome(x):
    if x < 10 or x % 10 == 0:
        return False
    x_str = str(x)
    for i in range(len(str(x)) // 2):
        if x_str[i] != x_str[-i - 1]:
            return False

if __name__ == "__main__":
    main()
<commit_msg>Completed problem 4<commit_after># imports here

def main():
    basenum_length, largest = 3, 0
    maxnum = 10 ** basenum_length - 1
    x, y = 0, 0
    for a in range(maxnum, 1, -1):
        for b in range(a, 1, -1):
            if isPalindrome(a * b) and a * b > largest:
                largest = a * b
                x, y = a, b
    print("%d is the product of %d and %d." % (largest, x, y))

def isPalindrome(x):
    if x < 10 or x % 10 == 0:
        return False
    x_str = str(x)
    for i in range(len(str(x)) // 2):
        if x_str[i] != x_str[-i - 1]:
            return False
    return True

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>from .display import ZasimDisplay
from .histogram import HistogramExtraDisplay

from ..external.qt import Qt, app
from .. import cagen

import numpy as np
import sys

def main(width=200, height=200, scale=2,
        onedim=False,
        beta=100, nondet=100,
        life=False, rule=None,
        copy_borders=True, black=None,
        histogram=True, activity=True,
        base=2):
    if black > 1:
        black = black / 100.

    beta = beta / 100.
    nondet = nondet / 100.

    w, h = width, height
    if onedim:
        size = (w,)
    else:
        size = w, h

    if black is not None:
        print size, base
        rands = np.random.rand(*size)
        config = np.random.randint(0, base, size)
        config[rands < black] = 0

        size = None
    else:
        config = None

    print size, config

    if onedim and not life:
        # get a random beautiful CA
        sim_obj = cagen.BinRule(rule=rule, size=size, config=config, nondet=nondet, beta=beta, activity=activity,
                histogram=histogram, copy_borders=copy_borders, base=base)

    else:
        if life:
            sim_obj = cagen.GameOfLife(size, nondet, histogram, activity, config, beta, copy_borders)
        else:
            sim_obj = cagen.ElementarySimulator(size, nondet, histogram, activity, rule, config, beta, copy_borders, base=base)

        if not life:
            print sim_obj.pretty_print()
            print sim_obj.t.rule, hex(sim_obj.rule_number)

    display = ZasimDisplay(sim_obj)
    display.set_scale(scale)

    display.control.start()

    if histogram:
        extra_hist = HistogramExtraDisplay(sim_obj, parent=display, height=200, maximum= w * h)
        extra_hist.show()
        display.window.attach_display(extra_hist)
        display.window.addDockWidget(Qt.RightDockWidgetArea, extra_hist)

    if activity:
        extra_activity = HistogramExtraDisplay(sim_obj, attribute="activity", parent=display, height=200, maximum=w*h)
        extra_activity.show()
        display.window.attach_display(extra_activity)
        display.window.addDockWidget(Qt.RightDockWidgetArea, extra_activity)

    sys.exit(app.exec_())

if __name__ == "__main__":
    import argparse

    argp = argparse.ArgumentParser(
        description="Run a 1d BinRule, a 2d Game of Life, or a 2d elementary "
                    "cellular automaton")
    argp.add_argument("--onedim", default=False, action="store_true",
            help="generate a one-dimensional cellular automaton")
    argp.add_argument("--twodim", default=True, action="store_false", dest="onedim",
            help="generate a two-dimensional cellular automaton")
    argp.add_argument("--life", default=False, action="store_true",
            help="generate a conway's game of life - implies --twodim")

    argp.add_argument("-x", "--width", default=200, dest="width", type=int,
            help="the width of the image surface")
    argp.add_argument("-y", "--height", default=200, dest="height", type=int,
            help="the height of the image surface")
    argp.add_argument("-z", "--scale", default=3, dest="scale", type=int,
            help="the size of each cell of the configuration")
    argp.add_argument("-r", "--rule", default=None, type=str,
            help="the elementary cellular automaton rule number to use")
    argp.add_argument("-c", "--dont-copy-borders", default=True, action="store_false", dest="copy_borders",
            help="copy borders or just read zeros?")
    argp.add_argument("--black", default=None, type=int,
            help="what percentage of the cells to make black at the beginning.")

    argp.add_argument("--nondet", default=100, type=int,
            help="with what percentage should cells be executed?")
    argp.add_argument("--beta", default=100, type=int,
            help="with what probability should a cell succeed in exposing its "\
                 "state to its neighbours?")

    argp.add_argument("--no-histogram", default=True, action="store_false", dest="histogram",
            help="don't display a histogram")
    argp.add_argument("--no-activity", default=True, action="store_false", dest="activity",
            help="don't display the activity")
    argp.add_argument("--base", default=2, type=int,
            help="The base of the cells.")

    args = argp.parse_args()

    if args.rule:
        if args.rule.startswith("0x"):
            args.rule = int(args.rule, 16)
        else:
            args.rule = int(args.rule)

    main(**vars(args))
<commit_msg>pretty-print for one- and twodim stepfuncs in gui<commit_after>from .display import ZasimDisplay
from .histogram import HistogramExtraDisplay

from ..external.qt import Qt, app
from .. import cagen

import numpy as np
import sys

def main(width=200, height=200, scale=2,
        onedim=False,
        beta=100, nondet=100,
        life=False, rule=None,
        copy_borders=True, black=None,
        histogram=True, activity=True,
        base=2):
    if black > 1:
        black = black / 100.

    beta = beta / 100.
    nondet = nondet / 100.

    w, h = width, height
    if onedim:
        size = (w,)
    else:
        size = w, h

    if black is not None:
        print size, base
        rands = np.random.rand(*size)
        config = np.random.randint(0, base, size)
        config[rands < black] = 0

        size = None
    else:
        config = None

    print size, config

    if onedim and not life:
        # get a random beautiful CA
        sim_obj = cagen.BinRule(rule=rule, size=size, config=config, nondet=nondet, beta=beta, activity=activity,
                histogram=histogram, copy_borders=copy_borders, base=base)

    else:
        if life:
            sim_obj = cagen.GameOfLife(size, nondet, histogram, activity, config, beta, copy_borders)
        else:
            sim_obj = cagen.ElementarySimulator(size, nondet, histogram, activity, rule, config, beta, copy_borders, base=base)

    if not life:
        print sim_obj.pretty_print()
        print sim_obj.t.rule, hex(sim_obj.rule_number)

    display = ZasimDisplay(sim_obj)
    display.set_scale(scale)

    display.control.start()

    if histogram:
        extra_hist = HistogramExtraDisplay(sim_obj, parent=display, height=200, maximum= w * h)
        extra_hist.show()
        display.window.attach_display(extra_hist)
        display.window.addDockWidget(Qt.RightDockWidgetArea, extra_hist)

    if activity:
        extra_activity = HistogramExtraDisplay(sim_obj, attribute="activity", parent=display, height=200, maximum=w*h)
        extra_activity.show()
        display.window.attach_display(extra_activity)
        display.window.addDockWidget(Qt.RightDockWidgetArea, extra_activity)

    sys.exit(app.exec_())

if __name__ == "__main__":
    import argparse

    argp = argparse.ArgumentParser(
        description="Run a 1d BinRule, a 2d Game of Life, or a 2d elementary "
                    "cellular automaton")
    argp.add_argument("--onedim", default=False, action="store_true",
            help="generate a one-dimensional cellular automaton")
    argp.add_argument("--twodim", default=True, action="store_false", dest="onedim",
            help="generate a two-dimensional cellular automaton")
    argp.add_argument("--life", default=False, action="store_true",
            help="generate a conway's game of life - implies --twodim")

    argp.add_argument("-x", "--width", default=200, dest="width", type=int,
            help="the width of the image surface")
    argp.add_argument("-y", "--height", default=200, dest="height", type=int,
            help="the height of the image surface")
    argp.add_argument("-z", "--scale", default=3, dest="scale", type=int,
            help="the size of each cell of the configuration")
    argp.add_argument("-r", "--rule", default=None, type=str,
            help="the elementary cellular automaton rule number to use")
    argp.add_argument("-c", "--dont-copy-borders", default=True, action="store_false", dest="copy_borders",
            help="copy borders or just read zeros?")
    argp.add_argument("--black", default=None, type=int,
            help="what percentage of the cells to make black at the beginning.")

    argp.add_argument("--nondet", default=100, type=int,
            help="with what percentage should cells be executed?")
    argp.add_argument("--beta", default=100, type=int,
            help="with what probability should a cell succeed in exposing its "\
                 "state to its neighbours?")

    argp.add_argument("--no-histogram", default=True, action="store_false", dest="histogram",
            help="don't display a histogram")
    argp.add_argument("--no-activity", default=True, action="store_false", dest="activity",
            help="don't display the activity")
    argp.add_argument("--base", default=2, type=int,
            help="The base of the cells.")

    args = argp.parse_args()

    if args.rule:
        if args.rule.startswith("0x"):
            args.rule = int(args.rule, 16)
        else:
            args.rule = int(args.rule)

    main(**vars(args))
<|endoftext|>


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

__author__ = '7sDream'
__version__ = '0.1.5'

from .client import ZhihuClient
from .question import Question
from .author import Author
from .activity import Activity
from .acttype import ActType
from .answer import Answer
from .collection import Collection
from .column import Column
from .post import Post
from .topic import Topic

__all__ = ['ZhihuClient', 'Question', 'Author', 'ActType', 'Activity',
           'Answer', 'Collection', 'Column', 'Post', 'Topic']
<commit_msg>change version number<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = '7sDream'
__version__ = '0.2.0'

from .client import ZhihuClient
from .question import Question
from .author import Author
from .activity import Activity
from .acttype import ActType
from .answer import Answer
from .collection import Collection
from .column import Column
from .post import Post
from .topic import Topic

__all__ = ['ZhihuClient', 'Question', 'Author', 'ActType', 'Activity',
           'Answer', 'Collection', 'Column', 'Post', 'Topic']
<|endoftext|>


<commit_before>from __future__ import absolute_import

import os
import dj_database_url

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

SECRET_KEY = os.environ["SECRET_KEY"]

DEBUG = os.environ.get("DEBUG","false").lower() == "true"

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = (
    'grappelli',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'oauth2_provider',
    'rest_framework',
    'rest_framework_swagger',
    'api_doc',
    'datastore',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

if DEBUG:
    MIDDLEWARE_CLASSES += 'django_pdb.middleware.PdbMiddleware'

ROOT_URLCONF = 'oeem_energy_datastore.urls'

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

WSGI_APPLICATION = 'oeem_energy_datastore.wsgi.application'

DATABASES = {'default': dj_database_url.config()}

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'
STATIC_ROOT = os.environ.get("STATIC_ROOT")

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

OAUTH2_PROVIDER = {
    'SCOPES': {'read': 'Read scope', 'write': 'Write scope'},
    'ACCESS_TOKEN_EXPIRE_SECONDS': 315360000, # 10 years
}

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

GRAPPELLI_ADMIN_TITLE = "Open Energy Efficiency Meter"

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(asctime)s %(levelname)s [%(name)s:%(lineno)s] %(module)s %(process)d %(thread)d %(message)s'
        }
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
    },
    'handlers': {
        'logfile': {
            'level': 'DEBUG',
            'filters': ['require_debug_false'],
            'class': 'logging.handlers.WatchedFileHandler',
            'formatter': 'verbose',
            'filename': os.environ.get("DJANGO_LOGFILE"),
        }
    },
    'loggers': {
        'django': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
        },
        'customer_registry.views': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

BROKER_URL = 'amqp://guest:guest@{}:5672//'.format(os.environ["BROKER_HOST"])

CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

SWAGGER_SETTINGS = {
    'base_path': '{}/docs'.format(os.environ["SERVER_NAME"]),
    'protocol': os.environ["PROTOCOL"],
}

# DJANGO DEBUG TOOLBAR
if DEBUG:
    INSTALLED_APPS += ('debug_toolbar',)
    MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
    DEBUG_TOOLBAR_PATCH_SETTINGS = False
    INTERNAL_IPS = ['0.0.0.0', '127.0.0.1', 'localhost']

<commit_msg>Use proper adding tuples syntax<commit_after>from __future__ import absolute_import

import os
import dj_database_url

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

SECRET_KEY = os.environ["SECRET_KEY"]

DEBUG = os.environ.get("DEBUG","false").lower() == "true"

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = (
    'grappelli',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'oauth2_provider',
    'rest_framework',
    'rest_framework_swagger',
    'api_doc',
    'datastore',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

if DEBUG:
    MIDDLEWARE_CLASSES += ('django_pdb.middleware.PdbMiddleware',)

ROOT_URLCONF = 'oeem_energy_datastore.urls'

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

WSGI_APPLICATION = 'oeem_energy_datastore.wsgi.application'

DATABASES = {'default': dj_database_url.config()}

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'
STATIC_ROOT = os.environ.get("STATIC_ROOT")

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

OAUTH2_PROVIDER = {
    'SCOPES': {'read': 'Read scope', 'write': 'Write scope'},
    'ACCESS_TOKEN_EXPIRE_SECONDS': 315360000, # 10 years
}

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

GRAPPELLI_ADMIN_TITLE = "Open Energy Efficiency Meter"

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(asctime)s %(levelname)s [%(name)s:%(lineno)s] %(module)s %(process)d %(thread)d %(message)s'
        }
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
    },
    'handlers': {
        'logfile': {
            'level': 'DEBUG',
            'filters': ['require_debug_false'],
            'class': 'logging.handlers.WatchedFileHandler',
            'formatter': 'verbose',
            'filename': os.environ.get("DJANGO_LOGFILE"),
        }
    },
    'loggers': {
        'django': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
        },
        'customer_registry.views': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

BROKER_URL = 'amqp://guest:guest@{}:5672//'.format(os.environ["BROKER_HOST"])

CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

SWAGGER_SETTINGS = {
    'base_path': '{}/docs'.format(os.environ["SERVER_NAME"]),
    'protocol': os.environ["PROTOCOL"],
}

# DJANGO DEBUG TOOLBAR
if DEBUG:
    INSTALLED_APPS += ('debug_toolbar',)
    MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
    DEBUG_TOOLBAR_PATCH_SETTINGS = False
    INTERNAL_IPS = ['0.0.0.0', '127.0.0.1', 'localhost']

<|endoftext|>