class InboundMessageV3(Model): bucket = 'inboundmessage' VERSION = 3 MIGRATOR = InboundMessageMigrator # key is message_id msg = VumiMessage(TransportUserMessage) batches = ManyToMany(BatchVNone) # Extra fields for compound indexes batches_with_timestamps = ListOf(Unicode(), index=True) batches_with_addresses = ListOf(Unicode(), index=True) def save(self): # We override this method to set our index fields before saving. batches_with_timestamps = [] batches_with_addresses = [] timestamp = self.msg['timestamp'] for batch_id in self.batches.keys(): batches_with_timestamps.append(u"%s$%s" % (batch_id, timestamp)) batches_with_addresses.append( u"%s$%s$%s" % (batch_id, timestamp, self.msg['from_addr'])) self.batches_with_timestamps = batches_with_timestamps self.batches_with_addresses = batches_with_addresses return super(InboundMessageV3, self).save()
class OutboundMessage(Model): VERSION = 5 MIGRATOR = OutboundMessageMigrator # key is message_id msg = VumiMessage(TransportUserMessage) batches = ManyToMany(Batch) # Extra fields for compound indexes batches_with_addresses = ListOf(Unicode(), index=True) batches_with_addresses_reverse = ListOf(Unicode(), index=True) def save(self): # We override this method to set our index fields before saving. self.batches_with_addresses = [] self.batches_with_addresses_reverse = [] timestamp = self.msg['timestamp'] if not isinstance(timestamp, basestring): timestamp = format_vumi_date(timestamp) reverse_ts = to_reverse_timestamp(timestamp) for batch_id in self.batches.keys(): self.batches_with_addresses.append( u"%s$%s$%s" % (batch_id, timestamp, self.msg['to_addr'])) self.batches_with_addresses_reverse.append( u"%s$%s$%s" % (batch_id, reverse_ts, self.msg['to_addr'])) return super(OutboundMessage, self).save()
def test_validate(self): """ By default, a ListOf field is a list of Unicode fields. """ listof = ListOf() listof.validate([u'foo', u'bar']) self.assertRaises(ValidationError, listof.validate, u'this is not a list') self.assertRaises(ValidationError, listof.validate, ['a', 2]) self.assertRaises(ValidationError, listof.validate, [1, 2])
class ComputedValueModel(Model): """ Toy model for ComputedValue tests. """ a = Integer() b = Unicode() c = ListOf(Unicode()) a_with_b = ComputedValue(lambda m: u"%s::%s" % (m.a, m.b), Unicode(index=True)) b_with_a = ComputedValue(lambda m: u"%s::%s" % (m.b, m.a), Unicode()) a_with_c = ComputedValue(lambda m: [u"%s::%s" % (m.a, c) for c in m.c], ListOf(Unicode(), index=True))
class Event(Model): VERSION = 2 MIGRATOR = EventMigrator # key is event_id event = VumiMessage(TransportEvent) message = ForeignKey(OutboundMessage) batches = ManyToMany(Batch) # Extra fields for compound indexes message_with_status = Unicode(index=True, null=True) batches_with_statuses_reverse = ListOf(Unicode(), index=True) def save(self): # We override this method to set our index fields before saving. timestamp = self.event['timestamp'] if not isinstance(timestamp, basestring): timestamp = format_vumi_date(timestamp) status = self.event['event_type'] if status == "delivery_report": status = "%s.%s" % (status, self.event['delivery_status']) self.message_with_status = u"%s$%s$%s" % (self.message.key, timestamp, status) self.batches_with_statuses_reverse = [] reverse_ts = to_reverse_timestamp(timestamp) for batch_id in self.batches.keys(): self.batches_with_statuses_reverse.append( u"%s$%s$%s" % (batch_id, reverse_ts, status)) return super(Event, self).save()
def test_validate_listof(self): """ If an explicit subtype is provided, its validation is used. """ comp = ComputedValue(lambda m: NotImplemented, ListOf()) comp.validate([u'foo', u'bar']) self.assertRaises(ValidationError, comp.validate, u'this is not a list') self.assertRaises(ValidationError, comp.validate, ['a', 2]) self.assertRaises(ValidationError, comp.validate, [1, 2])
def test_validate_with_subtype(self): """ If an explicit subtype is provided, its validation is used. """ listof_unicode = ListOf(Unicode()) listof_unicode.validate([u"a", u"b"]) self.assertRaises(ValidationError, listof_unicode.validate, [1, 2]) listof_int = ListOf(Integer()) listof_int.validate([1, 2]) self.assertRaises(ValidationError, listof_int.validate, [u"a", u"b"]) listof_smallint = ListOf(Integer(max=10)) listof_smallint.validate([1, 2]) self.assertRaises( ValidationError, listof_smallint.validate, [1, 100])
class OutboundMessage(Model): VERSION = 3 MIGRATOR = OutboundMessageMigrator # key is message_id msg = VumiMessage(TransportUserMessage) batches = ManyToMany(Batch) # Extra fields for compound indexes batches_with_timestamps = ListOf(Unicode(), index=True) batches_with_addresses = ListOf(Unicode(), index=True) def save(self): # We override this method to set our index fields before saving. batches_with_timestamps = [] batches_with_addresses = [] timestamp = format_vumi_date(self.msg['timestamp']) for batch_id in self.batches.keys(): batches_with_timestamps.append(u"%s$%s" % (batch_id, timestamp)) batches_with_addresses.append( u"%s$%s$%s" % (batch_id, timestamp, self.msg['to_addr'])) self.batches_with_timestamps = batches_with_timestamps self.batches_with_addresses = batches_with_addresses return super(OutboundMessage, self).save()
class Router(Model): """A router for sending messages to interesting places.""" VERSION = 1 MIGRATOR = None user_account = ForeignKey(UserAccount) name = Unicode(max_length=255) description = Unicode(default=u'') router_type = Unicode(index=True) config = Json(default=dict) extra_inbound_endpoints = ListOf(Unicode()) extra_outbound_endpoints = ListOf(Unicode()) created_at = Timestamp(default=datetime.utcnow, index=True) archived_at = Timestamp(null=True, index=True) archive_status = Unicode(default=ROUTER_ACTIVE, index=True) status = Unicode(default=ROUTER_STOPPED, index=True) batch = ForeignKey(Batch) def active(self): return self.archive_status == ROUTER_ACTIVE def archived(self): return self.archive_status == ROUTER_ARCHIVED def starting(self): return self.status == ROUTER_STARTING def running(self): return self.status == ROUTER_RUNNING def stopping(self): return self.status == ROUTER_STOPPING def stopped(self): return self.status == ROUTER_STOPPED # The following are to keep the implementation of this stuff in the model # rather than potentially multiple external places. def set_status_starting(self): self.status = ROUTER_STARTING def set_status_started(self): self.status = ROUTER_RUNNING def set_status_stopping(self): self.status = ROUTER_STOPPING def set_status_stopped(self): self.status = ROUTER_STOPPED def set_status_finished(self): self.archive_status = ROUTER_ARCHIVED def __unicode__(self): return self.name def get_inbound_connector(self): return GoConnector.for_router(self.router_type, self.key, GoConnector.INBOUND) def get_outbound_connector(self): return GoConnector.for_router(self.router_type, self.key, GoConnector.OUTBOUND)
class Batch(Model): # key is batch_id tags = ListOf(Tag()) metadata = Dynamic(Unicode())
class BatchVNone(Model): bucket = 'batch' # key is batch_id tags = ListOf(Tag()) metadata = Dynamic(Unicode())
def test_validate(self): listof = ListOf() listof.validate([u'foo', u'bar']) self.assertRaises(ValidationError, listof.validate, u'this is not a list') self.assertRaises(ValidationError, listof.validate, ['a', 2])
class ListOfModel(Model): items = ListOf(Integer())
class Conversation(Model): """A conversation with an audience""" VERSION = 3 MIGRATOR = ConversationMigrator user_account = ForeignKey(UserAccount) name = Unicode(max_length=255) description = Unicode(default=u'') conversation_type = Unicode(index=True) config = Json(default=dict) extra_endpoints = ListOf(Unicode()) created_at = Timestamp(default=datetime.utcnow, index=True) archived_at = Timestamp(null=True, index=True) archive_status = Unicode(default=CONVERSATION_ACTIVE, index=True) status = Unicode(default=CONVERSATION_STOPPED, index=True) groups = ManyToMany(ContactGroup) batch = ForeignKey(Batch) delivery_class = Unicode(null=True) def active(self): return self.archive_status == CONVERSATION_ACTIVE def archived(self): return self.archive_status == CONVERSATION_ARCHIVED def ended(self): # TODO: Get rid of this once the old UI finally goes away. return self.archived() def starting(self): return self.status == CONVERSATION_STARTING def running(self): return self.status == CONVERSATION_RUNNING def stopping(self): return self.status == CONVERSATION_STOPPING def stopped(self): return self.status == CONVERSATION_STOPPED def is_draft(self): # TODO: Get rid of this once the old UI finally goes away. return self.active() and self.status == CONVERSATION_STOPPED def get_status(self): """Get the status of this conversation. Possible values are: * CONVERSATION_STARTING * CONVERSATION_RUNNING * CONVERSATION_STOPPING * CONVERSATION_STOPPED :rtype: str """ return self.status # The following are to keep the implementation of this stuff in the model # rather than potentially multiple external places. def set_status_starting(self): self.status = CONVERSATION_STARTING def set_status_started(self): self.status = CONVERSATION_RUNNING def set_status_stopping(self): self.status = CONVERSATION_STOPPING def set_status_stopped(self): self.status = CONVERSATION_STOPPED def set_status_finished(self): self.archive_status = CONVERSATION_ARCHIVED def add_group(self, group): if isinstance(group, ContactGroup): self.groups.add(group) else: self.groups.add_key(group) def __unicode__(self): return self.name def get_contacts_addresses(self, contacts): """ Get the contacts assigned to this group with an address attribute that is appropriate for this conversation's delivery_class """ addrs = [contact.addr_for(self.delivery_class) for contact in contacts] return [addr for addr in addrs if addr] def get_connector(self): return GoConnector.for_conversation(self.conversation_type, self.key)
class IndexedListOfModel(Model): """ Toy model for ListOf index tests. """ items = ListOf(Integer(), index=True)
class ListOfModel(Model): """ Toy model for ListOf tests. """ items = ListOf(Integer()) texts = ListOf(Unicode())
def test_validate_with_subtype(self): """ If an explicit subtype is provided, its validation is used. """ listof_unicode = ListOf(Unicode()) listof_unicode.validate([u"a", u"b"]) self.assertRaises(ValidationError, listof_unicode.validate, [1, 2]) listof_int = ListOf(Integer()) listof_int.validate([1, 2]) self.assertRaises(ValidationError, listof_int.validate, [u"a", u"b"]) listof_smallint = ListOf(Integer(max=10)) listof_smallint.validate([1, 2]) self.assertRaises(ValidationError, listof_smallint.validate, [1, 100])