示例#1
0
class Event(models.Model):
    objects = EventManager()
    short = models.CharField(max_length=64, unique=True)
    name = models.CharField(max_length=128)
    receivername = models.CharField(max_length=128,
                                    blank=True,
                                    null=False,
                                    verbose_name='Receiver Name')
    targetamount = models.DecimalField(decimal_places=2,
                                       max_digits=20,
                                       validators=[positive, nonzero],
                                       verbose_name='Target Amount')
    minimumdonation = models.DecimalField(
        decimal_places=2,
        max_digits=20,
        validators=[positive, nonzero],
        verbose_name='Minimum Donation',
        help_text='Enforces a minimum donation amount on the donate page.',
        default=decimal.Decimal('1.00'))
    usepaypalsandbox = models.BooleanField(default=False,
                                           verbose_name='Use Paypal Sandbox')
    paypalemail = models.EmailField(max_length=128,
                                    null=False,
                                    blank=False,
                                    verbose_name='Receiver Paypal')
    paypalcurrency = models.CharField(max_length=8,
                                      null=False,
                                      blank=False,
                                      default=_currencyChoices[0][0],
                                      choices=_currencyChoices,
                                      verbose_name='Currency')
    donationemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        verbose_name='Donation Email Template',
        default=None,
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        related_name='event_donation_templates')
    pendingdonationemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        verbose_name='Pending Donation Email Template',
        default=None,
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        related_name='event_pending_donation_templates')
    donationemailsender = models.EmailField(
        max_length=128,
        null=True,
        blank=True,
        verbose_name='Donation Email Sender')
    scheduleid = models.CharField(max_length=128,
                                  unique=True,
                                  null=True,
                                  blank=True,
                                  verbose_name='Schedule ID')
    scheduletimezone = models.CharField(max_length=64,
                                        blank=True,
                                        choices=_timezoneChoices,
                                        default='US/Eastern',
                                        verbose_name='Schedule Timezone')
    scheduledatetimefield = models.CharField(max_length=128,
                                             blank=True,
                                             verbose_name='Schedule Datetime')
    schedulegamefield = models.CharField(max_length=128,
                                         blank=True,
                                         verbose_name='Schdule Game')
    schedulerunnersfield = models.CharField(max_length=128,
                                            blank=True,
                                            verbose_name='Schedule Runners')
    scheduleestimatefield = models.CharField(max_length=128,
                                             blank=True,
                                             verbose_name='Schedule Estimate')
    schedulesetupfield = models.CharField(max_length=128,
                                          blank=True,
                                          verbose_name='Schedule Setup')
    schedulecommentatorsfield = models.CharField(
        max_length=128, blank=True, verbose_name='Schedule Commentators')
    schedulecommentsfield = models.CharField(max_length=128,
                                             blank=True,
                                             verbose_name='Schedule Comments')
    date = models.DateField()
    timezone = TimeZoneField(default='US/Eastern')
    locked = models.BooleanField(
        default=False,
        help_text=
        'Requires special permission to edit this event or anything associated with it'
    )
    # Fields related to prize management
    prizecoordinator = models.ForeignKey(
        User,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Coordinator',
        help_text=
        'The person responsible for managing prize acceptance/distribution')
    allowed_prize_countries = models.ManyToManyField(
        'Country',
        blank=True,
        verbose_name="Allowed Prize Countries",
        help_text=
        "List of countries whose residents are allowed to receive prizes (leave blank to allow all countries)"
    )
    disallowed_prize_regions = models.ManyToManyField(
        'CountryRegion',
        blank=True,
        verbose_name='Disallowed Regions',
        help_text=
        'A blacklist of regions within allowed countries that are not allowed for drawings (e.g. Quebec in Canada)'
    )
    prize_accept_deadline_delta = models.IntegerField(
        default=14,
        null=False,
        blank=False,
        verbose_name='Prize Accept Deadline Delta',
        help_text=
        'The number of days a winner will be given to accept a prize before it is re-rolled.',
        validators=[positive, nonzero])
    prizecontributoremailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Contributor Accept/Deny Email Template',
        help_text=
        "Email template to use when responding to prize contributor's submission requests",
        related_name='event_prizecontributortemplates')
    prizewinneremailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Winner Email Template',
        help_text="Email template to use when someone wins a prize.",
        related_name='event_prizewinnertemplates')
    prizewinneracceptemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Accepted Email Template',
        help_text=
        "Email template to use when someone accepts a prize (and thus it needs to be shipped).",
        related_name='event_prizewinneraccepttemplates')
    prizeshippedemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Shipped Email Template',
        help_text=
        "Email template to use when the aprize has been shipped to its recipient).",
        related_name='event_prizeshippedtemplates')

    def __unicode__(self):
        return self.name

    def natural_key(self):
        return (self.short, )

    def clean(self):
        if self.id and self.id < 1:
            raise ValidationError('Event ID must be positive and non-zero')
        if not re.match('^\w+$', self.short):
            raise ValidationError('Event short name must be a url-safe string')
        if not self.scheduleid:
            self.scheduleid = None
        if self.donationemailtemplate != None or self.pendingdonationemailtemplate != None:
            if not self.donationemailsender:
                raise ValidationError(
                    'Must specify a donation email sender if automailing is used'
                )

    def start_push_notification(self, request):
        from django.core.urlresolvers import reverse
        approval_force = False
        try:
            credentials = CredentialsModel.objects.get(
                id=request.user).credentials
            if credentials:
                if not credentials.refresh_token:
                    approval_force = True
                    raise CredentialsModel.DoesNotExist
                elif credentials.access_token_expired:
                    import httplib2
                    credentials.refresh(httplib2.Http())
        except CredentialsModel.DoesNotExist:
            from django.conf import settings
            from django.http import HttpResponseRedirect
            FlowModel.objects.filter(id=request.user).delete()
            kwargs = {}
            if approval_force:
                kwargs['approval_prompt'] = 'force'
            defaultflow = OAuth2WebServerFlow(
                client_id=settings.GOOGLE_CLIENT_ID,
                client_secret=settings.GOOGLE_CLIENT_SECRET,
                scope='https://www.googleapis.com/auth/drive.metadata.readonly',
                redirect_uri=request.build_absolute_uri(
                    reverse('admin:google_flow')).replace(
                        '/cutler5:', '/cutler5.example.com:'),
                access_type='offline',
                **kwargs)
            flow = FlowModel(id=request.user, flow=defaultflow)
            flow.save()
            url = flow.flow.step1_get_authorize_url()
            return HttpResponseRedirect(url)
        from apiclient.discovery import build
        import httplib2
        import uuid
        import time
        drive = build('drive', 'v2', credentials.authorize(httplib2.Http()))
        body = {
            'kind':
            'api#channel',
            'resourceId':
            self.scheduleid,
            'id':
            unicode(uuid.uuid4()),
            'token':
            u'%s:%s' % (self.id, unicode(request.user)),
            'type':
            'web_hook',
            'address':
            request.build_absolute_uri(
                reverse('tracker.views.refresh_schedule')),
            'expiration':
            int(time.time() + 24 * 60 * 60) * 1000  # approx one day
        }
        try:
            drive.files().watch(fileId=self.scheduleid, body=body).execute()
        except Exception as e:
            from django.contrib import messages

            messages.error(request,
                           u'Could not start push notification: %s' % e)
            return False
        return True

    class Meta:
        app_label = 'tracker'
        get_latest_by = 'date'
        permissions = (('can_edit_locked_events', 'Can edit locked events'), )
        ordering = ('date', )
 def test_deconstruct(self):
     for org_field in self.test_fields:
         name, path, args, kwargs = org_field.deconstruct()
         new_field = TimeZoneField(*args, **kwargs)
         self.assertEqual(org_field.max_length, new_field.max_length)
         self.assertEqual(org_field.choices, new_field.choices)
示例#3
0
class RRule(models.Model):
    """
    Model that will hold rrule details and generate recurrences to be handled by the supplied handler
    """

    # Params used to generate the rrule
    rrule_params = JSONField()

    # Any meta data associated with the object that created this rule
    meta_data = JSONField(default=dict)

    # The timezone all dates should be converted to
    time_zone = TimeZoneField(default='UTC')

    # The last occurrence date that was handled
    last_occurrence = models.DateTimeField(null=True, default=None)

    # The next occurrence date that should be handled
    next_occurrence = models.DateTimeField(null=True, default=None)

    # A python path to the handler class used to handle when a recurrence occurs for this rrule
    # The configuration class must extend ambition_utils.rrule.handler.OccurrenceHandler
    occurrence_handler_path = models.CharField(max_length=500, blank=False, null=False)

    # Custom object manager
    objects = RRuleManager()

    def get_occurrence_handler_class_instance(self):
        """
        Gets an instance of the occurrence handler class associated with this rrule
        :rtype: ambition_utils.rrule.handler.OccurrenceHandler
        :return: The instance
        """
        return import_string(self.occurrence_handler_path)()

    def get_rrule(self):
        """
        Builds the rrule object by restoring all the params.
        The dtstart param will be converted to local time if it is set.
        :rtype: rrule
        """
        params = copy.deepcopy(self.rrule_params)

        # Convert next scheduled from utc back to time zone
        if params.get('dtstart') and not hasattr(params.get('dtstart'), 'date'):
            params['dtstart'] = parser.parse(params['dtstart'])

        # Convert until date from utc back to time zone
        if params.get('until') and not hasattr(params.get('until'), 'date'):
            params['until'] = parser.parse(params['until'])

        # Always cache
        params['cache'] = True

        # Return the rrule
        return rrule(**params)

    def get_next_occurrence(self, last_occurrence=None, force=False):
        """
        Builds the rrule and returns the next date in the series or None of it is the end of the series
        :param last_occurrence: The last occurrence that was generated
        :param force: If the next occurrence is none, force the rrule to generate another
        :rtype: rrule or None
        """
        # Get the last occurrence
        last_occurrence = last_occurrence or self.last_occurrence or datetime.utcnow()

        # Get the rule
        rule = self.get_rrule()

        # Convert to local time zone for getting next occurrence, otherwise time zones ahead of utc will return the same
        last_occurrence = fleming.convert_to_tz(last_occurrence, self.time_zone, return_naive=True)

        # Generate the next occurrence
        next_occurrence = rule.after(last_occurrence)

        # If next occurrence is none and force is true, force the rrule to generate another date
        if next_occurrence is None and force:
            # Keep a reference to the original rrule_params
            original_rrule_params = {}
            original_rrule_params.update(self.rrule_params)

            # Remove any limiting params
            self.rrule_params.pop('count', None)
            self.rrule_params.pop('until', None)

            # Refetch the rule
            rule = self.get_rrule()

            # Generate the next occurrence
            next_occurrence = rule.after(last_occurrence)

            # Restore the rrule params
            self.rrule_params = original_rrule_params

        # If there is a next occurrence, convert to utc
        if next_occurrence:
            next_occurrence = self.convert_to_utc(next_occurrence)

        # Return the next occurrence
        return next_occurrence

    def update_next_occurrence(self, save=True):
        """
        Sets the next_occurrence property to the next time in the series and sets the last_occurrence property
        to the previous value of next_occurrence. If the save option is True, the model will be saved. The
        save flag is typically set to False when wanting to bulk update records after updating the values
        of many models.
        :param save: Flag to save the model after updating the schedule.
        :type save: bool
        """
        if not self.next_occurrence:
            return None

        # Only handle if the current date is >= next occurrence
        if datetime.utcnow() < self.next_occurrence:
            return False

        self.last_occurrence = self.next_occurrence
        self.next_occurrence = self.get_next_occurrence(self.last_occurrence)

        # Only save if the flag is true
        if save:
            self.save(update_fields=['last_occurrence', 'next_occurrence'])

    def convert_to_utc(self, dt):
        """
        Treats the datetime object as being in the timezone of self.timezone and then converts it to utc timezone.
        :type dt: datetime
        """
        # Add timezone info
        dt = fleming.attach_tz_if_none(dt, self.time_zone)

        # Convert to utc
        dt = fleming.convert_to_tz(dt, pytz.utc, return_naive=True)

        return dt

    def refresh_next_occurrence(self, current_time=None):
        """
        Sets the next occurrence date based on the current rrule param definition. The date will be after the
        specified current_time or utcnow.
        :param current_time: Optional datetime object to compute the next time from
        """
        # Get the current time or go off the specified current time
        current_time = current_time or datetime.utcnow()

        # Next occurrence is in utc here
        next_occurrence = self.get_next_occurrence(last_occurrence=current_time)

        # Check if the start time is different but still greater than now
        if next_occurrence != self.next_occurrence and next_occurrence > datetime.utcnow():
            self.next_occurrence = next_occurrence

    def save(self, *args, **kwargs):
        """
        Saves the rrule model to the database. If this is a new object, the first next_scheduled time is
        determined and set. The `dtstart` and `until` objects will be safely encoded as strings if they are
        datetime objects.
        """

        # Check if this is a new rrule object
        if self.pk is None:
            # Convert next scheduled from utc back to time zone
            if self.rrule_params.get('dtstart') and not hasattr(self.rrule_params.get('dtstart'), 'date'):
                self.rrule_params['dtstart'] = parser.parse(self.rrule_params['dtstart'])

            # Convert until date from utc back to time zone
            if self.rrule_params.get('until') and not hasattr(self.rrule_params.get('until'), 'date'):
                self.rrule_params['until'] = parser.parse(self.rrule_params['until'])

            # Get the first scheduled time according to the rrule (this converts from utc back to local time)
            self.next_occurrence = self.get_rrule()[0]

            # Convert back to utc before saving
            self.next_occurrence = self.convert_to_utc(self.next_occurrence)

        # Serialize the datetime objects if they exist
        if self.rrule_params.get('dtstart') and hasattr(self.rrule_params.get('dtstart'), 'date'):
            self.rrule_params['dtstart'] = self.rrule_params['dtstart'].strftime('%Y-%m-%d %H:%M:%S')

        if self.rrule_params.get('until') and hasattr(self.rrule_params.get('until'), 'date'):
            self.rrule_params['until'] = self.rrule_params['until'].strftime('%Y-%m-%d %H:%M:%S')

        # Call the parent save method
        super().save(*args, **kwargs)
class TimerUser(AbstractUser):
    timezone = TimeZoneField(default='Canada/Mountain')
 def createField():
     TimeZoneField('a verbose name', 'a name', True, 42)
示例#6
0
class User(AbstractUser):
    """
        Project's base user model
    """
    LANGUAGE_CHOICES = (
        ('en-us', 'English'),
        ('pt-pt', _('Portuguese')),
    )

    organization = models.CharField(null=True,
                                    blank=True,
                                    max_length=80,
                                    verbose_name=_('Organization'))
    public_key = models.TextField(blank=True,
                                  null=True,
                                  verbose_name=_('Public key'))
    fingerprint = models.CharField(null=True,
                                   blank=True,
                                   max_length=50,
                                   verbose_name=_('Fingerprint'))
    keyserver_url = models.URLField(null=True,
                                    blank=True,
                                    verbose_name=_('Key server URL'))
    timezone = TimeZoneField(default='UTC', verbose_name=_('Timezone'))
    language = models.CharField(default="en-us",
                                max_length=16,
                                choices=LANGUAGE_CHOICES,
                                verbose_name=_('Language'))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.base_fingerprint = self.fingerprint

    def save(self, *args, **kwargs):
        ip = kwargs.pop('ip', None)
        agent = kwargs.pop('agent', '')
        with transaction.atomic():
            super().save(*args, **kwargs)
            if self.base_fingerprint != self.fingerprint:
                self.keychanges.create(user=self,
                                       prev_fingerprint=self.base_fingerprint,
                                       to_fingerprint=self.fingerprint,
                                       ip_address=ip,
                                       agent=agent)
                self.base_fingerprint = self.fingerprint

    def has_setup_complete(self):
        if self.public_key and self.fingerprint:
            return True
        return False

    @property
    def has_github_login(self):
        return self.socialaccount_set.filter(provider='github').count() >= 1

    @property
    def has_public_key(self):
        return True if self.public_key else False

    @property
    def has_keyserver_url(self):
        return True if self.keyserver_url else False
示例#7
0
文件: models.py 项目: Sukriva/hauki
class Resource(SoftDeletableModel, TimeStampedModel):
    name = models.CharField(verbose_name=_("Name"),
                            max_length=255,
                            null=True,
                            blank=True)
    description = models.TextField(verbose_name=_("Description"),
                                   null=True,
                                   blank=True)
    address = models.TextField(verbose_name=_("Street address"),
                               null=True,
                               blank=True)
    resource_type = EnumField(
        ResourceType,
        verbose_name=_("Resource type"),
        max_length=100,
        default=ResourceType.UNIT,
    )
    children = models.ManyToManyField(
        "self",
        verbose_name=_("Sub resources"),
        related_name="parents",
        blank=True,
        symmetrical=False,
    )
    organization = models.ForeignKey(
        Organization,
        on_delete=models.PROTECT,
        related_name="resources",
        db_index=True,
        null=True,
        blank=True,
    )
    data_sources = models.ManyToManyField(DataSource, through="ResourceOrigin")
    last_modified_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        editable=False,
    )
    extra_data = models.JSONField(verbose_name=_("Extra data"),
                                  null=True,
                                  blank=True)
    is_public = models.BooleanField(default=True)
    timezone = TimeZoneField(default=get_resource_default_timezone,
                             null=True,
                             blank=True)
    # Denormalized values from the parent resources
    ancestry_is_public = models.BooleanField(null=True, blank=True)
    ancestry_data_source = ArrayField(
        models.CharField(max_length=255),
        null=True,
        blank=True,
    )
    ancestry_organization = ArrayField(
        models.CharField(max_length=255),
        null=True,
        blank=True,
    )

    class Meta:
        verbose_name = _("Resource")
        verbose_name_plural = _("Resources")

    def __str__(self):
        return str(self.name)

    @property
    def _history_user(self):
        return self.last_modified_by

    @_history_user.setter
    def _history_user(self, value):
        self.last_modified_by = value

    def get_daily_opening_hours(self, start_date, end_date):
        # TODO: This is just an MVP. Things yet to do:
        #       - Support full_day

        all_daily_opening_hours = defaultdict(list)

        # Need to get one day before the start to handle cases where the previous days
        # opening hours extend to the next day.
        start_minus_one_day = start_date - relativedelta(days=1)

        # We can't filter the date_periods queryset here because we
        # want to allow the callers to use prefetch_related.
        for period in self.date_periods.all():
            # Filter the dates in code instead
            if period.start_date is not None and period.start_date > end_date:
                continue

            if period.end_date is not None and period.end_date < start_date:
                continue

            period_daily_opening_hours = period.get_daily_opening_hours(
                start_minus_one_day, end_date)
            for the_date, time_items in period_daily_opening_hours.items():
                all_daily_opening_hours[the_date].extend(time_items)

        days = list(all_daily_opening_hours.keys())
        days.sort()

        processed_opening_hours = {}
        for day in days:
            previous_day = day - relativedelta(days=1)

            # Add the time spans that might extend from the previous day to the
            # daily opening hours list for them to be considered in the combining step.
            for el in processed_opening_hours.get(previous_day, []):
                if not el.end_time_on_next_day:
                    continue

                all_daily_opening_hours[day].append(el.get_next_day_part())

            processed_opening_hours[day] = combine_and_apply_override(
                all_daily_opening_hours[day])

        # Remove the excessive day from the start
        if start_minus_one_day in processed_opening_hours:
            del processed_opening_hours[start_minus_one_day]

        return processed_opening_hours

    def _get_parent_data(self, acc=None):
        if acc is None:
            acc = {
                "is_public": None,
                "data_sources": set(),
                "organizations": set(),
            }

        parents = (
            self.parents.all().select_related("organization").prefetch_related(
                "origins",
                "origins__data_source",
            ))

        if not parents:
            return acc

        for parent in parents:
            if acc["is_public"] is None:
                acc["is_public"] = parent.is_public

            if not parent.is_public:
                acc["is_public"] = False

            acc["data_sources"].update(
                [i.data_source.id for i in parent.origins.all()])
            if parent.organization:
                acc["organizations"].add(parent.organization.id)

            parent._get_parent_data(acc)

        return acc

    def update_ancestry(self, update_child_ancestry_fields=True):
        data = self._get_parent_data()

        self.ancestry_is_public = data["is_public"]
        self.ancestry_data_source = list(data["data_sources"])
        self.ancestry_organization = list(data["organizations"])
        self.save(update_child_ancestry_fields=update_child_ancestry_fields)

    def save(
        self,
        force_insert=False,
        force_update=False,
        using=None,
        update_fields=None,
        update_child_ancestry_fields=True,
    ):
        super().save(
            force_insert=force_insert,
            force_update=force_update,
            using=using,
            update_fields=update_fields,
        )

        if update_child_ancestry_fields:
            for child in self.children.all():
                child.update_ancestry()

    def get_ancestors(self, acc=None):
        if acc is None:
            acc = set()

        parents = self.parents.all()

        if not parents:
            return acc

        for parent in parents:
            if parent == self or parent in acc:
                continue

            acc.add(parent)
            parent.get_ancestors(acc)

        return acc
示例#8
0
class Group(BaseModel, LocationModel, ConversationMixin):
    objects = GroupManager()

    name = models.CharField(max_length=settings.NAME_MAX_LENGTH, unique=True)
    description = models.TextField(blank=True)
    members = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                     related_name='groups',
                                     through='GroupMembership')
    password = models.CharField(max_length=255, blank=True)
    public_description = models.TextField(blank=True)
    timezone = TimeZoneField(default='Europe/Berlin', null=True, blank=True)
    slack_webhook = models.CharField(max_length=255, blank=True)
    active_agreement = models.OneToOneField('groups.Agreement',
                                            related_name='active_group',
                                            null=True,
                                            on_delete=models.SET_NULL)

    def __str__(self):
        return '{}'.format(self.name)

    def send_notifications(self):
        if self.slack_webhook.startswith('https://hooks.slack.com/services/'):
            for s in self.store.all():
                # get all pick-ups within the notification range
                for p in s.pickup_dates.filter(
                        date__lt=timezone.now() +
                        relativedelta(hours=s.upcoming_notification_hours),
                        date__gt=timezone.now()):
                    p.notify_upcoming_via_slack()

    def add_member(self, user, history_payload=None):
        GroupMembership.objects.create(group=self, user=user)
        History.objects.create(typus=HistoryTypus.GROUP_JOIN,
                               group=self,
                               users=[
                                   user,
                               ],
                               payload=history_payload)

    def remove_member(self, user):
        History.objects.create(typus=HistoryTypus.GROUP_LEAVE,
                               group=self,
                               users=[
                                   user,
                               ])
        GroupMembership.objects.filter(group=self, user=user).delete()

    def is_member(self, user):
        return not user.is_anonymous and GroupMembership.objects.filter(
            group=self, user=user).exists()

    def is_member_with_role(self, user, role_name):
        return not user.is_anonymous and GroupMembership.objects.filter(
            group=self, user=user, roles__contains=[role_name]).exists()

    def accept_invite(self, user, invited_by, invited_at):
        self.add_member(user,
                        history_payload={
                            'invited_by': invited_by.id,
                            'invited_at': invited_at.isoformat(),
                            'invited_via': 'e-mail'
                        })
示例#9
0
class Project(models.Model):
    DEFAULT_TIMEZONE = settings.TIME_ZONE

    program = models.ForeignKey(
        Program,
        blank=False,
        null=False,
        on_delete=models.CASCADE,
        help_text="The program this project belongs to.")

    name = models.CharField(
        max_length=300,
        null=False,
        blank=False,
        unique=True,
        verbose_name="Name",
        help_text="Enter a name for the project (required).")
    code = models.CharField(
        max_length=30,
        null=True,
        blank=True,
        verbose_name="Code",
        help_text="Provide a brief code or acronym for this project. "
        "This code could be used for prefixing site codes.")

    datum = models.IntegerField(
        null=True,
        blank=True,
        choices=DATUM_CHOICES,
        default=MODEL_SRID,
        verbose_name="Default Datum",
        help_text=
        "The datum all locations will be assumed to have unless otherwise specified."
    )

    timezone = TimeZoneField(
        blank=True,
        default=DEFAULT_TIMEZONE,
        help_text="The Timezone of your project e.g 'Australia/Perth.")

    attributes = JSONField(
        null=True,
        blank=True,
        help_text=
        "Define here all specific attributes of your project in the form of json "
        "'attribute name': 'attribute value")
    description = models.TextField(null=True,
                                   blank=True,
                                   verbose_name="Description",
                                   help_text="")

    geometry = models.GeometryField(
        srid=MODEL_SRID,
        spatial_index=True,
        null=True,
        blank=True,
        editable=True,
        verbose_name="Extent",
        help_text="The boundary of your project (not required). "
        "Can also be calculated from the extents of the project sites")
    site_data_package = JSONField(
        null=True,
        blank=True,
        verbose_name='Site attributes schema',
        help_text='Define here the attributes that all your sites will share. '
        'This allows validation when importing sites.')

    custodians = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        blank=False,
        help_text=
        "Users that have write/upload access to the data of this project.")

    def is_custodian(self, user):
        return user in self.custodians.all()

    def is_data_engineer(self, user):
        return self.program.is_data_engineer(user)

    # API permissions
    @staticmethod
    def has_read_permission(request):
        return True

    def has_object_read_permission(self, request):
        return True

    @staticmethod
    def has_metadata_permission(request):
        return True

    def has_object_metadata_permission(self, request):
        return True

    @staticmethod
    def has_create_permission(request):
        """
        Admin or data_engineer of the program the project would belong to.
        Check that the user is a data_engineer of the program pk passed in the POST data.
        :param request:
        :return:
        """
        result = False
        if is_admin(request.user):
            result = True
        elif 'program' in request.data:
            program = Program.objects.filter(
                pk=request.data['program']).first()
            result = program is not None and program.is_data_engineer(
                request.user)
        return result

    @staticmethod
    def has_update_permission(request):
        """
        The update is managed at the object level (see below)
        :param request:
        :return:
        """
        return True

    def has_object_update_permission(self, request):
        """
        Admin or program data_engineer or project custodian
        :param request:
        :return:
        """
        user = request.user
        return is_admin(user) or self.program.is_data_engineer(user)

    @staticmethod
    def has_destroy_permission(request):
        return True

    def has_object_destroy_permission(self, request):
        """
        Admin or program data_engineer or project custodian
        :param request:
        :return:
        """
        user = request.user
        return is_admin(user) or self.program.is_data_engineer(user)

    @property
    def centroid(self):
        return self.geometry.centroid if self.geometry else None

    @property
    def extent(self):
        return self.geometry.extent if self.geometry else None

    @property
    def dataset_count(self):
        return self.projects.count()

    @property
    def site_count(self):
        return self.site_set.count()

    @property
    def record_count(self):
        return Record.objects.filter(dataset__project=self).count()

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name
示例#10
0
class Article(TendenciBaseModel):
    CONTRIBUTOR_AUTHOR = 1
    CONTRIBUTOR_PUBLISHER = 2
    CONTRIBUTOR_CHOICES = ((CONTRIBUTOR_AUTHOR, _('Author')),
                           (CONTRIBUTOR_PUBLISHER, _('Publisher')))

    guid = models.CharField(max_length=40)
    slug = SlugField(_('URL Path'), unique=True)
    timezone = TimeZoneField(verbose_name=_('Time Zone'), default='US/Central', choices=get_timezone_choices(), max_length=100)
    headline = models.CharField(max_length=200, blank=True)
    summary = models.TextField(blank=True)
    body = tinymce_models.HTMLField()
    source = models.CharField(max_length=300, blank=True)
    first_name = models.CharField(_('First Name'), max_length=100, blank=True)
    last_name = models.CharField(_('Last Name'), max_length=100, blank=True)
    contributor_type = models.IntegerField(choices=CONTRIBUTOR_CHOICES,
                                           default=CONTRIBUTOR_AUTHOR)
    phone = models.CharField(max_length=50, blank=True)
    fax = models.CharField(max_length=50, blank=True)
    email = models.CharField(max_length=120, blank=True)
    website = models.CharField(max_length=300, blank=True)
    thumbnail = models.ForeignKey(File, null=True,
                                  on_delete=models.SET_NULL,
                                  help_text=_('The thumbnail image can be used on your homepage ' +
                                 'or sidebar if it is setup in your theme. The thumbnail image ' +
                                 'will not display on the news page.'))
    release_dt = models.DateTimeField(_('Release Date/Time'), null=True, blank=True)
    # used for better performance when retrieving a list of released articles
    release_dt_local = models.DateTimeField(null=True, blank=True)
    syndicate = models.BooleanField(_('Include in RSS feed'), default=True)
    featured = models.BooleanField(default=False)
    design_notes = models.TextField(_('Design Notes'), blank=True)
    group = models.ForeignKey(Group, null=True, default=get_default_group, on_delete=models.SET_NULL)
    tags = TagField(blank=True)

    # for podcast feeds
    enclosure_url = models.CharField(_('Enclosure URL'), max_length=500, blank=True)
    enclosure_type = models.CharField(_('Enclosure Type'), max_length=120, blank=True)
    enclosure_length = models.IntegerField(_('Enclosure Length'), default=0)

    not_official_content = models.BooleanField(_('Official Content'), blank=True, default=True)

    # html-meta tags
    meta = models.OneToOneField(MetaTags, null=True, on_delete=models.SET_NULL)

    categories = GenericRelation(CategoryItem,
                                          object_id_field="object_id",
                                          content_type_field="content_type")
    perms = GenericRelation(ObjectPermission,
                                          object_id_field="object_id",
                                          content_type_field="content_type")

    objects = ArticleManager()

    class Meta:
        permissions = (("view_article", _("Can view article")),)
        verbose_name = _("Article")
        verbose_name_plural = _("Articles")
        app_label = 'articles'

    def get_meta(self, name):
        """
        This method is standard across all models that are
        related to the Meta model.  Used to generate dynamic
        methods coupled to this instance.
        """
        return ArticleMeta().get_meta(self, name)

    def get_absolute_url(self):
        return reverse('article', args=[self.slug])

    def get_version_url(self, hash):
        return reverse('article.version', args=[hash])

    def __str__(self):
        return self.headline

    def get_thumbnail_url(self):
        if not self.thumbnail:
            return u''

        return reverse('file', args=[self.thumbnail.pk])

    def save(self, *args, **kwargs):
        if not self.id:
            self.guid = str(uuid.uuid4())
        self.assign_release_dt_local()
        super(Article, self).save(*args, **kwargs)

    def assign_release_dt_local(self):
        """
        convert release_dt to the corresponding local time

        example:

        if
            release_dt: 2014-05-09 03:30:00
            timezone: US/Pacific
            settings.TIME_ZONE: US/Central
        then
            the corresponding release_dt_local will be: 2014-05-09 05:30:00
        """
        now = datetime.now()
        now_with_tz = adjust_datetime_to_timezone(now, settings.TIME_ZONE)
        if self.timezone and self.release_dt and self.timezone.zone != settings.TIME_ZONE:
            time_diff = adjust_datetime_to_timezone(now, self.timezone) - now_with_tz
            self.release_dt_local = self.release_dt + time_diff
        else:
            self.release_dt_local = self.release_dt

    def age(self):
        return datetime.now() - self.create_dt

    @property
    def category_set(self):
        items = {}
        for cat in self.categories.select_related('category', 'parent'):
            if cat.category:
                items["category"] = cat.category
            elif cat.parent:
                items["sub_category"] = cat.parent
        return items

    @property
    def has_google_author(self):
        return self.contributor_type == self.CONTRIBUTOR_AUTHOR

    @property
    def has_google_publisher(self):
        return self.contributor_type == self.CONTRIBUTOR_PUBLISHER
示例#11
0
class Site(ChangeLoggedModel, CustomFieldModel):
    """
    A Site represents a geographic location within a network; typically a building or campus. The optional facility
    field can be used to include an external designation, such as a data center name (e.g. Equinix SV6).
    """
    name = models.CharField(max_length=50, unique=True)
    _name = NaturalOrderingField(target_field='name',
                                 max_length=100,
                                 blank=True)
    slug = models.SlugField(unique=True)
    status = models.CharField(max_length=50,
                              choices=SiteStatusChoices,
                              default=SiteStatusChoices.STATUS_ACTIVE)
    region = models.ForeignKey(to='dcim.Region',
                               on_delete=models.SET_NULL,
                               related_name='sites',
                               blank=True,
                               null=True)
    tenant = models.ForeignKey(to='tenancy.Tenant',
                               on_delete=models.PROTECT,
                               related_name='sites',
                               blank=True,
                               null=True)
    facility = models.CharField(max_length=50,
                                blank=True,
                                help_text='Local facility ID or description')
    asn = ASNField(blank=True,
                   null=True,
                   verbose_name='ASN',
                   help_text='32-bit autonomous system number')
    time_zone = TimeZoneField(blank=True)
    description = models.CharField(max_length=200, blank=True)
    physical_address = models.CharField(max_length=200, blank=True)
    shipping_address = models.CharField(max_length=200, blank=True)
    latitude = models.DecimalField(max_digits=8,
                                   decimal_places=6,
                                   blank=True,
                                   null=True,
                                   help_text='GPS coordinate (latitude)')
    longitude = models.DecimalField(max_digits=9,
                                    decimal_places=6,
                                    blank=True,
                                    null=True,
                                    help_text='GPS coordinate (longitude)')
    contact_name = models.CharField(max_length=50, blank=True)
    contact_phone = models.CharField(max_length=20, blank=True)
    contact_email = models.EmailField(blank=True,
                                      verbose_name='Contact E-mail')
    comments = models.TextField(blank=True)
    custom_field_values = GenericRelation(to='extras.CustomFieldValue',
                                          content_type_field='obj_type',
                                          object_id_field='obj_id')
    images = GenericRelation(to='extras.ImageAttachment')
    tags = TaggableManager(through=TaggedItem)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = [
        'name',
        'slug',
        'status',
        'region',
        'tenant',
        'facility',
        'asn',
        'time_zone',
        'description',
        'physical_address',
        'shipping_address',
        'latitude',
        'longitude',
        'contact_name',
        'contact_phone',
        'contact_email',
        'comments',
    ]
    clone_fields = [
        'status',
        'region',
        'tenant',
        'facility',
        'asn',
        'time_zone',
        'description',
        'physical_address',
        'shipping_address',
        'latitude',
        'longitude',
        'contact_name',
        'contact_phone',
        'contact_email',
    ]

    STATUS_CLASS_MAP = {
        SiteStatusChoices.STATUS_PLANNED: 'info',
        SiteStatusChoices.STATUS_STAGING: 'primary',
        SiteStatusChoices.STATUS_ACTIVE: 'success',
        SiteStatusChoices.STATUS_DECOMMISSIONING: 'warning',
        SiteStatusChoices.STATUS_RETIRED: 'danger',
    }

    class Meta:
        ordering = ('_name', )

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('dcim:site', args=[self.slug])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.get_status_display(),
            self.region.name if self.region else None,
            self.tenant.name if self.tenant else None,
            self.facility,
            self.asn,
            self.time_zone,
            self.description,
            self.physical_address,
            self.shipping_address,
            self.latitude,
            self.longitude,
            self.contact_name,
            self.contact_phone,
            self.contact_email,
            self.comments,
        )

    def get_status_class(self):
        return self.STATUS_CLASS_MAP.get(self.status)
示例#12
0
class Event(models.Model):
    objects = EventManager()
    short = models.CharField(max_length=64, unique=True)
    name = models.CharField(max_length=128)
    receivername = models.CharField(max_length=128,
                                    blank=True,
                                    null=False,
                                    verbose_name='Receiver Name')
    targetamount = models.DecimalField(decimal_places=2,
                                       max_digits=20,
                                       validators=[positive, nonzero],
                                       verbose_name='Target Amount')
    minimumdonation = models.DecimalField(
        decimal_places=2,
        max_digits=20,
        validators=[positive, nonzero],
        verbose_name='Minimum Donation',
        help_text='Enforces a minimum donation amount on the donate page.',
        default=decimal.Decimal('1.00'))
    usepaypalsandbox = models.BooleanField(default=False,
                                           verbose_name='Use Paypal Sandbox')
    paypalemail = models.EmailField(max_length=128,
                                    null=False,
                                    blank=False,
                                    verbose_name='Receiver Paypal')
    paypalcurrency = models.CharField(max_length=8,
                                      null=False,
                                      blank=False,
                                      default=_currencyChoices[0][0],
                                      choices=_currencyChoices,
                                      verbose_name='Currency')
    donationemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        verbose_name='Donation Email Template',
        default=None,
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        related_name='event_donation_templates')
    pendingdonationemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        verbose_name='Pending Donation Email Template',
        default=None,
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        related_name='event_pending_donation_templates')
    donationemailsender = models.EmailField(
        max_length=128,
        null=True,
        blank=True,
        verbose_name='Donation Email Sender')
    scheduleid = models.CharField(max_length=128,
                                  unique=True,
                                  null=True,
                                  blank=True,
                                  verbose_name='Schedule ID (LEGACY)',
                                  editable=False)
    datetime = models.DateTimeField()
    timezone = TimeZoneField(default='US/Eastern')
    locked = models.BooleanField(
        default=False,
        help_text=
        'Requires special permission to edit this event or anything associated with it'
    )
    # Fields related to prize management
    prizecoordinator = models.ForeignKey(
        User,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Coordinator',
        help_text=
        'The person responsible for managing prize acceptance/distribution',
        on_delete=models.PROTECT)
    allowed_prize_countries = models.ManyToManyField(
        'Country',
        blank=True,
        verbose_name="Allowed Prize Countries",
        help_text=
        "List of countries whose residents are allowed to receive prizes (leave blank to allow all countries)"
    )
    disallowed_prize_regions = models.ManyToManyField(
        'CountryRegion',
        blank=True,
        verbose_name='Disallowed Regions',
        help_text=
        'A blacklist of regions within allowed countries that are not allowed for drawings (e.g. Quebec in Canada)'
    )
    prize_accept_deadline_delta = models.IntegerField(
        default=14,
        null=False,
        blank=False,
        verbose_name='Prize Accept Deadline Delta',
        help_text=
        'The number of days a winner will be given to accept a prize before it is re-rolled.',
        validators=[positive, nonzero])
    prizecontributoremailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Contributor Accept/Deny Email Template',
        help_text=
        "Email template to use when responding to prize contributor's submission requests",
        related_name='event_prizecontributortemplates',
        on_delete=models.PROTECT)
    prizewinneremailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Winner Email Template',
        help_text="Email template to use when someone wins a prize.",
        related_name='event_prizewinnertemplates',
        on_delete=models.PROTECT)
    prizewinneracceptemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Accepted Email Template',
        help_text=
        "Email template to use when someone accepts a prize (and thus it needs to be shipped).",
        related_name='event_prizewinneraccepttemplates',
        on_delete=models.PROTECT)
    prizeshippedemailtemplate = models.ForeignKey(
        post_office.models.EmailTemplate,
        default=None,
        null=True,
        blank=True,
        verbose_name='Prize Shipped Email Template',
        help_text=
        "Email template to use when the aprize has been shipped to its recipient).",
        related_name='event_prizeshippedtemplates',
        on_delete=models.PROTECT)
    # Fields for Horaro schedule import
    horaro_id = models.CharField(max_length=100,
                                 verbose_name='Event ID',
                                 blank=True,
                                 default='',
                                 help_text='ID or slug for Horaro event')
    horaro_game_col = models.IntegerField(
        verbose_name='Game Column',
        blank=True,
        null=True,
        help_text='Column index for game info (start at 0)')
    horaro_category_col = models.IntegerField(
        verbose_name='Category Column',
        blank=True,
        null=True,
        help_text='Column index for category info (start at 0)')
    horaro_runners_col = models.IntegerField(
        verbose_name='Runners Column',
        blank=True,
        null=True,
        help_text='Column index for runner info (start at 0)')
    horaro_commentators_col = models.IntegerField(
        verbose_name='Commentators Column',
        blank=True,
        null=True,
        help_text='Column index for commentator info (start at 0)')

    # Fields for Tiltify donation import
    tiltify_enable_sync = models.BooleanField(
        default=False,
        verbose_name='Enable Tiltify Sync',
        help_text='Sync donations for this event via the Tiltify API')
    tiltify_api_key = models.CharField(max_length=100,
                                       verbose_name='Tiltify Campaign API Key',
                                       blank=True,
                                       default='')

    # Fields for Twitch chat announcements
    twitch_channel = models.CharField(
        max_length=100,
        verbose_name='Channel Name',
        blank=True,
        default='',
        help_text='Announcements will be made to this channel')
    twitch_login = models.CharField(
        max_length=100,
        verbose_name='Username',
        blank=True,
        default='',
        help_text='Username to use for chat announcements')
    twitch_oauth = models.CharField(
        max_length=200,
        verbose_name='OAuth Password',
        blank=True,
        default='',
        help_text='Get one here: http://www.twitchapps.com/tmi')

    def __str__(self):
        return self.name

    def natural_key(self):
        return (self.short, )

    def save(self, *args, **kwargs):
        if self.datetime is not None:
            if self.datetime.tzinfo is None or self.datetime.tzinfo.utcoffset(
                    self.datetime) is None:
                self.datetime = self.timezone.localize(self.datetime)
        super(Event, self).save(*args, **kwargs)

    def clean(self):
        errors = {}

        if self.id and self.id < 1:
            raise ValidationError('Event ID must be positive and non-zero')
        if not re.match('^\w+$', self.short):
            errors['short'] = 'Event short name must be a url-safe string'
        if not self.scheduleid:
            self.scheduleid = None
        if self.donationemailtemplate != None or self.pendingdonationemailtemplate != None:
            if not self.donationemailsender:
                errors[
                    'donationemailsender'] = 'Must specify a donation email sender if automailing is used'

        # If Tiltify sync is enabled, the API key must be populated.
        if self.tiltify_enable_sync and not self.tiltify_api_key:
            errors[
                'tiltify_api_key'] = 'Must be populated if Tiltify sync is enabled'

        # If any Twitch chat fields are filled in, they all must be.
        if self.twitch_channel or self.twitch_login or self.twitch_oauth:
            if not self.twitch_channel:
                errors[
                    'twitch_channel'] = 'Must be filled if enabling Twitch chat announcements'
            if not self.twitch_login:
                errors[
                    'twitch_login'] = '******'
            if not self.twitch_oauth:
                errors[
                    'twitch_oauth'] = 'Must be filled if enabling Twitch chat announcements'

        # Don't put the "oauth:" starting part on the token.  IRC code will add this automatically.
        if self.twitch_oauth.startswith("oauth:"):
            self.twitch_oauth = self.twitch_oauth[6:]

        if errors:
            raise ValidationError(errors)

    @property
    def date(self):
        return self.datetime.date()

    # Extra field for displaying Horaro columns on admin UI.
    def admin_horaro_check_cols(self):
        return format_html('<span id="horaro_cols"></span>')

    admin_horaro_check_cols.allow_tags = True
    admin_horaro_check_cols.short_description = "Schedule Columns"

    class Meta:
        app_label = 'tracker'
        get_latest_by = 'datetime'
        permissions = (('can_edit_locked_events', 'Can edit locked events'), )
        ordering = ('datetime', 'name')
示例#13
0
class UserProfile(caching.base.CachingMixin, models.Model):
    user = models.OneToOneField(User)
    bio = models.CharField(max_length=500, blank=True, null=True)
    time_zone = TimeZoneField(blank=True, null=True)
    latitude = models.FloatField(null=True, blank=True)
    longitude = models.FloatField(null=True, blank=True)
    location = models.CharField(max_length=255, null=True, blank=True)
    birthday = models.DateField(null=True, blank=True)
    tagline = models.CharField(max_length=180, null=True, blank=True)
    display_name = models.CharField(max_length=120, null=True, blank=True)
    has_commented = models.BooleanField(default=False)
    logo = models.ImageField(max_length=1024,
                             upload_to=logo_file_path,
                             blank=True,
                             null=True)
    dashboard_enabled = models.BooleanField(default=False)
    is_online = models.BooleanField(default=False)
    last_online_on = models.DateTimeField(blank=True, null=True)
    channel = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        verbose_name = 'User Profile'
        verbose_name_plural = 'User Profiles'

    def get_uhash(self):
        return hashlib.md5(self.user.username).hexdigest()

    def get_color_code(self):
        uhash = self.get_uhash()
        r = '0x%s' % str(uhash[0:2])
        g = '0x%s' % str(uhash[2:4])
        b = '0x%s' % str(uhash[4:6])
        rgb = (int(r, 16), int(g, 16), int(b, 16))
        return rgb

    def generate_default_avatar(self):
        from cStringIO import StringIO
        from django.core.files.uploadedfile import SimpleUploadedFile
        from PIL import Image, ImageFont, ImageDraw
        from avatar.models import Avatar

        tmpname = '%s.png' % self.get_uhash()
        code = self.get_color_code()
        mode = "RGB"
        W, H = settings.SIMPLEAVATAR_SIZE
        font = ImageFont.truetype(settings.SIMPLEAVATAR_FONT, 256)
        text = self.user.username[:1].upper()

        im = Image.new(mode, (W, H), code)
        draw = ImageDraw.Draw(im)
        text_x, text_y = font.getsize(text)
        x = (W - text_x) / 2.0
        y = ((H - text_y) / 2.0) - (text_y / 2.0)
        draw.text((x, y), text, font=font, fill=(255, 255, 255, 100))

        # Write new avatar to memory.
        tmphandle = StringIO()
        im.save(tmphandle, 'png')
        tmphandle.seek(0)

        suf = SimpleUploadedFile(tmpname,
                                 tmphandle.read(),
                                 content_type='image/png')
        av = Avatar(user=self.user, primary=True)
        av.avatar.save(tmpname, suf, save=False)
        av.save()

    def get_absolute_url(self):
        return ''

    def __unicode__(self):
        return "%s's Profile" % self.user
示例#14
0
class Member(models.Model):
    id = models.CharField(max_length=60, primary_key=True)
    real_name = models.CharField(max_length=60)
    tz = TimeZoneField(default='Europe/London')
示例#15
0
class User(TrackerModelMixin, AbstractUser):
    class ActivityStreamFilters(models.TextChoices):
        USERS = "users", _("Limited to only content from people I'm following")
        TAGS = "tags", _("Limited to only tags I'm following")

    name = models.CharField(_("Full name"), blank=True, max_length=255)
    bio = MarkdownField(blank=True)
    avatar = ImageField(upload_to="avatars", null=True, blank=True)

    language = models.CharField(
        max_length=6,
        choices=settings.LANGUAGES,
        default=settings.LANGUAGE_CODE,
    )

    default_timezone = TimeZoneField(default=settings.TIME_ZONE)

    activity_stream_filters = ChoiceArrayField(
        models.CharField(max_length=12, choices=ActivityStreamFilters.choices),
        default=list,
        blank=True,
    )

    show_external_images = models.BooleanField(default=True)
    show_sensitive_content = models.BooleanField(default=False)
    show_embedded_content = models.BooleanField(default=False)

    send_email_notifications = models.BooleanField(default=True)

    dismissed_notices = ArrayField(models.CharField(max_length=30),
                                   default=list)

    following = models.ManyToManyField("self",
                                       related_name="followers",
                                       blank=True,
                                       symmetrical=False)

    blocked = models.ManyToManyField("self",
                                     related_name="blockers",
                                     blank=True,
                                     symmetrical=False)

    following_tags = models.ManyToManyField(Tag, related_name="+", blank=True)

    blocked_tags = models.ManyToManyField(Tag, related_name="+", blank=True)

    search_document = SearchVectorField(null=True, editable=False)

    search_indexer = SearchIndexer(("A", "username"), ("B", "name"),
                                   ("C", "bio"))

    tracked_fields = ["avatar", "name", "bio"]

    objects = UserManager()

    class Meta(AbstractUser.Meta):

        indexes = [
            GinIndex(fields=["search_document"]),
            models.Index(fields=["name", "username"]),
        ]

    def get_absolute_url(self):
        return reverse("users:activities", args=[self.username])

    def get_display_name(self):
        """Displays full name or username

        Returns: str:  full display name
        """
        return self.name or self.username

    def get_initials(self):
        return "".join([n[0].upper()
                        for n in self.get_display_name().split()][:2])

    def get_notifications(self):
        """Returns notifications where the user is the target content object,
        *not* necessarily the actor or recipient.

        Returns:
            QuerySet
        """
        return get_generic_related_queryset(self, Notification)

    @cached_property
    def member_cache(self):
        """
        Returns:
            A MemberCache instance of membership status/roles across all communities
            the user belongs to.
        """

        mc = MemberCache()

        for community_id, role, active in Membership.objects.filter(
                member=self).values_list("community", "role", "active"):
            mc.add_role(community_id, role, active)
        return mc

    def has_role(self, community, *roles):
        """Checks if user has given role in the community, if any. Result
        is cached.
        Args:
            community (Community)
            *roles: roles i.e. one or more of "member", "moderator", "admin". If
                empty assumes any role.

        Returns:
            bool: if user has any of these roles
        """
        return self.member_cache.has_role(community.id, roles)

    def is_admin(self, community):
        return self.has_role(community, Membership.Role.ADMIN)

    def is_moderator(self, community):
        return self.has_role(community, Membership.Role.MODERATOR)

    def is_member(self, community):
        return self.has_role(community, Membership.Role.MEMBER)

    def is_active_member(self, community):
        """Checks if user an active member of any role.

        Returns:
            bool
        """
        return self.has_role(community)

    def is_inactive_member(self, community):
        """Checks if user has an inactive membership for this community.

        Returns:
            bool
        """
        return self.member_cache.is_inactive(community.id)

    def is_blocked(self, user):
        """Check if user is blocking this other user, or is blocked by this other
        user.

        Args:
            user (User)

        Returns:
            bool
        """
        if self == user:
            return False
        return self.get_blocked_users().filter(pk=user.id).exists()

    def is_activity_stream_tags_filter(self):
        return self.ActivityStreamFilters.TAGS in self.activity_stream_filters

    def is_activity_stream_users_filter(self):
        return self.ActivityStreamFilters.USERS in self.activity_stream_filters

    def is_activity_stream_all_filters(self):
        return (self.is_activity_stream_tags_filter()
                and self.is_activity_stream_users_filter())

    def get_blocked_users(self):
        """Return a) users I'm blocking and b) users blocking me.

        Returns:
            QuerySet
        """
        return (self.blockers.all() | self.blocked.all()).distinct()

    @transaction.atomic
    def block_user(self, user):
        """Blocks this user. Any following relationships are also removed.

        Args:
            user (User)
        """
        self.blocked.add(user)
        self.following.remove(user)
        self.followers.remove(user)

    @notify
    def notify_on_join(self, community):
        """Returns notification to all other current members that
        this user has just joined the community.

        Args:
            community (Community)

        Returns:
            list: list of Notification instances
        """
        return [
            Notification(
                content_object=self,
                actor=self,
                recipient=member,
                community=community,
                verb="new_member",
            ) for member in community.members.exclude(pk=self.pk)
        ]

    @notify
    def notify_on_follow(self, recipient, community):
        """Sends notification to recipient that they have just been followed.

        Args:
            recipient (User)
            community (Community)

        Returns:
            Notification
        """
        return Notification(
            content_object=self,
            actor=self,
            recipient=recipient,
            community=community,
            verb="new_follower",
        )

    @notify
    def notify_on_update(self):
        """Sends notification to followers that user has updated their profile.

        This is sent to followers across all communities where the user is
        an active member.

        If follower belongs to multiple common communities, we just send
        notification to one community.

        We only send notifications if certain tracked fields are updated
        e.g. bio or avatar.

        Returns:
            list: Notifications to followers
        """

        if self.has_tracker_changed():
            return takefirst(
                [
                    Notification(
                        content_object=self,
                        actor=self,
                        recipient=follower,
                        community=membership.community,
                        verb="update",
                    ) for membership in self.membership_set.filter(
                        active=True).select_related("community") for follower
                    in self.followers.for_community(membership.community)
                ],
                lambda n: n.recipient,
            )

    def get_email_addresses(self):
        """Get set of emails belonging to user.

        Returns:
            set: set of email addresses
        """
        return set([self.email]) | set(
            self.emailaddress_set.values_list("email", flat=True))

    def dismiss_notice(self, notice):
        """
        Adds notice permanently to list of dismissed notices.

        Args:
            notice (str): unique notice ID e.g. "private-stash"
        """
        if notice not in self.dismissed_notices:
            self.dismissed_notices.append(notice)
            self.save(update_fields=["dismissed_notices"])
示例#16
0
文件: models.py 项目: yvanss/trapper
class Location(models.Model):
    """Single location (Point) on map.
    This model is often referred by other models for establishing a
    spatial context.
    """

    location_id = models.CharField(max_length=100)
    name = models.CharField(max_length=255, null=True, blank=True)
    date_created = models.DateTimeField(blank=True, editable=False)
    description = models.TextField(null=True, blank=True)
    is_public = models.BooleanField(default=False)
    coordinates = models.PointField(srid=4326)
    timezone = TimeZoneField(default=timezone.get_default_timezone_name())
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              related_name='owned_locations')
    managers = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                      related_name='managed_locations',
                                      blank=True)
    country = models.CharField(max_length=100,
                               blank=True,
                               null=True,
                               editable=False)
    state = models.CharField(max_length=100,
                             blank=True,
                             null=True,
                             editable=False)
    county = models.CharField(max_length=100,
                              blank=True,
                              null=True,
                              editable=False)
    city = models.CharField(max_length=100,
                            blank=True,
                            null=True,
                            editable=False)
    research_project = models.ForeignKey('research.ResearchProject',
                                         blank=True,
                                         null=True)

    objects = LocationManager()

    class Meta:
        unique_together = ['research_project', 'location_id']

    @property
    def get_x(self):
        return self.coordinates.x

    @property
    def get_y(self):
        return self.coordinates.y

    @property
    def owner_name(self):
        return self.owner.username

    @property
    def latlng(self):
        return "{}, {}".format(self.coordinates.y, self.coordinates.x)

    def can_view(self, user=None):
        """Determines whether user can view the location.
        :param user: user for which the test is made
        :type user: :py:class:`django.contrib.auth.User`
        :return: True if user can see the location, False otherwise
        :rtype: bool
        """
        user = user or get_current_user()

        return (self.is_public or user == self.owner
                or user in self.managers.all())

    def can_update(self, user=None):
        user = user or get_current_user()
        return (user == self.owner or user in self.managers.all())

    def can_delete(self, user=None):
        user = user or get_current_user()
        return user == self.owner

    def save(self, **kwargs):
        if self.date_created is None:
            self.date_created = timezone.now()
        old_instance = None

        if self.pk:
            old_instance = Location.objects.get(pk=self.pk)

        if (settings.REVERSE_GEOCODING and
            (not self.pk or
             (old_instance and self.coordinates != old_instance.coordinates))):
            self.reverse_geocoding()

        super(Location, self).save(**kwargs)

        if old_instance and self.coordinates != old_instance.coordinates:
            for deployment in self.deployments.all():
                for resource in deployment.resources.all():
                    resource.refresh_collection_bbox()

    def reverse_geocoding(self, set_fields=True, return_data=False):
        """ using pygeocoder: http://code.xster.net/pygeocoder/wiki/Home
        update fields:

        .. code-block::
            * city
            * county
            * state
            * country

        In case of `GeocoderException` required fields will be set to empty.
        """
        parsed_data = {
            'city': '',
            'county': '',
            'state': '',
            'country': '',
        }

        try:
            results = Geocoder.reverse_geocode(self.coordinates.y,
                                               self.coordinates.x)
        except GeocoderError:
            pass
        else:

            for k in results.data[0]['address_components']:
                if 'locality' in k['types']:
                    parsed_data['city'] = k['long_name']
                if 'administrative_area_level_2' in k['types']:
                    parsed_data['county'] = k['long_name']
                if 'administrative_area_level_1' in k['types']:
                    parsed_data['state'] = k['long_name']
                if 'country' in k['types']:
                    parsed_data['country'] = k['long_name']

            if set_fields:
                for key, value in parsed_data.items():
                    setattr(self, key, value)
            if return_data:
                return parsed_data

    def __unicode__(self):
        return unicode("Location: %s" % (self.location_id, ))

    class Meta:
        ordering = ['-pk']
class User(AbstractUser):
    """User object

    User object, as defined and customized for project implementation.

    TODO: Document common patterns for User customization.
    """

    objects = UserManager()

    # First Name and Last Name do not cover name patterns
    # around the globe.
    name = models.CharField(_('Name of User'), blank=True, max_length=255)
    role = models.ForeignKey(Role, blank=True, null=True, on_delete=CASCADE)
    organization = models.CharField(_('Organization'), max_length=100, blank=True, null=True)
    timezone = TimeZoneField(blank=True, null=True)
    photo = models.ImageField(upload_to='photo', max_length=100, blank=True, null=True,
                              storage=get_media_file_storage(folder='media'))

    class Meta(object):
        ordering = ('username',)

    def __str__(self):
        return self.get_full_name()

    @property
    def is_admin(self):
        return self.role.is_admin

    @property
    def is_manager(self):
        return self.role.is_manager

    @property
    def is_reviewer(self):
        return self.role.is_reviewer

    def _fire_saved(self, old_instance=None):
        signals.user_saved.send(self.__class__, user=None, instance=self, old_instance=old_instance)

    def save(self, *args, **kwargs):
        if self.role is None:
            self.role = Role.objects.filter(is_admin=False, is_manager=False).last() \
                        or Role.objects.first()
        old_instance = User.objects.filter(pk=self.pk).first()
        res = super().save(*args, **kwargs)
        with transaction.atomic():
            transaction.on_commit(lambda: self._fire_saved(old_instance))
        return res

    def can_view_document(self, document):
        # TODO: review with new user access strategies

        # allow to any "power" user
        is_able = self.is_superuser or self.is_admin or self.is_manager

        # project-level perm. for reviewers
        if not is_able and self.is_reviewer:
            is_able = document.project.reviewers.filter(pk=self.pk).exists()

        # task-queue-level perm. for reviewers
        if not is_able and self.is_reviewer:
            is_able = self.taskqueue_set.filter(documents=document).exists()

        return is_able

    def get_full_name(self):
        """
        Returns the first_name plus the last_name, with a space in between
        or username
        """
        if self.name:
            return self.name
        if self.first_name and self.last_name:
            full_name = '%s %s' % (self.first_name, self.last_name)
            return full_name.strip()
        return self.username

    def get_time_zone(self):
        return self.timezone or tzlocal.get_localzone()
示例#18
0
class Member(models.Model):
    mid = models.CharField(max_length=12)
    real_name = models.CharField(max_length=60)
    tz = TimeZoneField(default='Europe/London')
示例#19
0
class Group(BaseModel, LocationModel, ConversationMixin):
    name = models.CharField(max_length=settings.NAME_MAX_LENGTH, unique=True)
    description = models.TextField(blank=True)
    members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='groups', through='GroupMembership')
    password = models.CharField(max_length=255, blank=True)  # TODO remove soon
    public_description = models.TextField(blank=True)
    application_questions = models.TextField(blank=True)
    status = models.CharField(
        default=GroupStatus.ACTIVE.value,
        choices=[(status.value, status.value) for status in GroupStatus],
        max_length=100,
    )
    sent_summary_up_to = DateTimeField(null=True)
    timezone = TimeZoneField(default='Europe/Berlin', null=True, blank=True)
    active_agreement = models.OneToOneField(
        'groups.Agreement', related_name='active_group', null=True, on_delete=models.SET_NULL
    )
    last_active_at = DateTimeField(default=tz.now)
    is_open = models.BooleanField(default=False)

    def __str__(self):
        return 'Group {}'.format(self.name)

    def add_member(self, user, history_payload=None):
        membership = GroupMembership.objects.create(group=self, user=user)
        History.objects.create(
            typus=HistoryTypus.GROUP_JOIN, group=self, users=[
                user,
            ], payload=history_payload
        )
        return membership

    def remove_member(self, user):
        History.objects.create(
            typus=HistoryTypus.GROUP_LEAVE, group=self, users=[
                user,
            ]
        )
        GroupMembership.objects.filter(group=self, user=user).delete()

    def is_member(self, user):
        return not user.is_anonymous and GroupMembership.objects.filter(group=self, user=user).exists()

    def is_member_with_role(self, user, role_name):
        return not user.is_anonymous and GroupMembership.objects.filter(
            group=self, user=user, roles__contains=[role_name]
        ).exists()

    def is_playground(self):
        return self.status == GroupStatus.PLAYGROUND.value

    def accept_invite(self, user, invited_by, invited_at):
        self.add_member(
            user,
            history_payload={
                'invited_by': invited_by.id,
                'invited_at': invited_at.isoformat(),
                'invited_via': 'e-mail'
            }
        )

    def refresh_active_status(self):
        self.last_active_at = tz.now()
        if self.status == GroupStatus.INACTIVE.value:
            self.status = GroupStatus.ACTIVE.value
        self.save()

    def has_recent_activity(self):
        return self.last_active_at >= tz.now() - timedelta(days=settings.NUMBER_OF_DAYS_UNTIL_GROUP_INACTIVE)

    def get_application_questions_or_default(self):
        return self.application_questions or self.get_application_questions_default()

    def get_application_questions_default(self):
        return render_to_string('default_application_questions.nopreview.jinja2', {
            'group': self,
        })
示例#20
0
class Userdetail(models.Model):
    userid = models.CharField(max_length=10)
    real_name = models.CharField(max_length=20)
    tz = TimeZoneField(default='Europe/London')
示例#21
0
class GCCUser(AbstractUser, AddressableModel):
    @staticmethod
    def upload_seed(instance):
        return 'prologinuser/{}'.format(instance.pk).encode()

    # user have to be imported by the oauth client
    id = models.IntegerField(primary_key=True)

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    gender = GenderField(blank=True, null=True, db_index=True)

    school_stage = EnumField(
        EducationStage,
        null=True,
        db_index=True,
        blank=True,
        verbose_name=_("Educational stage"),
    )

    phone = models.CharField(max_length=16,
                             blank=True,
                             verbose_name=_("Phone"))

    birthday = models.DateField(blank=True,
                                null=True,
                                verbose_name=_("Birth day"))

    allow_mailing = models.BooleanField(
        default=True,
        blank=True,
        db_index=True,
        verbose_name=_("Allow Girls Can Code! to send me emails"),
        help_text=_(
            "We only mail you to provide useful information during the "
            "various stages of the contest. We hate spam as much as "
            "you do!"),
    )

    signature = models.TextField(blank=True, verbose_name=_("Signature"))

    timezone = TimeZoneField(default=settings.TIME_ZONE,
                             verbose_name=_("Time zone"))

    preferred_locale = models.CharField(
        max_length=8,
        blank=True,
        verbose_name=_("Locale"),
        choices=settings.LANGUAGES,
    )

    @cached_property
    def participations_count(self):
        applicants = Applicant.objects.filter(user=self)
        return sum((applicant.status == ApplicantStatusTypes.confirmed.value)
                   for applicant in applicants)

    @property
    def unsubscribe_token(self):
        user_id = str(self.id).encode()
        secret = settings.SECRET_KEY.encode()
        return hashlib.sha256(user_id + secret).hexdigest()

    def has_partial_address(self):
        return any((self.address, self.city, self.country, self.postal_code))

    def has_complete_address(self):
        return all((self.address, self.city, self.country, self.postal_code))

    def has_complete_profile(self):
        return self.has_complete_address() and all((
            self.first_name,
            self.last_name,
            self.email,
            self.gender,
            self.birthday,
            self.phone,
        ))

    def get_absolute_url(self):
        return reverse('users:profile', args=[self.pk])

    def get_unsubscribe_url(self):
        return '{}{}?uid={}&token={}'.format(
            settings.SITE_BASE_URL,
            reverse('users:unsubscribe'),
            self.id,
            self.unsubscribe_token,
        )
示例#22
0
class Site(PrimaryModel, StatusModel):
    """
    A Site represents a geographic location within a network; typically a building or campus. The optional facility
    field can be used to include an external designation, such as a data center name (e.g. Equinix SV6).
    """

    name = models.CharField(max_length=100, unique=True)
    _name = NaturalOrderingField(target_field="name",
                                 max_length=100,
                                 blank=True)
    slug = models.SlugField(max_length=100, unique=True)
    region = models.ForeignKey(
        to="dcim.Region",
        on_delete=models.SET_NULL,
        related_name="sites",
        blank=True,
        null=True,
    )
    tenant = models.ForeignKey(
        to="tenancy.Tenant",
        on_delete=models.PROTECT,
        related_name="sites",
        blank=True,
        null=True,
    )
    facility = models.CharField(max_length=50,
                                blank=True,
                                help_text="Local facility ID or description")
    asn = ASNField(
        blank=True,
        null=True,
        verbose_name="ASN",
        help_text="32-bit autonomous system number",
    )
    time_zone = TimeZoneField(blank=True)
    description = models.CharField(max_length=200, blank=True)
    physical_address = models.CharField(max_length=200, blank=True)
    shipping_address = models.CharField(max_length=200, blank=True)
    latitude = models.DecimalField(
        max_digits=8,
        decimal_places=6,
        blank=True,
        null=True,
        help_text="GPS coordinate (latitude)",
    )
    longitude = models.DecimalField(
        max_digits=9,
        decimal_places=6,
        blank=True,
        null=True,
        help_text="GPS coordinate (longitude)",
    )
    contact_name = models.CharField(max_length=50, blank=True)
    contact_phone = models.CharField(max_length=20, blank=True)
    contact_email = models.EmailField(blank=True,
                                      verbose_name="Contact E-mail")
    comments = models.TextField(blank=True)
    images = GenericRelation(to="extras.ImageAttachment")

    csv_headers = [
        "name",
        "slug",
        "status",
        "region",
        "tenant",
        "facility",
        "asn",
        "time_zone",
        "description",
        "physical_address",
        "shipping_address",
        "latitude",
        "longitude",
        "contact_name",
        "contact_phone",
        "contact_email",
        "comments",
    ]
    clone_fields = [
        "status",
        "region",
        "tenant",
        "facility",
        "asn",
        "time_zone",
        "description",
        "physical_address",
        "shipping_address",
        "latitude",
        "longitude",
        "contact_name",
        "contact_phone",
        "contact_email",
    ]

    class Meta:
        ordering = ("_name", )

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("dcim:site", args=[self.slug])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.get_status_display(),
            self.region.name if self.region else None,
            self.tenant.name if self.tenant else None,
            self.facility,
            self.asn,
            self.time_zone,
            self.description,
            self.physical_address,
            self.shipping_address,
            self.latitude,
            self.longitude,
            self.contact_name,
            self.contact_phone,
            self.contact_email,
            self.comments,
        )
 def test_some_positional_args_ok(self):
     TimeZoneField('a verbose name', 'a name', True)
示例#24
0
class LilyUser(TenantMixin, PermissionsMixin, AbstractBaseUser):
    """
    A custom user class implementing a fully featured User model with
    admin-compliant permissions.

    Password and email are required. Other fields are optional.
    """
    first_name = models.CharField(_('first name'), max_length=45)
    preposition = models.CharField(_('preposition'),
                                   max_length=100,
                                   blank=True)
    last_name = models.CharField(_('last name'), max_length=45)
    email = models.EmailField(_('email address'), max_length=255, unique=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_(
            'Designates whether the user can log into this admin site.'))
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=
        _('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'
          ))
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    lily_groups = models.ManyToManyField(
        LilyGroup,
        verbose_name=_('Lily groups'),
        blank=True,
        related_name='user_set',
        related_query_name='user',
    )

    phone_number = models.CharField(_('phone number'),
                                    max_length=40,
                                    blank=True)
    social_media = models.ManyToManyField(
        SocialMedia, blank=True, verbose_name=_('list of social media'))

    language = models.CharField(_('language'),
                                max_length=3,
                                choices=settings.LANGUAGES,
                                default='en')
    timezone = TimeZoneField(default='Europe/Amsterdam')

    primary_email_account = models.ForeignKey('email.EmailAccount',
                                              blank=True,
                                              null=True)

    objects = LilyUserManager()

    EMAIL_TEMPLATE_PARAMETERS = [
        'first_name', 'preposition', 'last_name', 'full_name', 'twitter',
        'linkedin', 'phone_number', 'current_email_address', 'user_group'
    ]

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = [
        'first_name',
        'last_name',
    ]

    def get_absolute_url(self):
        """
        Get the url to the user page
        """
        return reverse('dashboard')

    @property
    def full_name(self):
        return self.get_full_name()

    def get_full_name(self):
        """
        Return full name of this user without unnecessary white space.
        """
        if self.preposition:
            return u' '.join(
                [self.first_name, self.preposition, self.last_name]).strip()

        return u' '.join([self.first_name, self.last_name]).strip()

    def get_short_name(self):
        """
        Returns the short name for the user.
        """
        return self.first_name

    def email_user(self, subject, message, from_email=None):
        """
        Sends an email to this User.
        """
        send_mail(subject, message, from_email, [self.email])

    @property
    def twitter(self):
        try:
            twitter = self.social_media.filter(name='twitter').first()
        except SocialMedia.DoesNotExist:
            pass
        else:
            return twitter.username

    @property
    def linkedin(self):
        try:
            linkedin = self.social_media.filter(name='linkedin').first()
        except SocialMedia.DoesNotExist:
            pass
        else:
            return linkedin.profile_url

    @property
    def user_group(self):
        user_group = self.lily_groups.first()

        if not user_group:
            return ''

        return user_group

    def __unicode__(self):
        return self.get_full_name() or unicode(self.get_username())

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        ordering = ['first_name', 'last_name']
        permissions = (("send_invitation",
                        _("Can send invitations to invite new users")), )
class TimeZoneFieldDeconstructTestCase(TestCase):

    test_fields = (
        TimeZoneField(),
        TimeZoneField(default='UTC'),
        TimeZoneField(max_length=42),
        TimeZoneField(choices=[
            (pytz.timezone('US/Pacific'), 'US/Pacific'),
            (pytz.timezone('US/Eastern'), 'US/Eastern'),
        ]),
        TimeZoneField(choices=[
            (pytz.timezone(b'US/Pacific'), b'US/Pacific'),
            (pytz.timezone(b'US/Eastern'), b'US/Eastern'),
        ]),
        TimeZoneField(choices=[
            ('US/Pacific', 'US/Pacific'),
            ('US/Eastern', 'US/Eastern'),
        ]),
        TimeZoneField(choices=[
            (b'US/Pacific', b'US/Pacific'),
            (b'US/Eastern', b'US/Eastern'),
        ]),
    )

    def test_deconstruct(self):
        for org_field in self.test_fields:
            name, path, args, kwargs = org_field.deconstruct()
            new_field = TimeZoneField(*args, **kwargs)
            self.assertEqual(org_field.max_length, new_field.max_length)
            self.assertEqual(org_field.choices, new_field.choices)

    def test_full_serialization(self):
        # ensure the values passed to kwarg arguments can be serialized
        # the recommended 'deconstruct' testing by django docs doesn't cut it
        # https://docs.djangoproject.com/en/1.7/howto/custom-model-fields/#field-deconstruction
        # replicates https://github.com/mfogel/django-timezone-field/issues/12
        for field in self.test_fields:
            # ensuring the following call doesn't throw an error
            MigrationWriter.serialize(field)

    def test_from_db_value(self):
        """
        Verify that the field can handle data coming back as bytes from the
        db.
        """
        field = TimeZoneField()

        # django 1.11 signuature
        value = field.from_db_value(b'UTC', None, None, None)
        self.assertEqual(pytz.UTC, value)

        # django 2.0+ signuature
        value = field.from_db_value(b'UTC', None, None)
        self.assertEqual(pytz.UTC, value)

    def test_default_kwargs_not_frozen(self):
        """
        Ensure the deconstructed representation of the field does not contain
        kwargs if they match the default.
        Don't want to bloat everyone's migration files.
        """
        field = TimeZoneField()
        name, path, args, kwargs = field.deconstruct()
        self.assertNotIn('choices', kwargs)
        self.assertNotIn('max_length', kwargs)

    def test_specifying_defaults_not_frozen(self):
        """
        If someone's matched the default values with their kwarg args, we
        shouldn't bothering freezing those.
        """
        field = TimeZoneField(max_length=63)
        name, path, args, kwargs = field.deconstruct()
        self.assertNotIn('max_length', kwargs)

        choices = [(pytz.timezone(tz), tz.replace('_', ' '))
                   for tz in pytz.common_timezones]
        field = TimeZoneField(choices=choices)
        name, path, args, kwargs = field.deconstruct()
        self.assertNotIn('choices', kwargs)

        choices = [(tz, tz.replace('_', ' ')) for tz in pytz.common_timezones]
        field = TimeZoneField(choices=choices)
        name, path, args, kwargs = field.deconstruct()
        self.assertNotIn('choices', kwargs)
示例#26
0
class UserDetail(AbstractUser):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    tz = TimeZoneField()
 def test_invalid_choices_display(self):
     self.assertRaises(ValueError,
                       lambda: TimeZoneField(choices_display='invalid'))
示例#28
0
class Doctor(models.Model):
    MEDECINE_CHOICES = settings.MEDECINE_CHOICES
    TITLE_CHOICES = settings.TITLE_CHOICES

    phone_regex = RegexValidator(
        regex=r'^\+?1?\d{9,15}$',
        message="Phone number must be entered in the format: '+999999999'."
        " Up to 15 digits allowed.")

    title = models.IntegerField(verbose_name=_(u'Title'),
                                choices=TITLE_CHOICES)
    picture = models.ImageField(upload_to=settings.IMAGE_UPLOAD_PATH,
                                blank=True,
                                null=True)
    speciality = models.IntegerField(verbose_name=_(u'Speciality'),
                                     choices=MEDECINE_CHOICES)
    slug = models.SlugField(verbose_name=_(u'slug'), max_length=50, blank=True)

    vat_number = models.CharField(verbose_name=_(u'VAT number'),
                                  max_length=20,
                                  blank=True)
    telephone = models.CharField(verbose_name=_(u'Telephone'),
                                 validators=[phone_regex],
                                 help_text=_(u'format : +32475123456'),
                                 max_length=20,
                                 blank=True)
    address = AddressField()
    start_time = models.TimeField(verbose_name=_(u'Start time'),
                                  blank=False,
                                  default="09:00")
    end_time = models.TimeField(verbose_name=_(u'End time'),
                                blank=False,
                                default="18:00")
    colorslots = models.ManyToManyField(ColorSlot,
                                        verbose_name=_(u'ColorSlot'),
                                        blank=True)
    view_busy_slot = models.BooleanField(verbose_name=_(u'Can see busy slots'),
                                         default=True)
    view_in_list = models.BooleanField(
        verbose_name=_(u'Can see in doctors list'), default=True)
    weektemplate = models.ForeignKey(WeekTemplate,
                                     verbose_name=_(u'Week template'),
                                     blank=True,
                                     null=True)
    slots = models.ManyToManyField(Slot, verbose_name=_(u'Slots'), blank=True)
    confirm = models.TextField(verbose_name=_(u'Confirm key'),
                               blank=True,
                               null=True)
    text_rdv = models.TextField(verbose_name=_(u'Text RDV'),
                                blank=True,
                                null=True)
    text_horaires = models.TextField(verbose_name=_(u'Text horaires'),
                                     blank=True,
                                     null=True)
    timezone = TimeZoneField(default=settings.TIME_ZONE)
    invoices = models.ManyToManyField(Invoice,
                                      verbose_name=_(u'Invoices'),
                                      blank=True)
    can_recharge = models.BooleanField(
        verbose_name=_(u'Can recharge type of subscription '),
        blank=False,
        null=False,
        default=True)
    refer_userprofile = models.ForeignKey('users.UserProfile',
                                          verbose_name=_('UserProfile'),
                                          related_name='refer_userprofile',
                                          null=True,
                                          blank=True)

    def __str__(self):
        return u"%s " % self.slug

    def get_title(self):
        return u"%s" % self.TITLE_CHOICES[self.title - 1][1]

    def get_speciality(self):
        return u"%s" % self.MEDECINE_CHOICES[self.speciality - 1][1]

    def full_name(self):
        return u"%s %s" % (self.get_title(), self.real_name())

    def real_name(self):
        if self.refer_userprofile is not None:
            return u"%s %s" % (self.refer_userprofile.user.first_name,
                               self.refer_userprofile.user.last_name)
        else:
            return None

    def get_n_colorslots(self):
        return len(self.colorslots.all())

    def get_colorslot(self, i):
        ret = None
        if self.get_n_colorslots() > 0:
            for cs in self.colorslots.all():
                if cs.slot == i:
                    ret = cs
        if ret is None:
            ret = ColorSlot(slot=i, free_slot_color=settings.SLOT_COLOR[i - 1])
            ret.save()
            self.colorslots.add(ret)
            self.save()
        return ret

    def set_slug(self):
        if not self.slug:
            if self.refer_userprofile is not None:
                self.slug = slugify(self.real_name())

    def get_all_slottemplates(self):
        out = []
        if len(self.get_weektemplate().days.all()) > 0:
            for dt in self.get_weektemplate().days.all():
                for s in dt.slots.all():
                    out.append(s.as_json(dt.day, self))
        return out

    def remove_all_slottemplates(self):
        self.get_weektemplate().remove_all_slottemplates()

    def get_weektemplate(self):
        if not self.weektemplate:
            wk = WeekTemplate()
            wk.save()
            self.weektemplate = wk
            self.save()
        return self.weektemplate

    def get_daytemplate(self, i):
        return self.get_weektemplate().get_daytemplate(i)

    def get_color(self, i, booked):
        slot = self.get_colorslot(i)
        return str(slot.booked_slot_color) if booked else str(
            slot.free_slot_color)

    def get_active_invoice(self):
        if len(self.invoices.all()):
            for i in self.invoices.filter(active=True):
                if i.active:
                    return i
        else:
            return None

    def already_use_free_invoice(self):
        out = False
        if len(self.invoices.all()):
            for i in self.invoices.all():
                if i.price_exVAT == 0:
                    out = True
        return out

    def save(self, *args, **kwargs):
        super(Doctor, self).save(*args, **kwargs)
        adr = self.address.raw.replace(' ', '+')
        response = requests.get(
            'https://maps.googleapis.com/maps/api/geocode/json?address=%s' %
            adr)
        resp_json_payload = response.json()
        sol = resp_json_payload['results'][0]
        dic_address = {}
        for d in sol['address_components']:
            dic_address[d['types'][0]] = d
        country = Country.objects.filter(
            code=dic_address['country']['short_name'])
        if len(country):
            country = country[0]
        else:
            country = Country(code=dic_address['country']['short_name'],
                              name=dic_address['country']['long_name'])
            country.save()
        state = State.objects.filter(
            country=country,
            name=dic_address['administrative_area_level_1']['long_name'])
        if len(state):
            state = state[0]
        else:
            state = State(
                country=country,
                code=dic_address['administrative_area_level_1']['short_name'],
                name=dic_address['administrative_area_level_1']['long_name'])
            state.save()
        locality = Locality.objects.filter(
            state=state,
            postal_code=dic_address['postal_code']['long_name'],
            name=dic_address['locality']['long_name'])
        if len(locality):
            locality = locality[0]
        else:
            locality = Locality(
                state=state,
                postal_code=dic_address['postal_code']['long_name'],
                name=dic_address['locality']['long_name'])
            locality.save()
        self.address.locality = locality
        self.address.latitude = sol['geometry']['location']['lat']
        self.address.longitude = sol['geometry']['location']['lng']
        self.address.route = dic_address['route']['long_name']
        self.address.street_number = dic_address['street_number']['long_name']
        self.address.save()
        super(Doctor, self).save(*args, **kwargs)

    def as_json(self):
        return {
            'doctor': self.full_name(),
            'lat': self.address.latitude,
            'link': '/doc/%s/' % self.slug,
            'lng': self.address.longitude,
            'spec': self.get_speciality(),
            'locality': self.address.locality.name,
            'img': self.picture if self.picture else None
        }
示例#29
0
class Airport(models.Model):

    title = models.CharField(
        verbose_name='Long Name of Airport', max_length=50)
    timezone = TimeZoneField(default='US/Eastern')
    abrev = models.CharField(
        verbose_name='Airport Abreviation Code',
        max_length=4,
        primary_key=True)
    latitude = models.FloatField(
        validators=[MinValueValidator(-90), MaxValueValidator(90)])
    longitude = models.FloatField(
        validators=[MinValueValidator(-180), MaxValueValidator(180)])
    sw_airport = models.BooleanField(verbose_name='Southwest Airport')

    country = models.CharField(max_length=20, blank=True)
    state = models.CharField(max_length=20, blank=True)

    objects = AirportManager()

    sw_airport.admin_order_field = 'title'

    def __str__(self):
        # Return the title and abrev as the default string
        return self.title + " - " + self.abrev

    def _get_sub_loc(self, key):
        # Here we use geolocator to get the proper key
        geolocator = Nominatim()
        location = geolocator.reverse("{:f}, {:f}".format(
            self.latitude, self.longitude), timeout=10)

        # Lots and lots of error checking...looking for error from Geolocator
        # and for missing fields for international or other addresses

        if 'error' in location.raw:
            # Got an error back from geolocator
            raise ValidationError(_(
                "Geolocator error: %(error)s - Check you have the right Lat/Long or that you have connection"),
                params=location.raw, code='geolocator')

        # Got a response...but we may be missing keys...looking here
        try:
            return location.raw['address'][key]
        except KeyError as err:
            if err == 'address':
                raise ValidationError(
                    _('Got a response from Geolocator, but had no address'), code='no_address')
            elif err == key:
                raise ValidationError(_('Got a response from Geolocator, had an address, but didnt have key: %(key)s'), params={
                                      'key': err}, code='no_{}'.format(err))
            else:
                raise ValidationError(_('Got a response from Geolocator, had an address,KEY_ERROR of some kind %(raw)s'), params={
                                      'raw': location.raw}, code='some_key')
        except:
            raise ValidationError(
                _('Geolocator - NO CLUE WHAT WENT WRONG'), code='no_clue')

    def get_tz_obj(self):
        if isinstance(self.timezone, string_types):
            return pytz.timezone(self.timezone)
        else:
            return self.timezone

    def get_country_code(self):
        return self._get_sub_loc('country_code')

    def get_state(self):
        return self._get_sub_loc('state')

    def add_loc_fields(self):
        if (self.country is None) or (self.country == ''):
            self.country = self.get_country_code()
        if ((self.state is None) or (self.state == '')) and self.country == 'us':
            self.state = self.get_state()
示例#30
0
文件: models.py 项目: zhaoyul/xauto
class EventDate(TimestampedModel):
    """
    Django models in relation with Event Models (Event Date)
    Start / End Date  - Price/Cost / featured
    """
    event = models.ForeignKey('Event',
                              related_name='event_dates',
                              verbose_name='Your Event')
    location_name = models.CharField(max_length=250,
                                     default='',
                                     null=True,
                                     blank=True)
    latitude = models.FloatField(default=0.00)
    longitude = models.FloatField(default=0.00)
    address_1 = models.CharField(max_length=100,
                                 default='',
                                 null=True,
                                 blank=True)
    address_2 = models.CharField(max_length=100,
                                 default='',
                                 null=True,
                                 blank=True)
    country = CountryField(null=True, blank=True)
    city = models.CharField(max_length=100, null=True, blank=True)
    state = models.CharField(max_length=50, null=True, blank=True)
    region = models.CharField(max_length=50, null=True, blank=True)
    zipcode = models.CharField(max_length=20, null=True, blank=True)

    timezone = TimeZoneField(null=False, blank=False, default='UTC')
    start_date = models.DateTimeField(null=True, blank=False)
    end_date = models.DateTimeField(null=True, blank=True)
    feature_headline = models.CharField(max_length=100)
    feature_detail = models.TextField()
    currency = models.ForeignKey(Currency, null=True, blank=True)
    attend_free = models.BooleanField(default=False)
    exhibit_free = models.BooleanField(default=False)
    attend_price_from = models.FloatField(
        default=0.0,
        verbose_name='Attend Price US$ (From)')  # price range from (attend)
    attend_price_to = models.FloatField(
        default=0.0,
        verbose_name='Attend Price US$ (To)')  # price range from (attend)
    exhibit_price_from = models.FloatField(
        default=0.0,
        verbose_name='Exhibit Price US$ (From)')  # price range from (exhibit)
    exhibit_price_to = models.FloatField(
        default=0.0,
        verbose_name='Exhibit Price US$ (To)')  # price range from (exhibit)
    shared = models.ManyToManyField(UserProfile,
                                    null=True,
                                    blank=True,
                                    related_name='shared_dates')

    class Meta:
        ordering = ('-start_date', )

    def __unicode__(self):
        return u'{} - {}'.format(self.event.title.capitalize(),
                                 self.get_date_display())

    def normalize_time(self, time):
        tz = pytz.timezone(self.timezone.zone)
        return time.astimezone(tz)

    def get_date_display(self):
        tz_start_date = self.normalize_time(self.start_date)
        tz_end_date = self.normalize_time(self.end_date)

        if tz_start_date.date() == tz_end_date.date():
            date = get_time_display(tz_start_date)
        else:
            date = u"{} - {}".format(get_time_display(tz_start_date),
                                     get_time_display(tz_end_date))
        return date