Exemple #1
0
class Food(models.Model):
    name = models.CharField(max_length=255)

    related = RelatedObjectsDescriptor()
    related_beverages = RelatedObjectsDescriptor(RelatedBeverage, 'food',
                                                 'beverage')

    def __unicode__(self):
        return self.name
Exemple #2
0
class Person(models.Model):
    name = models.CharField(max_length=255)

    related = RelatedObjectsDescriptor()

    def __unicode__(self):
        return self.name
Exemple #3
0
class ReportedIssue(models.Model):
    created = models.DateField(auto_now_add=True)
    # Each reported issue needs a status. These are defined in the helpers class.
    status = models.PositiveIntegerField(max_length=1,
                                         choices=STATUS_CHOICES,
                                         default=1)

    # Holds a generic link to a reportable object
    content_type = models.ForeignKey(ContentType, verbose_name="Type of Job")
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey()

    #reportable = models.ForeignKey(Reportable)

    related = RelatedObjectsDescriptor()

    def __unicode__(self):
        return "%s: %s" % (self.content_object.__class__.__name__,
                           self.content_object)

    # Override the save method to perform tasks on status change
    def save(self, *args, **kwargs):
        # Only applicable when editing the model
        if self.pk:
            old_instance = type(self).objects.get(pk=self.pk)
            if not old_instance.status == self.status:
                update_reports_status.delay(self)
                send_status_mail.delay(self)
        super(ReportedIssue, self).save(*args, **kwargs)

    class Meta:
        abstract = True
class ModelGroup(models.Model):
    name = models.CharField(max_length=100)

    related = RelatedObjectsDescriptor()

    def __unicode__(self):
        return self.name
Exemple #5
0
class Symptom(models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from="name", max_length=255)
    selfhacked_link = models.CharField(max_length=255, blank=True)
    related_objects = RelatedObjectsDescriptor()

    def __str__(self):
        return self.name
Exemple #6
0
class FacilityIssue(ReportedIssue):
    # Holds a foreign key link to the facility in question
    facility = models.ForeignKey(Facility)
    # Enables auction to override cost
    cost = models.DecimalField(max_digits=9, decimal_places=2, help_text='The initial cost of the issue')
    # To prevent concurrent editing, needs a locked field
    locked = models.BooleanField()

    related = RelatedObjectsDescriptor()
Exemple #7
0
class Document(models.Model):
    file = models.FileField(storage=fs, upload_to=UPLOAD_TO)
    related = RelatedObjectsDescriptor()

    def __unicode__(self):
        return self.file.name[len(UPLOAD_TO) + 1:]

    def get_download_url(self):
        return urlresolvers.reverse('documents_document_download',
                                    args=(self.pk, ))
class TestModel(models.Model):
    name = models.CharField(max_length=200)

    test = RelatedObjectsDescriptor()

    for_inline = models.ForeignKey('self',
                                   null=True,
                                   blank=True,
                                   related_name='inline_test_models')

    def __str__(self):
        return self.name
    class GmtmModel(models.Model):
        name = models.CharField(max_length=200)
        relation = RelatedObjectsDescriptor()

        noise = models.ForeignKey('FkModel', null=True, blank=True)
        for_inline = models.ForeignKey('self',
                                       null=True,
                                       blank=True,
                                       related_name='inline')

        def __str__(self):
            return self.name
Exemple #10
0
class VoteMixin(models.Model):
    """
    Mixin providing a 'through' m2m relationship and helper fields
    and methods to inheriting classes, allowing easy use of the vote app
    """
    votes = RelatedObjectsDescriptor(Vote)

    class Meta:
        abstract = True

    @property
    def upvotes(self):
        return self.votes.filter(is_upvote=True)

    @property
    def downvotes(self):
        return self.votes.filter(is_upvote=False)

    @property
    def vote_count(self):
        return self.upvotes.count() - self.downvotes.count()

    def voteup(self, user):
        return self._create_or_toggle_vote(user, True)

    def votedown(self, user):
        return self._create_or_toggle_vote(user, False)

    def get_vote_for_user(self, user):
        try:
            user_type = ContentType.objects.get(app_label="auth", model="user")
            vote = self.votes.get(object_id=user.pk, object_type=user_type)
            return vote
        except:
            return None

    def _create_or_toggle_vote(self, user, upvote):
        existing_vote = self.get_vote_for_user(user)
        if existing_vote is None:
            return self._create_vote(user, upvote)
        else:
            if existing_vote.is_upvote is None:
                existing_vote.is_upvote = upvote
            else:
                existing_vote.is_upvote = None
            existing_vote.save()
            return existing_vote

    def _create_vote(self, user, upvote):
        return self.votes.connect(user, is_upvote=upvote)
Exemple #11
0
class Report(models.Model):
    created = models.DateField(auto_now_add=True)
    modified = models.DateField(auto_now=True)
    user = models.ForeignKey(User)
    description = models.CharField(max_length=255)
    status = models.DecimalField(max_digits=5, default=0, decimal_places=2)

    # The report needs to hold all the issues, and each issue may be in a different report.
    # For this reason, we need a generic many-to-many field
    #issues = models.ManyToManyField(ReportedIssue)
    issues = RelatedObjectsDescriptor()

    def __unicode__(self):
        return "Report %d" % self.pk
class FullModel(models.Model):
    name = models.CharField(max_length=200)

    oto = models.OneToOneField('self', related_name='reverse_oto')
    fk = models.ForeignKey('self', related_name='reverse_fk')
    mtm = models.ManyToManyField('self', related_name='reverse_mtm')

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    gfk = GenericForeignKey("content_type", "object_id")

    if RelatedObjectsDescriptor:
        gmtm = RelatedObjectsDescriptor()

    def __str__(self):
        return self.name
Exemple #13
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 ""
Exemple #14
0
class FireDepartment(RecentlyUpdatedMixin, models.Model):
    """
    Models Fire Departments.
    """

    DEPARTMENT_TYPE_CHOICES = [
        ('Volunteer', 'Volunteer'),
        ('Mostly Volunteer', 'Mostly Volunteer'),
        ('Career', 'Career'),
        ('Mostly Career', 'Mostly Career'),
    ]

    REGION_CHOICES = [
        ('Northeast', 'Northeast'),
        ('West', 'West'),
        ('South', 'South'),
        ('Midwest', 'Midwest'),
        (None, '')
    ]

    POPULATION_CLASSES = [
        (0, 'Population less than 2,500.'),
        (1, 'Population between 2,500 and 4,999.'),
        (2, 'Population between 5,000 and 9,999.'),
        (3, 'Population between 10,000 and 24,999.'),
        (4, 'Population between 25,000 and 49,999.'),
        (5, 'Population between 50,000 and 99,999.'),
        (6, 'Population between 100,000 and 249,999.'),
        (7, 'Population between 250,000 and 499,999.'),
        (8, 'Population between 500,000 and 999,999.'),
        (9, 'Population greater than 1,000,000.'),
    ]

    created = models.DateTimeField(auto_now=True)
    modified = models.DateTimeField(auto_now=True)
    fdid = models.CharField(max_length=10)
    name = models.CharField(max_length=100)
    headquarters_address = models.ForeignKey(Address, null=True, blank=True, related_name='firedepartment_headquarters')
    mail_address = models.ForeignKey(Address, null=True, blank=True)
    headquarters_phone = PhoneNumberField(null=True, blank=True)
    headquarters_fax = PhoneNumberField(null=True, blank=True)
    department_type = models.CharField(max_length=20, choices=DEPARTMENT_TYPE_CHOICES, null=True, blank=True)
    organization_type = models.CharField(max_length=75, null=True, blank=True)
    website = models.URLField(null=True, blank=True)
    state = models.CharField(max_length=2)
    region = models.CharField(max_length=20, choices=REGION_CHOICES, null=True, blank=True)
    geom = models.MultiPolygonField(null=True, blank=True)
    objects = CalculationManager()
    priority_departments = PriorityDepartmentsManager()
    dist_model_score = models.FloatField(null=True, blank=True, editable=False, db_index=True)

    risk_model_deaths = models.FloatField(null=True, blank=True, db_index=True,
                                          verbose_name='Predicted deaths per year.')

    risk_model_injuries = models.FloatField(null=True, blank=True, db_index=True,
                                            verbose_name='Predicted injuries per year.')

    risk_model_fires = models.FloatField(null=True, blank=True, db_index=True,
                                         verbose_name='Predicted number of fires per year.')

    risk_model_fires_size0 = models.FloatField(null=True, blank=True, db_index=True,
                                               verbose_name='Predicted number of size 0 fires.')

    risk_model_fires_size0_percentage = models.FloatField(null=True, blank=True,
                                                          verbose_name='Percentage of size 0 fires.')

    risk_model_fires_size1 = models.FloatField(null=True, blank=True, db_index=True,
                                               verbose_name='Predicted number of size 1 fires.')

    risk_model_fires_size1_percentage = models.FloatField(null=True, blank=True,
                                                          verbose_name='Percentage of size 1 fires.')

    risk_model_fires_size2 = models.FloatField(null=True, blank=True, db_index=True,
                                                   verbose_name='Predicted number of size 2 firese.')

    risk_model_fires_size2_percentage = models.FloatField(null=True, blank=True,
                                                          verbose_name='Percentage of size 2 fires.')

    government_unit = RelatedObjectsDescriptor()
    population = models.IntegerField(null=True, blank=True)
    population_class = models.IntegerField(null=True, blank=True, choices=POPULATION_CLASSES)
    featured = models.BooleanField(default=False, db_index=True)

    class Meta:
        ordering = ('name',)
        index_together = [
            ['population', 'id', 'region'],
            ['population', 'region']
        ]

    @property
    def headquarters_geom(self):
        return getattr(self.headquarters_address, 'geom', None)

    @property
    def predicted_fires_sum(self):
        """
        Convenience method to sum
        """
        if self.risk_model_fires_size0 is None and self.risk_model_fires_size1 is None \
                and self.risk_model_fires_size2 is None:
            return

        return (self.risk_model_fires_size0 or 0) + (self.risk_model_fires_size1 or 0) + \
               (self.risk_model_fires_size2 or 0)

    @property
    def size2_and_greater_sum(self):
        """
        Convenience method to sum
        """
        if self.risk_model_fires_size1 is None and self.risk_model_fires_size2 is None:
            return

        return (self.risk_model_fires_size1 or 0) + (self.risk_model_fires_size2 or 0)

    @property
    def size2_and_greater_percentile_sum(self):
        """
        Convenience method to sum
        """
        if self.risk_model_fires_size1_percentage is None and self.risk_model_fires_size2_percentage is None:
            return

        return (self.risk_model_fires_size1_percentage or 0) + (self.risk_model_fires_size2_percentage or 0)

    @property
    def deaths_and_injuries_sum(self):

        if self.risk_model_deaths is None and self.risk_model_injuries is None:
            return

        return (self.risk_model_deaths or 0) + (self.risk_model_injuries or 0)

    @cached_property
    def population_class_stats(self):
        """
        Returns summary statistics for calculation fields in the same population class.
        """

        if not self.population_class:
            return []

        cache_key = 'population_class_{0}_stats'.format(self.population_class)
        cached = cache.get(cache_key)

        if cached:
            return cached

        fields = ['dist_model_score', 'risk_model_fires', 'risk_model_deaths_injuries_sum',
                  'risk_model_size1_percent_size2_percent_sum', 'residential_fires_avg_3_years']
        aggs = []

        for field in fields:
            aggs.append(Min(field))
            aggs.append(Max(field))
            aggs.append(Avg(field))

        results = self.population_metrics_table.objects.filter(population_class=self.population_class).aggregate(*aggs)
        cache.set(cache_key, results, timeout=60 * 60 * 24)
        return results

    def report_card_scores(self):
        if not self.population_metrics_table:
            return

        row = self.population_metrics_row

        from .managers import Ntile
        from django.db.models import When, Case, Q
        qs = self.population_metrics_table.objects.filter(risk_model_fires_quartile=row.risk_model_fires_quartile)
        qs = qs.annotate(**{'dist_quartile': Case(When(**{'dist_model_score__isnull': False, 'then': Ntile(4, output_field=models.IntegerField(), order_by='dist_model_score')}), output_field=models.IntegerField(), default=None)})
        qs = qs.annotate(**{'size2_plus_quartile': Case(When(**{'risk_model_size1_percent_size2_percent_sum_quartile__isnull': False, 'then': Ntile(4, output_field=models.IntegerField(), order_by='risk_model_size1_percent_size2_percent_sum_quartile')}), output_field=models.IntegerField(), default=None)})
        qs = qs.annotate(**{'deaths_injuries_quartile': Case(When(**{'risk_model_deaths_injuries_sum_quartile__isnull': False, 'then': Ntile(4, output_field=models.IntegerField(), order_by='risk_model_deaths_injuries_sum_quartile')}), output_field=models.IntegerField(), default=None)})
        qs = qs.filter(id=self.id)
        return qs


    @property
    def population_metrics_table(self):
        """
        Returns the appropriate population metrics table for this object.
        """
        try:
            return get_model('firestation.PopulationClass{0}Quartile'.format(self.population_class))
        except LookupError:
            return None

    @cached_property
    def population_metrics_row(self):
        """
        Returns the matching row from the population metrics table.
        """

        population_table = self.population_metrics_table

        if not population_table:
            return

        return population_table.objects.get(id=self.id)

    @property
    def government_unit_objects(self):
        """
        Memoize the government_unit generic key lookup.
        """
        if not getattr(self, '_government_unit_objects', None):
            self._government_unit_objects = self.government_unit.all().generic_objects()

        return self._government_unit_objects

    @property
    def fips(self):
        objs = self.government_unit_objects

        if objs:
            return [obj.fips for obj in objs if hasattr(obj, 'fips')]

        return []

    @property
    def geom_area(self):
        """
        Project the department's geometry into north america lambert conformal conic
        Returns km2
        """
        if self.geom:
            try:
                return self.geom.transform(102009, clone=True).area / 1000000
            except:
                return

    @cached_property
    def nfirs_deaths_and_injuries_sum(self):
        return self.nfirsstatistic_set.filter(Q(metric='civilian_casualties') | Q(metric='firefighter_casualties'),
                                              fire_department=self,
                                              year__gte=2010).aggregate(Avg('count'))

    @cached_property
    def residential_fires_3_year_avg(self):

        if self.population_metrics_row:
            return self.population_metrics_row.residential_fires_avg_3_years

        return self.nfirsstatistic_set.filter(fire_department=self,
                                              metric='residential_structure_fires',
                                              year__gte=2010).aggregate(Avg('count'))

    def get_population_class(self):
        """
        Returns the population class of a department based on NFPA community sizes categories as an integer.

        9: > 1,000,000
        8: (500000, 999999)
        7: (250000, 499999)
        6: (100000, 249999)
        5: (50000, 99999)
        4: (25000, 49999)
        3: (10000, 24999)
        2: (5000, 9999)
        1: (2500, 4999)
        0: < 2500
        """
        if self.population is None:
            return

        if self.population < 2500:
            return 0

        if self.population >= 1000000:
            return 9

        community_sizes = [
                (500000, 999999),
                (250000, 499999),
                (100000, 249999),
                (50000, 99999),
                (25000, 49999),
                (10000, 24999),
                (5000, 9999),
                (2500, 4999)]

        for clazz, min_max in zip(reversed(range(1, 9)), community_sizes):
            if min_max[0] <= self.population <= min_max[1]:
                return clazz

    @property
    def similar_departments(self, ignore_regions_min=1000000):
        """
        Identifies similar departments based on the protected population size and region.
        """

        params = {}

        if self.population >= 1000000:
            params['population__gte'] = 1000000

        elif self.population < 2500:
            params['population__lt'] = 2500

        else:
            community_sizes = [
                (500000, 999999),
                (250000, 499999),
                (100000, 249999),
                (50000, 99999),
                (25000, 49999),
                (10000, 24999),
                (5000, 9999),
                (2500, 4999)]

            for lower_bound, upper_bound in community_sizes:
                if lower_bound <= self.population <= upper_bound:
                    params['population__lte'] = upper_bound
                    params['population__gte'] = lower_bound

                break

        similar = FireDepartment.objects.filter(**params)\
            .exclude(id=self.id)\
            .extra(select={'difference': "abs(population - %s)"}, select_params=[self.population])\
            .extra(order_by=['difference'])

        # Large departments may not have similar departments in their region.
        if self.population < ignore_regions_min:
            similar = similar.filter(region=self.region)

        return similar

    @property
    def thumbnail_name(self):
        return slugify(' '.join(['us', self.state, self.name])) + '.jpg'

    @property
    def thumbnail_name_no_marker(self):
        return slugify(' '.join(['us', self.state, self.name, 'no marker'])) + '.jpg'

    @property
    def thumbnail(self):
        return 'https://s3.amazonaws.com/vida-static/department-thumbnails/{0}'.format(self.thumbnail_name)

    @property
    def thumbnail_no_marker(self):
        return 'https://s3.amazonaws.com/vida-static/department-thumbnails/{0}' \
            .format(self.thumbnail_name_no_marker)

    def generate_thumbnail(self, marker=True):
        geom = None

        if self.geom:
            geom = self.geom.centroid
        elif self.headquarters_address and self.headquarters_address.geom:
            geom = self.headquarters_address.geom
        else:
            return '/static/firestation/theme/assets/images/content/property-1.jpg'

        if marker and geom:
            marker = 'pin-l-embassy+0074D9({geom.x},{geom.y})/'.format(geom=geom)

        return 'http://api.tiles.mapbox.com/v4/garnertb.mmlochkh/{marker}' \
               '{geom.x},{geom.y},8/500x300.png?access_token={access_token}'.format(marker=marker,
                                                                                    geom=geom,
                                                                                    access_token=getattr(settings, 'MAPBOX_ACCESS_TOKEN', ''))

    def set_geometry_from_government_unit(self):
        objs = self.government_unit_objects

        if objs:
            self.geom = MultiPolygon([obj.geom for obj in objs if getattr(obj, 'geom', None)])
            self.save()

    def set_population_from_government_unit(self):
        """
        Stores the population of government units on the FD object to speed up querying.
        """
        objs = self.government_unit_objects

        if objs:

            for gov_unit in objs:
                pop = getattr(gov_unit, 'population', None)

                if pop is not None:
                    if self.population is None:
                        self.population = 0

                    self.population += pop
        else:
            self.population = None

        self.save()

    @classmethod
    def get_histogram(cls, field, bins=400):
        hist = histogram(list(cls.objects.filter(**{'{0}__isnull'.format(field): False})
                         .values_list(field, flat=True)), bins=bins)
        return json.dumps(zip(hist[1], hist[0]), separators=(',', ':'))

    def set_region(self, region):
        validate_choice(FireDepartment.REGION_CHOICES)(region)
        self.region = region
        self.save()

    @cached_property
    def description(self):
        """
        A text description of the department used for displaying on the client side.
        """
        try:
            name = self.name

            if not self.name.lower().endswith('department') and not self.name.lower().endswith('district'):
                name += ' fire department'

            return "The {name} is a {department_type} department located in the {object.region} NFPA region and headquartered in " \
                   "{object.headquarters_address.city}, {object.headquarters_address.state_province}."\
                .format(name=name,
                        department_type=self.department_type.lower(),
                        object=self).strip()
        except:
            return 'No description for Fire Department'

    def residential_structure_fire_counts(self):
        return self.nfirsstatistic_set.filter(metric='residential_structure_fires')\
            .extra(select={
                    'year_max': 'SELECT MAX(COUNT) FROM firestation_nfirsstatistic b WHERE b.year = firestation_nfirsstatistic.year and b.metric=firestation_nfirsstatistic.metric'
                   })\
            .extra(select={
                    'year_min': 'SELECT MIN(COUNT) FROM firestation_nfirsstatistic b WHERE b.year = firestation_nfirsstatistic.year and b.metric=firestation_nfirsstatistic.metric'
                   })

    @classmethod
    def load_from_usfa_csv(cls):
        """
        Loads Fire Departments from http://apps.usfa.fema.gov/census-download.
        """
        us, _ = Country.objects.get_or_create(name='United States of America', iso_code='US')

        with open(os.path.join(os.path.dirname(__file__), 'scripts/usfa-census-national.csv'), 'r') as csvfile:

            # This only runs once, since there isn't a good key to identify duplicates
            if not cls.objects.all().count():
                reader = csv.DictReader(csvfile)
                counter = 0
                for row in reader:
                    # only run once.
                    hq_address_params = {}
                    hq_address_params['address_line1'] = row.get('HQ Addr1')
                    hq_address_params['address_line2'] = row.get('HQ Addr2')
                    hq_address_params['city'] = row.get('HQ City')
                    hq_address_params['state_province'] = row.get('HQ State')
                    hq_address_params['postal_code'] = row.get('HQ Zip')
                    hq_address_params['country'] = us
                    headquarters_address, _ = Address.objects.get_or_create(**hq_address_params)
                    headquarters_address.save()

                    mail_address_params = {}
                    mail_address_params['address_line1'] = row.get('Mail Addr1')
                    mail_address_params['address_line2'] = row.get('Mail Addr2') or row.get('Mail PO Box')
                    mail_address_params['city'] = row.get('Mail City')
                    mail_address_params['state_province'] = row.get('Mail State')
                    mail_address_params['postal_code'] = row.get('Mail Zip')
                    mail_address_params['country'] = us
                    mail_address, _ = Address.objects.get_or_create(**mail_address_params)
                    mail_address.save()

                    params = {}
                    params['fdid'] = row.get('FDID')
                    params['name'] = row.get('Fire Dept Name')
                    params['headquarters_phone'] = row.get('HQ Phone')
                    params['headquarters_fax'] = row.get('HQ Fax')
                    params['department_type'] = row.get('Dept Type')
                    params['organization_type'] = row.get('Organization Type')
                    params['website'] = row.get('Website')
                    params['headquarters_address'] = headquarters_address
                    params['mail_address'] = mail_address
                    params['state'] = row.get('HQ State')

                    cls.objects.create(**params)
                    counter += 1

                assert counter == cls.objects.all().count()
    
    @cached_property
    def slug(self):
        return slugify(self.name)

    def get_absolute_url(self):
        return reverse('firedepartment_detail_slug', kwargs=dict(pk=self.id, slug=self.slug))

    def find_jurisdiction(self):
        from vida.usgs.models import CountyorEquivalent, IncorporatedPlace, UnincorporatedPlace

        counties = CountyorEquivalent.objects.filter(state_name='Virginia')
        for county in counties:
            incorporated = IncorporatedPlace.objects.filter(geom__intersects=county.geom)
            unincoporated = UnincorporatedPlace.objects.filter(geom__intersects=county.geom)
            station = FireStation.objects.filter(geom__intersects=county.geom)

            print 'County', county.name
            print 'Incorporated Place', incorporated.count()
            print 'Unincorporated Place', unincoporated.count()
            print 'Stations:', station

    def __unicode__(self):
        return self.name
Exemple #15
0
class BaseEntityComponent(PolymorphicModel):
    EVENT = 'EVT'
    CAMPAIGN = 'CMP'
    TABLE = 'TBL'
    WIZCARD = 'WZC'
    SPEAKER = 'SPK'
    SPONSOR = 'SPN'
    MEDIA = 'MED'
    ATTENDEE_INVITEE = 'ATI'
    EXHIBITOR_INVITEE = 'EXI'
    COOWNER = 'COW'
    AGENDA = 'AGN'
    AGENDA_ITEM = 'AGI'
    POLL = 'POL'
    BADGE_TEMPLATE = 'BDG'
    SCANNED_USER = '******'
    CATEGORY = 'CAT'

    SERIALIZER_L0 = 0
    SERIALIZER_L1 = 1
    SERIALIZER_L2 = 2
    SERIALIZER_FULL = 3

    ENTITY_CHOICES = ((EVENT, 'Event'), (CAMPAIGN, 'Campaign'),
                      (TABLE, 'Table'), (WIZCARD, 'Wizcard'),
                      (SPEAKER, 'Speaker'), (SPONSOR, 'Sponsor'), (COOWNER,
                                                                   'Coowner'),
                      (ATTENDEE_INVITEE,
                       'AttendeeInvitee'), (EXHIBITOR_INVITEE,
                                            'ExhibitorInvitee'), (MEDIA,
                                                                  'Media'),
                      (COOWNER, 'Coowner'), (AGENDA, 'Agenda'), (AGENDA_ITEM,
                                                                 'AgendaItem'),
                      (POLL, 'Polls'), (BADGE_TEMPLATE, 'Badges'),
                      (SCANNED_USER, 'Scans'), (CATEGORY, 'Category'))

    SUB_ENTITY_CAMPAIGN = 'e_campaign'
    SUB_ENTITY_TABLE = 'e_table'
    SUB_ENTITY_WIZCARD = 'e_wizcard'
    SUB_ENTITY_SPEAKER = 'e_speaker'
    SUB_ENTITY_SPONSOR = 'e_sponsor'
    SUB_ENTITY_MEDIA = 'e_media'
    SUB_ENTITY_COOWNER = 'e_coowner'
    SUB_ENTITY_AGENDA = 'e_agenda'
    SUB_ENTITY_AGENDA_ITEM = 'e_agendaitem'
    SUB_ENTITY_POLL = 'e_poll'
    SUB_ENTITY_EXHIBITOR_INVITEE = 'e_exhibitor'
    SUB_ENTITY_ATTENDEE_INVITEE = 'e_attendee'
    SUB_ENTITY_BADGE_TEMPLATE = 'e_badge'
    SUB_ENTITY_SCANNED_USER = '******'
    SUB_ENTITY_CATEGORY = 'e_category'

    ENTITY_STATE_CREATED = "CRT"
    ENTITY_STATE_PUBLISHED = "PUB"
    ENTITY_STATE_EXPIRED = "EXP"
    ENTITY_STATE_DELETED = "DEL"
    ENTITY_STATE_DESTROY = "DES"

    ENTITY_STATE_CHOICES = ((ENTITY_STATE_CREATED,
                             "Created"), (ENTITY_STATE_PUBLISHED, "Published"),
                            (ENTITY_STATE_EXPIRED,
                             "Expired"), (ENTITY_STATE_DELETED, "Deleted"))

    entity_types_mapping = {
        CAMPAIGN: SUB_ENTITY_CAMPAIGN,
        TABLE: SUB_ENTITY_TABLE,
        WIZCARD: SUB_ENTITY_WIZCARD,
        SPEAKER: SUB_ENTITY_SPEAKER,
        SPONSOR: SUB_ENTITY_SPONSOR,
        MEDIA: SUB_ENTITY_MEDIA,
        ATTENDEE_INVITEE: SUB_ENTITY_ATTENDEE_INVITEE,
        EXHIBITOR_INVITEE: EXHIBITOR_INVITEE,
        COOWNER: SUB_ENTITY_COOWNER,
        AGENDA: SUB_ENTITY_AGENDA,
        AGENDA_ITEM: SUB_ENTITY_AGENDA,
        POLL: SUB_ENTITY_POLL,
        BADGE_TEMPLATE: SUB_ENTITY_BADGE_TEMPLATE,
        SCANNED_USER: SUB_ENTITY_SCANNED_USER,
        CATEGORY: SUB_ENTITY_CATEGORY
    }

    # use this in overridden delete to know whether to remove or mark-deleted
    ENTITY_DELETE = 1
    ENTITY_EXPIRE = 2

    objects = BaseEntityComponentManager()

    entity_type = models.CharField(max_length=3,
                                   choices=ENTITY_CHOICES,
                                   default=EVENT)

    owners = models.ManyToManyField(User,
                                    through='BaseEntityComponentsOwner',
                                    related_name="owners_%(class)s_related")

    # sub-entities. using django-generic-m2m package
    related = RelatedObjectsDescriptor(WizcardRelatedField)

    engagements = models.OneToOneField(
        "EntityEngagementStats",
        null=True,
        related_name="engagements_%(class)s_related")

    tags = TaggableManager()

    entity_state = models.CharField(choices=ENTITY_STATE_CHOICES,
                                    default=ENTITY_STATE_CREATED,
                                    max_length=3)

    @classmethod
    def create(cls, e, owner, is_creator, **kwargs):
        obj = e.objects.create(**kwargs)

        # add owner
        BaseEntityComponentsOwner.objects.create(base_entity_component=obj,
                                                 owner=owner,
                                                 is_creator=is_creator)

        return obj

    @classmethod
    def my_entity_type(cls):
        return ""

    """
    updates an existing entry, which was already created. This method
    may not really be required since creator is set during creation time
    itself
    """

    @classmethod
    def update_creator(cls, obj, creator):
        BaseEntityComponentsOwner.objects.get(
            base_entity_component=obj, owner=creator).update(is_creator=True)

    @classmethod
    def add_owners(cls, obj, owners):
        for o in owners:
            BaseEntityComponentsOwner.objects.get_or_create(
                base_entity_component=obj,
                owner=o.user,
                defaults={'is_creator': False})

    @classmethod
    def remove_owners(cls, obj, owners):
        for o in owners:
            BaseEntityComponentsOwner.objects.filter(base_entity_component=obj,
                                                     owner=o.user).delete()

    @classmethod
    def entity_cls_from_type(cls, entity_type):
        from taganomy.models import Taganomy
        from entity.models import Event, Campaign, VirtualTable, \
            Speaker, Sponsor, AttendeeInvitee, ExhibitorInvitee, CoOwners, Agenda, AgendaItem
        from media_components.models import MediaEntities
        from polls.models import Poll
        from scan.models import ScannedEntity, BadgeTemplate

        if entity_type == cls.EVENT:
            return Event
        elif entity_type == cls.CAMPAIGN:
            return Campaign
        elif entity_type == cls.TABLE:
            return VirtualTable
        elif entity_type == cls.ATTENDEE_INVITEE:
            return AttendeeInvitee
        elif entity_type == cls.EXHIBITOR_INVITEE:
            return ExhibitorInvitee
        elif entity_type == cls.MEDIA:
            return MediaEntities
        elif entity_type == cls.COOWNER:
            return CoOwners
        elif entity_type == cls.SPEAKER:
            return Speaker
        elif entity_type == cls.SPONSOR:
            return Sponsor
        elif entity_type == cls.MEDIA:
            return MediaEntities
        elif entity_type == cls.AGENDA:
            return Agenda
        elif entity_type == cls.AGENDA_ITEM:
            return AgendaItem
        elif entity_type == cls.POLL:
            return Poll
        elif entity_type == cls.BADGE_TEMPLATE:
            return BadgeTemplate
        elif entity_type == cls.SCANNED_USER:
            return ScannedEntity
        elif entity_type == cls.CATEGORY:
            return Taganomy
        else:
            raise RuntimeError('invalid entity_type: %s', entity_type)

    @classmethod
    def entity_ser_from_type_and_level(cls,
                                       entity_type,
                                       level=SERIALIZER_FULL):
        from entity.serializers import EventSerializerL2, EventSerializer, EventSerializerL0, EventSerializerL1, \
            TableSerializerL1, TableSerializerL2, TableSerializer, \
            CampaignSerializerL1, CampaignSerializer, CampaignSerializerL2, CoOwnersSerializer, \
            SpeakerSerializerL2, SpeakerSerializer, SponsorSerializerL2, SponsorSerializerL1, SponsorSerializer, AttendeeInviteeSerializer, \
            ExhibitorInviteeSerializer, AgendaSerializer, AgendaSerializerL1, AgendaItemSerializer, PollSerializer, PollSerializerL1
        from scan.serializers import ScannedEntitySerializer, BadgeTemplateSerializer
        from entity.serializers import TaganomySerializer, TaganomySerializerL2
        from media_components.serializers import MediaEntitiesSerializer

        ser_mapping = {
            cls.EVENT: {
                cls.SERIALIZER_L0: EventSerializerL0,
                cls.SERIALIZER_L1: EventSerializerL1,
                cls.SERIALIZER_L2: EventSerializerL2,
                cls.SERIALIZER_FULL: EventSerializer
            },
            cls.CAMPAIGN: {
                cls.SERIALIZER_L0: CampaignSerializerL1,
                cls.SERIALIZER_L1: CampaignSerializerL1,
                cls.SERIALIZER_L2: CampaignSerializerL2,
                cls.SERIALIZER_FULL: CampaignSerializer
            },
            cls.TABLE: {
                cls.SERIALIZER_L0: TableSerializerL1,
                cls.SERIALIZER_L1: TableSerializerL1,
                cls.SERIALIZER_L2: TableSerializerL2,
                cls.SERIALIZER_FULL: TableSerializer
            },
            cls.ATTENDEE_INVITEE: {
                cls.SERIALIZER_FULL: AttendeeInviteeSerializer
            },
            cls.EXHIBITOR_INVITEE: {
                cls.SERIALIZER_FULL: ExhibitorInviteeSerializer
            },
            cls.MEDIA: {
                cls.SERIALIZER_L2: MediaEntitiesSerializer,
                cls.SERIALIZER_FULL: MediaEntitiesSerializer
            },
            cls.COOWNER: {
                cls.SERIALIZER_FULL: CoOwnersSerializer
            },
            cls.SPEAKER: {
                cls.SERIALIZER_L0: SpeakerSerializerL2,
                cls.SERIALIZER_L1: SpeakerSerializerL2,
                cls.SERIALIZER_L2: SpeakerSerializerL2,
                cls.SERIALIZER_FULL: SpeakerSerializer
            },
            cls.SPONSOR: {
                cls.SERIALIZER_L0: SponsorSerializerL1,
                cls.SERIALIZER_L1: SponsorSerializerL1,
                cls.SERIALIZER_L2: SponsorSerializerL2,
                cls.SERIALIZER_FULL: SponsorSerializer
            },
            cls.AGENDA: {
                cls.SERIALIZER_L0: AgendaSerializer,
                cls.SERIALIZER_L1: AgendaSerializerL1,
                cls.SERIALIZER_L2: AgendaSerializerL1,
                cls.SERIALIZER_FULL: AgendaSerializerL1,
            },
            cls.AGENDA_ITEM: {
                cls.SERIALIZER_L0: AgendaItemSerializer,
                cls.SERIALIZER_L1: AgendaItemSerializer,
                cls.SERIALIZER_L2: AgendaItemSerializer,
                cls.SERIALIZER_FULL: AgendaItemSerializer
            },
            cls.POLL: {
                cls.SERIALIZER_L0: PollSerializerL1,
                cls.SERIALIZER_L1: PollSerializerL1,
                cls.SERIALIZER_L2: PollSerializer,
                cls.SERIALIZER_FULL: PollSerializer
            },
            cls.SCANNED_USER: {
                cls.SERIALIZER_FULL: ScannedEntitySerializer
            },
            cls.CATEGORY: {
                cls.SERIALIZER_L0: TaganomySerializerL2,
                cls.SERIALIZER_L1: TaganomySerializerL2,
                cls.SERIALIZER_L2: TaganomySerializerL2,
                cls.SERIALIZER_FULL: TaganomySerializer
            },
            cls.BADGE_TEMPLATE: {
                cls.SERIALIZER_FULL: BadgeTemplateSerializer
            }
        }

        return ser_mapping[entity_type][level]

    @classmethod
    def entity_cls_ser_from_type_level(cls,
                                       entity_type=None,
                                       level=SERIALIZER_FULL):
        c = cls.entity_cls_from_type(entity_type)
        s = cls.entity_ser_from_type_and_level(entity_type, level)

        return c, s

    @classmethod
    def content_type_from_entity_type(cls, entity_type):
        c = BaseEntityComponent.entity_cls_from_type(entity_type=entity_type)
        return ContentType.objects.get_for_model(c)

    @classmethod
    def entity_type_from_content_type(cls, c_type):
        _cls = c_type.model_class()
        return _cls.my_entity_type()

    @classmethod
    def sub_entity_type_from_entity_type(cls, entity_type):
        return cls.entity_types_mapping[entity_type]

    @classmethod
    def entity_cls_from_subentity_type(cls, entity_type):
        from entity.models import Campaign, VirtualTable, \
            Speaker, Sponsor, CoOwners, Agenda, ExhibitorInvitee, AttendeeInvitee
        from taganomy.models import Taganomy
        from media_components.models import MediaEntities
        from wizcardship.models import Wizcard
        from polls.models import Poll
        from scan.models import ScannedEntity, BadgeTemplate
        if entity_type == cls.SUB_ENTITY_CAMPAIGN:
            c = Campaign
        elif type == cls.SUB_ENTITY_TABLE:
            c = VirtualTable
        elif entity_type == cls.SUB_ENTITY_WIZCARD:
            c = Wizcard
        elif entity_type == cls.SUB_ENTITY_SPEAKER:
            c = Speaker
        elif entity_type == cls.SUB_ENTITY_SPONSOR:
            c = Sponsor
        elif entity_type == cls.SUB_ENTITY_MEDIA:
            c = MediaEntities
        elif entity_type == cls.SUB_ENTITY_COOWNER:
            c = CoOwners
        elif entity_type == cls.SUB_ENTITY_AGENDA:
            c = Agenda
        elif entity_type == cls.SUB_ENTITY_POLL:
            c = Poll
        elif entity_type == cls.SUB_ENTITY_EXHIBITOR_INVITEE:
            c = ExhibitorInvitee
        elif entity_type == cls.SUB_ENTITY_ATTENDEE_INVITEE:
            c = AttendeeInvitee
        elif entity_type == cls.SUB_ENTITY_SCANNED_USER:
            c = ScannedEntity
        elif entity_type == cls.SUB_ENTITY_BADGE_TEMPLATE:
            c = BadgeTemplate
        elif entity_type == cls.SUB_ENTITY_CATEGORY:
            c = Taganomy
        else:
            raise AssertionError("Invalid sub_entity %s" % entity_type)

        return c

    def has_join_table_row(self, sub_entity):
        return self.get_sub_entities_gfk_of_type(
            object_id=sub_entity.id,
            alias=BaseEntityComponent.sub_entity_type_from_entity_type(
                sub_entity.entity_type)).exists()

    # gets the join table row between parent<->sub_entity.
    def get_join_table_row(self, sub_entity):
        if self.has_join_table_row(sub_entity):
            return self.get_sub_entities_gfk_of_type(
                object_id=sub_entity.id,
                alias=BaseEntityComponent.sub_entity_type_from_entity_type(
                    sub_entity.entity_type)).get()

        return BaseEntityComponent.objects.none()

    # this does not send notif
    def add_subentities(self, ids, type):
        if not ids:
            return []

        c = self.entity_cls_from_subentity_type(type)
        int_ids = map(lambda x: int(x), ids)

        objs = c.objects.filter(id__in=int_ids)
        for obj in objs:
            self.related.connect(obj, alias=type)

        return objs

    # this does not send notif
    def remove_subentities(self, ids, type):
        if not ids:
            return

        int_ids = map(lambda x: int(x), ids)

        self.related.filter(object_id__in=int_ids, alias=type).delete()

    # kind of tagonomy's pattern. add any new ones, remove those not in the list
    # this does not send notif
    def add_remove_sub_entities_of_type(self, ids, type):
        to_be_deleted_ids_qs = self.related.filter(alias=type)
        new_obj_ids = []

        for id in ids:
            if not to_be_deleted_ids_qs.filter(object_id=id).exists():
                new_obj_ids.append(id)
            to_be_deleted_ids_qs = to_be_deleted_ids_qs.exclude(object_id=id)

        # add the new ones
        self.add_subentities(new_obj_ids, type)

        # delete the rest
        to_be_deleted_ids_qs.delete()

    def add_subentity_obj(self, obj, alias, **kwargs):
        join_fields = kwargs.pop('join_fields', None)

        connection = self.related.connect(obj, alias=alias)

        if join_fields:
            connection.join_fields = join_fields
            connection.save()

        kwargs.update(notif_operation=verbs.NOTIF_OPERATION_CREATE)

        return connection, obj.post_connect_remove(self, **kwargs)

    def remove_sub_entity_obj(self, obj, subentity_type, **kwargs):
        self.related.filter(object_id=obj.id, alias=subentity_type).delete()
        kwargs.update(notif_operation=verbs.NOTIF_OPERATION_DELETE)

        return obj.post_connect_remove(self, **kwargs)

    def get_sub_entities_gfk_of_type(self, **kwargs):
        return self.related.filter(**kwargs)

    def get_sub_entities_of_type(self, entity_type, **kwargs):
        exclude = kwargs.pop('exclude', [self.ENTITY_STATE_DELETED])

        subent = self.related.filter(alias=entity_type).generic_objects()
        return [se for se in subent if se.entity_state not in exclude]

    def get_sub_entities_id_of_type(self, entity_type, **kwargs):
        # Ideally we could have avoided the 2 iterations, but this is to ensure that the logic is consistent across 2 functions
        subent = self.get_sub_entities_of_type(entity_type, **kwargs)
        return [se.id for se in subent]

    def get_media_filter(self, type, sub_type):
        media = self.get_sub_entities_of_type(BaseEntity.SUB_ENTITY_MEDIA)

        return [
            m for m in media
            if m.media_type in type and m.media_sub_type in sub_type
        ]

    def get_parent_entities(self, **kwargs):
        exclude = kwargs.pop('exclude', [self.ENTITY_STATE_DELETED])

        parents = self.related.related_to().generic_objects()
        return [p for p in parents if p.entity_state not in exclude]

    def get_parent_entities_by_contenttype_id(self, contenttype_id, **kwargs):
        exclude = kwargs.pop('exclude', [self.ENTITY_STATE_DELETED])

        parents = self.related.related_to().filter(
            parent_type_id=contenttype_id).generic_objects()
        return [p for p in parents if p.entity_state not in exclude]

    # is the instance of the kind that has notifiable users
    @property
    def is_floodable(self):
        return False

    def update_state_upon_link_unlink(self):
        return False

    # applies to child not parent. ie, self is the child
    def can_destroy_when_linked(self):
        return False

    def get_creator(self):
        return BaseEntityComponentsOwner.objects.filter(
            base_entity_component=self,
            is_creator=True).get().owner.profile.user

    def is_creator(self, user):
        return bool(user == self.get_creator())

    def is_owner(self, user):
        return user in self.owners.all()

    # when a sub-entity gets related, it might want to do things like sending notifications
    # override this in the derived classes to achieve the same
    def post_connect_remove(self, parent, **kwargs):
        notif_operation = kwargs.pop('notif_operation',
                                     verbs.NOTIF_OPERATION_CREATE)
        send_notif = kwargs.pop('send_notif', True)

        if self.update_state_upon_link_unlink():
            entity_state = BaseEntityComponent.ENTITY_STATE_CREATED if notif_operation == verbs.NOTIF_OPERATION_DELETE \
                else BaseEntityComponent.ENTITY_STATE_PUBLISHED
            self.set_entity_state(entity_state)

        if send_notif and parent.is_active():
            notify.send(
                self.get_creator(),
                # recipient is dummy
                recipient=self.get_creator(),
                notif_tuple=verbs.WIZCARD_ENTITY_UPDATE,
                target=parent,
                action_object=self,
                notif_operation=notif_operation)

        return send_notif

    def add_tags(self, taglist):
        self.tags.add(*taglist)

    def get_tags(self):
        return self.tags.names()

    def update_tags(self, taglist):
        return self.tags.set(*taglist)

    def modified_since(self, timestamp):
        return True

    def set_entity_state(self, state):
        self.entity_state = state
        self.save()

    def is_active(self):
        return bool(
            self.entity_state == BaseEntityComponent.ENTITY_STATE_PUBLISHED)

    def is_expired(self):
        return bool(
            self.entity_state == BaseEntityComponent.ENTITY_STATE_EXPIRED)

    def is_deleted(self):
        return bool(
            self.entity_state == BaseEntityComponent.ENTITY_STATE_DELETED)

    # nothing here, should be overridden in derived classes
    def user_state(self, user):
        return ""

    def delete(self, *args, **kwargs):
        type = kwargs.pop("type", BaseEntityComponent.ENTITY_DELETE)

        if type == BaseEntityComponent.ENTITY_EXPIRE:
            self.set_entity_state(BaseEntityComponent.ENTITY_STATE_EXPIRED)
        elif type == BaseEntityComponent.ENTITY_DELETE:
            self.set_entity_state(BaseEntityComponent.ENTITY_STATE_DELETED)
        else:
            super(BaseEntityComponent, self).delete(*args, **kwargs)

    @property
    def push_name_str(self):
        entity_to_push_name_str = {
            self.EVENT: ' ',
            self.CAMPAIGN: ' Campaign ',
            self.TABLE: ' Table ',
            self.SPEAKER: ' Speaker ',
            self.SPONSOR: ' Sponsor ',
            self.MEDIA: ' Media ',
            self.AGENDA: ' Agenda ',
            self.POLL: ' Poll ',
        }
        return entity_to_push_name_str[
            self.
            entity_type] if self.entity_type in entity_to_push_name_str else " "
Exemple #16
0
class Wizcard(WizcardBase):
    # TODO move this upstairs
    user = models.OneToOneField(User, related_name='wizcard')

    wizconnections_to = models.ManyToManyField('self',
                                            through='WizConnectionRequest',
                                            symmetrical=False,
                                            related_name='wizconnections_from')

    media = RelatedObjectsDescriptor()

    objects = WizcardManager()

    class Meta:
        verbose_name = _(u'wizcard')
        verbose_name_plural = _(u'wizcards')

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

    def wizconnection_count(self):
        return self.get_connections().count()

    wizconnection_count.short_description = _(u'Cards count')

    def wizconnection_summary(self, count=7):
        wizconnection_list = self.get_connections().all().select_related()[:count]
        return u'[%s%s]' % (u', '.join(unicode(f.user) for f in wizconnection_list),
                            u', ...' if self.wizconnection_count() > count else u'')

    wizconnection_summary.short_description = _(u'Summary of wizconnections')

    def serialize_wizconnections(self):
        out = []
        # doing import here to avoid circular import. This does affect performance
        # (eventhough django caches re-imports). Still, doing it here since this
        # method is called only in the resync path
        from wizcardship.serializers import WizcardSerializerL1, WizcardSerializerL2
        admin = self.get_admin_wizcard()
        out.append(WizcardSerializerL2(admin, many=True, context={'user_state': verbs.ADMIN}).data)

        connected = self.get_connections_without_admin()
        if connected:
            out.append(WizcardSerializerL2(connected, many=True, context={'user_state': verbs.CONNECTED}).data)

        following = self.get_following_only()
        if following:
            out.append(WizcardSerializerL1(following, many=True, context={'user_state': verbs.FOLLOWED}).data)

        return out

    def flood(self):
        # Q two aync notifs, one for half and one each for full & half
        notify.send(
            self.user,
            # recipient is dummy at this stage
            recipient=self.user,
            notif_tuple=verbs.WIZCARD_UPDATE_HALF,
            target=self
        )

        notify.send(
            self.user,
            # recipient is dummy at this stage
            recipient=self.user,
            notif_tuple=verbs.WIZCARD_UPDATE_FULL,
            target=self
        )

    # typically kwargs can contain the notif tuple
    def flood_set(self, **kwargs):
        # full card for connections and half for followers
        fs_w = self.get_connections() if verbs.get_notif_type(kwargs.pop('ntuple')) == verbs.NOTIF_UPDATE_WIZCARD_F \
            else self.get_followers_only()

        fs_u = [x.user for x in fs_w]
        return fs_u

    def check_flick_duplicates(self, lat, lng):
        if not settings.DO_FLICK_AGGLOMERATE:
            return None
        #check if nearby cards can be combined...do we need to adjust centroid and all that ?
        for w in self.flicked_cards.exclude(expired=True):
            if wizlib.haversine(w.lng, w.lat, lng, lat) < settings.WIZCARD_FLICK_AGGLOMERATE_RADIUS:
                return w
        return None

    def get_relationship(self, wizcard):
        try:
            return WizConnectionRequest.objects.get(
                        from_wizcard=self,
                        to_wizcard=wizcard)
        except:
            return None

    def add_relationship(self, wizcard, status=verbs.PENDING, ctx=""):
        rel = self.get_relationship(wizcard)
        if not rel:
            rel = WizConnectionRequest.objects.create(
                from_wizcard=self,
                to_wizcard=wizcard,
                cctx=ctx,
                status=status)
        else:
            rel.cctx=ctx
            rel.status=status
            rel.save()
        return rel

    def remove_relationship(self, wizcard):
        WizConnectionRequest.objects.filter(
            from_wizcard=self,
            to_wizcard=wizcard).delete()

    def set_delete_relationship(self, wizcard):
        WizConnectionRequest.objects.filter(
            from_wizcard=self,
            to_wizcard=wizcard).update(status=verbs.DELETED)

    # ME ->
    def get_connected_to(self, status):
        return self.wizconnections_to.filter(
            requests_to__status=status)

    # ME <-
    def get_connected_from(self, status):
        return self.wizconnections_from.filter(
            requests_from__status=status)

    # cards I have deleted
    def get_deleted(self):
        return self.wizconnections_from.filter(
            requests_from__status=verbs.DELETED
        )

    #2 way connected...
    def get_connections(self):
        return self.wizconnections_to.filter(
            requests_to__status=verbs.ACCEPTED,
            requests_from__status=verbs.ACCEPTED,
            requests_from__to_wizcard=self
        )

    #2 way connected + admin wizcard
    def get_connections_without_admin(self):
        return self.wizconnections_to.filter(
            Q(user__profile__is_admin=False) |
            Q(requests_to__status=verbs.ACCEPTED,
              requests_from__status=verbs.ACCEPTED,
              requests_from__to_wizcard=self
              )
        ).distinct()

    def get_admin_wizcard(self):
        # ofcourse, optimal way is to simply look up via UserProfile, or
        # even cache the admin wizcard. importing UserProfile here is causing
        # circular import issue
        return self.wizconnections_to.filter(Q(user__profile__is_admin=True))

    def get_pending_from(self):
        return self.get_connected_from(verbs.PENDING)

    # those having my card (=my flood list)
    # wrapper around get_connected_to
    def get_followers(self):
        return self.get_connected_to(verbs.ACCEPTED)

    #my rolodex
    def get_following(self):
        return self.get_connected_from(verbs.ACCEPTED)

    # exclude connected
    def get_followers_only(self):
        return self.get_connected_to(verbs.ACCEPTED).exclude(
            id__in=Wizcard.objects.filter(
                requests_from__status=verbs.ACCEPTED,
                requests_from__to_wizcard=self))

    # note: this excludes admin wizcard
    def get_following_only(self):
        return self.get_connected_from(verbs.ACCEPTED).exclude(
            id__in=Wizcard.objects.filter(
                Q(requests_to__status=verbs.ACCEPTED,
                requests_to__from_wizcard=self)| Q(user__profile__is_admin=True)))

    def get_following_no_admin(self):
        return self.get_connected_from(verbs.ACCEPTED).exclude(
            id__in=Wizcard.objects.filter(Q(user__profile__is_admin=True)))
Exemple #17
0
class WizcardBase(PolymorphicModel, Base413Mixin):
    sms_url = URLField(blank=True)
    media = RelatedObjectsDescriptor()

    def get_latest_company(self):
        qs = self.contact_container.all()
        if qs.exists():
            return qs[0].company
        return None

    def get_latest_cc_fields(self, *args):
        cc = self.contact_container.all()[0]
        return attrgetter(*args)(cc)

    def is_admin_wizcard(self):
        return self.user.profile.is_admin

    def save_sms_url(self, url):
        self.sms_url = wizlib.shorten_url(url)
        self.save()

    def get_sms_url(self):
        return self.sms_url

    def get_thumbnail_url(self):
        tn = [x.media_element for x in self.media.all().generic_objects() if x.media_sub_type == MediaMixin.SUB_TYPE_THUMBNAIL]
        if tn:
            return tn

        return ""

    def save_vcard(self, vobj):
        self.vcard = vobj
        self.save()

    def get_name(self):
        return self.user.first_name + " " + self.user.last_name

    def get_video_url(self):
        vd = [(x.media_element, x.media_iframe) for x in self.media.all().generic_objects() if x.media_type == MediaMixin.TYPE_VIDEO]
        if vd:
            return vd

        return ""

    @property
    def get_ext_fields(self):
        return self.ext_fields

    @property
    def get_vcard(self):
        return self.vcard

    @property
    def get_email(self):
        return self.email

    def get_latest_title(self):
        qs = self.contact_container.all()
        if qs.exists():
            return qs[0].title
        return None
Exemple #18
0
class Note(models.Model):
    content = models.TextField()

    related = RelatedObjectsDescriptor(AnotherRelatedObject)
Exemple #19
0
def monkey_patch(model_class, name='related', descriptor=None):
    rel_obj = descriptor or RelatedObjectsDescriptor()
    rel_obj.contribute_to_class(model_class, name)
    setattr(model_class, name, rel_obj)
    return True