Beispiel #1
0
class Media(models.Model):

    MEDIA_TYPES = Choices(
        (3, _('Books')),
        (4, _('Maps')),
        (8, _('Other documents')),
        (6, _('Photos')),
        (10, _('PR materials')),
        (9, _('Presentations')),
        (1, _('SLM questionnaires')),
        (2, _('Training materials')),
        (5, _('Videos')),
    )

    title = models.CharField(
        'Title',
        max_length=255,
        unique=True
    )
    abstract = models.TextField(
        'Abstract',
        blank=True
    )
    teaser_image = models.ForeignKey(
        'wagtailimages.Image',
        verbose_name='Teaser image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

    @property
    def image(self):
        return self.teaser_image or None

    video = models.URLField(
        verbose_name='Video',
        blank=True,
    )

    year = models.PositiveIntegerField(
        'Year',
        default=get_default_year_now,
        validators=[MaxValueValidator(4000)],
        blank=True, null=True
    )

    languages = models.ManyToManyField(
        verbose_name='Languages',
        to=Language,
        blank=True
    )

    content = StreamField(
        CORE_BLOCKS,
        blank=True,
    )
    file = models.ForeignKey(
        'wagtaildocs.Document',
        null=True, blank=True,
        on_delete=models.PROTECT,
        related_name='+',
        help_text='This field is only used if the content is empty.',
    )
    author = models.CharField(
        'Author',
        max_length=255,
        blank=True,
    )
    countries = models.ManyToManyField(
        verbose_name='Countries',
        to=Country,
        blank=True,
    )
    continent = models.ForeignKey(
        to=Continent,
        blank=True, null=True,
    )
    media_type = models.IntegerField(
        choices=MEDIA_TYPES, db_column='media_type_id')

    class Meta:
        verbose_name = 'Media'
        verbose_name_plural = 'Media'

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('media:detail', args=[self.id])

    panels = [
        FieldPanel('title'),
        FieldPanel('abstract'),
        FieldPanel('media_type'),
        FieldPanel('video'),
        DocumentChooserPanel('file'),
        ImageChooserPanel('teaser_image'),
        FieldPanel('author'),
        FieldPanel('countries'),
        FieldPanel('continent'),
        FieldPanel('year'),
        FieldPanel('languages'),
        StreamFieldPanel('content'),
    ]
Beispiel #2
0
class Problem(SoftDeletableModel, TimeStampedModel):
    STATUS_CHOICES = Choices(
        (0, 'draft', _('Draft')),
        (1, 'published', _('Published')),
    )

    LEVEL_CHOICES = Choices(
        (1, 'level1', _('Level 1')),
        (2, 'level2', _('Level 2')),
        (3, 'level3', _('Level 3')),
        (4, 'level4', _('Level 4')),
        (5, 'level5', _('Level 5')),
    )

    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        verbose_name=_('Author'),
        db_index=True,
        null=True,
        blank=True,
        editable=True,
        on_delete=models.SET_NULL,
        related_name='%(app_label)s_%(class)s_owned',
    )

    title = models.CharField(
        verbose_name=_('Problem title'),
        max_length=255,
    )

    content = models.TextField(verbose_name=_('Problem content'), )

    input_description = models.TextField(verbose_name=_('Input description'), )

    output_description = models.TextField(
        verbose_name=_('Output description'), )

    sample_input = models.TextField(verbose_name=_('Sample input data'), )

    sample_output = models.TextField(verbose_name=_('Sample output data'), )

    time_limit = models.IntegerField(
        verbose_name=_('Time limit'),
        help_text=_('Seconds'),
    )

    memory_limit = models.IntegerField(
        verbose_name=_('Memory limit'),
        help_text=_('MB'),
    )

    level = models.IntegerField(
        verbose_name=_('Level'),
        choices=LEVEL_CHOICES,
        default=LEVEL_CHOICES.level1,
        db_index=True,
    )

    category = TreeForeignKey(
        'quest.Category',
        verbose_name=_('Category'),
        null=True,
        blank=True,
        db_index=True,
        on_delete=models.SET_NULL,
    )

    status = models.IntegerField(
        verbose_name=_('Status'),
        choices=STATUS_CHOICES,
        default=STATUS_CHOICES.draft,
        db_index=True,
    )

    class Meta:
        verbose_name = _('Problem')
        verbose_name_plural = _('Problems')

    def __str__(self):
        return self.title
Beispiel #3
0
    # ("epilepsy", "Epilepsy"),
    # ("diabetes", "Diabetes"),
    # ("other_chronic_medical_condition", "Other Chronic Medical Condition"),
    # ("other_genetic_condition", "Other Genetic Condition"),
    # ("gifted_advanced_learning_needs", "Gifted/Advanced learning needs"),
    # ("adopted", "Adopted"),
    # ("has_older_sibling", "Has at least one older sibling"),
    # ("has_younger_sibling", "Has at least one younger sibling"),
)

# Keeping for now, though this will probably not be needed.
MULTIPLE_BIRTH_CHOICES = Choices(
    ("twin", _("Twin")),
    ("triplet", _("Triplet")),
    ("quadruplet", _("Quadruplet")),
    ("quintuplet", _("Quintuplet")),
    ("sextuplet", _("Sextuplet")),
    ("septuplet", _("Septuplet")),
    ("octuplet", _("Octuplet")),
)

# Ranked by # of speakers globally, except English is on top.
LANGUAGES = (
    ("en", "English"),
    ("am", "Amharic"),
    ("bn", "Bengali"),
    ("bho", "Bhojpuri"),
    ("my", "Burmese"),
    ("ceb", "Cebuano"),
    ("hne", "Chhattisgarhi"),
    ("nl", "Dutch"),
Beispiel #4
0
class Outreach(TimeStampedModel):

    EAV_TYPE = 'outreach'

    RESULT = Choices(('graduated', _('Graduated')), ('failed', _('Failed')))

    LANGUAGES = Choices(('english', _('English')), ('french', _('French')))

    YES_NO = Choices(('yes', _('Yes')), ('no', _('No')))

    student = models.ForeignKey(
        Student,
        blank=False,
        null=True,
        related_name='alp_enrollment',
    )
    partner = models.ForeignKey(
        PartnerOrganization,
        blank=True,
        null=True,
        related_name='+',
    )
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=False,
        null=True,
        related_name='+',
    )
    modified_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=True,
        null=True,
        related_name='modifications',
    )
    school = models.ForeignKey(
        School,
        blank=True,
        null=True,
        related_name='alp_school',
    )
    location = models.ForeignKey(
        Location,
        blank=True,
        null=True,
        related_name='+',
    )
    last_class_level = models.ForeignKey(
        ClassLevel,
        blank=True,
        null=True,
        related_name='+',
    )
    average_distance = models.CharField(max_length=10,
                                        blank=True,
                                        null=True,
                                        choices=Choices(
                                            u'<= 2.5km', u'> 2.5km',
                                            u'> 10km'))
    exam_year = models.CharField(max_length=4,
                                 blank=True,
                                 null=True,
                                 choices=((str(x), x)
                                          for x in range(1990, 2051)))
    exam_month = models.CharField(max_length=2,
                                  blank=True,
                                  null=True,
                                  choices=Person.MONTHS)
    exam_day = models.CharField(max_length=2,
                                blank=True,
                                null=True,
                                choices=((str(x), x) for x in range(1, 33)))
    alp_round = models.ForeignKey(
        ALPRound,
        blank=True,
        null=True,
        related_name='+',
    )
    section = models.ForeignKey(
        Section,
        blank=True,
        null=True,
        related_name='+',
        verbose_name='Current Section',
    )
    classroom = models.ForeignKey(ClassRoom,
                                  blank=True,
                                  null=True,
                                  related_name='+')
    alp_year = models.CharField(
        max_length=20,
        blank=True,
        null=True,
    )
    status = models.BooleanField(blank=True, default=True)
    enrolled_in_this_school = models.BooleanField(blank=True, default=True)
    not_enrolled_in_this_school = models.BooleanField(blank=True,
                                                      default=False)
    exam_not_exist_in_school = models.BooleanField(blank=True, default=False)
    registered_in_unhcr = models.CharField(max_length=50,
                                           blank=True,
                                           null=True,
                                           choices=YES_NO)
    last_education_level = models.ForeignKey(ClassRoom,
                                             blank=True,
                                             null=True,
                                             related_name='+')
    last_education_year = models.CharField(
        max_length=10,
        blank=True,
        null=True,
        choices=((str(x - 1) + '/' + str(x), str(x - 1) + '/' + str(x))
                 for x in range(2001, 2021)))
    last_year_result = models.CharField(max_length=50,
                                        blank=True,
                                        null=True,
                                        choices=RESULT)
    participated_in_alp = models.CharField(max_length=50,
                                           blank=True,
                                           null=True,
                                           choices=YES_NO)
    last_informal_edu_level = models.ForeignKey(
        EducationLevel,
        blank=True,
        null=True,
        related_name='+',
    )
    last_informal_edu_year = models.CharField(
        max_length=10,
        blank=True,
        null=True,
        choices=((str(x - 1) + '/' + str(x), str(x - 1) + '/' + str(x))
                 for x in range(2001, 2021)))
    last_informal_edu_result = models.CharField(max_length=50,
                                                blank=True,
                                                null=True,
                                                choices=RESULT)
    last_informal_edu_round = models.ForeignKey(
        ALPRound,
        blank=True,
        null=True,
        related_name='+',
    )
    last_informal_edu_final_result = models.ForeignKey(
        ClassLevel,
        blank=True,
        null=True,
        related_name='+',
    )
    exam_result_arabic = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    exam_result_language = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    exam_result_math = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    exam_result_science = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    exam_language = models.CharField(max_length=50,
                                     blank=True,
                                     null=True,
                                     choices=LANGUAGES)
    exam_corrector_arabic = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    exam_corrector_language = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    exam_corrector_math = models.IntegerField(blank=True,
                                              null=True,
                                              default=0,
                                              choices=((x, x)
                                                       for x in range(0, 101)))
    exam_corrector_science = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    registered_in_school = models.CharField(max_length=50,
                                            blank=True,
                                            null=True,
                                            choices=YES_NO)
    level = models.ForeignKey(
        EducationLevel,
        blank=True,
        null=True,
        related_name='+',
        verbose_name='Entrance Test (Pre-Test)',
    )
    registered_in_level = models.ForeignKey(
        EducationLevel,
        blank=True,
        null=True,
        related_name='+',
        verbose_name='Current level',
    )
    assigned_to_level = models.ForeignKey(
        EducationLevel,
        blank=True,
        null=True,
        related_name='+',
        verbose_name='Pre-test result',
    )
    exam_school = models.ForeignKey(
        School,
        blank=True,
        null=True,
        related_name='+',
    )
    deleted = models.BooleanField(blank=True, default=False)

    post_exam_result_arabic = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    post_exam_result_language = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    post_exam_result_math = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    post_exam_result_science = models.FloatField(
        blank=True,
        null=True,
        default=0,
    )
    post_exam_language = models.CharField(max_length=50,
                                          blank=True,
                                          null=True,
                                          choices=LANGUAGES)
    post_exam_corrector_arabic = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    post_exam_corrector_language = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    post_exam_corrector_math = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    post_exam_corrector_science = models.IntegerField(
        blank=True,
        null=True,
        default=0,
        choices=((x, x) for x in range(0, 101)))
    refer_to_level = models.ForeignKey(
        ClassLevel,
        blank=True,
        null=True,
        related_name='+',
        verbose_name='Post-test result',
    )
    dropout_status = models.BooleanField(blank=True, default=False)
    outreach_barcode = models.CharField(
        max_length=50,
        blank=True,
        null=True,
    )
    new_registry = models.CharField(max_length=50,
                                    blank=True,
                                    null=True,
                                    choices=Choices((1, _("Yes")),
                                                    (0, _("No"))))
    student_outreached = models.CharField(max_length=50,
                                          blank=True,
                                          null=True,
                                          choices=Choices((1, _("Yes")),
                                                          (0, _("No"))))
    have_barcode = models.CharField(max_length=50,
                                    blank=True,
                                    null=True,
                                    choices=Choices((1, _("Yes")),
                                                    (0, _("No"))))

    objects = OutreachManager()
    drop_objects = OutreachDropoutManager()

    class Meta:
        ordering = ['id']
        verbose_name = "All ALP data"

    @property
    def student_fullname(self):
        if self.student:
            return self.student.__unicode__()
        return ''

    @property
    def student_mother_fullname(self):
        if self.student:
            return self.student.mother_fullname
        return ''

    @property
    def exam_total(self):
        total = 0
        # if self.exam_result_arabic:
        #     total += self.exam_result_arabic
        if self.exam_result_language:
            total += self.exam_result_language
        if self.exam_result_math:
            total += self.exam_result_math
        if self.exam_result_science:
            total += self.exam_result_science
        return total

    @property
    def pretest_total(self):
        if self.level:
            return "{}/{}".format(self.exam_total, self.level.note)
        return 0

    @property
    def posttest_total(self):
        if self.level:
            return "{}/{}".format(self.post_exam_total, '80')
        return 0

    @property
    def next_level(self):
        if self.refer_to_level:
            return self.refer_to_level
        return ''

    @property
    def post_exam_total(self):
        total = 0
        if self.post_exam_result_arabic:
            total += self.post_exam_result_arabic
        if self.post_exam_result_language:
            total += self.post_exam_result_language
        if self.post_exam_result_math:
            total += self.post_exam_result_math
        if self.post_exam_result_science:
            total += self.post_exam_result_science
        return total

    @property
    def student_age(self):
        if self.student:
            return self.student.age
        return 0

    @property
    def student_sex(self):
        if self.student:
            return self.student.sex
        return ''

    @property
    def student_number(self):
        if self.student:
            return self.student.number
        return ''

    @property
    def student_nationality(self):
        if self.student:
            return self.student.nationality
        return ''

    def calculate_pre_result(self):
        self.assigned_to_level = assign_to_level(self.level, self.exam_total)

    def calculate_post_result(self):
        self.refer_to_level = refer_to_level(self.student_age,
                                             self.registered_in_level,
                                             self.post_exam_total)

    def __unicode__(self):
        if self.student:
            return self.student.__unicode__()
        return str(self.id)
class TicketFilter(django_filters.FilterSet):
    STATUS = Choices(
        'Open',
        'Close',
        'Pending',
    )
    SOURCE = Choices(
        'Call_in',
        'Call_out',
        'CUG',
        'Viber',
        'Skype',
        'Message',
    )

    username = django_filters.CharFilter(
        field_name='client_id',
        lookup_expr='icontains',
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': 'username'
        }),
    )

    branch = django_filters.ModelChoiceFilter(
        label='Client',
        field_name='branch_id',
        queryset=Branch.objects.all(),
        empty_label='Select Branch',
        widget=forms.Select(attrs={'class': 'form-control'}),
    )

    problem_domain = django_filters.ModelChoiceFilter(
        label='Problem Domain',
        field_name='problem_domain_id',
        queryset=ProblemDomain.objects.all(),
        empty_label='Select Problem Domain',
        widget=forms.Select(attrs={'class': 'form-control'}),
    )

    status = django_filters.ChoiceFilter(
        choices=STATUS,
        label='Status',
        empty_label='Select Status',
        widget=forms.Select(attrs={'class': 'form-control'}),
    )

    source = django_filters.ChoiceFilter(
        choices=SOURCE,
        label='Source',
        empty_label='Select Source',
        widget=forms.Select(attrs={'class': 'form-control'}),
    )

    date = django_filters.DateFilter(
        label='Date',
        field_name='issue_date',
        lookup_expr='icontains',
        widget=forms.DateInput(
            attrs={
                'class': 'form-control',
                'id': 'datepicker',
                'type': 'text',
                'placeholder': 'YYYY - MM - DD'
            }),
    )

    class Meta:
        model = Ticket
        fields = [
            'client_id', 'branch_id', 'problem_domain_id', 'status', 'source',
            'issue_date'
        ]
Beispiel #6
0
class StatusFieldChoicesName(models.Model):
    NAMED_STATUS = Choices((0, "no", "No"), (1, "yes", "Yes"))
    status = StatusField(choices_name='NAMED_STATUS')
Beispiel #7
0
class Monitor(models.Model):
    COUNTIES = Choices(*County.names)
    LOCATION = Choices('inside', 'outside')

    LAST_ACTIVE_LIMIT = 60 * 10
    PAYLOAD_SCHEMA = None
    SENSORS = ['']

    id = SmallUUIDField(
        default=uuid_default(),
        primary_key=True,
        db_index=True,
        editable=False,
        verbose_name='ID'
    )

    name = models.CharField(max_length=250)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)
    access_key = models.UUIDField(default=uuid.uuid4)

    is_hidden = models.BooleanField(default=False, help_text="Hides the monitor on the map.")
    is_sjvair = models.BooleanField(default=False, help_text="Is this monitor part of the SJVAir network?")

    # Where is this sensor setup?
    position = models.PointField(null=True, db_index=True)
    county = models.CharField(max_length=20, blank=True, choices=COUNTIES)
    location = models.CharField(max_length=10, choices=LOCATION)

    notes = models.TextField(blank=True, help_text="Notes for internal use.")

    latest = models.ForeignKey('monitors.Entry', blank=True, null=True, related_name='latest_for', on_delete=models.SET_NULL)
    default_sensor = models.CharField(max_length=50, default='', blank=True)

    pm25_calibration_formula = models.CharField(max_length=255, blank=True,
        default='', validators=[validate_formula])

    objects = InheritanceManager()

    class Meta:
        ordering = ('name',)

    def __str__(self):
        return self.name

    @classmethod
    def subclasses(cls):
        return cls.objects.get_queryset()._get_subclasses_recurse(cls)

    @property
    def device(self):
        return self.__class__.__name__

    @property
    def is_active(self):
        if not self.latest_id:
            return False
        now = timezone.now()
        cutoff = timedelta(seconds=self.LAST_ACTIVE_LIMIT)
        return (now - self.latest.timestamp) < cutoff

    def get_absolute_url(self):
        return f'/#/monitor/{self.pk}'

    def get_current_pm25_average(self, minutes):
        end_time = timezone.now()
        start_time = end_time - timedelta(minutes=minutes)
        queryset = self.entries.filter(
            timestamp__range=(start_time, end_time),
            sensor=self.default_sensor,
            pm25__isnull=False,
        )

        aggregate = queryset.aggregate(average=Avg('pm25'))
        return aggregate['average']

    def get_pm25_calibration_formula(self):
        # Check for a formula set on this specific monitor.
        if self.pm25_calibration_formula:
            return self.pm25_calibration_formula

        # Fallback to the formula for this kind of monitor in this county.
        try:
            return Calibration.objects.values_list('pm25_formula', flat=True).get(
                county=self.county,
                monitor_type=self._meta.model_name
            )
        except Calibration.DoesNotExist:
            # Default to an empty string
            return ''

    def create_entry(self, payload, sensor=None):
        return Entry(
            monitor=self,
            payload=payload,
            sensor=sensor or '',
            position=self.position,
            location=self.location,
            is_processed=False,
        )

    def process_entry(self, entry):
        entry.position = self.position
        entry.location = self.location
        entry.calibrate_pm25(self.get_pm25_calibration_formula())
        # entry.calculate_aqi()
        entry.calculate_averages()
        entry.is_processed = True
        return entry

    # TODO: rename to update_if_latest()
    def check_latest(self, entry):
        from camp.api.v1.monitors.serializers import EntrySerializer

        if self.latest_id:
            is_latest = make_aware(entry.timestamp) > self.latest.timestamp
        else:
            is_latest = True

        if entry.sensor == self.default_sensor and is_latest:
            self.latest = entry
            self.save() # TODO: Don't save here.

    def save(self, *args, **kwargs):
        if self.position:
            # TODO: Can we do this only when self.position is updated?
            self.county = County.lookup(self.position)
        super().save(*args, **kwargs)
Beispiel #8
0
import os
import uuid

from django.db import models
from django.urls import reverse

from model_utils import Choices
from model_utils.models import TimeStampedModel

from common import constants

CABIN_STATUS_CHOICES = Choices(('none', 'No cabins'),
                               ('mixed', 'Mixed cabins/camping'),
                               ('full', 'All cabins'))
ROUTE_POINT_CHOICES = Choices(('trailhead', 'Trailhead'),
                              ('peak', 'Top 100 peak'), ('cabin', 'Cabin'))
ITINERARY_REST_CHOICES = Choices(('cabin', 'Cabin'),
                                 ('campground', 'Campground'))


class Cabin(TimeStampedModel):
    name = models.CharField(max_length=255)
    name_zh = models.CharField(max_length=255,
                               verbose_name='Name (中文)',
                               help_text=("Cabin's Chinese name, i.e. 南湖山屋"))
    description = models.TextField(
        help_text=
        "A description of cabin amenities, water supply, and any special features. Approximately 250-300 characters"
    )
    capacity_beds = models.IntegerField(
        null=True, blank=True, help_text="Number of bed slots available")
Beispiel #9
0
"""
from django.contrib.auth.models import User
from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
from model_utils import Choices

from .api import add_course_goal, remove_course_goal
from course_modes.models import CourseMode
from student.models import CourseEnrollment

# Each goal is represented by a goal key and a string description.
GOAL_KEY_CHOICES = Choices(
    ('certify', _('Earn a certificate')),
    ('complete', _('Complete the course')),
    ('explore', _('Explore the course')),
    ('unsure', _('Not sure yet')),
)


class CourseGoal(models.Model):
    """
    Represents a course goal set by a user on the course home page.
    """
    user = models.ForeignKey(User, blank=False)
    course_key = CourseKeyField(max_length=255, db_index=True)
    goal_key = models.CharField(max_length=100,
                                choices=GOAL_KEY_CHOICES,
                                default=GOAL_KEY_CHOICES.unsure)

    def __unicode__(self):
Beispiel #10
0
class Protein(Authorable, StatusModel, TimeStampedModel):
    """ Protein class to store individual proteins, each with a unique AA sequence and name  """

    STATUS = Choices("pending", "approved", "hidden")

    MONOMER = "m"
    DIMER = "d"
    TANDEM_DIMER = "td"
    WEAK_DIMER = "wd"
    TETRAMER = "t"
    AGG_CHOICES = (
        (MONOMER, "Monomer"),
        (DIMER, "Dimer"),
        (TANDEM_DIMER, "Tandem dimer"),
        (WEAK_DIMER, "Weak dimer"),
        (TETRAMER, "Tetramer"),
    )

    BASIC = "b"
    PHOTOACTIVATABLE = "pa"
    PHOTOSWITCHABLE = "ps"
    PHOTOCONVERTIBLE = "pc"
    MULTIPHOTOCHROMIC = "mp"
    TIMER = "t"
    OTHER = "o"
    SWITCHING_CHOICES = (
        (BASIC, "Basic"),
        (PHOTOACTIVATABLE, "Photoactivatable"),
        (PHOTOSWITCHABLE, "Photoswitchable"),
        (PHOTOCONVERTIBLE, "Photoconvertible"),
        (MULTIPHOTOCHROMIC,
         "Multi-photochromic"),  # both convertible and switchable
        (OTHER, "Multistate"),
        (TIMER, "Timer"),
    )

    BILIRUBIN = "br"
    BILIVERDIN = "bv"
    FLAVIN = "fl"
    PHYCOCYANOBILIN = "pc"
    RIBITYL_LUMAZINE = "rl"
    COFACTOR_CHOICES = (
        (BILIRUBIN, "Bilirubin"),
        (BILIVERDIN, "Biliverdin"),
        (FLAVIN, "Flavin"),
        (PHYCOCYANOBILIN, "Phycocyanobilin"),
        (RIBITYL_LUMAZINE, "ribityl-lumazine"),
    )

    # Attributes
    # uuid        = models.UUIDField(default=uuid_lib.uuid4, editable=False, unique=True)  # for API
    uuid = models.CharField(
        max_length=5,
        default=prot_uuid,
        editable=False,
        unique=True,
        db_index=True,
        verbose_name="FPbase ID",
    )
    name = models.CharField(max_length=128,
                            help_text="Name of the fluorescent protein",
                            db_index=True)
    slug = models.SlugField(
        max_length=64, unique=True,
        help_text="URL slug for the protein")  # for generating urls
    base_name = models.CharField(
        max_length=128)  # easily searchable "family" name
    aliases = ArrayField(models.CharField(max_length=200),
                         blank=True,
                         null=True)
    chromophore = models.CharField(max_length=5, null=True, blank=True)
    seq_validated = models.BooleanField(
        default=False, help_text="Sequence has been validated by a moderator")
    # seq must be nullable because of uniqueness contraints
    seq = SequenceField(
        unique=True,
        blank=True,
        null=True,
        verbose_name="Sequence",
        help_text="Amino acid sequence (IPG ID is preferred)",
    )
    seq_comment = models.CharField(
        max_length=512,
        blank=True,
        help_text="if necessary, comment on source of sequence",
    )

    pdb = ArrayField(
        models.CharField(max_length=4),
        blank=True,
        null=True,
        verbose_name="Protein DataBank IDs",
    )
    genbank = models.CharField(
        max_length=12,
        null=True,
        blank=True,
        unique=True,
        verbose_name="Genbank Accession",
        help_text="NCBI Genbank Accession",
    )
    uniprot = models.CharField(
        max_length=10,
        null=True,
        blank=True,
        unique=True,
        verbose_name="UniProtKB Accession",
        validators=[validate_uniprot],
    )
    ipg_id = models.CharField(
        max_length=12,
        null=True,
        blank=True,
        unique=True,
        verbose_name="IPG ID",
        help_text="Identical Protein Group ID at Pubmed",
    )  # identical protein group uid
    mw = models.FloatField(null=True, blank=True,
                           help_text="Molecular Weight")  # molecular weight
    agg = models.CharField(
        max_length=2,
        choices=AGG_CHOICES,
        blank=True,
        verbose_name="Oligomerization",
        help_text="Oligomerization tendency",
    )
    oser = models.FloatField(null=True, blank=True,
                             help_text="OSER score")  # molecular weight
    switch_type = models.CharField(
        max_length=2,
        choices=SWITCHING_CHOICES,
        blank=True,
        default="b",
        verbose_name="Switching Type",
        help_text="Photoswitching type (basic if none)",
    )
    blurb = models.TextField(max_length=512,
                             blank=True,
                             help_text="Brief descriptive blurb")
    cofactor = models.CharField(
        max_length=2,
        choices=COFACTOR_CHOICES,
        blank=True,
        help_text="Required for fluorescence",
    )

    # Relations
    parent_organism = models.ForeignKey(
        "Organism",
        related_name="proteins",
        verbose_name="Parental organism",
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        help_text="Organism from which the protein was engineered",
    )
    primary_reference = models.ForeignKey(
        Reference,
        related_name="primary_proteins",
        verbose_name="Primary Reference",
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text="Preferably the publication that introduced the protein",
    )  # usually, the original paper that published the protein
    references = models.ManyToManyField(
        Reference, related_name="proteins",
        blank=True)  # all papers that reference the protein
    # FRET_partner = models.ManyToManyField('self', symmetrical=False, through='FRETpair', blank=True)
    default_state = models.ForeignKey(
        "State",
        related_name="default_for",
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )

    # __original_ipg_id = None

    # managers
    objects = ProteinManager()
    visible = QueryManager(~Q(status="hidden"))

    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     # store IPG_ID so that we know if it changes
    #     self.__original_ipg_id = self.ipg_id

    def mutations_from_root(self):
        try:
            root = self.lineage.get_root()
            if root.protein.seq and self.seq:
                muts = root.protein.seq.mutations_to(self.seq)
                return muts
        except ObjectDoesNotExist:
            return None

    @property
    def mless(self):
        return mless(self.name)

    @property
    def description(self):
        return util.long_blurb(self)

    @property
    def _base_name(self):
        '''return core name of protein, stripping prefixes like "m" or "Tag"'''
        return get_base_name(self.name)

    @property
    def versions(self):
        return Version.objects.get_for_object(self)

    def last_approved_version(self):
        if self.status == "approved":
            return self
        try:
            return (Version.objects.get_for_object(self).filter(
                serialized_data__contains='"status": "approved"').first())
        except Exception:
            return None

    @property
    def additional_references(self):
        return self.references.exclude(
            id=self.primary_reference_id).order_by("-year")

    @property
    def em_css(self):
        if self.states.count() > 1:
            from collections import OrderedDict

            stops = OrderedDict({st.emhex: "" for st in self.states.all()})
            bgs = []
            stepsize = int(100 / (len(stops) + 1))
            sub = 0
            for i, _hex in enumerate(stops):
                if _hex == "#000":
                    sub = 18
                bgs.append("{} {}%".format(_hex, (i + 1) * stepsize - sub))
            return "linear-gradient(90deg, {})".format(", ".join(bgs))
        elif self.default_state:
            return self.default_state.emhex
        else:
            return "repeating-linear-gradient(-45deg,#333,#333 8px,#444 8px,#444 16px);"

    @property
    def em_svg(self):
        if self.states.count() > 1:
            stops = [st.emhex for st in self.states.all()]
            stepsize = int(100 / (len(stops) + 1))
            svgdef = "linear:"
            for i, color in enumerate(stops):
                perc = (i + 1) * stepsize
                if color == "#000":
                    perc *= 0.2
                svgdef += '<stop offset="{}%" style="stop-color:{};" />'.format(
                    perc, color)
            return svgdef
        if self.default_state:
            return self.default_state.emhex
        return "?"

    @property
    def color(self):
        try:
            return get_color_group(self.default_state.ex_max,
                                   self.default_state.em_max)[0]
        except Exception:
            return ""

    # Methods
    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("proteins:protein-detail", args=[self.slug])

    def has_default(self):
        return bool(self.default_state)

    def mutations_to(self, other, **kwargs):
        if isinstance(other, Protein):
            other = other.seq
        if not (self.seq and other):
            return None
        return self.seq.mutations_to(other, **kwargs)

    def mutations_from(self, other, **kwargs):
        if isinstance(other, Protein):
            other = other.seq
        if not (self.seq and other):
            return None
        return other.seq.mutations_to(self.seq, **kwargs)

    def has_spectra(self):
        for state in self.states.all():
            if state.has_spectra():
                return True
        return False

    def has_bleach_measurements(self):
        return self.states.filter(bleach_measurements__isnull=False).exists()

    def d3_spectra(self):
        spectra = []
        for state in self.states.all():
            spectra.extend(state.d3_dicts())
        return json.dumps(spectra)

    def spectra_img(self, fmt="svg", output=None, **kwargs):
        spectra = list(
            Spectrum.objects.filter(owner_state__protein=self).exclude(
                subtype="2p"))
        title = self.name if kwargs.pop("title", False) else None
        if kwargs.get("twitter", False):
            title = self.name
        info = ""
        if self.default_state:
            info += "Ex/Em λ: {}/{}".format(self.default_state.ex_max,
                                            self.default_state.em_max)
            info += "\nEC: {}   QY: {}".format(self.default_state.ext_coeff,
                                               self.default_state.qy)
        return spectra_fig(spectra,
                           fmt,
                           output,
                           title=title,
                           info=info,
                           **kwargs)

    def set_default_state(self):
        # FIXME: should allow control of default states in form
        # if only 1 state, make it the default state
        if not self.default_state or self.default_state.is_dark:
            if self.states.count() == 1 and not self.states.first().is_dark:
                self.default_state = self.states.first()
            # otherwise use farthest red non-dark state
            elif self.states.count() > 1:
                self.default_state = (self.states.exclude(
                    is_dark=True).order_by("-em_max").first())

    def clean(self):
        errors = {}
        # Don't allow basic switch_types to have more than one state.
        #        if self.switch_type == 'b' and self.states.count() > 1:
        #            errors.update({'switch_type': 'Basic (non photoconvertible) proteins '
        #                                          'cannot have more than one state.'})
        if self.pdb:
            self.pdb = list(set(self.pdb))
            for item in self.pdb:
                if (Protein.objects.exclude(id=self.id).filter(
                        pdb__contains=[item]).exists()):
                    p = Protein.objects.filter(pdb__contains=[item]).first()
                    errors.update({
                        "pdb":
                        "PDB ID {} is already in use by protein {}".format(
                            item, p.name)
                    })

        if errors:
            raise ValidationError(errors)

    def save(self, *args, **kwargs):

        # if the IPG ID has changed... refetch the sequence
        # if self.ipg_id != self.__original_ipg_id:
        #    s = fetch_ipg_sequence(uid=self.ipg_id)
        #    self.seq = s[1] if s else None

        self.slug = slugify(self.name)
        self.base_name = self._base_name
        self.set_default_state()

        super().save(*args, **kwargs)
        # self.__original_ipg_id = self.ipg_id

    # Meta
    class Meta:
        ordering = ["name"]

    def history(self, ignoreKeys=[]):
        from proteins.util.history import get_history

        return get_history(self, ignoreKeys)

    # ##################################
    # for algolia index

    def is_visible(self):
        return self.status != "hidden"

    def img_url(self):
        if self.has_spectra():
            return ("https://www.fpbase.org" +
                    reverse("proteins:spectra-img", args=[self.slug]) +
                    ".png?xlabels=0&xlim=400,800")
        else:
            return None

    def tags(self):
        tags = [
            self.get_switch_type_display(),
            self.get_agg_display(), self.color
        ]
        return [i for i in tags if i]

    def date_published(self, norm=False):
        d = None
        if self.primary_reference:
            d = self.primary_reference.date
        if norm:
            return (d.year - 1992) / (datetime.datetime.now().year -
                                      1992) if d else 0
        return datetime.datetime.combine(
            d, datetime.datetime.min.time()) if d else None

    def n_faves(self, norm=False):
        nf = (Favorite.objects.for_model(Protein).filter(
            target_object_id=self.id).count())
        if norm:
            from collections import Counter

            mx = Counter(
                Favorite.objects.for_model(Protein).values_list(
                    "target_object_id", flat=True)).most_common(1)
            if mx:
                mx = mx[0][1]
            else:
                mx = 1
            return nf / mx
        return nf

    def n_cols(self):
        return ProteinCollection.objects.filter(proteins=self.id).count()

    def ga_views(self, period="month", norm=False):
        from proteins.extrest.ga import cached_ga_popular

        hits = cached_ga_popular()[period]
        for slug, name, rating in hits:
            if slug == self.slug:
                return rating / max(list(zip(*hits))[2]) if norm else rating
        return 0

    def switchType(self):
        return self.get_switch_type_display()

    def _agg(self):
        return self.get_agg_display()

    def url(self):
        return self.get_absolute_url()

    def ex(self):
        if not self.states.exists():
            return None
        ex = [s.ex_max for s in self.states.all()]
        return ex[0] if len(ex) == 1 else ex

    def em(self):
        if not self.states.exists():
            return None
        em = [s.em_max for s in self.states.all()]
        return em[0] if len(em) == 1 else em

    def pka(self):
        if not self.states.exists():
            return None
        n = [s.pka for s in self.states.all()]
        return n[0] if len(n) == 1 else n

    def ec(self):
        if not self.states.exists():
            return None
        n = [s.ext_coeff for s in self.states.all()]
        return n[0] if len(n) == 1 else n

    def qy(self):
        if not self.states.exists():
            return None
        n = [s.qy for s in self.states.all()]
        return n[0] if len(n) == 1 else n

    def rank(self):
        # max rank is 1
        return (0.5 * self.date_published(norm=True) + 0.6 *
                self.ga_views(norm=True) + 1.0 * self.n_faves(norm=True)) / 2.5

    def local_brightness(self):
        if self.states.exists():
            return max([s.local_brightness for s in self.states.all()])

    def first_author(self):
        if self.primary_reference and self.primary_reference.first_author:
            return self.primary_reference.first_author.family
Beispiel #11
0
class Shirt(models.Model):
    related_fields = ["collection", "fabric", "size_option", "size", "hem", "placket", "pocket", "back",
                      "custom_buttons_type", "custom_buttons", "shawl", "yoke"]

    CLASP_OPTIONS = Choices((False, _(u'Не использовать застежку')), (True, _(u'Использовать застежку')))

    is_template = models.BooleanField(_(u'Используется как шаблон'), default=False)
    is_standard = models.BooleanField(_(u'Используется как стандартный вариант'), default=False, editable=False)
    collection = models.ForeignKey(Collection, verbose_name=_(u'Коллекция'), related_name='shirts', null=True)
    code = models.CharField(_(u'Артикул'), max_length=255, null=True)
    individualization = models.TextField(_(u'Индивидуализация'), null=True, blank=True)

    fabric = models.ForeignKey(Fabric, verbose_name=_(u'Ткань'), null=True)

    showcase_image = models.ImageField(_(u'Изображение для витрины'), blank=False, null=True, upload_to='showcase')
    showcase_image_list = ImageSpecField(source='showcase_image',
                                         processors=[ResizeToFill(*settings.SHOWCASE_IMAGE_SIZE)],
                                         format='JPEG',
                                         options={'quality': 100})

    showcase_image_detail = ImageSpecField(source='showcase_image',
                                           processors=[ResizeToFill(*settings.SHOWCASE_DETAILS_IMAGE_SIZE)],
                                           format='JPEG',
                                           options={'quality': 100})

    size_option = models.ForeignKey('dictionaries.SizeOptions', verbose_name=_(u'Выбранный вариант размера'))
    size = models.ForeignKey('dictionaries.Size', verbose_name=_(u'Размер'), blank=True, null=True)

    hem = models.ForeignKey('dictionaries.HemType', verbose_name=_(u'Низ'), related_name='hem_shirts')
    placket = models.ForeignKey('dictionaries.PlacketType', verbose_name=_(u'Полочка'), related_name='placket_shirts')
    pocket = models.ForeignKey('dictionaries.PocketType', verbose_name=_(u'Карман'), related_name='pocket_shirts')
    sleeve = models.ForeignKey('dictionaries.SleeveType', verbose_name=_(u'Рукав'), related_name='sleeve_shirts',
                               default=ResolveDefault(SleeveType))
    fit = ChainedForeignKey(Fit, verbose_name=_(u'Талия'), chained_field='collection',
                            chained_model_field='collections', show_all=False, blank=True, null=True)

    tuck = ChainedForeignKey('dictionaries.TuckType', verbose_name=_(u'Вытачки'), chained_field='collection',
                             chained_model_field='collections', show_all=False)

    back = models.ForeignKey('dictionaries.BackType', verbose_name=_(u'Спинка'), related_name='back_shirts')

    custom_buttons_type = models.ForeignKey('dictionaries.CustomButtonsType', verbose_name=_(u'Тип кастомных пуговиц'),
                                            null=True, blank=True, related_name='back_shirts')
    custom_buttons = ChainedForeignKey(CustomButtons, verbose_name=_(u'Кастомные пуговицы'),
                                       chained_field='custom_buttons_type',
                                       chained_model_field='type', show_all=False, null=True, blank=True)

    shawl = models.ForeignKey(ShawlOptions, verbose_name=_(u'Платок'), null=True, related_name='shirts',
                              default=ResolveDefault(ShawlOptions))
    yoke = models.ForeignKey('dictionaries.YokeType', verbose_name=_(u'Кокетка'), null=True)
    clasp = models.BooleanField(_(u'Застежка под штифты'), choices=CLASP_OPTIONS, default=False)

    STITCH = Choices(('none', _(u'0 мм (без отстрочки)')), ('1mm', _(u'1 мм (только со съемными косточками)')),
                     ('5mm', _(u'5 мм')))
    stitch = models.CharField(_(u'Ширина отстрочки'), max_length=10, choices=STITCH)

    price = models.DecimalField(_(u'Цена'), max_digits=10, decimal_places=2, editable=False, null=True)

    def save(self, *args, **kwargs):
        cuff = getattr(self, 'cuff', None)
        if cuff and not self.sleeve.cuffs:
            if cuff.id:
                cuff.delete()

        super(Shirt, self).save(*args, **kwargs)

    class Meta:
        ordering = ('code',)
        verbose_name = _(u'Сорочка')
        verbose_name_plural = _(u'Сорочки')

    def __unicode__(self):
        return self.code if self.code else self.id
Beispiel #12
0
class AssessmentWorkflow(TimeStampedModel, StatusModel):
    """Tracks the open-ended assessment status of a student submission.

    It's important to note that although we track the status as an explicit
    field here, it is not the canonical status. This is because the
    determination of what we need to do in order to be "done" is specified by
    the OpenAssessmentBlock problem definition and can change. So every time
    we are asked where the student is, we have to query the peer, self, and
    later other assessment APIs with the latest requirements (e.g. "number of
    submissions you have to assess = 5"). The "status" field on this model is
    an after the fact recording of the last known state of that information so
    we can search easily.
    """
    STEPS = ASSESSMENT_API_DICT.keys()

    STATUSES = [
        "waiting",  # User has done all necessary assessment but hasn't been
                    # graded yet -- we're waiting for assessments of their
                    # submission by others.
        "done",  # Complete
        "cancelled"  # User submission has been cancelled.
    ]

    STATUS_VALUES = STEPS + STATUSES

    STATUS = Choices(*STATUS_VALUES)  # implicit "status" field

    # For now, we use a simple scoring mechanism:
    # Once a student has completed all assessments,
    # we search assessment APIs
    # in priority order until one of the APIs provides a score.
    # We then use that score as the student's overall score.
    # This Django setting is a list of assessment steps (defined in `settings.ORA2_ASSESSMENTS`)
    # in descending priority order.
    DEFAULT_ASSESSMENT_SCORE_PRIORITY = ['peer', 'self']
    ASSESSMENT_SCORE_PRIORITY = getattr(
        settings, 'ORA2_ASSESSMENT_SCORE_PRIORITY',
        DEFAULT_ASSESSMENT_SCORE_PRIORITY
    )

    STAFF_ANNOTATION_TYPE = "staff_defined"

    submission_uuid = models.CharField(max_length=36, db_index=True, unique=True)
    uuid = models.UUIDField(db_index=True, unique=True, default=uuid4)

    # These values are used to find workflows for a particular item
    # in a course without needing to look up the submissions for that item.
    # Because submissions are immutable, we can safely duplicate the values
    # here without violating data integrity.
    course_id = models.CharField(max_length=255, blank=False, db_index=True)
    item_id = models.CharField(max_length=255, blank=False, db_index=True)

    class Meta:
        ordering = ["-created"]
        # TODO: In migration, need a non-unique index on (course_id, item_id, status)
        app_label = "workflow"

    def __init__(self, *args, **kwargs):
        super(AssessmentWorkflow, self).__init__(*args, **kwargs)
        if 'staff' not in AssessmentWorkflow.STEPS:
            new_list = ['staff']
            new_list.extend(AssessmentWorkflow.STEPS)
            AssessmentWorkflow.STEPS = new_list
            AssessmentWorkflow.STATUS_VALUES = AssessmentWorkflow.STEPS + AssessmentWorkflow.STATUSES
            AssessmentWorkflow.STATUS = Choices(*AssessmentWorkflow.STATUS_VALUES)

        if 'staff' not in AssessmentWorkflow.ASSESSMENT_SCORE_PRIORITY:
            new_list = ['staff']
            new_list.extend(AssessmentWorkflow.ASSESSMENT_SCORE_PRIORITY)
            AssessmentWorkflow.ASSESSMENT_SCORE_PRIORITY = new_list

    @classmethod
    @transaction.atomic
    def start_workflow(cls, submission_uuid, step_names, on_init_params):
        """
        Start a new workflow.

        Args:
            submission_uuid (str): The UUID of the submission associated with this workflow.
            step_names (list): The names of the assessment steps in the workflow.
            on_init_params (dict): The parameters to pass to each assessment module
                on init.  Keys are the assessment step names.

        Returns:
            AssessmentWorkflow

        Raises:
            SubmissionNotFoundError
            SubmissionRequestError
            SubmissionInternalError
            DatabaseError
            Assessment-module specific errors
        """
        submission_dict = sub_api.get_submission_and_student(submission_uuid)

        staff_auto_added = False
        if 'staff' not in step_names:
            staff_auto_added = True
            new_list = ['staff']
            new_list.extend(step_names)
            step_names = new_list

        # Create the workflow and step models in the database
        # For now, set the status to waiting; we'll modify it later
        # based on the first step in the workflow.
        workflow = cls.objects.create(
            submission_uuid=submission_uuid,
            status=AssessmentWorkflow.STATUS.waiting,
            course_id=submission_dict['student_item']['course_id'],
            item_id=submission_dict['student_item']['item_id']
        )
        workflow_steps = [
            AssessmentWorkflowStep.objects.create(
                workflow=workflow, name=step, order_num=i
            )
            for i, step in enumerate(step_names)
        ]
        workflow.steps.add(*workflow_steps)

        # Initialize the assessment APIs
        has_started_first_step = False
        for step in workflow_steps:
            api = step.api()

            if api is not None:
                # Initialize the assessment module
                # We do this for every assessment module
                on_init_func = getattr(api, 'on_init', lambda submission_uuid, **params: None)
                on_init_func(submission_uuid, **on_init_params.get(step.name, {}))

                # If we auto-added a staff step, it is optional and should be marked complete immediately
                if step.name == "staff" and staff_auto_added:
                    step.assessment_completed_at = now()
                    step.save()

                # For the first valid step, update the workflow status
                # and notify the assessment module that it's being started
                if not has_started_first_step:
                    # Update the workflow
                    workflow.status = step.name
                    workflow.save()

                    # Notify the assessment module that it's being started
                    on_start_func = getattr(api, 'on_start', lambda submission_uuid: None)
                    on_start_func(submission_uuid)

                    # Remember that we've already started the first step
                    has_started_first_step = True

        # Update the workflow (in case some of the assessment modules are automatically complete)
        # We do NOT pass in requirements, on the assumption that any assessment module
        # that accepts requirements would NOT automatically complete.
        workflow.update_from_assessments(None)

        # Return the newly created workflow
        return workflow

    @property
    def score(self):
        """Latest score for the submission we're tracking.

        Returns:
            score (dict): The latest score for this workflow, or None if the workflow is incomplete.
        """
        score = None
        if self.status == self.STATUS.done:
            score = sub_api.get_latest_score_for_submission(self.submission_uuid)
        return score

    def status_details(self):
        """
        Returns workflow status in the form of a dictionary. Each step in the
        workflow is a key, and each key maps to a dictionary defining whether
        the step is complete (submitter requirements fulfilled) and graded (the
        submission has been assessed).
        """
        status_dict = {}
        steps = self._get_steps()
        for step in steps:
            status_dict[step.name] = {
                "complete": step.is_submitter_complete(),
                "graded": step.is_assessment_complete(),
            }
        return status_dict

    def get_score(self, assessment_requirements, step_for_name):
        """Iterate through the assessment APIs in priority order
         and return the first reported score.

        Args:
            assessment_requirements (dict): Dictionary passed to the assessment API.
                This defines the requirements for each assessment step; the APIs
                can refer to this to decide whether the requirements have been
                met.  Note that the requirements could change if the author
                updates the problem definition.
            step_for_name (dict): a key value pair for step name: step

        Returns:
             score dict.
        """
        score = None
        for assessment_step_name in self.ASSESSMENT_SCORE_PRIORITY:

            # Check if the problem contains this assessment type
            assessment_step = step_for_name.get(assessment_step_name)

            # Query the corresponding assessment API for a score
            # If we find one, then stop looking
            if assessment_step is not None:

                # Check if the assessment API defines a score function at all
                get_score_func = getattr(assessment_step.api(), 'get_score', None)
                if get_score_func is not None:
                    if assessment_requirements is None:
                        step_requirements = None
                    else:
                        step_requirements = assessment_requirements.get(assessment_step_name, {})
                    score = get_score_func(self.submission_uuid, step_requirements)
                    if assessment_step_name == self.STATUS.staff and score == None:
                        if step_requirements and step_requirements.get('required', False):
                            break # A staff score was not found, and one is required. Return None
                        continue # A staff score was not found, but it is not required, so try the next type of score
                    break

        return score

    def update_from_assessments(self, assessment_requirements, override_submitter_requirements=False):
        """Query assessment APIs and change our status if appropriate.

        If the status is done, we do nothing. Once something is done, we never
        move back to any other status.

        If an assessment API says that our submitter's requirements are met,
        then move to the next assessment.  For example, in peer assessment,
        if the submitter we're tracking has assessed the required number
        of submissions, they're allowed to continue.

        If the submitter has finished all the assessments, then we change
        their status to `waiting`.

        If we're in the `waiting` status, and an assessment API says it can score
        this submission, then we record the score in the submissions API and move our
        `status` to `done`.

        By convention, if `assessment_requirements` is `None`, then assessment
        modules that need requirements should automatically say that they're incomplete.
        This allows us to update the workflow even when we don't know the
        current state of the problem.  For example, if we're updating the workflow
        at the completion of an asynchronous call, we won't necessarily know the
        current state of the problem, but we would still want to update assessments
        that don't have any requirements.

        Args:
            assessment_requirements (dict): Dictionary passed to the assessment API.
                This defines the requirements for each assessment step; the APIs
                can refer to this to decide whether the requirements have been
                met.  Note that the requirements could change if the author
                updates the problem definition.
            override_submitter_requirements (bool): If True, the presence of a new
                staff score will cause all of the submitter's requirements to be
                fulfilled, moving the workflow to DONE and exposing their grade.

        """
        if self.status == self.STATUS.cancelled:
            return

        # Update our AssessmentWorkflowStep models with the latest from our APIs
        steps = self._get_steps()

        step_for_name = {step.name: step for step in steps}

        new_staff_score = self.get_score(assessment_requirements, {'staff': step_for_name.get('staff', None)})
        if new_staff_score:
            # new_staff_score is just the most recent staff score, it may already be recorded in sub_api
            old_score = sub_api.get_latest_score_for_submission(self.submission_uuid)
            if (
                    # Does a prior score exist? Is it a staff score? Do the points earned match?
                    not old_score or
                    not self.STAFF_ANNOTATION_TYPE in [
                        annotation['annotation_type'] for annotation in old_score['annotations']
                    ] or
                    old_score['points_earned'] != new_staff_score['points_earned']
            ):
                # Set the staff score using submissions api, and log that fact
                self.set_staff_score(new_staff_score)
                self.save()
                logger.info((
                    u"Workflow for submission UUID {uuid} has updated score using staff assessment."
                ).format(uuid=self.submission_uuid))

                # Update the assessment_completed_at field for all steps
                # All steps are considered "assessment complete", as the staff score will override all
                for step in steps:
                    common_now = now()
                    step.assessment_completed_at = common_now
                    if override_submitter_requirements:
                        step.submitter_completed_at = common_now
                    step.save()

        if self.status == self.STATUS.done:
            return

        # Go through each step and update its status.
        for step in steps:
            step.update(self.submission_uuid, assessment_requirements)

        # Fetch name of the first step that the submitter hasn't yet completed.
        new_status = next(
            (step.name for step in steps if step.submitter_completed_at is None),
            self.STATUS.waiting  # if nothing's left to complete, we're waiting
        )

        # If the submitter is beginning the next assessment, notify the
        # appropriate assessment API.
        new_step = step_for_name.get(new_status)
        if new_step is not None:
            on_start_func = getattr(new_step.api(), 'on_start', None)
            if on_start_func is not None:
                on_start_func(self.submission_uuid)

        # If the submitter has done all they need to do, let's check to see if
        # all steps have been fully assessed (i.e. we can score it).
        if (
                new_status == self.STATUS.waiting and
                all(step.assessment_completed_at for step in steps)
        ):

            score = self.get_score(assessment_requirements, step_for_name)
            # If we found a score, then we're done
            if score is not None:
                # Only set the score if it's not a staff score, in which case it will have already been set above
                if score.get("staff_id") is None:
                    self.set_score(score)
                new_status = self.STATUS.done

        # Finally save our changes if the status has changed
        if self.status != new_status:
            self.status = new_status
            self.save()
            logger.info((
                u"Workflow for submission UUID {uuid} has updated status to {status}"
            ).format(uuid=self.submission_uuid, status=new_status))

    def _get_steps(self):
        """
        Simple helper function for retrieving all the steps in the given
        Workflow.
        """
        # A staff step must always be available, to allow for staff overrides
        try:
            self.steps.get(name=self.STATUS.staff)
        except AssessmentWorkflowStep.DoesNotExist:
            for step in list(self.steps.all()):
                step.order_num += 1
            staff_step, _ = AssessmentWorkflowStep.objects.get_or_create(
                name=self.STATUS.staff,
                order_num=0,
                assessment_completed_at=now(),
                workflow=self,
            )
            self.steps.add(
                staff_step
            )

        # Do not return steps that are not recognized in the AssessmentWorkflow.
        steps = list(self.steps.filter(name__in=AssessmentWorkflow.STEPS))
        if not steps:
            # If no steps exist for this AssessmentWorkflow, assume
            # peer -> self for backwards compatibility, with an optional staff override
            self.steps.add(
                AssessmentWorkflowStep(name=self.STATUS.staff, order_num=0, assessment_completed_at=now()),
                AssessmentWorkflowStep(name=self.STATUS.peer, order_num=1),
                AssessmentWorkflowStep(name=self.STATUS.self, order_num=2)
            )
            steps = list(self.steps.all())

        return steps

    def set_staff_score(self, score, reason=None):
        """
        Set a staff score for the workflow.

        Allows for staff scores to be set on a submission, with annotations to provide an audit trail if needed.
        This method can be used for both required staff grading, and staff overrides.

        Args:
            score (dict): A dict containing 'points_earned', 'points_possible', and 'staff_id'.
            is_override (bool): Optionally True if staff is overriding a previous score.
            reason (string): An optional parameter specifying the reason for the staff grade. A default value
                will be used in the event that this parameter is not provided.

        """
        if reason is None:
            reason = "A staff member has defined the score for this submission"
        sub_dict = sub_api.get_submission_and_student(self.submission_uuid)
        sub_api.reset_score(
            sub_dict['student_item']['student_id'],
            self.course_id,
            self.item_id,
            emit_signal=False
        )
        sub_api.set_score(
            self.submission_uuid,
            score["points_earned"],
            score["points_possible"],
            annotation_creator=score["staff_id"],
            annotation_type=self.STAFF_ANNOTATION_TYPE,
            annotation_reason=reason
        )

    def set_score(self, score):
        """
        Set a score for the workflow.

        Scores are persisted via the Submissions API, separate from the Workflow
        Data. Score is associated with the same submission_uuid as this workflow

        Args:
            score (dict): A dict containing 'points_earned' and
                'points_possible'.

        """
        if not self.staff_score_exists():
            sub_api.set_score(
                self.submission_uuid,
                score["points_earned"],
                score["points_possible"]
            )

    def staff_score_exists(self):
        """
        Check if a staff score exists for this submission.
        """
        steps = self._get_steps()
        step_for_name = {step.name: step for step in steps}
        staff_step = step_for_name.get("staff")
        if staff_step is not None:
            get_latest_func = getattr(staff_step.api(), 'get_latest_assessment', None)
            if get_latest_func is not None:
                staff_assessment = get_latest_func(self.submission_uuid)
                if staff_assessment is not None:
                    return True
        return False

    def cancel(self, assessment_requirements):
        """
        Cancel workflow for all steps.

        Set the points earned to 0 and workflow status to cancelled.

        Args:
            assessment_requirements (dict): Dictionary that currently looks like:
                `{"peer": {"must_grade": <int>, "must_be_graded_by": <int>}}`
                `must_grade` is the number of assessments a student must complete.
                `must_be_graded_by` is the number of assessments a submission must
                receive to be scored. `must_grade` should be greater than
                `must_be_graded_by` to ensure that everyone will get scored.
                The intention is to eventually pass in more assessment sequence
                specific requirements in this dict.
        """
        steps = self._get_steps()
        step_for_name = {step.name: step for step in steps}

        # Cancel the workflow for each step.
        for step in steps:
            on_cancel_func = getattr(step.api(), 'on_cancel', None)
            if on_cancel_func is not None:
                on_cancel_func(self.submission_uuid)

        try:
            score = self.get_score(assessment_requirements, step_for_name)
        except AssessmentError as exc:
            logger.info("TNL-5799, exception in get_score during cancellation. {}".format(exc))
            score = None

        # Set the points_earned to 0.
        if score is not None:
            score['points_earned'] = 0
            self.set_score(score)

        # Save status if it is not cancelled.
        if self.status != self.STATUS.cancelled:
            self.status = self.STATUS.cancelled
            self.save()
            logger.info(
                u"Workflow for submission UUID {uuid} has updated status to {status}".format(
                    uuid=self.submission_uuid, status=self.STATUS.cancelled
                )
            )

    @classmethod
    def cancel_workflow(cls, submission_uuid, comments, cancelled_by_id, assessment_requirements):
        """
        Add an entry in AssessmentWorkflowCancellation table for a AssessmentWorkflow.

        AssessmentWorkflow which has been cancelled is no longer included in the
        peer grading pool.

        Args:
            submission_uuid (str): The UUID of the workflow's submission.
            comments (str): The reason for cancellation.
            cancelled_by_id (str): The ID of the user who cancelled the peer workflow.
            assessment_requirements (dict): Dictionary that currently looks like:
            `{"peer": {"must_grade": <int>, "must_be_graded_by": <int>}}`
            `must_grade` is the number of assessments a student must complete.
            `must_be_graded_by` is the number of assessments a submission must
            receive to be scored. `must_grade` should be greater than
            `must_be_graded_by` to ensure that everyone will get scored.
            The intention is to eventually pass in more assessment sequence
            specific requirements in this dict.
        """
        try:
            workflow = cls.objects.get(submission_uuid=submission_uuid)
            AssessmentWorkflowCancellation.create(workflow=workflow, comments=comments, cancelled_by_id=cancelled_by_id)
            # Cancel the related step's workflow.
            workflow.cancel(assessment_requirements)
        except (cls.DoesNotExist, cls.MultipleObjectsReturned):
            error_message = u"Error finding workflow for submission UUID {}.".format(submission_uuid)
            logger.exception(error_message)
            raise AssessmentWorkflowError(error_message)
        except DatabaseError:
            error_message = u"Error creating assessment workflow cancellation for submission UUID {}.".format(
                submission_uuid)
            logger.exception(error_message)
            raise AssessmentWorkflowInternalError(error_message)

    @classmethod
    def get_by_submission_uuid(cls, submission_uuid):
        """
        Retrieve the Assessment Workflow associated with the given submission UUID.

        Args:
            submission_uuid (str): The string representation of the UUID belonging
                to the associated Assessment Workflow.

        Returns:
            workflow (AssessmentWorkflow): The most recent assessment workflow associated with
                this submission UUID.

        Raises:
            AssessmentWorkflowError: Thrown when no workflow can be found for
                the associated submission UUID. This should always exist before a
                student is allow to request submissions for peer assessment.

        """
        try:
            return cls.objects.get(submission_uuid=submission_uuid)
        except cls.DoesNotExist:
            return None
        except DatabaseError as exc:
            message = u"Error finding workflow for submission UUID {} due to error: {}.".format(submission_uuid, exc)
            logger.exception(message)
            raise AssessmentWorkflowError(message)

    @property
    def is_cancelled(self):
        """
        Check if assessment workflow is cancelled.

        Returns:
            True/False
        """
        return self.cancellations.exists()
Beispiel #13
0
def userlist(request):
    email = request.session.get('email', None)
    if email is None:
        return Response(e, status=status.HTTP_404_NOT_FOUND, template_name=None, content_type=None)

    draw = request.GET.get('draw', '')
    length = request.GET.get('length', '')
    start = request.GET.get('start', '')
    search_value = request.GET.get('search[value]', '')
    order_column = request.GET.get('order[0][column]', '')
    order = request.GET.get('order[0][dir]', '')

    if draw:
        draw = int(draw)
    else:
        draw = int(1)
    if length:
        length = int(length)
    else:
        length = int(10)
    if start:
        start = int(start)
    else:
        start = int(0)

    ORDER_COLUMN_CHOICES = Choices(
        ('0', 'account_no'),
    )

    order_column = ORDER_COLUMN_CHOICES[order_column]
    if order == 'asc':
        order_column = '-' + order_column


    queryset = CustomerAccountdetail.objects.all().select_related('acc_user')
    print(queryset.query)
    total = queryset.count()

    count = queryset.count()
    queryset = queryset.order_by(order_column)[start:start + length]
    result = dict()
    CanresultData = list()
    for data in queryset:
        print(data)
        resultData = dict()
        resultData['account_no'] = data.account_no
        resultData['first_name'] = data.acc_user.first_name
        resultData['last_name'] = data.acc_user.last_name
        resultData['address'] = data.address
        if data.acc_user.is_superuser == 1:
            resultData['profile_type'] = 'Manager'
        else:
            resultData['profile_type'] = 'Customer'
        resultData['email'] = data.acc_user.email
        date = format(data.acc_user.date_joined, 'd/m/Y H:i')
        resultData['created_at'] = date
        resultData['status'] = data.acc_user.is_active
        resultData['id'] = data.acc_user.id
        CanresultData.append(resultData)

    result['data'] = CanresultData
    result['draw'] = draw
    result['recordsTotal'] = total
    result['recordsFiltered'] = count
    return JsonResponse(result, safe=False)
Beispiel #14
0
from apps.patients.models import (PatientMedication, )
from apps.plans.models import (CarePlanTemplate, CarePlan, )


FREQUENCY_CHOICES = (
    ('once', 'Once'),
    ('daily', 'Daily'),
    ('every_other_day', 'Every Other Day'),
    ('weekly', 'Weekly'),
    ('weekdays', 'Weekdays'),
    ('weekends', 'Weekends'),
)

CATEGORY_CHOICES = Choices(
    ('notes', 'Notes'),
    ('interaction', 'Patient Interaction'),
    ('coordination', 'Care Team Coordination'),
)


class StateMixin(object):

    def check_if_missed(self):
        """
        This method will only be used for PatientTask and MedicationTask.
        By default, we set it to False to disregard this. This method should
        be overridden in PatientTask and MedicationTask model to allow for
        custom condition for `missed` state
        """
        return False
Beispiel #15
0
class Status(StatusModel):
    STATUS = Choices(
        ("active", _("active")),
        ("deleted", _("deleted")),
        ("on_hold", _("on hold")),
    )
class AbstractConfig(BaseConfig):
    """
    Abstract model implementing the
    NetJSON DeviceConfiguration object
    """

    device = models.OneToOneField(get_model_name('config', 'Device'),
                                  on_delete=models.CASCADE)
    templates = SortedManyToManyField(
        get_model_name('config', 'Template'),
        related_name='config_relations',
        verbose_name=_('templates'),
        base_class=TemplatesThrough,
        blank=True,
        help_text=_('configuration templates, applied from first to last'),
    )
    vpn = models.ManyToManyField(
        get_model_name('config', 'Vpn'),
        through=get_model_name('config', 'VpnClient'),
        related_name='vpn_relations',
        blank=True,
    )

    STATUS = Choices('modified', 'applied', 'error')
    status = StatusField(
        _('configuration status'),
        help_text=_(
            '"modified" means the configuration is not applied yet; \n'
            '"applied" means the configuration is applied successfully; \n'
            '"error" means the configuration caused issues and it was rolled back;'
        ),
    )
    context = JSONField(
        blank=True,
        default=dict,
        help_text=_('Additional '
                    '<a href="http://netjsonconfig.openwisp.org/'
                    'en/stable/general/basics.html#context" target="_blank">'
                    'context (configuration variables)</a> in JSON format'),
        load_kwargs={'object_pairs_hook': collections.OrderedDict},
        dump_kwargs={'indent': 4},
    )

    _CHECKSUM_CACHE_TIMEOUT = 60 * 60 * 24 * 30  # 10 days

    class Meta:
        abstract = True
        verbose_name = _('configuration')
        verbose_name_plural = _('configurations')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # for internal usage
        self._just_created = False
        self._initial_status = self.status
        self._send_config_modified_after_save = False
        self._send_config_status_changed = False

    def __str__(self):
        if self._has_device():
            return self.name
        return str(self.pk)

    @property
    def name(self):
        """
        returns device name
        (kept for backward compatibility with pre 0.6 versions)
        """
        if self._has_device():
            return self.device.name
        return str(self.pk)

    @property
    def mac_address(self):
        """
        returns device mac address
        (kept for backward compatibility with pre 0.6 versions)
        """
        return self.device.mac_address

    @property
    def key(self):
        """
        returns device key
        (kept for backward compatibility with pre 0.6 versions)
        """
        return self.device.key

    @cache_memoize(timeout=_CHECKSUM_CACHE_TIMEOUT,
                   args_rewrite=get_cached_checksum_args_rewrite)
    def get_cached_checksum(self):
        """
        Handles caching,
        timeout=None means value is cached indefinitely
        (invalidation handled on post_save/post_delete signal)
        """
        logger.debug(f'calculating checksum for config ID {self.pk}')
        return self.checksum

    @classmethod
    def get_template_model(cls):
        return cls.templates.rel.model

    @classmethod
    def _get_templates_from_pk_set(cls, pk_set):
        """
        Retrieves templates from pk_set
        Called in ``clean_templates``, may be reused in third party apps
        """
        # coming from signal
        if isinstance(pk_set, set):
            template_model = cls.get_template_model()
            templates = template_model.objects.filter(pk__in=list(pk_set))
        # coming from admin ModelForm
        else:
            templates = pk_set
        return templates

    @classmethod
    def clean_templates(cls, action, instance, pk_set, **kwargs):
        """
        validates resulting configuration of config + templates
        raises a ValidationError if invalid
        must be called from forms or APIs
        this method is called from a django signal (m2m_changed)
        see config.apps.DjangoNetjsonconfigApp.connect_signals
        """
        templates = cls.clean_templates_org(action, instance, pk_set, **kwargs)
        if not templates:
            return
        backend = instance.get_backend_instance(template_instances=templates)
        try:
            cls.clean_netjsonconfig_backend(backend)
        except ValidationError as e:
            message = 'There is a conflict with the specified templates. {0}'
            message = message.format(e.message)
            raise ValidationError(message)

    @classmethod
    def templates_changed(cls, action, instance, **kwargs):
        """
        this method is called from a django signal (m2m_changed)
        see config.apps.ConfigConfig.connect_signals

        NOTE: post_clear is ignored because it is used by the
        sortedm2m package to reorder templates
        (m2m relationships are first cleared and then added back),
        there fore we need to ignore it to avoid emitting signals twice
        """
        if action not in ['post_add', 'post_remove']:
            return
        # use atomic to ensure any code bound to
        # be executed via transaction.on_commit
        # is executed after the whole block
        with transaction.atomic():
            # do not send config modified signal if
            # config instance has just been created
            if not instance._just_created:
                # sends only config modified signal
                instance._send_config_modified_signal(
                    action='m2m_templates_changed')
            if instance.status != 'modified':
                # sends both status modified and config modified signals
                instance.set_status_modified(send_config_modified_signal=False)

    @classmethod
    def manage_vpn_clients(cls, action, instance, pk_set, **kwargs):
        """
        automatically manages associated vpn clients if the
        instance is using templates which have type set to "VPN"
        and "auto_cert" set to True.
        This method is called from a django signal (m2m_changed)
        see config.apps.DjangoNetjsonconfigApp.connect_signals
        """
        if action not in ['post_add', 'post_remove', 'post_clear']:
            return
        vpn_client_model = cls.vpn.through
        # coming from signal
        if isinstance(pk_set, set):
            template_model = cls.get_template_model()
            templates = template_model.objects.filter(pk__in=list(pk_set))
        # coming from admin ModelForm
        else:
            templates = pk_set
        # when clearing all templates
        if action == 'post_clear':
            for client in instance.vpnclient_set.all():
                client.delete()
            return
        # when adding or removing specific templates
        for template in templates.filter(type='vpn'):
            if action == 'post_add':
                client = vpn_client_model(config=instance,
                                          vpn=template.vpn,
                                          auto_cert=template.auto_cert)
                client.full_clean()
                client.save()
            elif action == 'post_remove':
                for client in instance.vpnclient_set.filter(vpn=template.vpn):
                    client.delete()

    @classmethod
    def clean_templates_org(cls, action, instance, pk_set, **kwargs):
        if action != 'pre_add':
            return False
        templates = cls._get_templates_from_pk_set(pk_set)
        # when using the admin, templates will be a list
        # we need to get the queryset from this list in order to proceed
        if not isinstance(templates, models.QuerySet):
            template_model = cls.templates.rel.model
            pk_list = [template.pk for template in templates]
            templates = template_model.objects.filter(pk__in=pk_list)
        # lookg for invalid templates
        invalids = (templates.exclude(
            organization=instance.device.organization).exclude(
                organization=None).values('name'))

        if templates and invalids:
            names = ''
            for invalid in invalids:
                names = '{0}, {1}'.format(names, invalid['name'])
            names = names[2:]
            message = _('The following templates are owned by organizations '
                        'which do not match the organization of this '
                        'configuration: {0}').format(names)
            raise ValidationError(message)
        # return valid templates in order to save computation
        # in the following operations
        return templates

    @classmethod
    def enforce_required_templates(cls, action, instance, pk_set, **kwargs):
        """
        This method is called from a django signal (m2m_changed),
        see config.apps.ConfigConfig.connect_signals.
        It raises a PermissionDenied if a required template
        is unassigned from a config.
        It adds back required templates on post_clear events
        (post-clear is used by sortedm2m to assign templates).
        """
        if action not in ['pre_remove', 'post_clear']:
            return False
        # trying to remove a required template will raise PermissionDenied
        if action == 'pre_remove':
            templates = cls._get_templates_from_pk_set(pk_set)
            if templates.filter(required=True).exists():
                raise PermissionDenied(
                    _('Required templates cannot be removed from the configuration'
                      ))
        if action == 'post_clear':
            # retrieve required templates related to this
            # device and ensure they're always present
            required_templates = (cls.get_template_model().objects.filter(
                required=True).filter(
                    models.Q(organization=instance.device.organization)
                    | models.Q(organization=None)))
            if required_templates.exists():
                instance.templates.add(*required_templates.order_by(
                    'name').values_list('pk', flat=True))

    def get_default_templates(self):
        """
        retrieves default templates of a Config object
        may be redefined with a custom logic if needed
        """

        queryset = self.templates.model.objects.filter(default=True)
        try:
            org_id = self.device.organization_id
        except ObjectDoesNotExist:
            org_id = None
        return get_default_templates_queryset(organization_id=org_id,
                                              queryset=queryset,
                                              backend=self.backend)

    def clean(self):
        """
        * validates context field
        * modifies status if key attributes of the configuration
          have changed (queries the database)
        """
        super().clean()
        if not self.context:
            self.context = {}
        if not isinstance(self.context, dict):
            raise ValidationError(
                {'context': _('the supplied value is not a JSON object')})
        if self._state.adding:
            return
        current = self.__class__.objects.get(pk=self.pk)
        for attr in ['backend', 'config', 'context']:
            if getattr(self, attr) != getattr(current, attr):
                if self.status != 'modified':
                    self.set_status_modified(save=False)
                else:
                    # config modified signal is always sent
                    # regardless of the current status
                    self._send_config_modified_after_save = True
                break

    def save(self, *args, **kwargs):
        created = self._state.adding
        self._just_created = created
        result = super().save(*args, **kwargs)
        if created:
            default_templates = self.get_default_templates()
            if default_templates:
                self.templates.add(*default_templates)
        if not created and self._send_config_modified_after_save:
            self._send_config_modified_signal(action='config_changed')
            self._send_config_modified_after_save = False
        if self._send_config_status_changed:
            self._send_config_status_changed_signal()
            self._send_config_status_changed = False
        self._initial_status = self.status
        return result

    def _send_config_modified_signal(self, action):
        """
        Emits ``config_modified`` signal.
        Called also by Template when templates of a device are modified
        """
        assert action in [
            'config_changed',
            'related_template_changed',
            'm2m_templates_changed',
        ]
        config_modified.send(
            sender=self.__class__,
            instance=self,
            previous_status=self._initial_status,
            action=action,
            # kept for backward compatibility
            config=self,
            device=self.device,
        )

    def _send_config_status_changed_signal(self):
        """
        Emits ``config_status_changed`` signal.
        Called also by Template when templates of a device are modified
        """
        config_status_changed.send(sender=self.__class__, instance=self)

    def _set_status(self, status, save=True):
        self.status = status
        self._send_config_status_changed = True
        if save:
            self.save(update_fields=['status'])

    def set_status_modified(self, save=True, send_config_modified_signal=True):
        if send_config_modified_signal:
            self._send_config_modified_after_save = True
        self._set_status('modified', save)

    def set_status_applied(self, save=True):
        self._set_status('applied', save)

    def set_status_error(self, save=True):
        self._set_status('error', save)

    def _has_device(self):
        return hasattr(self, 'device')

    def get_vpn_context(self):
        c = super().get_context()
        for vpnclient in self.vpnclient_set.all().select_related(
                'vpn', 'cert'):
            vpn = vpnclient.vpn
            vpn_id = vpn.pk.hex
            context_keys = vpn._get_auto_context_keys()
            ca = vpn.ca
            cert = vpnclient.cert
            # CA
            ca_filename = 'ca-{0}-{1}.pem'.format(
                ca.pk, ca.common_name.replace(' ', '_'))
            ca_path = '{0}/{1}'.format(app_settings.CERT_PATH, ca_filename)
            # update context
            c.update({
                context_keys['ca_path']: ca_path,
                context_keys['ca_contents']: ca.certificate,
            })
            # conditional needed for VPN without x509 authentication
            # eg: simple password authentication
            if cert:
                # cert
                cert_filename = 'client-{0}.pem'.format(vpn_id)
                cert_path = '{0}/{1}'.format(app_settings.CERT_PATH,
                                             cert_filename)
                # key
                key_filename = 'key-{0}.pem'.format(vpn_id)
                key_path = '{0}/{1}'.format(app_settings.CERT_PATH,
                                            key_filename)
                # update context
                c.update({
                    context_keys['cert_path']: cert_path,
                    context_keys['cert_contents']: cert.certificate,
                    context_keys['key_path']: key_path,
                    context_keys['key_contents']: cert.private_key,
                })
        return c

    def get_context(self, system=False):
        """
        additional context passed to netjsonconfig
        """
        c = collections.OrderedDict()
        extra = {}
        if self._has_device():
            c.update([
                ('name', self.name),
                ('mac_address', self.mac_address),
                ('id', str(self.device.id)),
                ('key', self.key),
            ])
            if self.context and not system:
                extra.update(self.context)
        extra.update(self.get_vpn_context())
        if app_settings.HARDWARE_ID_ENABLED and self._has_device():
            extra.update({'hardware_id': str(self.device.hardware_id)})
        c.update(sorted(extra.items()))
        return c

    def get_system_context(self):
        return self.get_context(system=True)
Beispiel #17
0
class StatusFieldDefaultNotFilled(models.Model):
    STATUS = Choices((0, "no", "No"), (1, "yes", "Yes"))
    status = StatusField()
Beispiel #18
0
class InstitutionCharge(Charge):
    """
    This is a charge in the institution (city council, city government, mayor).
    """
    MAYOR_CHARGE = 1
    ASSESSOR_CHARGE = 2
    COUNSELOR_CHARGE = 3
    COUNCIL_PRES_CHARGE = 4
    COUNCIL_VICE_CHARGE = 5
    COMMITTEE_MEMBER_CHARGE = 6
    CHARGE_TYPES = Choices(
        (MAYOR_CHARGE, _('Mayor')),
        (ASSESSOR_CHARGE, _('Town government member')),
        (COUNCIL_PRES_CHARGE, _('Counsil president')),
        (COUNCIL_VICE_CHARGE, _('Counsil vice president')),
        (COUNSELOR_CHARGE, _('Counselor')),
        (COMMITTEE_MEMBER_CHARGE, _('Committee member')),
    )
    substitutes = models.OneToOneField('InstitutionCharge',
                                       blank=True,
                                       null=True,
                                       related_name='reverse_substitute_set',
                                       on_delete=models.PROTECT,
                                       verbose_name=_('in substitution of'))
    substituted_by = models.OneToOneField(
        'InstitutionCharge',
        blank=True,
        null=True,
        related_name='reverse_substituted_by_set',
        on_delete=models.PROTECT,
        verbose_name=_('substituted by'))
    institution = models.ForeignKey('Institution',
                                    on_delete=models.PROTECT,
                                    verbose_name=_('institution'),
                                    related_name='charge_set')
    charge_type = models.IntegerField(_('charge type'), choices=CHARGE_TYPES)
    op_charge_id = models.IntegerField(_('openpolis institution charge ID'),
                                       blank=True,
                                       null=True)
    n_rebel_votations = models.IntegerField(default=0)
    n_present_votations = models.IntegerField(default=0)
    n_absent_votations = models.IntegerField(default=0)

    class Meta(Charge.Meta):
        db_table = u'people_institution_charge'
        verbose_name = _('institution charge')
        verbose_name_plural = _('institution charges')

    def __unicode__(self):
        # TODO: implement ``get_charge_type_display()`` method
        return u'%s - %s dal %s' % (self.person,
                                    self.get_charge_type_display(),
                                    self.start_date.strftime('%d/%m/%Y'))

    # TODO: model validation: check that ``substitutes`` and ``substituted_by`` fields
    # point to ``InstitutionCharge``s of the same kind

    @property
    def presented_acts(self):
        """
        The QuerySet of acts presented by this charge.
        """
        return self.presented_act_set.all()

    @property
    def received_acts(self):
        """
        The QuerySet of acts received by this charge.
        """
        return self.received_act_set.all()

    @property
    def council_group(self):
        """
        Returns the city council's group this charge currently belongs to (if any).

        If the charge doesn't belong to any council's group  -- e.g. because (s)he
        is not a counselor, return ``None``.
        """
        # this property only make sense for counselors
        if self.charge_type == InstitutionCharge.COUNSELOR_CHARGE:
            # This query should return only one record, since a counselor
            # may belong to only one council group at a time.
            # If multiple records match the query, instead, a ``MultipleObjectsReturned``
            # exception will be raised, providing a useful integrity check for data
            group = Group.objects.get(groupcharge__charge__id=self.id,
                                      groupcharge__end_date__isnull=True)
            return group
        else:
            return None

    def compute_rebellion_cache(self):
        """
        Re-compute the number of votations where the charge has vote differently from her group
        and update the n_rebel_votations counter
        """
        self.n_rebel_votations = self.chargevote_set.filter(
            is_rebel=True).count()
        self.save()

    def compute_presence_cache(self):
        """
        Re-compute the number of votations where the charge was present/absent
        and update the respective counters
        """
        from open_municipio.votations.models import ChargeVote

        absent = ChargeVote.ABSENT
        self.n_present_votations = self.chargevote_set.exclude(
            vote=absent).count()
        self.n_absent_votations = self.chargevote_set.filter(
            vote=absent).count()
        self.save()
Beispiel #19
0
from django.db import models
from django.utils.translation import ugettext_lazy as _
from helpers.constants import GENDERS
from model_utils import Choices
from model_utils.models import TimeStampedModel

OCCUPATIONS = Choices(
    ("developer", _("Developer")),
    ("student", _("Student")),
    ("researcher", _("Researcher")),
    ("unemployed", _("Unemployed")),
    ("other", _("Other")),
)

GRANT_TYPES = Choices(
    ("diversity", _("Diversity")),
    ("unemployed", _("Unemployed")),
    ("speaker", _("Speaker")),
)

INTERESTED_IN_VOLUNTEERING = Choices(
    ("no", _("No")), ("yes", _("Yes")),
    ("absolutely", _("My soul is yours to take!")))


class Grant(TimeStampedModel):
    name = models.CharField(_("name"), max_length=300)
    full_name = models.CharField(_("full name"), max_length=300)
    conference = models.ForeignKey(
        "conferences.Conference",
        on_delete=models.CASCADE,
Beispiel #20
0
class Person(models.Model, MonitorizedItem):
    FEMALE_SEX = 0
    MALE_SEX = 1
    SEX = Choices(
        (MALE_SEX, _('Male')),
        (FEMALE_SEX, _('Female')),
    )
    first_name = models.CharField(_('first name'), max_length=128)
    last_name = models.CharField(_('last name'), max_length=128)
    birth_date = models.DateField(_('birth date'))
    birth_location = models.CharField(_('birth location'),
                                      blank=True,
                                      max_length=128)
    slug = models.SlugField(unique=True, blank=True, null=True, max_length=128)
    sex = models.IntegerField(_('sex'), choices=SEX)
    op_politician_id = models.IntegerField(_('openpolis politician ID'),
                                           blank=True,
                                           null=True)

    # manager to handle the list of monitoring having as content_object this instance
    monitoring_set = generic.GenericRelation(Monitoring,
                                             object_id_field='object_pk')

    class Meta:
        verbose_name = _('person')
        verbose_name_plural = _('people')

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

    def save(self, *args, **kwargs):
        if self.slug is None:
            self.slug = slugify(
                "%s %s %s" %
                (self.first_name, self.last_name, self.birth_date))
        super(Person, self).save(*args, **kwargs)

    @permalink
    def get_absolute_url(self):
        return 'om_politician_detail', (), {'slug': self.slug}

    @property
    def full_name(self):
        return "%s %s" % (self.first_name, self.last_name)

    @property
    def all_institution_charges(self):
        """
        Returns the QuerySet of all institution charges held by this person during his/her career.
        """
        return self.institutioncharge_set.all()

    @property
    def current_institution_charges(self):
        """
        Returns a QuerySet of institution charges currently held by this person.
        """
        return self.institutioncharge_set.current()

    @property
    def resources(self):
        """
        Returns the list of resources associated with this person
        """
        return self.resource_set.all()

    @property
    def content_type_id(self):
        """
        Return id of the content type associated with this instance.
        """
        return ContentType.objects.get_for_model(self).id
Beispiel #21
0
class User(AbstractUser):
    email = models.EmailField(unique=True, null=True)
    phone = models.CharField(max_length=30, blank=True, null=True, default=None,
                             validators=[validate_mobile_phone])
    ROLE = Choices(
        (1, 'student', 'Student'),
        (2, 'trainer', 'Trainer'),
        (2, 'company', 'Company'),
    )
    role = models.PositiveIntegerField(choices=ROLE, blank=True, null=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']
    objects = CustomUserManager()

    @property
    def name(self):
        name = self.get_full_name()
        if not name:
            name = self.username
        return name

    def get_student(self):
        return self.students.select_related('training').last()

    def notification_register(self):
        data = {
            'token': default_token_generator.make_token(self),
            'uid': int_to_base36(self.id),
            'host': settings.HOST,
            'user': self,
            'email_title': 'Aktivasi Akun'
        }

        send = mail.send(
            [self.email],
            settings.DEFAULT_FROM_EMAIL,
            subject='Aktivasi Akun',
            html_message=render_to_string('emails/register.html', context=data)
        )
        return send

    def notification_status_training(self, training_materials):
        data = {
            'host': settings.HOST,
            'user': self,
            'training_materials': training_materials,
            'email_title': 'Status Pelatihan'
        }

        send = mail.send(
            [self.email],
            settings.DEFAULT_FROM_EMAIL,
            subject='Status Pelatihan',
            html_message=render_to_string('emails/training-status.html', context=data)
        )
        return send

    def get_count_training_status(self):
        count_status = self.training_status.aggregate(
            graduate=Count(
                Case(When(status=TrainingStatus.STATUS.graduate, then=1),
                     output_field=IntegerField())
            ),
            not_yet=Count(
                Case(When(status=TrainingStatus.STATUS.not_yet, then=1),
                     output_field=IntegerField())
            ),
            repeat=Count(
                Case(When(status=TrainingStatus.STATUS.repeat, then=1),
                     output_field=IntegerField())
            )
        )
        return count_status

    def indicator_reached(self, status):
        if status['graduate'] >= settings.INDICATOR_GRADUATED and status['not_yet'] == 0:
            return True
        return False

    def save_training_status_to_log(self):
        LogTrainingStatus.objects.bulk_create([
            LogTrainingStatus(
                code=training.training_material.code,
                title=training.training_material.title,
                status=training.status,
                user=self,
                student=self.get_student()
            ) for training in self.training_status.select_related('training_material')
        ])

    def delete_training_status(self):
        self.training_status.all().delete()
Beispiel #22
0
class Institution(Body):
    """
    Institutional bodies can be of different types (as specified by the ``institution_type`` field).
    
    This model has a relation with itself, in order to map hierarchical bodies (joint committees, ...).
    """
    MAYOR = 1
    CITY_GOVERNMENT = 2
    COUNCIL = 3
    COMMITTEE = 4
    JOINT_COMMITTEE = 5
    INSTITUTION_TYPES = Choices(
        (MAYOR, _('Mayor')),
        (COUNCIL, _('Council')),
        (CITY_GOVERNMENT, _('Town government')),
        (COMMITTEE, _('Committee')),
        (JOINT_COMMITTEE, _('Joint committee')),
    )

    parent = models.ForeignKey('Institution',
                               related_name='sub_body_set',
                               blank=True,
                               null=True)
    institution_type = models.IntegerField(choices=INSTITUTION_TYPES)

    class Meta(Body.Meta):
        verbose_name = _('institution')
        verbose_name_plural = _('institutions')

    def save(self, *args, **kwargs):
        """slugify name on first save"""
        if not self.id:
            self.slug = slugify(self.name)
        super(Institution, self).save(*args, **kwargs)

    def get_absolute_url(self):
        if self.institution_type == self.MAYOR:
            return reverse("om_institution_mayor")
        elif self.institution_type == self.CITY_GOVERNMENT:
            return reverse("om_institution_citygov")
        elif self.institution_type == self.COUNCIL:
            return reverse("om_institution_council")
        elif self.institution_type == self.COMMITTEE:
            return reverse("om_institution_committee",
                           kwargs={'slug': self.slug})

    @property
    def charges(self):
        """
        The QuerySet of all *current* charges (``InstitutionCharge`` instances) 
        associated with this institution.  
        """
        return self.charge_set.current()

    @property
    def emitted_acts(self):
        """
        The QuerySet of all acts emitted by this institution.
        
        Note that the objects comprising the resulting QuerySet aren't generic ``Act`` instances,
        but instances of specific ``Act`` subclasses (i.e. ``Deliberation``, ``Motion``, etc.).
        This is made possible by the fact that the default manager for the ``Act`` model is 
        ``model_utils.managers.InheritanceManager``, and this manager class declares 
        ``use_for_related_fields = True``.   See `Django docs`_ for details.
        
        .. _`Django docs`: https://docs.djangoproject.com/en/1.3/topics/db/managers/#controlling-automatic-manager-types
        """
        # NOTE: See also Django bug #14891
        return self.emitted_act_set.all().select_subclasses()
Beispiel #23
0
class AbstractConfig(BaseConfig):
    """
    Abstract model implementing the
    NetJSON DeviceConfiguration object
    """
    device = models.OneToOneField('django_netjsonconfig.Device',
                                  on_delete=models.CASCADE)
    STATUS = Choices('modified', 'applied', 'error')
    status = StatusField(
        _('configuration status'),
        help_text=_(
            '"modified" means the configuration is not applied yet; \n'
            '"applied" means the configuration is applied successfully; \n'
            '"error" means the configuration caused issues and it was rolled back;'
        ))
    context = JSONField(
        null=True,
        blank=True,
        help_text=_('Additional '
                    '<a href="http://netjsonconfig.openwisp.org/'
                    'en/stable/general/basics.html#context" target="_blank">'
                    'context (configuration variables)</a> in JSON format'))

    class Meta:
        abstract = True
        verbose_name = _('configuration')
        verbose_name_plural = _('configurations')

    def __str__(self):
        if self._has_device():
            return self.name
        return str(self.pk)

    def clean(self):
        """
        modifies status if key attributes of the configuration
        have changed (queries the database)
        """
        super(AbstractConfig, self).clean()
        if self._state.adding:
            return
        current = self.__class__.objects.get(pk=self.pk)
        for attr in ['backend', 'config', 'context']:
            if getattr(self, attr) != getattr(current, attr):
                self.set_status_modified(save=False)
                break

    def save(self, *args, **kwargs):
        result = super(AbstractConfig, self).save(*args, **kwargs)
        if not self._state.adding and getattr(
                self, '_send_config_modified_after_save', False):
            self._send_config_modified_signal()
        return result

    def _send_config_modified_signal(self):
        """
        sends signal ``config_modified``
        """
        config_modified.send(sender=self.__class__,
                             config=self,
                             device=self.device)

    def _set_status(self, status, save=True):
        self.status = status
        if save:
            self.save()

    def set_status_modified(self, save=True):
        self._set_status('modified', save)
        if save:
            self._send_config_modified_signal()
        else:
            # set this attribute that will be
            # checked in the save method
            self._send_config_modified_after_save = True

    def set_status_applied(self, save=True):
        self._set_status('applied', save)

    def set_status_error(self, save=True):
        self._set_status('error', save)

    def _has_device(self):
        return hasattr(self, 'device')

    def get_context(self):
        """
        additional context passed to netjsonconfig
        """
        c = {}
        if self._has_device():
            c.update({
                'id': str(self.device.id),
                'key': self.key,
                'name': self.name,
                'mac_address': self.mac_address
            })
            if self.context:
                c.update(self.context)
        c.update(app_settings.CONTEXT)
        if app_settings.HARDWARE_ID_ENABLED and self._has_device():
            c.update({'hardware_id': self.device.hardware_id})
        return c

    @property
    def name(self):
        """
        returns device name
        (kept for backward compatibility with pre 0.6 versions)
        """
        if self._has_device():
            return self.device.name
        return str(self.pk)

    @property
    def mac_address(self):
        """
        returns device mac address
        (kept for backward compatibility with pre 0.6 versions)
        """
        return self.device.mac_address

    @property
    def key(self):
        """
        returns device key
        (kept for backward compatibility with pre 0.6 versions)
        """
        return self.device.key
Beispiel #24
0
class Notification(models.Model):
    """
    Action model describing the actor acting out a verb (on an optional
    target).
    Nomenclature based on http://activitystrea.ms/specs/atom/1.0/

    Generalized Format::

        <actor> <verb> <time>
        <actor> <verb> <target> <time>
        <actor> <verb> <action_object> <target> <time>

    Examples::

        <justquick> <reached level 60> <1 minute ago>
        <brosner> <commented on> <pinax/pinax> <2 hours ago>
        <washingtontimes> <started follow> <justquick> <8 minutes ago>
        <mitsuhiko> <closed> <issue 70> on <mitsuhiko/flask> <about 2 hours ago>

    Unicode Representation::

        justquick reached level 60 1 minute ago
        mitsuhiko closed issue 70 on mitsuhiko/flask 3 hours ago

    HTML Representation::

        <a href="http://oebfare.zcom/">brosner</a> commented on <a href="http://github.com/pinax/pinax">pinax/pinax</a> 2 hours ago

    """
    LEVELS = Choices('success', 'info', 'warning', 'error')
    level = models.CharField(choices=LEVELS,
                             default=LEVELS.info,
                             max_length=20)

    recipient = models.ForeignKey(settings.AUTH_USER_MODEL,
                                  blank=False,
                                  related_name='notifications')
    unread = models.BooleanField(default=True, blank=False)

    actor_content_type = models.ForeignKey(ContentType,
                                           related_name='notify_actor')
    actor_object_id = models.CharField(max_length=255)
    actor = GenericForeignKey('actor_content_type', 'actor_object_id')

    verb = models.CharField(max_length=255)
    description = models.TextField(blank=True, null=True)

    target_content_type = models.ForeignKey(ContentType,
                                            related_name='notify_target',
                                            blank=True,
                                            null=True)
    target_object_id = models.CharField(max_length=255, blank=True, null=True)
    target = GenericForeignKey('target_content_type', 'target_object_id')

    action_object_content_type = models.ForeignKey(
        ContentType,
        related_name='notify_action_object',
        blank=True,
        null=True)
    action_object_object_id = models.CharField(max_length=255,
                                               blank=True,
                                               null=True)
    action_object = GenericForeignKey('action_object_content_type',
                                      'action_object_object_id')

    timestamp = models.DateTimeField(default=now)

    public = models.BooleanField(default=True)
    deleted = models.BooleanField(default=False)
    emailed = models.BooleanField(default=False)

    data = JSONField(blank=True, null=True)
    objects = managers.PassThroughManager.for_queryset_class(
        NotificationQuerySet)()

    class Meta:
        ordering = ('-timestamp', )
        app_label = 'notifications'

    def __unicode__(self):
        ctx = {
            'actor': self.actor,
            'verb': self.verb,
            'action_object': self.action_object,
            'target': self.target,
            'timesince': self.timesince()
        }
        if self.target:
            if self.action_object:
                return u'%(actor)s %(verb)s %(action_object)s on %(target)s %(timesince)s ago' % ctx
            return u'%(actor)s %(verb)s %(target)s %(timesince)s ago' % ctx
        if self.action_object:
            return u'%(actor)s %(verb)s %(action_object)s %(timesince)s ago' % ctx
        return u'%(actor)s %(verb)s %(timesince)s ago' % ctx

    def __str__(self):  #Adds support for Python 3
        return self.__unicode__()

    def timesince(self, now=None):
        """
        Shortcut for the ``django.utils.timesince.timesince`` function of the
        current timestamp.
        """
        from django.utils.timesince import timesince as timesince_
        return timesince_(self.timestamp, now)

    @property
    def slug(self):
        return id2slug(self.id)

    def mark_as_read(self):
        if self.unread:
            self.unread = False
            self.save()

    def mark_as_unread(self):
        if not self.unread:
            self.unread = True
            self.save()
from model_utils import Choices

FEE_TYPE = Choices(
    ('fixed', 'Fixed'),
    ('percentage', 'Percentage'),
)

CACHE_KEY_CONFIG = 'system_config.{}'
CACHE_KEY_FEE = 'system_fee.{}'
CACHE_KEY_COUNTRY_DEFAULT = 'system_country_default.{}'
CACHE_KEY_SYSTEM_NOTIFICATION = 'system_notification.{}'
CACHE_KEY_SYSTEM_REMINDER = 'system_reminder.{}'
CACHE_KEY_BONUS = 'system_bonus.{}'
Beispiel #26
0
from __future__ import unicode_literals

from model_utils import Choices


DIRECTION = Choices(
    ('1', 'incoming', 'Incoming'),
    ('2', 'outgoing', 'Outgoing'),
)
Beispiel #27
0
* Use timestamp to control current running price, which means price can
pre-define

"""

from django.db import models
from model_utils import Choices
from django.core.validators import RegexValidator, MinValueValidator
from demosite.utils import ItemType
from decimal import Decimal
import hashlib
from random import randrange

# Choices class for model Field

TYPE_CHOICES = Choices()
for item in ItemType:
    TYPE_CHOICES += Choices((item.value, item.name))


class Item(models.Model):
    """Item model design

    Parameters
    ----------
    sku: Char Field
        Unique ascii & number max 8 length sku code
    name: Char Field
        Name of the item
    item_type: Interger Field
        Only allow single item type
Beispiel #28
0
class Order(StatusModel):

    MAX_STEPS = 4

    RECEIVED = "received"
    FORMAT_RECEIVED = "Rebut"

    PREPARING = 'preparing'
    FORMAT_PREPARING = 'En procés'

    ON_DELIVERY = "on_delivery"
    FORMAT_ON_DELIVERY = "En camí"

    PAID = 'paid'
    FORMAT_PAID = 'Pagat'

    CANCELLED = 'cancelled'
    FORMAT_CANCELLED = 'Cancel·lat'

    @classmethod
    def get_status_step(cls, status):
        result = 1
        if status == cls.PREPARING:
            result = 2
        elif status == cls.ON_DELIVERY:
            result = 3
        elif status == cls.PAID:
            result = 4
        elif status == cls.CANCELLED:
            result = 5
        return result

    STATUS = Choices(
        RECEIVED,
        PREPARING,
        ON_DELIVERY,
        PAID,
        CANCELLED
    )

    PAYMENT_CARD = 'card'
    PAYMENT_CASH = 'cash'

    PAYMENT_OPTIONS = Choices('card', 'cash')

    # Relations
    # Attributes - Mandatory
    slug = models.SlugField(default=uuid.uuid4, editable=False)
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name='Hora')
    seat_number = models.PositiveSmallIntegerField(verbose_name='Cadira')
    total_price = models.DecimalField(default=0.00, decimal_places=2, max_digits=20, verbose_name='Preu')
    status = models.CharField(max_length=32, choices=STATUS, default='received', verbose_name='estat')
    payment_method = models.CharField(max_length=16, choices=PAYMENT_OPTIONS, default=PAYMENT_CARD, verbose_name='Pagament')
    # Attributes - Optional
    payment_amount = models.DecimalField(decimal_places=2, max_digits=20, null=True, default=None)
    comment = models.TextField(null=True, blank=True)
    # Object Manager
    objects = OrderManager()

    # Custom Properties
    @property
    def status_steps(self):
        return self.get_status_step(status=self.status)

    @property
    def payment_change(self):
        return self.total_price - self.payment_amount if self.payment_method == self.PAYMENT_CASH else None

    # Methods
    def save(self, *args, **kwargs):
        items = self.items.all()
        self.total_price = items.aggregate(Sum('total_price'))['total_price__sum'] if items.exists() else 0.00
        if self.payment_method != self.PAYMENT_CASH:
            self.payment_amount = None
        super().save(*args, **kwargs)

    def get_edit_url(self):
        return reverse('update_order', kwargs={'pk': self.id})

    def get_delete_url(self):
        return reverse('delete_order', kwargs={'pk': self.id})

    # Meta and String
    class Meta:
        ordering = ['timestamp']
        verbose_name = _('order')
        verbose_name_plural = _('orders')

    def __str__(self):
        return str(self.seat_number)
Beispiel #29
0
class AbstractConfig(BaseConfig):
    """
    Abstract model implementing the
    NetJSON DeviceConfiguration object
    """
    device = models.OneToOneField('django_netjsonconfig.Device',
                                  on_delete=models.CASCADE)
    STATUS = Choices('modified', 'running', 'error')
    status = StatusField(help_text=_(
        'modified means the configuration is not applied yet; '
        'running means applied and running; '
        'error means the configuration caused issues and it was rolledback'))
    last_ip = models.GenericIPAddressField(
        blank=True,
        null=True,
        help_text=_('indicates the last ip from which the '
                    'configuration was downloaded from '
                    '(except downloads from this page)'))

    class Meta:
        abstract = True
        verbose_name = _('configuration')
        verbose_name_plural = _('configurations')

    def __str__(self):
        if self._has_device():
            return self.name
        return str(self.pk)

    def clean(self):
        """
        modifies status if key attributes of the configuration
        have changed (queries the database)
        """
        super(AbstractConfig, self).clean()
        if self._state.adding:
            return
        current = self.__class__.objects.get(pk=self.pk)
        for attr in ['backend', 'config']:
            if getattr(self, attr) != getattr(current, attr):
                self.set_status_modified(save=False)
                break

    def save(self, *args, **kwargs):
        result = super(AbstractConfig, self).save(*args, **kwargs)
        if not self._state.adding and getattr(
                self, '_send_config_modified_after_save', False):
            self._send_config_modified_signal()
        return result

    def _send_config_modified_signal(self):
        """
        sends signal ``config_modified``
        """
        config_modified.send(sender=self.__class__,
                             config=self,
                             device=self.device)

    def _set_status(self, status, save=True):
        self.status = status
        if save:
            self.save()

    def set_status_modified(self, save=True):
        self._set_status('modified', save)
        if save:
            self._send_config_modified_signal()
        else:
            # set this attribute that will be
            # checked in the save method
            self._send_config_modified_after_save = True

    def set_status_running(self, save=True):
        self._set_status('running', save)

    def set_status_error(self, save=True):
        self._set_status('error', save)

    def _has_device(self):
        return hasattr(self, 'device')

    def get_context(self):
        """
        additional context passed to netjsonconfig
        """
        c = {}
        if self._has_device():
            c.update({
                'id': str(self.device.id),
                'key': self.key,
                'name': self.name,
                'mac_address': self.mac_address
            })
        c.update(app_settings.CONTEXT)
        return c

    @property
    def name(self):
        """
        returns device name
        (kept for backward compatibility with pre 0.6 versions)
        """
        if self._has_device():
            return self.device.name
        return str(self.pk)

    @property
    def mac_address(self):
        """
        returns device mac address
        (kept for backward compatibility with pre 0.6 versions)
        """
        return self.device.mac_address

    @property
    def key(self):
        """
        returns device key
        (kept for backward compatibility with pre 0.6 versions)
        """
        return self.device.key
Beispiel #30
0
class DataRequest(BaseRequest, StatusModel):

    DATA_TYPE_CHOICES = Choices(
        ('interpreted', _('Interpreted')),
        ('raw', _('Raw')),
        ('processed', _('Processed')),
        ('other', _('Other')),
    )

    DATASET_USE_CHOICES = Choices(
        ('commercial', _('Commercial')),
        ('noncommercial', _('Non-commercial')),
    )

    REJECTION_REASON_CHOICES = Choices(
        ('reason1', _('Reason 1')),
        ('reason2', _('Reason 2')),
        ('reason3', _('Reason 3')),
    )

    profile_request = models.ForeignKey(ProfileRequest, null=True, blank=True)

    jurisdiction_shapefile = models.ForeignKey(Layer, null=True, blank=True)

    project_summary = models.TextField(_('Summary of Project/Program'),
                                       null=True,
                                       blank=True)

    data_type = TaggableManager(_('data_types'),
                                blank=True,
                                help_text="Data Type Selected")

    data_class_other = models.CharField(_('Requester-specified Data Type'),
                                        null=True,
                                        blank=True,
                                        max_length=50)

    data_type_requested = models.CharField(
        _('Type of Data Requested'),
        choices=DATA_TYPE_CHOICES,
        default=DATA_TYPE_CHOICES.processed,
        max_length=15,
    )

    purpose = models.TextField(_('Purpose of Data'), null=True, blank=True)

    intended_use_of_dataset = models.CharField(
        _('Intended Use of Dataset'),
        choices=DATASET_USE_CHOICES,
        default=DATASET_USE_CHOICES.commercial,
        max_length=15,
    )

    #For place name
    place_name = models.TextField(_('Geolocation name provided by Google'),
                                  null=True,
                                  blank=True)

    area_coverage = models.DecimalField(
        _('Area of Coverage'),
        max_digits=30,
        decimal_places=4,
        help_text=_('Sqr KMs'),
        default=0,
        null=True,
        blank=True,
    )

    #For jurisdiction data size
    juris_data_size = models.FloatField(
        _('Data size of requested jurisdiction in bytes'),
        null=True,
        blank=True,
        default=0)

    #For request letter
    request_letter = models.ForeignKey(Document, null=True, blank=True)

    suc = TaggableManager(_('SUCs'),
                          blank=True,
                          help_text="SUC jurisdictions within this ROI",
                          through=SUCTaggedRequest,
                          related_name="suc_request_tag")

    suc_notified = models.BooleanField(null=False, blank=False, default=False)
    suc_notified_date = models.DateTimeField(null=True, blank=True)
    forwarded = models.BooleanField(null=False, blank=False, default=False)
    forwarded_date = models.DateTimeField(null=True, blank=True)

    class Meta:
        app_label = "datarequests"
        verbose_name = _('Data Request')
        verbose_name_plural = _('Data Requests')
        ordering = ('-created', )

    def __init__(self, *args, **kwargs):
        models.Model.__init__(self, *args, **kwargs)
        #self.status = self.STATUS.unconfirmed

    def __unicode__(self):
        if self.profile_request or self.profile:
            return (_('{} request by {} {}').format(
                self.status,
                unidecode(self.get_first_name()),
                unidecode(self.get_last_name()),
            ))
        else:
            return (_('Data request # {}').format(self.pk))

    def get_absolute_url(self):
        return reverse('datarequests:data_request_detail',
                       kwargs={'pk': self.pk})

    def set_status(self, status, administrator=None):
        self.status = status
        self.administrator = administrator
        self.save()

    def assign_jurisdiction(self):
        # Link shapefile to account
        uj = None
        try:
            uj = UserJurisdiction.objects.get(user=self.profile)
        except ObjectDoesNotExist:
            uj = UserJurisdiction()
            uj.user = self.profile
        uj.jurisdiction_shapefile = self.jurisdiction_shapefile
        uj.save()
        #Add view permission on resource
        resource = self.jurisdiction_shapefile
        perms = resource.get_all_level_info()
        perms["users"][self.profile.username] = ["view_resourcebase"]
        resource.set_permissions(perms)

    def get_first_name(self):
        if self.profile:
            return self.profile.first_name
        if self.profile_request:
            return self.profile_request.first_name

    def get_last_name(self):
        if self.profile:
            return self.profile.last_name
        if self.profile_request:
            return self.profile_request.last_name

    def get_email(self):
        if self.profile:
            return self.profile.email
        if self.profile_request:
            return self.profile_request.email

    def get_contact_number(self):
        if self.profile:
            return self.profile.voice
        if self.profile_request:
            return self.profile_request.contact_number

    def get_organization(self):
        if self.profile:
            return self.profile.organization
        if self.profile_request:
            return self.profile_request.organization

    def get_organization_type(self):
        if self.profile_request:
            return self.profile_request.org_type
        elif self.profile:
            return self.profile.org_type
        else:
            return None

    def to_values_list(self,
                       fields=[
                           'id', 'name', 'email', 'contact_number',
                           'organization', 'project_summary', 'created',
                           'status', 'data_size', 'area_coverage',
                           'has_profile_request'
                       ]):
        out = []
        for f in fields:
            if f is 'id':
                out.append(getattr(self, 'pk'))
            elif f is 'name':
                first_name = unidecode(self.get_first_name())
                last_name = unidecode(self.get_last_name())
                out.append(first_name + " " + last_name)
            elif f is 'email':
                out.append(self.get_email())
            elif f is 'contact_number':
                out.append(self.get_contact_number())
            elif f is 'organization':
                if self.get_organization():
                    out.append(unidecode(self.get_organization()))
                else:
                    out.append(None)
            elif f is 'created':
                created = getattr(self, f)
                out.append(
                    str(created.month) + "/" + str(created.day) + "/" +
                    str(created.year))
            elif f == 'status update':
                date_of_action = getattr(self, 'status_changed')
                if date_of_action:
                    out.append(
                        str(date_of_action.month) + "/" +
                        str(date_of_action.day) + "/" +
                        str(date_of_action.year))
                else:
                    out.append('')
            elif f is 'org_type' or f is 'organization_type':
                out.append(self.get_organization_type())
            elif f is 'has_letter':
                if self.request_letter:
                    out.append('yes')
                else:
                    out.append('no')
            elif f is 'has_shapefile':
                if self.jurisdiction_shapefile:
                    out.append('yes')
                else:
                    out.append('no')
            elif f is 'data_request_status':
                if self.data_request:
                    out.append(data_request.status)
                else:
                    out.append("NA")
            elif f is 'rejection_reason':
                out.append(str(getattr(self, 'rejection_reason')))
            elif f is 'place_name':
                out.append(str(getattr(self, 'place_name')))
            elif f is 'juris_data_size':
                out.append(str(getattr(self, 'juris_data_size')))
            elif f is 'area_coverage':
                out.append(str(getattr(self, 'area_coverage')))
            elif f is 'has_profile_request':
                if self.profile_request:
                    out.append('yes')
                else:
                    out.append('no')
            elif f is 'has_account':
                if self.profile:
                    out.append('yes')
                else:
                    out.append('no')
            else:
                try:
                    val = getattr(self, f)
                    if isinstance(val, unicode):
                        out.append(unidecode(val))
                    else:
                        out.append(str(val))
                except Exception:
                    out.append("NA")

        return out

    def send_email(self, subj, msg, html_msg):
        text_content = msg

        html_content = html_msg

        email_subject = _(subj)

        msg = EmailMultiAlternatives(email_subject, text_content,
                                     settings.DEFAULT_FROM_EMAIL, [
                                         self.get_email(),
                                     ])
        msg.attach_alternative(html_content, "text/html")
        msg.send()

    def send_new_request_notif_to_admins(self, request_type="Data"):
        site = Site.objects.get_current()
        text_content = email_utils.NEW_REQUEST_EMAIL_TEXT.format(
            request_type, settings.BASEURL + self.get_absolute_url())

        html_content = email_utils.NEW_REQUEST_EMAIL_HTML.format(
            request_type, settings.BASEURL + self.get_absolute_url(),
            settings.BASEURL + self.get_absolute_url())

        email_subject = "[LiPAD] A new request has been submitted"
        self.send_email(email_subject, text_content, html_content)

    def send_approval_email(self, username):
        site = Site.objects.get_current()
        profile_url = (reverse('profile_detail', kwargs={'username':
                                                         username}))
        profile_url = iri_to_uri(profile_url)

        text_content = email_utils.DATA_APPROVAL_TEXT.format(
            unidecode(self.get_first_name()),
            local_settings.LIPAD_SUPPORT_MAIL)

        html_content = email_utils.DATA_APPROVAL_HTML.format(
            unidecode(self.get_first_name()),
            local_settings.LIPAD_SUPPORT_MAIL,
            local_settings.LIPAD_SUPPORT_MAIL)

        email_subject = _('[LiPAD] Data Request Status')
        self.send_email(email_subject, text_content, html_content)

    def send_rejection_email(self):

        additional_details = 'Additional Details: ' + str(
            self.additional_rejection_reason)

        text_content = email_utils.DATA_REJECTION_TEXT.format(
            unidecode(self.get_first_name()),
            self.rejection_reason,
            additional_details,
            local_settings.LIPAD_SUPPORT_MAIL,
        )

        html_content = email_utils.DATA_REJECTION_HTML.format(
            unidecode(self.get_first_name()), self.rejection_reason,
            additional_details, local_settings.LIPAD_SUPPORT_MAIL,
            local_settings.LIPAD_SUPPORT_MAIL)

        email_subject = _('[LiPAD] Data Request Status')
        self.send_email(email_subject, text_content, html_content)

    def send_suc_notification(self, suc=None):
        if not suc:
            if len(self.suc.names()) > 1:
                suc = "UPD"
            else:
                suc = self.suc.names()[0]

        suc_contacts = SUC_Contact.objects.filter(
            institution_abrv=suc).exclude(position="Program Leader")
        suc_pl = SUC_Contact.objects.get(institution_abrv=suc,
                                         position="Program Leader")
        organization = ""
        if self.get_organization():
            organization = unidecode(self.get_organization())

        data_classes = ""
        for n in self.data_type.names():
            data_classes += str(n)

        data_classes += ", " + str(self.data_class_other)

        text_content = email_utils.DATA_SUC_REQUEST_NOTIFICATION_TEXT.format(
            suc_pl.salutation,
            suc_pl.name,
            unidecode(self.get_first_name()),
            unidecode(self.get_last_name()),
            organization,
            self.get_email(),
            self.project_summary,
            data_classes,
            self.purpose,
        )

        html_content = email_utils.DATA_SUC_REQUEST_NOTIFICATION_HTML.format(
            suc_pl.salutation,
            suc_pl.name,
            unidecode(self.get_first_name()),
            unidecode(self.get_last_name()),
            organization,
            self.get_email(),
            self.project_summary,
            data_classes,
            self.purpose,
        )

        cc = suc_contacts.values_list('email_address', flat=True)

        email_subject = _('[LiPAD] Data Request Forwarding')

        msg = EmailMultiAlternatives(email_subject,
                                     text_content,
                                     settings.DEFAULT_FROM_EMAIL, [
                                         suc_pl.email_address,
                                     ],
                                     cc=cc)

        msg.attach_alternative(html_content, "text/html")
        msg.send()
        self.suc_notified = True
        self.suc_notified_date = timezone.now()
        self.save()

    def send_jurisdiction(self, suc=None):
        if not suc:
            if len(self.suc.names()) == 1:
                suc = self.suc.names()[0]
            else:
                suc = "UPD"

        suc_contacts = SUC_Contact.objects.filter(
            institution_abrv=suc).exclude(position="Program Leader")
        suc_pl = SUC_Contact.objects.get(institution_abrv=suc,
                                         position="Program Leader")

        text_content = email_utils.DATA_SUC_JURISDICTION_TEXT.format(
            suc_pl.salutation,
            suc_pl.name,
            settings.BASEURL + self.jurisdiction_shapefile.get_absolute_url(),
        )

        html_content = email_utils.DATA_SUC_JURISDICTION_HTML.format(
            suc_pl.salutation,
            suc_pl.name,
            settings.BASEURL + self.jurisdiction_shapefile.get_absolute_url(),
            settings.BASEURL + self.jurisdiction_shapefile.get_absolute_url(),
        )

        cc = suc_contacts.values_list('email_address', flat=True)

        email_subject = _('[LiPAD] Data Request Forwarding')

        msg = EmailMultiAlternatives(email_subject,
                                     text_content,
                                     settings.DEFAULT_FROM_EMAIL, [
                                         suc_pl.email_address,
                                     ],
                                     cc=cc)

        username = suc_pl.username

        if not suc == "UPD":

            resource = self.jurisdiction_shapefile
            perms = resource.get_all_level_info()
            #user_level_perms = getattr(perms, "user", {})
            user_perms = getattr(perms["users"], str(username), [])
            if "view_resourcebase" not in user_perms:
                user_perms.append("view_resourcebase")

            if "download_resourcebase" not in user_perms:
                user_perms.append("download_resourcebase")

            perms["users"][suc_pl.username] = user_perms
            resource.set_permissions(perms)

        msg.attach_alternative(html_content, "text/html")
        msg.send()

        self.forwarded = True
        self.forwarded_date = timezone.now()
        self.save()

    def notify_user_preforward(self, suc=None):
        if not suc:
            if len(self.suc.names()) == 1:
                suc = self.suc.names()[0]
            else:
                suc = "UPD"

        suc_contact = SUC_Contact.objects.get(institution_abrv=suc,
                                              position="Program Leader")

        text_content = email_utils.DATA_USER_PRE_FORWARD_NOTIFICATION_TEXT.format(
            self.get_first_name(), self.get_last_name(),
            suc_contact.institution_full, suc_contact.institution_abrv,
            suc_contact.salutation, suc_contact.name)

        html_content = email_utils.DATA_USER_PRE_FORWARD_NOTIFICATION_HTML.format(
            self.get_first_name(), self.get_last_name(),
            suc_contact.institution_full, suc_contact.institution_abrv,
            suc_contact.salutation, suc_contact.name)

        email_subject = _('[LiPAD] Data Request Forwarding')

        msg = EmailMultiAlternatives(
            email_subject,
            text_content,
            settings.DEFAULT_FROM_EMAIL,
            [
                self.get_email(),
            ],
        )

        msg.attach_alternative(html_content, "text/html")
        msg.send()

    def notify_user_forward(self, suc=None):
        if not suc:
            if len(self.suc.names()) == 1:
                suc = self.suc.names()[0]
            else:
                suc = "UPD"

        text_content = email_utils.DATA_USER_FORWARD_NOTIFICATION_TEXT.format(
            self.get_first_name(), self.get_last_name(), suc)

        html_content = email_utils.DATA_USER_FORWARD_NOTIFICATION_HTML.format(
            self.get_first_name(), self.get_last_name(), suc)

        email_subject = _('[LiPAD] Data Request Forwarding')

        msg = EmailMultiAlternatives(
            email_subject,
            text_content,
            settings.DEFAULT_FROM_EMAIL,
            [
                self.get_email(),
            ],
        )

        msg.attach_alternative(html_content, "text/html")
        msg.send()