<commit_before>from uuid import uuid4

import mock

from eventsourcing.domain.model.entity import AttributeChanged, Created, CreatedMutatorRequiresTypeNotInstance, \
    EntityIDConsistencyError, EntityVersionConsistencyError, TimestampedVersionedEntity, attribute, created_mutator
from eventsourcing.domain.model.events import VersionedEntityEvent, publish, subscribe, unsubscribe, DomainEvent
from eventsourcing.example.infrastructure import ExampleRepository
from eventsourcing.example.domainmodel import Example, register_new_example
from eventsourcing.exceptions import ProgrammingError, RepositoryKeyError, ConcurrencyError
from eventsourcing.tests.sequenced_item_tests.base import WithPersistencePolicy
from eventsourcing.tests.sequenced_item_tests.test_cassandra_active_record_strategy import \
    WithCassandraActiveRecordStrategies
from eventsourcing.tests.sequenced_item_tests.test_sqlalchemy_active_record_strategy import \
    WithSQLAlchemyActiveRecordStrategies

class TestExampleEntity(WithSQLAlchemyActiveRecordStrategies, WithPersistencePolicy):
    def test_entity_lifecycle(self):
        # Check the factory creates an instance.
        example1 = register_new_example(a=1, b=2)
        self.assertIsInstance(example1, Example)

        # Check the properties of the Example class.
        self.assertEqual(1, example1.a)
        self.assertEqual(2, example1.b)

        # Check the properties of the TimestampedVersionedEntity class.
        self.assertTrue(example1.id)
        self.assertEqual(1, example1.version)
        self.assertTrue(example1.created_on)

        # Check a second instance with the same values is not "equal" to the first.
        example2 = register_new_example(a=1, b=2)
        self.assertNotEqual(example1, example2)

        # Setup the repo.
        repo = ExampleRepository(self.versioned_entity_event_store)

        # Check the example entities can be retrieved from the example repository.
        entity1 = repo[example1.id]
        self.assertIsInstance(entity1, Example)
        self.assertEqual(1, entity1.a)
        self.assertEqual(2, entity1.b)

        entity2 = repo[example2.id]
        self.assertIsInstance(entity2, Example)
        self.assertEqual(1, entity2.a)
        self.assertEqual(2, entity2.b)

        # Check the entity can be updated.
        entity1.a = 100
        self.assertEqual(100, repo[entity1.id].a)
        entity1.b = -200
        self.assertEqual(-200, repo[entity1.id].b)

        self.assertEqual(0, entity1.count_heartbeats())
        entity1.beat_heart()
        entity1.beat_heart()
        entity1.beat_heart()
        self.assertEqual(3, entity1.count_heartbeats())
        self.assertEqual(3, repo[entity1.id].count_heartbeats())

        # Check the entity can publish multiple events simultaneously.
        entity1.beat_heart(number_of_beats=3)
        self.assertEqual(6, repo[entity1.id].count_heartbeats())

        # Check the entity can be discarded.
        entity1.discard()

        # Check the repo now raises a KeyError.
        self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id)

        # Check the entity can't be discarded twice.
        self.assertRaises(AssertionError, entity1.discard)

        # Should fail to validate event with wrong entity ID.
        with self.assertRaises(EntityIDConsistencyError):
            entity2._validate_originator(
                VersionedEntityEvent(
                    entity_id=uuid4(),
                    entity_version=0
                )
            )
        # Should fail to validate event with wrong entity version.
        with self.assertRaises(EntityVersionConsistencyError):
            entity2._validate_originator(
                VersionedEntityEvent(
                    entity_id=entity2.id,
                    entity_version=0,
                )
        )

        # Should validate event with correct entity ID and version.
        entity2._validate_originator(
            VersionedEntityEvent(
                entity_id=entity2.id,
                entity_version=entity2.version,
            )
        )

        # Check an entity cannot be reregistered with the ID of a discarded entity.
        replacement_event = Example.Created(entity_id=entity1.id, a=11, b=12)
        with self.assertRaises(ConcurrencyError):
            publish(event=replacement_event)

    def test_not_implemented_error(self):
        # Define an event class.
        class UnsupportedEvent(DomainEvent): pass

        # Check we get an error when attempting to mutate on the event.
        self.assertRaises(NotImplementedError, Example.mutate, Example, UnsupportedEvent())

    def test_attribute(self):
        # Check we get an error when called with something other than a function.
        self.assertRaises(ProgrammingError, attribute, 'not a getter')
        self.assertRaises(ProgrammingError, attribute, 123)
        self.assertRaises(ProgrammingError, attribute, None)

        # Call the decorator with a function.
        getter = lambda: None
        p = attribute(getter)

        # Check we got a property object.
        self.assertIsInstance(p, property)

        # Check the property object has both setter and getter functions.
        self.assertTrue(p.fset)
        self.assertTrue(p.fget)

        # Pretend we decorated an object.
        entity_id = uuid4()
        o = TimestampedVersionedEntity(entity_id=entity_id, entity_version=0)
        o.__dict__['_<lambda>'] = 'value1'

        # Call the property's getter function.
        value = p.fget(o)
        self.assertEqual(value, 'value1')

        # Call the property's setter function.
        p.fset(o, 'value2')

        # Check the attribute has changed.
        value = p.fget(o)
        self.assertEqual(value, 'value2')

        # Check the property's getter function isn't the getter function we passed in.
        self.assertNotEqual(p.fget, getter)

        # Define a class that uses the decorator.
        class Aaa(TimestampedVersionedEntity):
            "An event sourced entity."

            def __init__(self, a, *args, **kwargs):
                super(Aaa, self).__init__(*args, **kwargs)
                self._a = a

            @attribute
            def a(self):
                "A mutable event sourced property."

        # Instantiate the class and check assigning to the property publishes an event and updates the object state.
        published_events = []
        subscription = (lambda x: True, lambda x: published_events.append(x))
        subscribe(*subscription)
        entity_id = uuid4()
        try:
            aaa = Aaa(entity_id=entity_id, entity_version=1, a=1)
            self.assertEqual(aaa.a, 1)
            aaa.a = 'value1'
            self.assertEqual(aaa.a, 'value1')
        finally:
            unsubscribe(*subscription)

        # Check an event was published.
        self.assertEqual(len(published_events), 1)

        # Check the published event was an AttributeChanged event, with the expected attribute values.
        published_event = published_events[0]
        self.assertIsInstance(published_event, AttributeChanged)
        self.assertEqual(published_event.name, '_a')
        self.assertEqual(published_event.value, 'value1')
        self.assertTrue(published_event.entity_version, 1)
        self.assertEqual(published_event.entity_id, entity_id)

    def test_static_mutator_method(self):
        self.assertRaises(NotImplementedError, TimestampedVersionedEntity._mutator, 1, 2)

    def test_created_mutator_error(self):
        with self.assertRaises(CreatedMutatorRequiresTypeNotInstance):
            created_mutator(mock.Mock(spec=Created), 'not a class')

class CustomValueObject(object):
    def __init__(self, value):
        self.value = value

class TestExampleEntityWithCassandra(WithCassandraActiveRecordStrategies, TestExampleEntity):
    pass
<commit_msg>Added test for created_mutator() TypeError exception.<commit_after>from uuid import uuid4

import mock

from eventsourcing.domain.model.entity import AttributeChanged, Created, CreatedMutatorRequiresTypeNotInstance, \
    EntityIDConsistencyError, EntityVersionConsistencyError, TimestampedVersionedEntity, attribute, created_mutator
from eventsourcing.domain.model.events import VersionedEntityEvent, publish, subscribe, unsubscribe, DomainEvent
from eventsourcing.example.infrastructure import ExampleRepository
from eventsourcing.example.domainmodel import Example, register_new_example
from eventsourcing.exceptions import ProgrammingError, RepositoryKeyError, ConcurrencyError
from eventsourcing.tests.sequenced_item_tests.base import WithPersistencePolicy
from eventsourcing.tests.sequenced_item_tests.test_cassandra_active_record_strategy import \
    WithCassandraActiveRecordStrategies
from eventsourcing.tests.sequenced_item_tests.test_sqlalchemy_active_record_strategy import \
    WithSQLAlchemyActiveRecordStrategies

class TestExampleEntity(WithSQLAlchemyActiveRecordStrategies, WithPersistencePolicy):
    def test_entity_lifecycle(self):
        # Check the factory creates an instance.
        example1 = register_new_example(a=1, b=2)
        self.assertIsInstance(example1, Example)

        # Check the properties of the Example class.
        self.assertEqual(1, example1.a)
        self.assertEqual(2, example1.b)

        # Check the properties of the TimestampedVersionedEntity class.
        self.assertTrue(example1.id)
        self.assertEqual(1, example1.version)
        self.assertTrue(example1.created_on)

        # Check a second instance with the same values is not "equal" to the first.
        example2 = register_new_example(a=1, b=2)
        self.assertNotEqual(example1, example2)

        # Setup the repo.
        repo = ExampleRepository(self.versioned_entity_event_store)

        # Check the example entities can be retrieved from the example repository.
        entity1 = repo[example1.id]
        self.assertIsInstance(entity1, Example)
        self.assertEqual(1, entity1.a)
        self.assertEqual(2, entity1.b)

        entity2 = repo[example2.id]
        self.assertIsInstance(entity2, Example)
        self.assertEqual(1, entity2.a)
        self.assertEqual(2, entity2.b)

        # Check the entity can be updated.
        entity1.a = 100
        self.assertEqual(100, repo[entity1.id].a)
        entity1.b = -200
        self.assertEqual(-200, repo[entity1.id].b)

        self.assertEqual(0, entity1.count_heartbeats())
        entity1.beat_heart()
        entity1.beat_heart()
        entity1.beat_heart()
        self.assertEqual(3, entity1.count_heartbeats())
        self.assertEqual(3, repo[entity1.id].count_heartbeats())

        # Check the entity can publish multiple events simultaneously.
        entity1.beat_heart(number_of_beats=3)
        self.assertEqual(6, repo[entity1.id].count_heartbeats())

        # Check the entity can be discarded.
        entity1.discard()

        # Check the repo now raises a KeyError.
        self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id)

        # Check the entity can't be discarded twice.
        self.assertRaises(AssertionError, entity1.discard)

        # Should fail to validate event with wrong entity ID.
        with self.assertRaises(EntityIDConsistencyError):
            entity2._validate_originator(
                VersionedEntityEvent(
                    entity_id=uuid4(),
                    entity_version=0
                )
            )
        # Should fail to validate event with wrong entity version.
        with self.assertRaises(EntityVersionConsistencyError):
            entity2._validate_originator(
                VersionedEntityEvent(
                    entity_id=entity2.id,
                    entity_version=0,
                )
        )

        # Should validate event with correct entity ID and version.
        entity2._validate_originator(
            VersionedEntityEvent(
                entity_id=entity2.id,
                entity_version=entity2.version,
            )
        )

        # Check an entity cannot be reregistered with the ID of a discarded entity.
        replacement_event = Example.Created(entity_id=entity1.id, a=11, b=12)
        with self.assertRaises(ConcurrencyError):
            publish(event=replacement_event)

    def test_not_implemented_error(self):
        # Define an event class.
        class UnsupportedEvent(DomainEvent): pass

        # Check we get an error when attempting to mutate on the event.
        self.assertRaises(NotImplementedError, Example.mutate, Example, UnsupportedEvent())

    def test_attribute(self):
        # Check we get an error when called with something other than a function.
        self.assertRaises(ProgrammingError, attribute, 'not a getter')
        self.assertRaises(ProgrammingError, attribute, 123)
        self.assertRaises(ProgrammingError, attribute, None)

        # Call the decorator with a function.
        getter = lambda: None
        p = attribute(getter)

        # Check we got a property object.
        self.assertIsInstance(p, property)

        # Check the property object has both setter and getter functions.
        self.assertTrue(p.fset)
        self.assertTrue(p.fget)

        # Pretend we decorated an object.
        entity_id = uuid4()
        o = TimestampedVersionedEntity(entity_id=entity_id, entity_version=0)
        o.__dict__['_<lambda>'] = 'value1'

        # Call the property's getter function.
        value = p.fget(o)
        self.assertEqual(value, 'value1')

        # Call the property's setter function.
        p.fset(o, 'value2')

        # Check the attribute has changed.
        value = p.fget(o)
        self.assertEqual(value, 'value2')

        # Check the property's getter function isn't the getter function we passed in.
        self.assertNotEqual(p.fget, getter)

        # Define a class that uses the decorator.
        class Aaa(TimestampedVersionedEntity):
            "An event sourced entity."

            def __init__(self, a, *args, **kwargs):
                super(Aaa, self).__init__(*args, **kwargs)
                self._a = a

            @attribute
            def a(self):
                "A mutable event sourced property."

        # Instantiate the class and check assigning to the property publishes an event and updates the object state.
        published_events = []
        subscription = (lambda x: True, lambda x: published_events.append(x))
        subscribe(*subscription)
        entity_id = uuid4()
        try:
            aaa = Aaa(entity_id=entity_id, entity_version=1, a=1)
            self.assertEqual(aaa.a, 1)
            aaa.a = 'value1'
            self.assertEqual(aaa.a, 'value1')
        finally:
            unsubscribe(*subscription)

        # Check an event was published.
        self.assertEqual(len(published_events), 1)

        # Check the published event was an AttributeChanged event, with the expected attribute values.
        published_event = published_events[0]
        self.assertIsInstance(published_event, AttributeChanged)
        self.assertEqual(published_event.name, '_a')
        self.assertEqual(published_event.value, 'value1')
        self.assertTrue(published_event.entity_version, 1)
        self.assertEqual(published_event.entity_id, entity_id)

    def test_static_mutator_method(self):
        self.assertRaises(NotImplementedError, TimestampedVersionedEntity._mutator, 1, 2)

    def test_created_mutator_errors(self):
        # Check the guard condition raises exception.
        with self.assertRaises(CreatedMutatorRequiresTypeNotInstance):
            created_mutator(mock.Mock(spec=Created), 'not a class')

        # Check the instantiation type error.
        with self.assertRaises(TypeError):
            created_mutator(mock.Mock(spec=Created), TimestampedVersionedEntity)

class CustomValueObject(object):
    def __init__(self, value):
        self.value = value

class TestExampleEntityWithCassandra(WithCassandraActiveRecordStrategies, TestExampleEntity):
    pass
<|endoftext|>


<commit_before>import json, re
import sys, time

from occi_libs import *
from occi_curl import occi_curl

categories = []

#'Category: offline;scheme="http://schemas.ogf.org/occi/infrastructure/storagelink/action#";class="action";title="deactivate storagelink"'
required_categories = [
    'http://schemas.ogf.org/occi/core#entity',
    'http://schemas.ogf.org/occi/core#resource',
    'http://schemas.ogf.org/occi/core#link'
]

# parse and check the body, and get categories
def parse_body(body):
    err_msg = []
    categories = []
    category_ids = {}
    check_headers = True
    check_unique = True

    for line in body:
        item = {}
        chunks = re.split(';', line)
        if re.match(r'^Category:', chunks[0]):
            value = re.sub(r'^Category:\s+', '', chunks[0])
            item['category'] = value

            # skip the first chunk (category)
            for chunk in chunks[1:]:
                keyvalue = re.split(r'\s*=\s*', chunk, 1)
                key = keyvalue[0]
                value = keyvalue[1].strip('"')
                item[key] = value

            categories.append(item)

            # check uniqueness
            key = item['category'] + item['scheme']
            if key in category_ids.keys():
                check_unique = False
                duplicate_item = item
            else:
                category_ids[key] = True
        else:
            check_headers = False

    if not check_headers:
        err_msg.append('Only "Category" expected response headers')

    if not check_unique:
        err_msg.append('Category not unique (term "%s", scheme "%s")' % (duplicate_item['category'], duplicate_item['scheme']))

    return [check_headers and check_unique, categories, err_msg]

def get_categories():
    global categories

    body, response_headers, http_status, content_type = occi_curl()

    # TODO: ignoring possible errors
    check_parse, categories, err_msg = parse_body(body)

    return [body, response_headers, http_status, content_type]

def check_content_type(content_type):
    if content_type in ['text/occi', 'text/plain', 'application/occi+json']:
        return [True, []]
    else:
        return [False, ['Wrong Content-Type in response']]

def check_requested_content_type(content_type):
    if content_type == occi_config['mimetype']:
        return [True, []]
    else:
        return [False, ['Result mime type differs']]

def check_http_status(http_expected_status, http_status):
    if not re.match(r'^HTTP/.* %s' % http_expected_status, http_status):
        return [False, ['HTTP status from getting categories not %s (%s)' % (http_expected_status, http_status)]]
    else:
        return [True, []]

def pretest_http_status(http_ok_status):
    err_msg = []
    check_pretest = True
    body = None
    response_headers = None
    http_status = None
    content_type = None

    global categories
    if not categories:
        body, response_headers, http_status, content_type = get_categories()
        check_pretest, tmp_err_msg = check_http_status(http_ok_status, http_status)
        err_msg += tmp_err_msg
    return [body, response_headers, http_status, content_type, check_pretest, err_msg]

def match_category(category, filter):
    for key, value in filter.items():
        if not (key in category and category[key] == value):
            return False
    return True

def search_category(filter):
    for cat in categories:
        if match_category(cat, filter):
            return cat
    return None

def DISCOVERY001():
    err_msg = []

    check01 = False
    check02 = False
    check03 = False

    body, response_headers, http_status, content_type, check_pretest, tmp_err_msg = pretest_http_status("200 OK")
    err_msg += tmp_err_msg

    check01, tmp_err_msg = check_content_type(content_type)
    err_msg += tmp_err_msg

    check02, tmp_err_msg = check_requested_content_type(content_type)
    err_msg += tmp_err_msg

    count = 0
    for category in required_categories:
        for line in body:
            if re.search(r"%s" % category, line):
                count += 1
                break
    if count == 3:
        check03 = True
    else:
        err_msg.append('Body doesn\'t contain appropriate categories')

    return [check_pretest and check01 and check02 and check03, err_msg]

def DISCOVERY002():
    err_msg = []

    check02a = False
    check02b = False

    body, response_headers, http_status, content_type, check_pretest, tmp_err_msg = pretest_http_status("200 OK")
    err_msg += tmp_err_msg

    cat_in = []
    cat_in.append('Content-Type: text/occi')
    cat_in.append('Category: %s; scheme="%s"; class="%s"' % (categories[0]['category'], categories[0]['scheme'], categories[0]['class']))

    body, response_headers, http_status, content_type = occi_curl(headers = cat_in)

    check01, err_msg = check_content_type(content_type)

    if re.match(r'^HTTP/.* 200 OK', http_status):
        check02a = True
    else:
        err_msg.append('HTTP status on filter not 200 OK (%s)' % http_status)

    check02b, tmp_err_msg = check_requested_content_type(content_type)
    err_msg += tmp_err_msg

    check_parse, filtered_categories, tmp_err_msg = parse_body(body)
    err_msg += tmp_err_msg

    category = categories[0]
    check_filter = False
    for item in filtered_categories:
        if category['category'] == item['category'] and category['scheme'] == item['scheme'] and category['class'] == item['class']:
            check_filter = True
            break
    if not check_filter:
        err_msg.append('Category "%s" (schema "%s") not in filtered result' % (category['category'], category['scheme']))

    return [check_pretest and check01 and check02a and check02b and check_parse and check_filter, err_msg]

def CREATE001():
    err_msg = []
    has_kind = True

    body, response_headers, http_status, content_type, check_pretest, tmp_err_msg = pretest_http_status("200 OK")
    err_msg += tmp_err_msg

    #kind = search_category({'class': 'kind'})
    kind = search_category({'class': 'kind', 'category': 'compute'})
    #print kind

    if not kind:
        has_kind = False
        err_msg.append('No OCCI Kind found')
    for item in ['location', 'category', 'scheme']:
        if not item in kind.keys():
            has_kind = False
            err_msg.append('No %s in OCCI Kind' % item)

    #new_cat = '\n\r'.join([
    #    'Category: %s; scheme="%s"; class="%s";' % (kind['category'], kind['scheme'], kind['class']),
    #])
    #new_cat = dict()
    #new_cat['Category'], '%s; scheme="%s"; class="%s";' % (kind['category'], kind['scheme'], kind['class'])
    ##new_cat['X-OOCI-Attribute'] = 'occi.core.id=1'

    new_cat = 'Category: compute; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"; title="titulek"\n\r\
X-OCCI-Attributr: occi.core.id=1\n\r\
X-OCCI-Attributr: occi.core.title="titulek"\n\r\
X-OCCI-Attributr: occi.core.summary="sumarko"\n\r\
X-OCCI-Attributr: occi.core.architecture="arch"\n\r\
'
    body, response_headers, http_status, content_type = occi_curl(url = kind['location'], headers = ['Content-Type: text/plain'], post=new_cat)
#, headers = ['Content-Type: text/plain', 'Category: compute; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"; title="titulek2"']
    check_create, tmp_err_msg = check_http_status("201 Created", http_status)
    err_msg += tmp_err_msg

    return [has_kind and check_create, err_msg]
<commit_msg>Function for parsing attributes, fix typos.<commit_after>import json, re
import sys, time

from occi_libs import *
from occi_curl import occi_curl

categories = []

#'Category: offline;scheme="http://schemas.ogf.org/occi/infrastructure/storagelink/action#";class="action";title="deactivate storagelink"'
required_categories = [
    'http://schemas.ogf.org/occi/core#entity',
    'http://schemas.ogf.org/occi/core#resource',
    'http://schemas.ogf.org/occi/core#link'
]

# occi.core.id{immutable required} occi.core.title occi.core.target occi.core.source{required}
def parse_attributes(chunk, err_msg):
    result = []

    m = True
    while m:
        m = re.match(r'([^\{ ]+)(\{[^\}]*\})?\s*', chunk)
        if not m:
            break
        matches = m.groups()
        name = matches[0]
        attrs = matches[1]
        chunk = chunk[m.end():]

        if attrs:
            attrs = attrs[1:-1]
            attrs = re.split(' ', attrs)

        result.append({'name': name, 'attrs': attrs})

    if chunk:
        err_msg.append('Error parsing OCCI attributes')
        return None

    return result

def parse_attributes(chunk):
    # occi.core.id{immutable required} occi.core.title occi.core.target occi.core.source{required}
    return re.match(r'([^\{]+)(\{[^\}]*\})?', chunk).groups()

# parse and check the body, and get categories
def parse_body(body, err_msg):
    categories = []
    category_ids = {}
    check_headers = True
    check_unique = True

    for line in body:
        item = {}
        chunks = re.split(';', line)
        if re.match(r'^Category:', chunks[0]):
            value = re.sub(r'^Category:\s+', '', chunks[0])
            item['category'] = value

            # skip the first chunk (category)
            for chunk in chunks[1:]:
                keyvalue = re.split(r'\s*=\s*', chunk, 1)
                key = keyvalue[0]
                value = keyvalue[1].strip('"')
                item[key] = value

            categories.append(item)

            # check uniqueness
            key = item['category'] + item['scheme']
            if key in category_ids.keys():
                check_unique = False
                duplicate_item = item
            else:
                category_ids[key] = True
        else:
            check_headers = False

    if not check_headers:
        err_msg.append('Only "Category" expected response headers')

    if not check_unique:
        err_msg.append('Category not unique (term "%s", scheme "%s")' % (duplicate_item['category'], duplicate_item['scheme']))

    return [check_headers and check_unique, categories]

def get_categories():
    global categories
    err_msg = []

    body, response_headers, http_status, content_type = occi_curl()

    # TODO: ignoring possible errors
    check_parse, categories = parse_body(body, err_msg)

    return [body, response_headers, http_status, content_type]

def check_content_type(content_type):
    if content_type in ['text/occi', 'text/plain', 'application/occi+json']:
        return [True, []]
    else:
        return [False, ['Wrong Content-Type in response']]

def check_requested_content_type(content_type):
    if content_type == occi_config['mimetype']:
        return [True, []]
    else:
        return [False, ['Result mime type differs']]

def check_http_status(http_expected_status, http_status):
    if not re.match(r'^HTTP/.* %s' % http_expected_status, http_status):
        return [False, ['HTTP status from getting categories not %s (%s)' % (http_expected_status, http_status)]]
    else:
        return [True, []]

def pretest_http_status(http_ok_status):
    err_msg = []
    check_pretest = True
    body = None
    response_headers = None
    http_status = None
    content_type = None

    global categories
    if not categories:
        body, response_headers, http_status, content_type = get_categories()
        check_pretest, tmp_err_msg = check_http_status(http_ok_status, http_status)
        err_msg += tmp_err_msg
    return [body, response_headers, http_status, content_type, check_pretest, err_msg]

def match_category(category, filter):
    for key, value in filter.items():
        if not (key in category and category[key] == value):
            return False
    return True

def search_category(filter):
    for cat in categories:
        if match_category(cat, filter):
            return cat
    return None

def DISCOVERY001():
    err_msg = []

    check01 = False
    check02 = False
    check03 = False

    body, response_headers, http_status, content_type, check_pretest, tmp_err_msg = pretest_http_status("200 OK")
    err_msg += tmp_err_msg

    check01, tmp_err_msg = check_content_type(content_type)
    err_msg += tmp_err_msg

    check02, tmp_err_msg = check_requested_content_type(content_type)
    err_msg += tmp_err_msg

    count = 0
    for category in required_categories:
        for line in body:
            if re.search(r"%s" % category, line):
                count += 1
                break
    if count == 3:
        check03 = True
    else:
        err_msg.append('Body doesn\'t contain appropriate categories')

    return [check_pretest and check01 and check02 and check03, err_msg]

def DISCOVERY002():
    err_msg = []

    check02a = False
    check02b = False

    body, response_headers, http_status, content_type, check_pretest, tmp_err_msg = pretest_http_status("200 OK")
    err_msg += tmp_err_msg

    cat_in = []
    cat_in.append('Content-Type: text/occi')
    cat_in.append('Category: %s; scheme="%s"; class="%s"' % (categories[0]['category'], categories[0]['scheme'], categories[0]['class']))

    body, response_headers, http_status, content_type = occi_curl(headers = cat_in)

    check01, err_msg = check_content_type(content_type)

    if re.match(r'^HTTP/.* 200 OK', http_status):
        check02a = True
    else:
        err_msg.append('HTTP status on filter not 200 OK (%s)' % http_status)

    check02b, tmp_err_msg = check_requested_content_type(content_type)
    err_msg += tmp_err_msg

    check_parse, filtered_categories = parse_body(body, err_msg)

    category = categories[0]
    check_filter = False
    for item in filtered_categories:
        if category['category'] == item['category'] and category['scheme'] == item['scheme'] and category['class'] == item['class']:
            check_filter = True
            break
    if not check_filter:
        err_msg.append('Category "%s" (schema "%s") not in filtered result' % (category['category'], category['scheme']))

    return [check_pretest and check01 and check02a and check02b and check_parse and check_filter, err_msg]

def CREATE001():
    err_msg = []
    has_kind = True

    body, response_headers, http_status, content_type, check_pretest, tmp_err_msg = pretest_http_status("200 OK")
    err_msg += tmp_err_msg

    #kind = search_category({'class': 'kind'})
    kind = search_category({'class': 'kind', 'category': 'compute'})
    #print kind

    if not kind:
        has_kind = False
        err_msg.append('No OCCI Kind found')
    for item in ['location', 'category', 'scheme']:
        if not item in kind.keys():
            has_kind = False
            err_msg.append('No %s in OCCI Kind' % item)

    #new_cat = '\n\r'.join([
    #    'Category: %s; scheme="%s"; class="%s";' % (kind['category'], kind['scheme'], kind['class']),
    #])
    #new_cat = dict()
    #new_cat['Category'], '%s; scheme="%s"; class="%s";' % (kind['category'], kind['scheme'], kind['class'])
    ##new_cat['X-OOCI-Attribute'] = 'occi.core.id=1'

    new_cat = 'Category: compute; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"; title="titulek"\n\r\
X-OCCI-Attribute: occi.core.id="titulek"\n\r\
X-OCCI-Attribute: occi.core.title="titulek"\n\r\
X-OCCI-Attribute: occi.core.summary="sumarko"\n\r\
X-OCCI-Attribute: occi.compute.architecture="arch"\n\r\
'

    body, response_headers, http_status, content_type = occi_curl(url = kind['location'], headers = ['Content-Type: text/plain'], post=new_cat)
#, headers = ['Content-Type: text/plain', 'Category: compute; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"; title="titulek2"']
    check_create, tmp_err_msg = check_http_status("201 Created", http_status)
    err_msg += tmp_err_msg

    return [has_kind and check_create, err_msg]
<|endoftext|>


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

from datetime import date, time, datetime

from csvkit.typeinference import NULL_VALUES, TRUE_VALUES, FALSE_VALUES, DEFAULT_DATETIME
from dateutil.parser import parse

from panda.exceptions import TypeCoercionError

TYPE_NAMES_MAPPING = {
    'unicode': unicode,
    'int': int,
    'bool': bool,
    'float': float,
    'datetime': datetime,
    'date': date,
    'time': time
}

CURRENCY_SYMBOLS_ASCII = '$,'
CURRENCY_SYMBOLS_UNICODE_TRANSLATE_TABLE = dict([(ord(c), None) for c in '$,€£₱'])

class DataTyper(object):
    """
    A callable object that adds typed columns to a Solr object based on a Dataset schema.
    Along the way it also updates the schema based on the new data.
    """
    def __init__(self, schema):
        self.schema = schema

        # Min/max values for dates/times/datetimes get stored as strings and need to be coerced back
        for n, c in enumerate(self.schema):
            if c['indexed'] and c['type']:
                t = TYPE_NAMES_MAPPING[c['type']]

                if t in (date, time, datetime):
                    self.schema[n]['min'] = self.coerce_type(c['min'], datetime)
                    self.schema[n]['max'] = self.coerce_type(c['max'], datetime)

        self.errors = [[] for c in self.schema]

    def __call__(self, data, row):
        """
        Given a Solr data object and a row of data, will ad typed columns to the data
        object and then return it.
        """
        for n, c in enumerate(self.schema):
            if c['indexed'] and c['type']:
                try:
                    t = TYPE_NAMES_MAPPING[c['type']]
                    value = self.coerce_type(row[n], t)
                    data[c['indexed_name']] = value

                    if t in [int, float, date, time, datetime] and value is not None:
                        if c['min'] is None or value < c['min']:
                            self.schema[n]['min'] = value

                        if c['max'] is None or value > c['max']:
                            self.schema[n]['max'] = value
                except TypeCoercionError, e:
                    self.errors[n].append(e)

        return data

    def summarize(self):
        """
        Generate a plain-text summary of typing, suitable for an email notification.
        """
        if any([c['indexed'] for c in self.schema]):
            summary = 'Summary of column filters:\n\n'

            for n, c in enumerate(self.schema):
                if c['indexed'] and c['type']:
                    error_count = len(self.errors[n])

                    if not error_count:
                        summary += '%s: all values succesfully converted to type "%s"\n' % (c['name'], c['type'])
                    else:
                        summary += '%s: failed to convert %i values to type "%s"\n' % (c['name'], error_count, c['type'])

            return summary
        else:
            return None

    def coerce_type(self, value, normal_type):
        """
        Coerce a single value into a type supported by PANDA.

        All one function for performance.
        """
        if isinstance(value, basestring) and value.lower() in NULL_VALUES:
            value = None

        # All types support nulls
        if value is None:
            return None

        try:
            # unicode
            if normal_type is unicode:
                return unicode(value)
            # int
            elif normal_type is int:
                # Filter currency symbols
                if isinstance(value, str):
                    value = value.translate(None, CURRENCY_SYMBOLS_ASCII)
                elif isinstance(value, unicode):
                    value = value.translate(CURRENCY_SYMBOLS_UNICODE_TRANSLATE_TABLE)

                return int(value)
            # bool
            elif normal_type is bool:
                if isinstance(value, basestring):
                    lcase = value.lower()

                    if lcase in TRUE_VALUES:
                        value = True
                    elif lcase in FALSE_VALUES:
                        value = False
                    else:
                        raise ValueError()

                return bool(value)
            # float
            elif normal_type is float:
                # Filter currency symbols
                if isinstance(value, str):
                    value = value.translate(None, CURRENCY_SYMBOLS_ASCII)
                elif isinstance(value, unicode):
                    value = value.translate(CURRENCY_SYMBOLS_UNICODE_TRANSLATE_TABLE)

                return float(value)
            # date, time, datetime
            elif normal_type in [date, time, datetime]:
                # Don't parse empty strings!
                if not value:
                    raise ValueError()

                try:
                    d = parse(value, default=DEFAULT_DATETIME)
                except OverflowError:
                    raise ValueError()
                except TypeError:
                    raise ValueError()

                return d
        except ValueError:
            raise TypeCoercionError(value, normal_type)

<commit_msg>Add every mono-character currency symbol on Wikipedia to supported set. #514.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import date, time, datetime

from csvkit.typeinference import NULL_VALUES, TRUE_VALUES, FALSE_VALUES, DEFAULT_DATETIME
from dateutil.parser import parse

from panda.exceptions import TypeCoercionError

TYPE_NAMES_MAPPING = {
    'unicode': unicode,
    'int': int,
    'bool': bool,
    'float': float,
    'datetime': datetime,
    'date': date,
    'time': time
}

CURRENCY_SYMBOLS_ASCII = '$,'

# Via http://en.wikipedia.org/wiki/Currency_sign
CURRENCY_SYMBOLS_UNICODE_TRANSLATE_TABLE = dict([(ord(c), None) for c in '$,€£₱؋฿₵₡₫ƒ₣₲₴₭ლ₥₦£៛₹₪৳₮₩¥'])

class DataTyper(object):
    """
    A callable object that adds typed columns to a Solr object based on a Dataset schema.
    Along the way it also updates the schema based on the new data.
    """
    def __init__(self, schema):
        self.schema = schema

        # Min/max values for dates/times/datetimes get stored as strings and need to be coerced back
        for n, c in enumerate(self.schema):
            if c['indexed'] and c['type']:
                t = TYPE_NAMES_MAPPING[c['type']]

                if t in (date, time, datetime):
                    self.schema[n]['min'] = self.coerce_type(c['min'], datetime)
                    self.schema[n]['max'] = self.coerce_type(c['max'], datetime)

        self.errors = [[] for c in self.schema]

    def __call__(self, data, row):
        """
        Given a Solr data object and a row of data, will ad typed columns to the data
        object and then return it.
        """
        for n, c in enumerate(self.schema):
            if c['indexed'] and c['type']:
                try:
                    t = TYPE_NAMES_MAPPING[c['type']]
                    value = self.coerce_type(row[n], t)
                    data[c['indexed_name']] = value

                    if t in [int, float, date, time, datetime] and value is not None:
                        if c['min'] is None or value < c['min']:
                            self.schema[n]['min'] = value

                        if c['max'] is None or value > c['max']:
                            self.schema[n]['max'] = value
                except TypeCoercionError, e:
                    self.errors[n].append(e)

        return data

    def summarize(self):
        """
        Generate a plain-text summary of typing, suitable for an email notification.
        """
        if any([c['indexed'] for c in self.schema]):
            summary = 'Summary of column filters:\n\n'

            for n, c in enumerate(self.schema):
                if c['indexed'] and c['type']:
                    error_count = len(self.errors[n])

                    if not error_count:
                        summary += '%s: all values succesfully converted to type "%s"\n' % (c['name'], c['type'])
                    else:
                        summary += '%s: failed to convert %i values to type "%s"\n' % (c['name'], error_count, c['type'])

            return summary
        else:
            return None

    def coerce_type(self, value, normal_type):
        """
        Coerce a single value into a type supported by PANDA.

        All one function for performance.
        """
        if isinstance(value, basestring) and value.lower() in NULL_VALUES:
            value = None

        # All types support nulls
        if value is None:
            return None

        try:
            # unicode
            if normal_type is unicode:
                return unicode(value)
            # int
            elif normal_type is int:
                # Filter currency symbols
                if isinstance(value, str):
                    value = value.translate(None, CURRENCY_SYMBOLS_ASCII)
                elif isinstance(value, unicode):
                    value = value.translate(CURRENCY_SYMBOLS_UNICODE_TRANSLATE_TABLE)

                return int(value)
            # bool
            elif normal_type is bool:
                if isinstance(value, basestring):
                    lcase = value.lower()

                    if lcase in TRUE_VALUES:
                        value = True
                    elif lcase in FALSE_VALUES:
                        value = False
                    else:
                        raise ValueError()

                return bool(value)
            # float
            elif normal_type is float:
                # Filter currency symbols
                if isinstance(value, str):
                    value = value.translate(None, CURRENCY_SYMBOLS_ASCII)
                elif isinstance(value, unicode):
                    value = value.translate(CURRENCY_SYMBOLS_UNICODE_TRANSLATE_TABLE)

                return float(value)
            # date, time, datetime
            elif normal_type in [date, time, datetime]:
                # Don't parse empty strings!
                if not value:
                    raise ValueError()

                try:
                    d = parse(value, default=DEFAULT_DATETIME)
                except OverflowError:
                    raise ValueError()
                except TypeError:
                    raise ValueError()

                return d
        except ValueError:
            raise TypeCoercionError(value, normal_type)

<|endoftext|>


<commit_before>"""
Name: Dimitri Somoff
Final Project: Flappy bird remake "Crappy Bird"
"""
from ggame import App, Color, LineStyle, Sprite, ImageAsset, Frame
import random

class Bird(Sprite):
    asset1 = ImageAsset("images/0.png")
    asset2 = ImageAsset("images/1.png")
    asset3 = ImageAsset("images/2.png")

    def __init__(self, position):
        super().__init__(Bird.asset1, position)
        self.birdy = 350
        self.gravity = .1
        self.wallx = 400
        self.wally = random.randint(-400, 0)
        #bottomwally = self.wally - 130
        CrappyApp.listenKeyEvent("keydown", "space", self.Jump)

    def step(self):
        self.gravity += .05
        self.birdy += self.gravity
        self.y = self.birdy
        if self.walx == 400:
            TopWall((self.wallx, self.wally))
        """
        TopWall((self.wallx, self.wally))
        #BottomWall((self.wallx, bottomwally))
        self.wallx -= 5
"""
    def Jump(self, event):
        self.birdy -= 20
        self.gravity = .1

class TopWall(Sprite):
    top = ImageAsset("images/top.png")
    def __init__(self, position):
        super().__init__(TopWall.top, position)

class BottomWall(Sprite):
    bottom = ImageAsset("images/bottom.png")
    def __init__(self, position):
        super().__init__(BottomWall.bottom, position)

class CrappyApp(App):
    def __init__(self, width, height):
        super().__init__(width, height)
        bg_asset = ImageAsset("images/background.png")
        bg = Sprite(bg_asset, (0,0))
        Bird((20, 350))

    def step(self):
        for bird in self.getSpritesbyClass(Bird):
            bird.step()

myapp = CrappyApp(400, 708)
myapp.run()<commit_msg>Updated from Brython Server: 12/15/2015 6:55:20 PM<commit_after>"""
Name: Dimitri Somoff
Final Project: Flappy bird remake "Crappy Bird"
"""
from ggame import App, Color, LineStyle, Sprite, ImageAsset, Frame
import random

class Bird(Sprite):
    asset1 = ImageAsset("images/0.png")
    asset2 = ImageAsset("images/1.png")
    asset3 = ImageAsset("images/2.png")

    def __init__(self, position):
        super().__init__(Bird.asset1, position)
        self.birdy = 350
        self.gravity = .1
        self.wallx = 400
        self.wally = random.randint(-400, 0)
        #bottomwally = self.wally - 130
        CrappyApp.listenKeyEvent("keydown", "space", self.Jump)

    def step(self):
        self.gravity += .05
        self.birdy += self.gravity
        self.y = self.birdy
        TopWall((self.wallx, self.wally))
        self.wallx -= 5
        #TopWall((self.wallx, self.wally))
        #BottomWall((self.wallx, bottomwally))
        #self.wallx -= 5

    def Jump(self, event):
        self.birdy -= 20
        self.gravity = .1

class TopWall(Sprite):
    top = ImageAsset("images/top.png")
    def __init__(self, position):
        super().__init__(TopWall.top, position)

class BottomWall(Sprite):
    bottom = ImageAsset("images/bottom.png")
    def __init__(self, position):
        super().__init__(BottomWall.bottom, position)

class CrappyApp(App):
    def __init__(self, width, height):
        super().__init__(width, height)
        bg_asset = ImageAsset("images/background.png")
        bg = Sprite(bg_asset, (0,0))
        Bird((20, 350))

    def step(self):
        for bird in self.getSpritesbyClass(Bird):
            bird.step()

myapp = CrappyApp(400, 708)
myapp.run()<|endoftext|>


<commit_before>"""
    ulmo.usgs.ned.core
    ~~~~~~~~~~~~~~~~~~~~~

    This module provides access to the `National Elevation Dataset` provided by the `United States Geological
    Survey`_ `National Map`_ system.

    .. _National Elevation Dataset: http://ned.usgs.gov/
    .. _United States Geological Survey: http://www.usgs.gov/
    .. _National Map: http://nationalmap.gov

"""

import hashlib
import json
import logging
import numpy as np
import os
import pandas as pd
import requests
import subprocess
from ulmo import util
import zipfile

# NED ftp url.
NED_FTP_URL = 'ftp://rockyftp.cr.usgs.gov/vdelivery/Datasets/Staged/NED/<layer>/IMG/'

# ScienceBase webservice url for IMG format NED tiles
# https://www.sciencebase.gov/catalog/items?fields=id,title,summary,body,tags,webLinks,dates,spatial&q=&filter=tags=National Elevation Dataset (NED) 1/9 arc-second&filter=spatialQuery=Polygon ((-95.26155638325938 40.07132704825149,-94.16292357075272 40.07132704825149,-94.16292357075272 40.594749211728654,-95.26155638325938 40.594749211728654,-95.26155638325938 40.07132704825149))&format=json
NED_WS_URL = 'https://www.sciencebase.gov/catalog/items?fields=webLinks&q=&filter=tags=National Elevation Dataset (NED) %s&filter=tags=IMG&filter=spatialQuery=Polygon ((%s))&format=json'

# default file path (appended to default ulmo path)
DEFAULT_FILE_PATH = 'usgs/ned/'

layer_dict = {
        'Alaska 2 arc-second': '2',
        '1 arc-second': '1',
        '1/3 arc-second': '13',
        '1/9 arc-second': '19',
    }

# configure logging
LOG_FORMAT = '%(message)s'
logging.basicConfig(format=LOG_FORMAT)
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)

def get_file_index(path=None, update_cache=False):
    if path is None:
        path = os.path.join(util.get_ulmo_dir(), DEFAULT_FILE_PATH)

    filename = os.path.join(path, 'index.json')

    if not os.path.exists(filename) or update_cache:
        for dirname in layer_dict.itervalues():
            layer_path = os.path.join(path, dirname, 'zip')
            if not os.path.exists(layer_path):
                os.makedirs(layer_path)

        _update_file_index(filename)

    with open(filename) as f:
        return json.load(f)

def get_tile_urls(layer, xmin, ymin, xmax, ymax, path=None, use_webservice=False):
    """
        Find tile urls corresponding to the given layer and bounding box
    """
    if use_webservice:
        polygon = ','.join([(repr(x) + ' ' + repr(y)) for x,y in [
            (xmin, ymax),
            (xmin, ymin),
            (xmax, ymin),
            (xmax, ymax),
            (xmin, ymax)]])
        url = NED_WS_URL % (layer, polygon)
        r = requests.get(url)
        urls = []
        for tile in r.json()['items']:
            urls.append([x for x in tile['webLinks'] if x['type']=='download'][0]['uri'])

        return sorted(urls)

    base_url = NED_FTP_URL.replace('<layer>', layer_dict[layer])
    file_index = get_file_index(path=path)

    if layer in ['1 arc-second', '1/3 arc-second', 'Alaska 2 arc-second']:
        lats = np.arange(np.ceil(ymin), np.ceil(ymax)+1)
        lons = np.arange(np.floor(xmin), np.floor(xmax)+1)
        files = []
        fmt_lat = lambda x: 's%0d' % np.abs(x) if x<0 else 'n%0d' % x
        fmt_lon = lambda x: 'w%03d' % np.abs(x) if x<0 else 'e%03d' % x
        fmt = '%s%s.zip'
        for lat in lats:
            for lon in lons:
                files.append(fmt % (fmt_lat(lat), fmt_lon(lon)))

        available_files = list(set(file_index[layer]).intersection(set(files)))

        urls = [base_url + filename for filename in available_files]
        return sorted(urls)

def _update_file_index(filename):
    index = {}
    for name, layer in layer_dict.iteritems():
        print 'retrieving file index for NED layer - %s' % name
        url = NED_FTP_URL.replace('<layer>', layer)
        index[name] = sorted([line for line in util.dir_list(url) if 'zip' in line])

    with open(filename, 'wb') as outfile:
        json.dump(index, outfile)
        print 'ned raster file index saved in %s' % filename

    return filename

def get_raster(layer, xmin, ymin, xmax, ymax, path=None, use_cache=True,
    check_modified=False):

    if path is None:
        path = os.path.join(util.get_ulmo_dir(), DEFAULT_FILE_PATH)

    if not os.path.exists(path):
        os.makedirs(path)

    if not os.path.exists(os.path.join(path, 'by_boundingbox')):
        os.makedirs(os.path.join(path, 'by_boundingbox'))

    uid = hashlib.md5(','.join([layer, repr(xmin), repr(ymin), repr(xmax), repr(ymax)])).hexdigest()
    output_path = os.path.join(path, 'by_boundingbox', uid + '.tif')

    if os.path.isfile(output_path):
        return output_path

    print 'Downloading tiles needed for requested bounding box:'
    raster_tiles = []
    tiles = get_tile_urls(layer, xmin, ymin, xmax, ymax)
    for i, url in enumerate(tiles):
        filename = os.path.split(url)[-1]
        zip_path = os.path.join(path, layer_dict[layer], 'zip', filename)

        print '... downloading tile %s of %s from %s' % (i+1, len(tiles), url)
        util.download_if_new(url, zip_path, check_modified=check_modified)
        print '... ... zipfile saved at %s' % zip_path
        tile_path = zip_path.replace('/zip', '')
        raster_tiles.append(_extract_raster_from_zip(zip_path, tile_path))

    print 'Mosaic and clip to bounding box extents'
    tile_path = os.path.split(tile_path)[0]
    print subprocess.check_output(['gdalwarp', '-te', repr(xmin), repr(ymin), repr(xmax), repr(ymax)] + raster_tiles + [output_path])
    return output_path

def _extract_raster_from_zip(zip_path, tile_path):
    tile_path = os.path.splitext(tile_path)[0] + '.img'
    if os.path.exists(tile_path):
        if os.stat(zip_path).st_mtime < os.stat(tile_path).st_mtime:
            return tile_path

    with zipfile.ZipFile(zip_path) as z:
        fname = [x for x in z.namelist() if '.img' in x][0]
        with open(tile_path, 'w') as f:
            f.write(z.read(fname))
            print '... ... .img format raster saved at %s' % (tile_path)

    return tile_path
<commit_msg>put in a NotImplemented exception for get_tile_url w/ 1/9 arc-second NED<commit_after>"""
    ulmo.usgs.ned.core
    ~~~~~~~~~~~~~~~~~~~~~

    This module provides access to the `National Elevation Dataset` provided by the `United States Geological
    Survey`_ `National Map`_ system.

    .. _National Elevation Dataset: http://ned.usgs.gov/
    .. _United States Geological Survey: http://www.usgs.gov/
    .. _National Map: http://nationalmap.gov

"""

import hashlib
import json
import logging
import numpy as np
import os
import pandas as pd
import requests
import subprocess
from ulmo import util
import zipfile

# NED ftp url.
NED_FTP_URL = 'ftp://rockyftp.cr.usgs.gov/vdelivery/Datasets/Staged/NED/<layer>/IMG/'

# ScienceBase webservice url for IMG format NED tiles
# https://www.sciencebase.gov/catalog/items?fields=id,title,summary,body,tags,webLinks,dates,spatial&q=&filter=tags=National Elevation Dataset (NED) 1/9 arc-second&filter=spatialQuery=Polygon ((-95.26155638325938 40.07132704825149,-94.16292357075272 40.07132704825149,-94.16292357075272 40.594749211728654,-95.26155638325938 40.594749211728654,-95.26155638325938 40.07132704825149))&format=json
NED_WS_URL = 'https://www.sciencebase.gov/catalog/items?fields=webLinks&q=&filter=tags=National Elevation Dataset (NED) %s&filter=tags=IMG&filter=spatialQuery=Polygon ((%s))&format=json'

# default file path (appended to default ulmo path)
DEFAULT_FILE_PATH = 'usgs/ned/'

layer_dict = {
        'Alaska 2 arc-second': '2',
        '1 arc-second': '1',
        '1/3 arc-second': '13',
        '1/9 arc-second': '19',
    }

# configure logging
LOG_FORMAT = '%(message)s'
logging.basicConfig(format=LOG_FORMAT)
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)

def get_file_index(path=None, update_cache=False):
    if path is None:
        path = os.path.join(util.get_ulmo_dir(), DEFAULT_FILE_PATH)

    filename = os.path.join(path, 'index.json')

    if not os.path.exists(filename) or update_cache:
        for dirname in layer_dict.itervalues():
            layer_path = os.path.join(path, dirname, 'zip')
            if not os.path.exists(layer_path):
                os.makedirs(layer_path)

        _update_file_index(filename)

    with open(filename) as f:
        return json.load(f)

def get_tile_urls(layer, xmin, ymin, xmax, ymax, path=None, use_webservice=False):
    """
        Find tile urls corresponding to the given layer and bounding box
    """
    if use_webservice:
        polygon = ','.join([(repr(x) + ' ' + repr(y)) for x,y in [
            (xmin, ymax),
            (xmin, ymin),
            (xmax, ymin),
            (xmax, ymax),
            (xmin, ymax)]])
        url = NED_WS_URL % (layer, polygon)
        r = requests.get(url)
        urls = []
        for tile in r.json()['items']:
            urls.append([x for x in tile['webLinks'] if x['type']=='download'][0]['uri'])

        return sorted(urls)

    base_url = NED_FTP_URL.replace('<layer>', layer_dict[layer])
    file_index = get_file_index(path=path)

    if layer in ['1 arc-second', '1/3 arc-second', 'Alaska 2 arc-second']:
        lats = np.arange(np.ceil(ymin), np.ceil(ymax)+1)
        lons = np.arange(np.floor(xmin), np.floor(xmax)+1)
        files = []
        fmt_lat = lambda x: 's%0d' % np.abs(x) if x<0 else 'n%0d' % x
        fmt_lon = lambda x: 'w%03d' % np.abs(x) if x<0 else 'e%03d' % x
        fmt = '%s%s.zip'
        for lat in lats:
            for lon in lons:
                files.append(fmt % (fmt_lat(lat), fmt_lon(lon)))

        available_files = list(set(file_index[layer]).intersection(set(files)))

        urls = [base_url + filename for filename in available_files]
        return sorted(urls)

    if layer=='1/9 arc-second':
        raise NotImplementedError("1/9 arc-second NED local tile determination not implemented yet")

def _update_file_index(filename):
    index = {}
    for name, layer in layer_dict.iteritems():
        print 'retrieving file index for NED layer - %s' % name
        url = NED_FTP_URL.replace('<layer>', layer)
        index[name] = sorted([line for line in util.dir_list(url) if 'zip' in line])

    with open(filename, 'wb') as outfile:
        json.dump(index, outfile)
        print 'ned raster file index saved in %s' % filename

    return filename

def get_raster(layer, xmin, ymin, xmax, ymax, path=None, use_cache=True,
    check_modified=False):

    if path is None:
        path = os.path.join(util.get_ulmo_dir(), DEFAULT_FILE_PATH)

    if not os.path.exists(path):
        os.makedirs(path)

    if not os.path.exists(os.path.join(path, 'by_boundingbox')):
        os.makedirs(os.path.join(path, 'by_boundingbox'))

    uid = hashlib.md5(','.join([layer, repr(xmin), repr(ymin), repr(xmax), repr(ymax)])).hexdigest()
    output_path = os.path.join(path, 'by_boundingbox', uid + '.tif')

    if os.path.isfile(output_path):
        return output_path

    print 'Downloading tiles needed for requested bounding box:'
    raster_tiles = []
    tiles = get_tile_urls(layer, xmin, ymin, xmax, ymax)
    for i, url in enumerate(tiles):
        filename = os.path.split(url)[-1]
        zip_path = os.path.join(path, layer_dict[layer], 'zip', filename)

        print '... downloading tile %s of %s from %s' % (i+1, len(tiles), url)
        util.download_if_new(url, zip_path, check_modified=check_modified)
        print '... ... zipfile saved at %s' % zip_path
        tile_path = zip_path.replace('/zip', '')
        raster_tiles.append(_extract_raster_from_zip(zip_path, tile_path))

    print 'Mosaic and clip to bounding box extents'
    tile_path = os.path.split(tile_path)[0]
    print subprocess.check_output(['gdalwarp', '-te', repr(xmin), repr(ymin), repr(xmax), repr(ymax)] + raster_tiles + [output_path])
    return output_path

def _extract_raster_from_zip(zip_path, tile_path):
    tile_path = os.path.splitext(tile_path)[0] + '.img'
    if os.path.exists(tile_path):
        if os.stat(zip_path).st_mtime < os.stat(tile_path).st_mtime:
            return tile_path

    with zipfile.ZipFile(zip_path) as z:
        fname = [x for x in z.namelist() if '.img' in x][0]
        with open(tile_path, 'w') as f:
            f.write(z.read(fname))
            print '... ... .img format raster saved at %s' % (tile_path)

    return tile_path
<|endoftext|>


<commit_before>import datetime

import discord
from discord.ext import commands
from discord.ext.commands.cooldowns import BucketType
from discord.ext.commands.errors import BadArgument

from ..exceptions import APIError, APIForbidden, APINotFound

class GeneralGuild:
    @commands.group()
    async def guild(self, ctx):
        """Guild related commands."""
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)

    @guild.command(name="info", usage="<guild name>")
    @commands.cooldown(1, 20, BucketType.user)
    async def guild_info(self, ctx, *, guild_name=None):
        """General guild stats

        Required permissions: guilds
        """
        # Read preferred guild from DB
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoint = "guild/{0}".format(guild_id)
            results = await self.call_api(endpoint, ctx.author, ["guilds"])
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(
            description='General Info about {0}'.format(guild_name),
            colour=self.embed_color)
        data.set_author(name="{} [{}]".format(results["name"], results["tag"]))
        data.add_field(name='Influence', value=results["influence"])
        data.add_field(name='Aetherium', value=results["aetherium"])
        data.add_field(name='Resonance', value=results["resonance"])
        data.add_field(name='Favor', value=results["favor"])
        data.add_field(
            name='Members',
            value="{}/{}".format(results["member_count"],
                                 str(results["member_capacity"])))
        if "motd" in results:
            data.add_field(
                name='Message of the day:',
                value=results["motd"],
                inline=False)
        data.set_footer(text='A level {} guild'.format(results["level"]))
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="members", usage="<guild name>")
    @commands.cooldown(1, 20, BucketType.user)
    async def guild_members(self, ctx, *, guild_name=None):
        """Get list of the first 20 members and their ranks.
        Only displays the highest ranks.

        Required permissions: guilds and in game permissions
        """
        user = ctx.author
        scopes = ["guilds"]
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoints = [
                "guild/{}/members".format(guild_id),
                "guild/{}/ranks".format(guild_id)
            ]
            results, ranks = await self.call_multiple(endpoints, user, scopes)
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(description="Members", colour=self.embed_color)
        data.set_author(name=guild_name.title())
        counter = 0
        order_id = 1
        # For each order the rank has, go through each member and add it with
        # the current order increment to the embed
        for order in ranks:
            for member in results:
                # Filter invited members
                if member['rank'] != "invited":
                    member_rank = member['rank']
                    # associate order from /ranks with rank from /members
                    for rank in ranks:
                        if member_rank == rank['id']:
                            if rank['order'] == order_id:
                                if counter < 20:
                                    data.add_field(
                                        name=member['name'],
                                        value=member['rank'])
                                    counter += 1
            order_id += 1
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="treasury", usage="<guild name>")
    @commands.cooldown(1, 20, BucketType.user)
    async def guild_treasury(self, ctx, *, guild_name=None):
        """Get list of current and needed items for upgrades

        Required permissions: guilds and in game permissions"""
        # Read preferred guild from DB
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoint = "guild/{0}/treasury".format(guild_id)
            treasury = await self.call_api(endpoint, ctx.author, ["guilds"])
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(description="Treasury", colour=self.embed_color)
        data.set_author(name=guild_name.title())
        counter = 0
        item_counter = 0
        amount = 0
        itemlist = []
        for item in treasury:
            res = await self.db.items.find_one({"_id": item["item_id"]})
            itemlist.append(res)
        # Collect amounts
        if treasury:
            for item in treasury:
                if counter < 20:
                    current = item["count"]
                    item_name = itemlist[item_counter]["name"]
                    needed = item["needed_by"]
                    for need in needed:
                        amount = amount + need["count"]
                    if amount != current:
                        data.add_field(
                            name=item_name,
                            value=str(current) + "/" + str(amount),
                            inline=True)
                        counter += 1
                    amount = 0
                    item_counter += 1
        else:
            await ctx.send("Treasury is empty!")
            return
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="log", usage="<guild name>")
    @commands.cooldown(1, 10, BucketType.user)
    async def guild_log(self, ctx, *, guild_name=None):
        """Get log of last 20 entries of stash
        Required permissions: guilds and in game permissions"""
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoint = "guild/{0}/log/".format(guild_id)
            log = await self.call_api(endpoint, ctx.author, ["guilds"])
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(description="Stash Log", colour=self.embed_color)
        data.set_author(name=guild_name.title())
        counter = 0
        for entry in log:
            if entry["type"] == "stash":
                if counter < 20:
                    quantity = entry["count"]
                    time = entry["time"]
                    timedate = datetime.datetime.strptime(
                        time,
                        "%Y-%m-%dT%H:%M:%S.%fZ").strftime('%d.%m.%Y %H:%M')
                    user = entry["user"]
                    if entry["item_id"] is 0:
                        item_name = self.gold_to_coins(entry["coins"])
                        quantity = ""
                        multiplier = ""
                    else:
                        itemdoc = await self.fetch_item(entry["item_id"])
                        item_name = itemdoc["name"]
                        multiplier = "x"
                    if entry["operation"] == "withdraw":
                        operator = " withdrew"
                    else:
                        operator = " deposited"
                    data.add_field(
                        name=timedate,
                        value=user + "{} {}{} {}".format(
                            operator, quantity, multiplier, item_name),
                        inline=False)
                    counter += 1
        if counter == 0:
            return await ctx.send(
                "No stash log entries yet for {}".format(guild_name.title()))
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="default", usage="<guild name>")
    @commands.guild_only()
    @commands.cooldown(1, 10, BucketType.user)
    @commands.has_permissions(manage_guild=True)
    async def guild_default(self, ctx, *, guild_name=None):
        """ Set your preferred guild for guild commands on this Discord Server.
        Commands from the guild command group invoked
        without a guild name will default to this guild.

        Invoke this command without an argument to reset the default guild.
        """
        guild = ctx.guild
        if guild_name is None:
            await self.bot.database.set_guild(guild, {
                "guild_ingame": None,
            }, self)
            return await ctx.send(
                "Your preferred guild is now reset for "
                "this server. Invoke this command with a guild "
                "name to set a default guild.")
        endpoint_id = "guild/search?name=" + guild_name.replace(' ', '%20')
        # Guild ID to Guild Name
        try:
            guild_id = await self.call_api(endpoint_id)
            guild_id = guild_id[0]
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)

        # Write to DB, overwrites existing guild
        await self.bot.database.set_guild(guild, {
            "guild_ingame": guild_id,
        }, self)
        await ctx.send("Your default guild is now set to {} for this server. "
                       "All commands from the `guild` command group "
                       "invoked without a specified guild will default to "
                       "this guild. To reset, simply invoke this command "
                       "without specifying a guild".format(guild_name.title()))
<commit_msg>Expand guild log with treasury/members/stash (#35)<commit_after>import datetime

import discord
from discord.ext import commands
from discord.ext.commands.cooldowns import BucketType
from discord.ext.commands.errors import BadArgument

from ..exceptions import APIError, APIForbidden, APINotFound

class GeneralGuild:
    @commands.group()
    async def guild(self, ctx):
        """Guild related commands."""
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)

    @guild.command(name="info", usage="<guild name>")
    @commands.cooldown(1, 20, BucketType.user)
    async def guild_info(self, ctx, *, guild_name=None):
        """General guild stats

        Required permissions: guilds
        """
        # Read preferred guild from DB
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoint = "guild/{0}".format(guild_id)
            results = await self.call_api(endpoint, ctx.author, ["guilds"])
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(
            description='General Info about {0}'.format(guild_name),
            colour=self.embed_color)
        data.set_author(name="{} [{}]".format(results["name"], results["tag"]))
        data.add_field(name='Influence', value=results["influence"])
        data.add_field(name='Aetherium', value=results["aetherium"])
        data.add_field(name='Resonance', value=results["resonance"])
        data.add_field(name='Favor', value=results["favor"])
        data.add_field(
            name='Members',
            value="{}/{}".format(results["member_count"],
                                 str(results["member_capacity"])))
        if "motd" in results:
            data.add_field(
                name='Message of the day:',
                value=results["motd"],
                inline=False)
        data.set_footer(text='A level {} guild'.format(results["level"]))
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="members", usage="<guild name>")
    @commands.cooldown(1, 20, BucketType.user)
    async def guild_members(self, ctx, *, guild_name=None):
        """Get list of the first 20 members and their ranks.
        Only displays the highest ranks.

        Required permissions: guilds and in game permissions
        """
        user = ctx.author
        scopes = ["guilds"]
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoints = [
                "guild/{}/members".format(guild_id),
                "guild/{}/ranks".format(guild_id)
            ]
            results, ranks = await self.call_multiple(endpoints, user, scopes)
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(description="Members", colour=self.embed_color)
        data.set_author(name=guild_name.title())
        counter = 0
        order_id = 1
        # For each order the rank has, go through each member and add it with
        # the current order increment to the embed
        for order in ranks:
            for member in results:
                # Filter invited members
                if member['rank'] != "invited":
                    member_rank = member['rank']
                    # associate order from /ranks with rank from /members
                    for rank in ranks:
                        if member_rank == rank['id']:
                            if rank['order'] == order_id:
                                if counter < 20:
                                    data.add_field(
                                        name=member['name'],
                                        value=member['rank'])
                                    counter += 1
            order_id += 1
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="treasury", usage="<guild name>")
    @commands.cooldown(1, 20, BucketType.user)
    async def guild_treasury(self, ctx, *, guild_name=None):
        """Get list of current and needed items for upgrades

        Required permissions: guilds and in game permissions"""
        # Read preferred guild from DB
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoint = "guild/{0}/treasury".format(guild_id)
            treasury = await self.call_api(endpoint, ctx.author, ["guilds"])
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)
        data = discord.Embed(description="Treasury", colour=self.embed_color)
        data.set_author(name=guild_name.title())
        counter = 0
        item_counter = 0
        amount = 0
        itemlist = []
        for item in treasury:
            res = await self.db.items.find_one({"_id": item["item_id"]})
            itemlist.append(res)
        # Collect amounts
        if treasury:
            for item in treasury:
                if counter < 20:
                    current = item["count"]
                    item_name = itemlist[item_counter]["name"]
                    needed = item["needed_by"]
                    for need in needed:
                        amount = amount + need["count"]
                    if amount != current:
                        data.add_field(
                            name=item_name,
                            value=str(current) + "/" + str(amount),
                            inline=True)
                        counter += 1
                    amount = 0
                    item_counter += 1
        else:
            await ctx.send("Treasury is empty!")
            return
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="log", usage="stash/treasury/members <guild name>")
    @commands.cooldown(1, 10, BucketType.user)
    async def guild_log(self, ctx, log_type, *, guild_name=None):
        """Get log of last 20 entries of stash/treasury/members
        Required permissions: guilds and in game permissions"""
        state = log_type.lower()
        member_list = ["invited", "joined", "invite_declined"]
        if state not in ("stash", "treasury", "members"):
            return await self.bot.send_cmd_help(ctx)
        try:
            guild = await self.get_guild(ctx, guild_name=guild_name)
            if not guild:
                raise BadArgument
            guild_id = guild["id"]
            guild_name = guild["name"]
            endpoint = "guild/{0}/log/".format(guild_id)
            log = await self.call_api(endpoint, ctx.author, ["guilds"])
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)

        data = discord.Embed(description="{0} Log".format(state.capitalize()), colour=self.embed_color)
        data.set_author(name=guild_name.title())
        counter = 0
        for entry in log:
            if entry["type"] == state:
                if counter < 20:
                    time = entry["time"]
                    timedate = datetime.datetime.strptime(
                        time,
                        "%Y-%m-%dT%H:%M:%S.%fZ").strftime('%d.%m.%Y %H:%M')
                    user = entry["user"]
                    if state == "stash" or state == "treasury":
                        quantity = entry["count"]
                        if entry["item_id"] is 0:
                            item_name = self.gold_to_coins(entry["coins"])
                            quantity = ""
                            multiplier = ""
                        else:
                            itemdoc = await self.fetch_item(entry["item_id"])
                            item_name = itemdoc["name"]
                            multiplier = "x"
                        if state == "stash":
                            if entry["operation"] == "withdraw":
                                operator = " withdrew"
                            else:
                                operator = " deposited"
                        else:
                            operator = " donated"
                        data.add_field(
                            name=timedate,
                            value=user + "{} {}{} {}".format(
                                operator, quantity, multiplier, item_name),
                            inline=False)
                        counter += 1
            if state == "members":
                if entry["type"] in member_list:
                    time = entry["time"]
                    timedate = datetime.datetime.strptime(
                        time,
                        "%Y-%m-%dT%H:%M:%S.%fZ").strftime('%d.%m.%Y %H:%M')
                    user = entry["user"]
                    if entry["type"] == "invited":
                        invited_by = entry["invited_by"]
                        data.add_field(name=timedate, value="{} has invited {} to the guild.".format(invited_by, user),
                                       inline=False)
                    elif entry["type"] == "joined":
                        data.add_field(name=timedate, value="{} has joined the guild.".format(user), inline=False)
                    elif entry["type"] == "kick":
                        kicked_by = entry["kicked_by"]
                        if kicked_by == user:
                            data.add_field(name=timedate, value="{} has left the guild.".format(user), inline=False)
                        else:
                            data.add_field(name=timedate, value="{} has been kicked by {}.".format(user, kicked_by),
                                           inline=False)
                    elif entry["type"] == "rank_change":
                        old_rank = entry["old_rank"]
                        new_rank = entry["new_rank"]
                        changed_by = entry["changed_by"]
                        data.add_field(name=timedate,
                                       value="{} has changed the role of {} from {} to {}.".format(changed_by, user,
                                                                                old_rank, new_rank),
                                       inline=False)
                    counter += 1
        if counter == 0:
            return await ctx.send(
                "No {} log entries yet for {}".format(state, guild_name.title()))
        try:
            await ctx.send(embed=data)
        except discord.Forbidden:
            await ctx.send("Need permission to embed links")

    @guild.command(name="default", usage="<guild name>")
    @commands.guild_only()
    @commands.cooldown(1, 10, BucketType.user)
    @commands.has_permissions(manage_guild=True)
    async def guild_default(self, ctx, *, guild_name=None):
        """ Set your preferred guild for guild commands on this Discord Server.
        Commands from the guild command group invoked
        without a guild name will default to this guild.

        Invoke this command without an argument to reset the default guild.
        """
        guild = ctx.guild
        if guild_name is None:
            await self.bot.database.set_guild(guild, {
                "guild_ingame": None,
            }, self)
            return await ctx.send(
                "Your preferred guild is now reset for "
                "this server. Invoke this command with a guild "
                "name to set a default guild.")
        endpoint_id = "guild/search?name=" + guild_name.replace(' ', '%20')
        # Guild ID to Guild Name
        try:
            guild_id = await self.call_api(endpoint_id)
            guild_id = guild_id[0]
        except (IndexError, APINotFound):
            return await ctx.send("Invalid guild name")
        except APIForbidden:
            return await ctx.send(
                "You don't have enough permissions in game to "
                "use this command")
        except APIError as e:
            return await self.error_handler(ctx, e)

        # Write to DB, overwrites existing guild
        await self.bot.database.set_guild(guild, {
            "guild_ingame": guild_id,
        }, self)
        await ctx.send("Your default guild is now set to {} for this server. "
                       "All commands from the `guild` command group "
                       "invoked without a specified guild will default to "
                       "this guild. To reset, simply invoke this command "
                       "without specifying a guild".format(guild_name.title()))
<|endoftext|>


<commit_before>from django.shortcuts import render, redirect
from django.http import Http404
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AuthenticationForm
from .models import Person, Bill, Organization, Action, Event
from haystack.forms import FacetedSearchForm
from datetime import date, timedelta
from itertools import groupby
import councilmatic.city_config as city_config

class CouncilmaticSearchForm(FacetedSearchForm):

    def __init__(self, *args, **kwargs):
        self.load_all = True

        super(CouncilmaticSearchForm, self).__init__(*args, **kwargs)

    def no_query_found(self):
        return self.searchqueryset.all()

def city_context(request):
	city_context = {
		'city_name': city_config.CITY_NAME,
		'city_council_name': city_config.CITY_COUNCIL_NAME,
		'search_placeholder_text': city_config.SEARCH_PLACEHOLDER_TEXT,
		'legislation_type_descriptions': city_config.LEGISLATION_TYPE_DESCRIPTIONS,
	}
	return city_context

@login_required(login_url='/login/')
def index(request):
	one_month_ago = date.today() + timedelta(days=-30)
	recent_legislation = Bill.objects.exclude(last_action_date=None).filter(last_action_date__gt=one_month_ago).order_by('-last_action_date').all()
	recently_passed = [l for l in recent_legislation if l.inferred_status == 'Passed']

	context = {
		'recent_legislation': recent_legislation,
		'recently_passed': recently_passed,
		'next_council_meeting': Event.next_city_council_meeting(),
		'upcoming_committee_meetings': Event.upcoming_committee_meetings(),
	}

	return render(request, 'core/index.html', context)

def about(request):

	return render(request, 'core/about.html')

def not_found(request):
	return render(request, 'core/404.html')

def council_members(request):
	city_council = Organization.objects.filter(ocd_id=city_config.OCD_CITY_COUNCIL_ID).first()
	context = {
		'city_council': city_council
	}

	return render(request, 'core/council_members.html', context)

def bill_detail(request, slug):

	legislation = Bill.objects.filter(slug=slug).first()

	if not legislation:
		raise Http404("Legislation does not exist")

	actions = legislation.actions.all().order_by('-order')

	context={
		'legislation': legislation,
		'actions': actions
	}

	return render(request, 'core/legislation.html', context)

def committees(request):

	committees = Organization.committees().filter(name__startswith='Committee')

	subcommittees = Organization.committees().filter(name__startswith='Subcommittee')

	taskforces = Organization.committees().filter(name__startswith='Task Force')

	context={
		'committees': committees,
		'subcommittees': subcommittees,
		'taskforces': taskforces,
	}

	return render(request, 'core/committees.html', context)

def committee_detail(request, slug):

	committee = Organization.objects.filter(slug=slug).first()

	if not committee:
		raise Http404("Committee does not exist")

	chairs = committee.memberships.filter(role="CHAIRPERSON")
	memberships = committee.memberships.filter(role="Committee Member")
	committee_description = city_config.COMMITTEE_DESCIPTIONS[committee.slug] if committee.slug in city_config.COMMITTEE_DESCIPTIONS else None

	context = {
		'committee': committee,
		'chairs': chairs,
		'memberships': memberships,
		'committee_description': committee_description,
	}

	return render(request, 'core/committee.html', context)

def person(request, slug):

	person = Person.objects.filter(slug=slug).first()

	if not person:
		raise Http404("Person does not exist")

	sponsorships = person.sponsorships.order_by('-bill__last_action_date')[:20]

	chairs = person.memberships.filter(role="CHAIRPERSON")
	memberships = person.memberships.filter(role="Committee Member")

	context = {
		'person': person,
		'chairs': chairs,
		'memberships': memberships,
		'sponsorships': sponsorships,
		'sponsored_legislation': [s.bill for s in sponsorships]
	}

	return render(request, 'core/person.html', context)

def events(request, year=None, month=None):

	if not year or not month:
		year = date.today().year
		month = date.today().month

		upcoming_dates = Event.objects.filter(start_time__gt=date.today()).datetimes('start_time', 'day').order_by('start_time')[:50]
		upcoming_events = []
		for d in upcoming_dates:
			events_on_day = Event.objects.filter(start_time__year=d.year).filter(start_time__month=d.month).filter(start_time__day=d.day).order_by('start_time').all()
			upcoming_events.append([d, events_on_day])

		past_dates = Event.objects.datetimes('start_time', 'day').order_by('-start_time')[:50]
		past_events = []
		for d in past_dates:
			events_on_day = Event.objects.filter(start_time__year=d.year).filter(start_time__month=d.month).filter(start_time__day=d.day).order_by('start_time').all()
			past_events.append([d, events_on_day])

		context = {
			'upcoming_events': upcoming_events,
			'past_events': past_events,
		}

		return render(request, 'core/events.html', context)
	else:
		year = int(year)
		month = int(month)

		month_dates = Event.objects.filter(start_time__year=year).filter(start_time__month=month).datetimes('start_time', 'day').order_by('start_time')
		month_events = []
		for d in month_dates:
			events_on_day = Event.objects.filter(start_time__year=d.year).filter(start_time__month=d.month).filter(start_time__day=d.day).order_by('start_time').all()
			month_events.append([d, events_on_day])

		context = {
			'first_date': month_dates[0],
			'month_events': month_events,
		}

		return render(request, 'core/events.html', context)

def event_detail(request, slug):

	event = Event.objects.filter(slug=slug).first()
	agenda_items = event.agenda_items.order_by('order').all()
	agenda_deduped = []
	for a in agenda_items:
		if a.description not in agenda_deduped:
			agenda_deduped.append(a.description)

	participants = [ Organization.objects.filter(name=p.entity_name).first() for p in event.participants.all()]
	context = {
		'event': event,
		'participants': participants,
		'agenda_clean': agenda_deduped,
	}

	return render(request, 'core/event.html', context)

def user_login(request):
	if request.method == 'POST':
		form = AuthenticationForm(data=request.POST)
		if form.is_valid():
			user = form.get_user()
			if user is not None:
				login(request, user)
				return redirect('index')
	else:
		form = AuthenticationForm()

	return render(request, 'core_user/login.html', {'form': form})

def user_logout(request):
    logout(request)
    return redirect('index')
<commit_msg>require login for all pages, closes #44<commit_after>from django.shortcuts import render, redirect
from django.http import Http404
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AuthenticationForm
from .models import Person, Bill, Organization, Action, Event
from haystack.forms import FacetedSearchForm
from datetime import date, timedelta
from itertools import groupby
import councilmatic.city_config as city_config

class CouncilmaticSearchForm(FacetedSearchForm):

    def __init__(self, *args, **kwargs):
        self.load_all = True

        super(CouncilmaticSearchForm, self).__init__(*args, **kwargs)

    def no_query_found(self):
        return self.searchqueryset.all()

def city_context(request):
	city_context = {
		'city_name': city_config.CITY_NAME,
		'city_council_name': city_config.CITY_COUNCIL_NAME,
		'search_placeholder_text': city_config.SEARCH_PLACEHOLDER_TEXT,
		'legislation_type_descriptions': city_config.LEGISLATION_TYPE_DESCRIPTIONS,
	}
	return city_context

@login_required(login_url='/login/')
def index(request):
	one_month_ago = date.today() + timedelta(days=-30)
	recent_legislation = Bill.objects.exclude(last_action_date=None).filter(last_action_date__gt=one_month_ago).order_by('-last_action_date').all()
	recently_passed = [l for l in recent_legislation if l.inferred_status == 'Passed']

	context = {
		'recent_legislation': recent_legislation,
		'recently_passed': recently_passed,
		'next_council_meeting': Event.next_city_council_meeting(),
		'upcoming_committee_meetings': Event.upcoming_committee_meetings(),
	}

	return render(request, 'core/index.html', context)

@login_required(login_url='/login/')
def about(request):

	return render(request, 'core/about.html')

def not_found(request):
	return render(request, 'core/404.html')

@login_required(login_url='/login/')
def council_members(request):
	city_council = Organization.objects.filter(ocd_id=city_config.OCD_CITY_COUNCIL_ID).first()
	context = {
		'city_council': city_council
	}

	return render(request, 'core/council_members.html', context)

@login_required(login_url='/login/')
def bill_detail(request, slug):

	legislation = Bill.objects.filter(slug=slug).first()

	if not legislation:
		raise Http404("Legislation does not exist")

	actions = legislation.actions.all().order_by('-order')

	context={
		'legislation': legislation,
		'actions': actions
	}

	return render(request, 'core/legislation.html', context)

@login_required(login_url='/login/')
def committees(request):

	committees = Organization.committees().filter(name__startswith='Committee')

	subcommittees = Organization.committees().filter(name__startswith='Subcommittee')

	taskforces = Organization.committees().filter(name__startswith='Task Force')

	context={
		'committees': committees,
		'subcommittees': subcommittees,
		'taskforces': taskforces,
	}

	return render(request, 'core/committees.html', context)

@login_required(login_url='/login/')
def committee_detail(request, slug):

	committee = Organization.objects.filter(slug=slug).first()

	if not committee:
		raise Http404("Committee does not exist")

	chairs = committee.memberships.filter(role="CHAIRPERSON")
	memberships = committee.memberships.filter(role="Committee Member")
	committee_description = city_config.COMMITTEE_DESCIPTIONS[committee.slug] if committee.slug in city_config.COMMITTEE_DESCIPTIONS else None

	context = {
		'committee': committee,
		'chairs': chairs,
		'memberships': memberships,
		'committee_description': committee_description,
	}

	return render(request, 'core/committee.html', context)

@login_required(login_url='/login/')
def person(request, slug):

	person = Person.objects.filter(slug=slug).first()

	if not person:
		raise Http404("Person does not exist")

	sponsorships = person.sponsorships.order_by('-bill__last_action_date')[:20]

	chairs = person.memberships.filter(role="CHAIRPERSON")
	memberships = person.memberships.filter(role="Committee Member")

	context = {
		'person': person,
		'chairs': chairs,
		'memberships': memberships,
		'sponsorships': sponsorships,
		'sponsored_legislation': [s.bill for s in sponsorships]
	}

	return render(request, 'core/person.html', context)

@login_required(login_url='/login/')
def events(request, year=None, month=None):

	if not year or not month:
		year = date.today().year
		month = date.today().month

		upcoming_dates = Event.objects.filter(start_time__gt=date.today()).datetimes('start_time', 'day').order_by('start_time')[:50]
		upcoming_events = []
		for d in upcoming_dates:
			events_on_day = Event.objects.filter(start_time__year=d.year).filter(start_time__month=d.month).filter(start_time__day=d.day).order_by('start_time').all()
			upcoming_events.append([d, events_on_day])

		past_dates = Event.objects.datetimes('start_time', 'day').order_by('-start_time')[:50]
		past_events = []
		for d in past_dates:
			events_on_day = Event.objects.filter(start_time__year=d.year).filter(start_time__month=d.month).filter(start_time__day=d.day).order_by('start_time').all()
			past_events.append([d, events_on_day])

		context = {
			'upcoming_events': upcoming_events,
			'past_events': past_events,
		}

		return render(request, 'core/events.html', context)
	else:
		year = int(year)
		month = int(month)

		month_dates = Event.objects.filter(start_time__year=year).filter(start_time__month=month).datetimes('start_time', 'day').order_by('start_time')
		month_events = []
		for d in month_dates:
			events_on_day = Event.objects.filter(start_time__year=d.year).filter(start_time__month=d.month).filter(start_time__day=d.day).order_by('start_time').all()
			month_events.append([d, events_on_day])

		context = {
			'first_date': month_dates[0],
			'month_events': month_events,
		}

		return render(request, 'core/events.html', context)

@login_required(login_url='/login/')
def event_detail(request, slug):

	event = Event.objects.filter(slug=slug).first()
	agenda_items = event.agenda_items.order_by('order').all()
	agenda_deduped = []
	for a in agenda_items:
		if a.description not in agenda_deduped:
			agenda_deduped.append(a.description)

	participants = [ Organization.objects.filter(name=p.entity_name).first() for p in event.participants.all()]
	context = {
		'event': event,
		'participants': participants,
		'agenda_clean': agenda_deduped,
	}

	return render(request, 'core/event.html', context)

def user_login(request):
	if request.method == 'POST':
		form = AuthenticationForm(data=request.POST)
		if form.is_valid():
			user = form.get_user()
			if user is not None:
				login(request, user)
				return redirect('index')
	else:
		form = AuthenticationForm()

	return render(request, 'core_user/login.html', {'form': form})

def user_logout(request):
    logout(request)
    return redirect('index')
<|endoftext|>