class UserAccountV1(Model): """A user account.""" bucket = "useraccount" VERSION = 1 MIGRATOR = UserAccountMigrator # key is uuid username = Unicode(max_length=255) # TODO: tagpools can be made OneToMany once vumi.persist.fields # gains a OneToMany field tagpools = ManyToMany(UserTagPermissionVNone) applications = ManyToMany(UserAppPermissionVNone) created_at = Timestamp(default=datetime.utcnow) event_handler_config = Json(default=list) msisdn = Unicode(max_length=255, null=True) confirm_start_conversation = Boolean(default=False) # `tags` is allowed to be null so that we can detect freshly-migrated # accounts and populate the tags from active conversations. A new account # has no legacy tags or conversations, so we start with an empty list and # skip the tag collection. tags = Json(default=[], null=True) @Manager.calls_manager def has_tagpool_permission(self, tagpool): for tp_bunch in self.tagpools.load_all_bunches(): for tp in (yield tp_bunch): if tp.tagpool == tagpool: returnValue(True) returnValue(False)
class UserAccountV4(Model): """A user account.""" VERSION = 4 # key is uuid username = Unicode(max_length=255) # TODO: tagpools can be made OneToMany once vumi.persist.fields # gains a OneToMany field tagpools = ManyToMany(UserTagPermissionVNone) applications = ManyToMany(UserAppPermissionVNone) created_at = Timestamp(default=datetime.utcnow) event_handler_config = Json(default=list) msisdn = Unicode(max_length=255, null=True) confirm_start_conversation = Boolean(default=False) can_manage_optouts = Boolean(default=False) email_summary = Unicode(max_length=255, null=True) tags = Json(default=[]) routing_table = RoutingTableField(default=RoutingTable({})) @Manager.calls_manager def has_tagpool_permission(self, tagpool): for tp_bunch in self.tagpools.load_all_bunches(): for tp in (yield tp_bunch): if tp.tagpool == tagpool: returnValue(True) returnValue(False)
class UserAccountVNone(Model): """A user account.""" bucket = "useraccount" # key is uuid username = Unicode(max_length=255) # TODO: tagpools can be made OneToMany once vumi.persist.fields # gains a OneToMany field tagpools = ManyToMany(UserTagPermissionVNone) applications = ManyToMany(UserAppPermissionVNone) created_at = Timestamp(default=datetime.utcnow) event_handler_config = Json(null=True) msisdn = Unicode(max_length=255, null=True) confirm_start_conversation = Boolean(default=False)
def test_from_riak(self): j = Json() d = {"foo": [1, 2, 3]} self.assertEqual(j.from_riak(d), d)
def test_to_riak(self): j = Json() d = {"foo": 5} self.assertEqual(j.to_riak(d), d)
def test_validate(self): j = Json() j.validate({"foo": None}) self.assertRaises(ValidationError, j.validate, None)
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 ConversationV1(Model): """A conversation with an audience""" VERSION = 1 MIGRATOR = ConversationMigrator bucket = 'conversation' user_account = ForeignKey(UserAccount) name = Unicode(max_length=255) description = Unicode(default=u'') conversation_type = Unicode(index=True) config = Json(default=dict) created_at = Timestamp(default=datetime.utcnow, index=True) start_timestamp = Timestamp(index=True) end_timestamp = Timestamp(null=True, index=True) status = Unicode(default=CONVERSATION_DRAFT, index=True) groups = ManyToMany(ContactGroup) batches = ManyToMany(Batch) delivery_class = Unicode(null=True) delivery_tag_pool = Unicode(null=True) delivery_tag = Unicode(null=True) def started(self): return self.running() or self.ended() def ended(self): return self.status == CONVERSATION_FINISHED def running(self): return self.status == CONVERSATION_RUNNING def get_status(self): """ Get the status of this conversation :rtype: str, (CONVERSATION_FINISHED, CONVERSATION_RUNNING, or CONVERSATION_DRAFT) """ 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_started(self): self.status = CONVERSATION_RUNNING def set_status_finished(self): self.status = CONVERSATION_FINISHED 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_routing_name(self): return ':'.join((self.conversation_type, self.key))
class ConversationVNone(Model): """A conversation with an audience""" MIGRATOR = ConversationMigrator bucket = 'conversation' user_account = ForeignKey(UserAccount) subject = Unicode(max_length=255) message = Unicode() start_timestamp = Timestamp() end_timestamp = Timestamp(null=True, index=True) created_at = Timestamp(default=datetime.utcnow) groups = ManyToMany(ContactGroup) conversation_type = Unicode() delivery_class = Unicode(null=True) delivery_tag_pool = Unicode(null=True) delivery_tag = Unicode(null=True) batches = ManyToMany(Batch) metadata = Json(null=True) def started(self): # TODO: Better way to tell if we've started than looking for batches. return bool(self.batches.keys()) def ended(self): return self.end_timestamp is not None def running(self): return self.started() and not self.ended() def get_status(self): """ Get the status of this conversation :rtype: str, (CONVERSATION_FINISHED, CONVERSATION_RUNNING, or CONVERSATION_DRAFT) """ if self.ended(): return CONVERSATION_FINISHED elif self.running(): return CONVERSATION_RUNNING else: return CONVERSATION_DRAFT def add_group(self, group): if isinstance(group, ContactGroup): self.groups.add(group) else: self.groups.add_key(group) def __unicode__(self): return self.subject 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]
class JsonModel(Model): """ Toy model for Json tests. """ j = Json()
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)