예제 #1
0
class AB_Candidate_Names(models.Model):
    first_name = TruncatingCharField(max_length=40)
    last_name = TruncatingCharField(max_length=40)
    ab_entry = models.ForeignKey(AddressBook, related_name='candidate_names')

    def __repr__(self):
        return self.first_name + " " + self.last_name
예제 #2
0
class WizcardFlick(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    a_created = TruncatingCharField(max_length=40, blank=True)
    wizcard = models.ForeignKey(Wizcard, related_name='flicked_cards')
    timeout = models.IntegerField(default=30)
    lat = models.FloatField(null=True, default=None)
    lng = models.FloatField(null=True, default=None)
    location = GenericRelation(LocationMgr)
    expired = models.BooleanField(default=False)
    reverse_geo_name = TruncatingCharField(max_length=100, default=None)
    #who picked my flicked card?
    flick_pickers = models.ManyToManyField(Wizcard)

    objects = WizcardFlickManager()

    def create_location(self, lat, lng):
        #create
        key = wizlib.create_geohash(lat, lng)
        retval = location.send(sender=self,
                               lat=lat,
                               lng=lng,
                               key=key,
                               tree="WTREE")
        loc = retval[0][1]

        return loc

    # AA: TODO. The whole flick thing needs to be revisited anyway.
    def delete(self, *args, **kwargs):
        notif = kwargs.pop('type', None)
        self.location.get().delete()

        if notif[0] == verbs.WIZCARD_FLICK_TIMEOUT[0]:
            #timeout
            logger.debug('timeout flicked wizcard %s', self.id)
            self.expired = True
            self.save()
            notify.send(
                self.wizcard.user,
                recipient=self.wizcard.user,
                notif_tuple=verbs.WIZCARD_FLICK_TIMEOUT,
                target=self
            )
        else:
            #withdraw/delete flick case
            logger.debug('withdraw flicked wizcard %s', self.id)
            super(WizcardFlick, self).delete(*args, **kwargs)

    def get_tag(self):
        return WizcardFlick.objects.tag

    def time_remaining(self):
        if not self.expired:
            return self.location.get().timer.get().time_remaining()
        else:
            return 0
예제 #3
0
class Base411Mixin(models.Model):
    class Meta:
        abstract = True

    created = models.DateTimeField(auto_now_add=True, null=True)
    modified = models.DateTimeField(auto_now=True, null=True)
    name = TruncatingCharField(max_length=50, default="")
    email = EmailField(blank=True)
예제 #4
0
class DeadCard(WizcardBase):
    user = models.ForeignKey(User, related_name="dead_cards")
    first_name = TruncatingCharField(max_length=30, default="")
    last_name = TruncatingCharField(max_length=30, default="")
    invited = models.BooleanField(default=False)
    activated = models.BooleanField(default=False)
    cctx = PickledObjectField(blank=True, default={})

    def __unicode__(self):
        return _(u'%(user)s\'s deadcard') % {'user': unicode(self.user)}

    def delete(self, *args, **kwargs):
        # incomplete...need to take care of storage cleanup and/or, not deleting
        # but setting a flag instead
        super(DeadCard, self).delete(*args, **kwargs)

    def recognize(self, path):
        ocr = OCR()
        result = ocr.process(path)

        self.first_name = result.get('first_name', "")
        self.last_name = result.get('last_name', "")
        self.phone = result.get('phone', "")
        self.email = result.get('email', "")
        self.ext_fields = dict(web=result.get('web', ""))

        c = self.contact_container.get()
        c.company = result.get('company', "")
        c.title = result.get('job', "")

        c.save()
        self.save()

    def set_context(self, cctx):
        self.cctx = cctx
        self.save()

    def get_context(self):
        return self.cctx
예제 #5
0
class ContactContainer(CompanyTitleMixin):
    wizcard = models.ForeignKey(WizcardBase, related_name="contact_container")
    phone = TruncatingCharField(max_length=20, blank=True)
    media = RelatedObjectsDescriptor()

    def __unicode__(self):
        return (u'%(user)s\'s contact container: %(title)s@ %(company)s \n') % \
               {'user': unicode(self.wizcard.user), 'title': unicode(self.title), 'company': unicode(self.company)}

    class Meta:
        ordering = ['id']

    def get_fbizcard_url(self):
        bz = [x.media_element for x in self.media.all().generic_objects() if x.media_sub_type == MediaMixin.SUB_TYPE_F_BIZCARD]
        if bz:
            return bz

        return ""
예제 #6
0
class AB_Candidate_Phones(models.Model):
    phone = TruncatingCharField(max_length=20)
    ab_entry = models.ForeignKey(AddressBook, related_name='candidate_phones')

    def __repr__(self):
        return self.phone
예제 #7
0
class AddressBook(models.Model):
    # this is the high confidence, cleaned up phone
    phone = TruncatingCharField(max_length=20, blank=True)
    # to indicate if above entry is definitely the right one
    phone_finalized = models.BooleanField(default=False)

    email = EmailField(blank=True)
    # to indicate if above entry is definitely the right one
    email_finalized = models.BooleanField(default=False)

    first_name = TruncatingCharField(max_length=40, blank=True)
    last_name = TruncatingCharField(max_length=40, blank=True)
    # to indicate if above entry is definitely the right one
    first_name_finalized = models.BooleanField(default=False)
    last_name_finalized = models.BooleanField(default=False)
    users = models.ManyToManyField(User, through='AB_User')

    def __repr__(self):
        return self.first_name + " " + self.last_name + " " + self.email + " " + self.phone

    def serialize(self, template=fields.addressbook_template):
        return serialize(self, **template)

    # look through all the candidates and check if there is
    # a majority wins case
    def run_finalize_decision(self):
        save = False
        try:
            if not self.phone_finalized and self.candidate_phones.count():
                common, count = wizlib.most_common(
                    map(lambda x: x.phone, self.candidate_phones.all()))
                if count >= MIN_MATCHES_FOR_PHONE_DECISION:
                    self.phone = common
                    self.phone_finalized = True
                    save = True

            if not self.email_finalized and self.candidate_emails.count():
                common, count = wizlib.most_common(
                    map(lambda x: x.email, self.candidate_emails.all()))
                if count >= MIN_MATCHES_FOR_EMAIL_DECISION:
                    self.email = common
                    self.email_finalized = True
                    save = True

            if not self.first_name_finalized and self.candidate_names.count():
                common, count = wizlib.most_common(
                    map(lambda x: x.first_name, self.candidate_names.all()))
                if count >= MIN_MATCHES_FOR_NAME_DECISION:
                    self.first_name = common
                    self.first_name_finalized = True
                    save = True

            if not self.last_name_finalized and self.candidate_names.count():
                common, count = wizlib.most_common(
                    map(lambda x: x.last_name, self.candidate_names.all()))
                if count >= MIN_MATCHES_FOR_NAME_DECISION:
                    self.last_name = common
                    self.last_name_finalized = True
                    save = True
            if save:
                self.save()
        except:
            # really weird..adding debugs to see wtf is happening
            logger.error('WTF IS HAPPENING %s: %s, %s, %s', self,
                         self.candidate_names.all(),
                         self.candidate_phones.all(),
                         self.candidate_emails.all())
            pass

    def get_phone(self):
        if self.phone_finalized:
            return self.phone
        else:
            if self.candidate_phones.all():
                return wizlib.most_common(
                    map(lambda x: x.phone, self.candidate_phones.all()))[0]
            else:
                return ""

    def get_all_phones(self):
        if self.phone_finalized:
            return [self.phone]
        else:
            if self.candidate_phones.all():
                return [
                    wizlib.most_common(
                        map(lambda x: x.phone, self.candidate_phones.all()))[0]
                ]
            else:
                return []

    def get_all_emails(self):
        if self.email_finalized:
            return [self.email]
        else:
            if self.candidate_emails.all():
                return [
                    wizlib.most_common(
                        map(lambda x: x.email, self.candidate_emails.all()))[0]
                ]
            else:
                return []

    def get_email(self):
        if self.email_finalized:
            return self.email
        else:
            if self.candidate_emails.all():
                return wizlib.most_common(
                    map(lambda x: x.email, self.candidate_emails.all()))[0]
            else:
                return ""

    def get_name(self):
        first_name = \
            self.first_name if self.first_name_finalized else \
                wizlib.most_common(map(lambda x: x.first_name, self.candidate_names.all()))[0]
        last_name = self.last_name if self.last_name_finalized else \
            wizlib.most_common(map(lambda x: x.last_name, self.candidate_names.all()))[0]

        return first_name.capitalize() + " " + last_name.capitalize()

    def is_phone_final(self):
        return self.phone_finalized

    def is_email_final(self):
        return self.email_finalized

    def is_name_final(self):
        return self.first_name_finalized and self.last_name_finalized
예제 #8
0
class FutureUser(models.Model):
    inviter = models.ForeignKey(User, related_name='invitees')
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    phone = TruncatingCharField(max_length=20, blank=True)
    email = EmailField(blank=True)
    created = models.DateTimeField(auto_now_add=True)
    entity_state = models.CharField(
        choices=BaseEntityComponent.ENTITY_STATE_CHOICES,
        default=BaseEntityComponent.ENTITY_STATE_CREATED,
        max_length=3)

    objects = FutureUserManager()

    def generate_self_invite(self, real_user):
        cctx = ConnectionContext(
            asset_obj=self.content_object,
            connection_mode=verbs.INVITE_VERBS[verbs.SMS_INVITE]
            if self.phone else verbs.INVITE_VERBS[verbs.EMAIL_INVITE])
        if ContentType.objects.get_for_model(self.content_object) == \
                ContentType.objects.get(model="wizcard"):

            # spoof an exchange, as if it came from the inviter
            rel12 = Wizcard.objects.cardit(self.content_object,
                                           real_user.wizcard,
                                           cctx=cctx)
            cctx = ConnectionContext(
                asset_obj=real_user.wizcard,
                connection_mode=verbs.INVITE_VERBS[verbs.SMS_INVITE]
                if self.phone else verbs.INVITE_VERBS[verbs.EMAIL_INVITE])
            # sender always accepts the receivers wizcard
            rel21 = Wizcard.objects.cardit(real_user.wizcard,
                                           self.content_object,
                                           status=verbs.ACCEPTED,
                                           cctx=cctx)
            # Q notif for to_wizcard
            notify.send(self.inviter,
                        recipient=real_user,
                        notif_tuple=verbs.WIZREQ_U,
                        description=cctx.description,
                        target=self.content_object,
                        action_object=rel12)

            # Q implicit notif for from_wizcard
            notify.send(real_user,
                        recipient=self.inviter,
                        notif_tuple=verbs.WIZREQ_T,
                        description=cctx.description,
                        target=real_user.wizcard,
                        action_object=rel21)
        elif ContentType.objects.get_for_model(self.content_object) == \
                ContentType.objects.get(model="virtualtable"):
            # Q this to the receiver
            notify.send(self.inviter,
                        recipient=real_user,
                        notif_tuple=verbs.WIZCARD_TABLE_INVITE,
                        target=self.content_object)

    def delete(self, *args, **kwargs):
        self.entity_state = BaseEntityComponent.ENTITY_STATE_DELETED
        self.save()
예제 #9
0
class AppUser(BaseUser):
    DEVICE_CHOICES = (
        (settings.DEVICE_IOS, 'iPhone'),
        (settings.DEVICE_ANDROID, 'Android'),
    )

    location = GenericRelation(LocationMgr)
    do_sync = models.BooleanField(default=False)
    device_id = TruncatingCharField(max_length=100)
    reg_token = models.CharField(db_index=True, max_length=200)
    device_type = TruncatingCharField(max_length=10, choices=DEVICE_CHOICES)
    reco_generated_at = models.DateTimeField(default=RECO_DEFAULT_TIME)
    reco_ready = models.PositiveIntegerField(default=0)
    settings = models.OneToOneField(AppUserSettings, related_name='base_user')

    objects = UserProfileManager()

    def online_key(self):
        return self.profile.userid

    def online(self):
        cache.set(settings.USER_ONLINE_PREFIX % self.online_key(),
                  timezone.now(), settings.USER_LASTSEEN_TIMEOUT)

    def can_send_data(self, on_wifi):
        return True if on_wifi else not self.is_wifi_data

    def last_seen(self):
        now = timezone.now()
        ls = cache.get(settings.USER_ONLINE_PREFIX % self.online_key())
        if bool(ls):
            return True, (now - ls)
        else:
            return False, None

    def is_online(self):
        on, ls = self.last_seen()
        delta = timezone.timedelta(seconds=settings.USER_ONLINE_TIMEOUT)
        if on and (ls < delta):
            return True
        return False

    def create_or_update_location(self, lat, lng):
        try:
            loc = self.location.get()
            updated = loc.do_update(lat, lng)
            loc.reset_timer()
            return loc
        except ObjectDoesNotExist:
            # create
            l_tuple = location.send(sender=self,
                                    lat=lat,
                                    lng=lng,
                                    tree="PTREE")
            l_tuple[0][1].start_timer(settings.USER_ACTIVE_TIMEOUT)

    def lookup(self, n, count_only=False):
        users = None
        try:
            loc = self.location.get()
        except ObjectDoesNotExist:
            return None, None

        result, count = loc.lookup(n)
        # convert result to query set result
        if count and not count_only:
            users = [
                AppUser.objects.get(id=x).profile.user for x in result
                if AppUser.objects.filter(id=x,
                                          profile__activated=True,
                                          settings__is_visible=True).exists()
            ]
            count = len(users)
        return users, count

    def do_resync(self):
        s = {}
        # add callouts to all serializable objects here

        # wizcard
        try:
            wizcard = self.profile.user.wizcard
        except ObjectDoesNotExist:
            return s

        s['wizcard'] = WizcardSerializerL2(wizcard,
                                           context={
                                               'user': self.profile.user
                                           }).data

        # # flicks (put  before wizconnections since wizconnection could refer to flicks)
        # if wizcard.flicked_cards.count():
        #     wf = wizcard.serialize_wizcardflicks()
        #     s['wizcard_flicks'] = wf

        # wizconnections
        if wizcard.wizconnections_from.count():
            wc = wizcard.serialize_wizconnections()
            s['wizconnections'] = wc

        # Populate Context for Wizcards that this user  is following
        conn = WizConnectionRequest.objects.filter(to_wizcard=wizcard,
                                                   status=verbs.ACCEPTED)
        if conn:
            cctx = map(
                lambda x: NotifContext(description=x.cctx.description,
                                       asset_id=x.cctx.asset_id,
                                       asset_type=x.cctx.asset_type,
                                       connection_mode=x.cctx.connection_mode,
                                       notes=x.cctx.notes,
                                       timestamp=x.created.strftime("%d %B %Y")
                                       ).context, conn)

            s['context'] = serialize(cctx)

        # tables
        tables = VirtualTable.objects.users_entities(
            self.profile.user,
            user_filter={'state': UserEntity.JOIN},
            entity_filter={
                'entity_state': [BaseEntityComponent.ENTITY_STATE_PUBLISHED]
            })

        if tables:
            # serialize created and joined tables
            tbls = TableSerializerL1(tables,
                                     many=True,
                                     context={
                                         'user': self.profile.user
                                     }).data
            s['tables'] = tbls

        # dead card
        deadcards = self.profile.user.dead_cards.filter(activated=True)
        if deadcards.count():
            dc = DeadCardSerializerL2(deadcards,
                                      many=True,
                                      context={
                                          'user': self.profile.user
                                      }).data
            s['deadcards'] = dc

        campaigns = Campaign.objects.users_entities(
            self.profile.user,
            user_filter={'state': UserEntity.PIN},
            entity_filter={
                'entity_state': [BaseEntityComponent.ENTITY_STATE_PUBLISHED]
            })

        if campaigns:
            camp_data = CampaignSerializer(campaigns,
                                           many=True,
                                           context={
                                               'user': self.profile.user
                                           }).data
            s['campaigns'] = camp_data

        # events. Using L1 serializer. App will call detail on these events when needed.

        events = Event.objects.users_entities(
            self.profile.user,
            user_filter={'state__in': [UserEntity.JOIN, UserEntity.PIN]},
            entity_filter={
                'entity_state': [BaseEntityComponent.ENTITY_STATE_PUBLISHED]
            })

        if len(events):
            _ser = BaseEntityComponent.entity_ser_from_type_and_level(
                entity_type=BaseEntityComponent.EVENT,
                level=BaseEntityComponent.SERIALIZER_L1)
            evts = _ser(events, many=True, context={
                'user': self.profile.user
            }).data
            s['events'] = evts

        # notifications. This is done by simply setting readed=False for
        # those user.notifs which have acted=False
        # This way, these notifs will be sent natively via get_cards
        SyncNotification.objects.unacted(
            self.profile.user).update(readed=False)
        return s

    def connect_subentities(self):
        pass
예제 #10
0
class BaseEntity(BaseEntityComponent, Base414Mixin):
    secure = models.BooleanField(default=False)
    password = TruncatingCharField(max_length=40, blank=True, null=True)

    timeout = models.IntegerField(default=30)

    is_deleted = models.BooleanField(default=False)

    users = models.ManyToManyField(User,
                                   through='UserEntity',
                                   related_name="users_%(class)s_related")

    num_users = models.IntegerField(default=0)

    location = GenericRelation(LocationMgr)

    objects = BaseEntityManager()

    def __unicode__(self):
        return self.entity_type + '.' + self.name

    def create_or_update_location(self, lat, lng):
        try:
            l = self.location.get()
            updated = l.do_update(lat, lng)
            return updated, l
        except ObjectDoesNotExist:
            updated = False
            # create
            l_tuple = location.send(
                sender=self,
                lat=lat,
                lng=lng,
                tree=BaseEntity.objects.get_location_tree_name(
                    self.entity_type))
            return updated, l_tuple[0][1]

    # get user's friends within the entity
    def users_friends(self, user, limit=None):
        from wizcardship.models import Wizcard
        entity_wizcards = [
            w.wizcard for w in self.users.all().order_by('?')
            if hasattr(w, 'wizcard')
        ]
        entity_friends = [
            x for x in entity_wizcards
            if Wizcard.objects.is_wizcard_following(x, user.wizcard)
        ]

        return entity_friends[:limit]

    def user_attach(self, user, state, **kwargs):

        ue, created = UserEntity.user_attach(user, self, state=state)

        do_notify = kwargs.pop('do_notify', True)
        if do_notify and created:
            if hasattr(user, 'wizcard'):
                notify.send(
                    user,
                    # recipient is dummy
                    recipient=self.get_creator(),
                    notif_tuple=verbs.WIZCARD_ENTITY_ATTACH,
                    target=self,
                    action_object=user,
                    do_push=False)

            if state == UserEntity.JOIN and created:
                self.num_users += 1
                self.save()

        ser = BaseEntity.entity_ser_from_type_and_level(
            entity_type=self.entity_type,
            level=BaseEntityComponent.SERIALIZER_L2)

        return ser

    def user_detach(self, user, state, **kwargs):
        UserEntity.user_detach(user, self)

        do_notify = kwargs.pop('do_notify', True)
        if do_notify:
            if hasattr(user, 'wizcard'):
                notify.send(
                    user,
                    # recipient is dummy
                    recipient=self.get_creator(),
                    notif_tuple=verbs.WIZCARD_ENTITY_DETACH,
                    target=self,
                    action_object=user,
                    do_push=False)

            if state == UserEntity.LEAVE:
                self.num_users -= 1
                self.save()

        return self

    # override. BaseEntity derived objects can have subscribers. This can be further
    # overridden in sub-entities if needed
    @property
    def is_floodable(self):
        return True

    # This is used to control if the entity needs to send serialized wizcards
    # as part of the serialized output. Presently we want to do this only for
    # Event.
    @property
    def send_wizcard_on_access(self):
        return False

    def is_joined(self, user):
        return bool(
            user.userentity_set.filter(entity=self,
                                       state=UserEntity.JOIN).exists())

    def user_state(self, user):
        # There can only be 1 entry per user per entity
        if user.userentity_set.filter(entity=self, user=user).exists():
            return user.userentity_set.get(entity=self, user=user).state

        return ""

    def get_users_after(self, timestamp):
        # AA: REVERT ME. Temp for app testing
        ue = UserEntity.objects.select_related('user').filter(entity=self)
        # ue = UserEntity.objects.filter(entity=self, created__gte=timestamp)

        # this won't (shouldn't cause db lookup since user is prefetched.
        users = map(lambda x: x.user, ue)

        return users

    def flood_set(self, **kwargs):
        ntuple = kwargs.pop('ntuple', None)
        sender = kwargs.pop('sender', None)

        flood_list = [x for x in self.users.all() if hasattr(x, 'wizcard')]

        # special case. Not nice. This (supress notif to sender) is the only
        # case presently (for NOTIF_ATTACH). If there are more, we should move
        # this to the ntuple dict.
        if ntuple and verbs.get_notif_type(
                ntuple) == verbs.NOTIF_ENTITY_ATTACH:
            # remove sender
            if sender in flood_list:
                flood_list.remove(sender)

        return flood_list

    def delete(self, *args, **kwargs):
        if self.location.exists():
            self.location.get().delete()

        super(BaseEntity, self).delete(*args, **kwargs)

    def do_expire(self, *args, **kwargs):
        kwargs.update(type=self.ENTITY_EXPIRE)
        self.delete(*args, **kwargs)

    def modified_since(self, timestamp):
        return self.modified > timestamp
예제 #11
0
class PhoneMixin(models.Model):
    class Meta:
        abstract = True

    phone = TruncatingCharField(max_length=20, blank=True)
예제 #12
0
class CompanyTitleMixin(models.Model):
    class Meta:
        abstract = True

    company = TruncatingCharField(max_length=100, blank=True)
    title = TruncatingCharField(max_length=200, blank=True)