class Bid (models.Model): price = models.DecimalField(max_digits=10 ,decimal_places=2, default=0, validators=[MinValueValidator(0)]) buyer = models.ForeignKey(User, on_delete=CASCADE, related_name="buyers") listing = models.ForeignKey(Listing, on_delete=CASCADE, related_name="bids") def __str__(self): return f"{self.buyer} Plaatst een bod op product: {self.listing.product} van {self.price} euro"
class Advanced(Model): adv_consolemenu = models.BooleanField( verbose_name=_("Enable Console Menu"), default=False, ) adv_serialconsole = models.BooleanField( verbose_name=_("Use Serial Console"), default=False, ) adv_serialport = models.CharField( max_length=120, default="0x2f8", help_text=_( "Set this to match your serial port address (0x3f8, 0x2f8, etc.)"), verbose_name=_("Serial Port Address"), choices=choices.SERIAL_CHOICES(), ) adv_serialspeed = models.CharField( max_length=120, choices=choices.SERIAL_SPEED, default="9600", help_text=_("Set this to match your serial port speed"), verbose_name=_("Serial Port Speed")) adv_consolescreensaver = models.BooleanField( verbose_name=_("Enable screen saver"), default=False, ) adv_powerdaemon = models.BooleanField( verbose_name=_("Enable powerd (Power Saving Daemon)"), default=False, ) adv_swapondrive = models.IntegerField( validators=[MinValueValidator(0)], verbose_name=_( "Swap size on each drive in GiB, affects new disks " "only. Setting this to 0 disables swap creation completely " "(STRONGLY DISCOURAGED)."), default=2, ) adv_consolemsg = models.BooleanField( verbose_name=_("Show console messages in the footer"), default=True, ) adv_traceback = models.BooleanField( verbose_name=_("Show tracebacks in case of fatal errors"), default=True, ) adv_advancedmode = models.BooleanField( verbose_name=_("Show advanced fields by default"), default=False, help_text=_( "By default only essential fields are shown. Fields considered " "advanced can be displayed through the Advanced Mode button."), ) adv_autotune = models.BooleanField( verbose_name=_("Enable autotune"), default=False, help_text=_( "Attempt to automatically tune the network and ZFS system control " "variables based on memory available."), ) adv_debugkernel = models.BooleanField( verbose_name=_("Enable debug kernel"), default=False, help_text=_( "The kernel built with debug symbols will be booted instead."), ) adv_uploadcrash = models.BooleanField( verbose_name=_( "Enable automatic upload of kernel crash dumps and daily telemetry" ), default=True, ) adv_anonstats = models.BooleanField( verbose_name=_("Enable report anonymous statistics"), default=True, editable=False, ) adv_anonstats_token = models.TextField( blank=True, editable=False, ) adv_motd = models.TextField( max_length=1024, verbose_name=_("MOTD banner"), default='Welcome', ) adv_boot_scrub = models.IntegerField( default=35, editable=False, ) adv_periodic_notifyuser = UserField( default="root", verbose_name=_("Periodic Notification User"), help_text= _("If you wish periodic emails to be sent to a different email address than " "the alert emails are set to (root) set an email address for a user and " "select that user in the dropdown.")) adv_graphite = models.CharField( max_length=120, default="", blank=True, verbose_name=_("Remote Graphite Server Hostname"), help_text=_( "A hostname or IP here will be used as the destination to send collectd " "data to using the graphite plugin to collectd.")) class Meta: verbose_name = _("Advanced") class FreeAdmin: deletable = False
class Settings(Model): stg_guiprotocol = models.CharField(max_length=120, choices=choices.PROTOCOL_CHOICES, default="http", verbose_name=_("Protocol")) stg_guicertificate = models.ForeignKey( "Certificate", verbose_name=_("Certificate"), limit_choices_to={'cert_CSR__isnull': True}, on_delete=models.SET_NULL, blank=True, null=True) stg_guiaddress = models.CharField(max_length=120, blank=True, default='0.0.0.0', verbose_name=_("WebGUI IPv4 Address")) stg_guiv6address = models.CharField(max_length=120, blank=True, default='::', verbose_name=_("WebGUI IPv6 Address")) stg_guiport = models.IntegerField( verbose_name=_("WebGUI HTTP Port"), validators=[MinValueValidator(1), MaxValueValidator(65535)], default=80, ) stg_guihttpsport = models.IntegerField( verbose_name=_("WebGUI HTTPS Port"), validators=[MinValueValidator(1), MaxValueValidator(65535)], default=443, ) stg_guihttpsredirect = models.BooleanField( verbose_name=_('WebGUI HTTP -> HTTPS Redirect'), default=True, help_text=_( 'Redirect HTTP (port 80) to HTTPS when only the HTTPS protocol is ' 'enabled'), ) stg_language = models.CharField(max_length=120, choices=settings.LANGUAGES, default="en", verbose_name=_("Language")) stg_kbdmap = models.CharField( max_length=120, choices=choices.KBDMAP_CHOICES(), verbose_name=_("Console Keyboard Map"), blank=True, ) stg_timezone = models.CharField(max_length=120, choices=choices.TimeZoneChoices(), default="America/Los_Angeles", verbose_name=_("Timezone")) stg_sysloglevel = models.CharField( max_length=120, choices=choices.SYS_LOG_LEVEL, default="f_info", verbose_name=_("Syslog level"), help_text=_("Specifies which messages will be logged by " "server. INFO and VERBOSE log transactions that " "server performs on behalf of the client. " "f_is_debug specify higher levels of debugging output. " "The default is f_info."), ) stg_syslogserver = models.CharField( default='', blank=True, max_length=120, verbose_name=_("Syslog server"), help_text=_( "Specifies the server and port syslog messages " "will be sent to. The accepted format is hostname:port " "or ip:port, if :port is not specified it will default to " "port 514 (this field currently only takes IPv4 addresses)"), ) stg_wizardshown = models.BooleanField( editable=False, default=False, ) stg_pwenc_check = models.CharField( max_length=100, editable=False, ) class Meta: verbose_name = _("General")
class ConsultaMedica(models.Model): fk_consulta_expediente = models.ForeignKey(Expediente, null=False, blank=False) fecha = models.DateField('Fecha', auto_now_add=True) hora = models.TimeField('Hora de Consulta', blank=False, null=False) peso = models.DecimalField('Peso', max_digits=5, decimal_places=2, blank=False, null=False, validators=[MinValueValidator(0)]) talla = models.DecimalField('Talla', max_digits=5, decimal_places=2, blank=False, null=False, validators=[MinValueValidator(0)]) ta = models.CharField('Tensión arterial', max_length=6, blank=False, null=False, help_text='Tensión arterial ###/##') fc = models.DecimalField('Frecuencia cardíaca', max_digits=5, decimal_places=2, blank=False, null=False, help_text='Frecuencia cardíaca', validators=[MinValueValidator(0)]) problema = models.CharField('Historia del problema', max_length=256, blank=False, null=False, help_text='Motivo de consulta') diagnostico = models.CharField('Diagnostico', max_length=256, blank=False, null=False) prox_control = models.DateTimeField(blank=True, null=True) precio_consulta = models.DecimalField('Precio de la Consulta', max_digits=5, decimal_places=2, blank=False, null=False, validators=[MinValueValidator(0)]) def __str__(self): return '{}: {}'.format('Consulta del expediente', self.fk_consulta_expediente) def get_edad(self): diff = (self.fecha - self.fk_consulta_expediente.paciente.fecha_nacimiento).days edad = str(int(diff / 365)) cantidad_tiempo = 'años' if edad == '0': edad = str(int(diff / 12)) cantidad_tiempo = 'meses' return '{} {}'.format(self.edad, self.cantidad_tiempo) class Meta: ordering = ["fecha", "hora"] verbose_name = 'Cita Médica' verbose_name_plural = 'Citas Médicas'
class Application(models.Model): # META uuid = models.UUIDField(default=uuid.uuid4, editable=False) user = models.OneToOneField(User, primary_key=True) invited_by = models.ForeignKey(User, related_name='invited_applications', blank=True, null=True) # When was the application submitted submission_date = models.DateTimeField(default=timezone.now) # When was the last status update status_update_date = models.DateTimeField(blank=True, null=True) # Application status status = models.CharField(choices=STATUS, default=APP_PENDING, max_length=2) # ABOUT YOU # Population analysis, optional gender = models.CharField(max_length=20, choices=GENDERS, default=NO_ANSWER) # Personal data (asking here because we don't want to ask birthday) under_age = models.BooleanField() phone_number = models.CharField(blank=True, null=True, max_length=16, validators=[RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: \ '+#########'. Up to 15 digits allowed.")]) # Where is this person coming from? origin = models.CharField(max_length=300) # Is this your first hackathon? first_timer = models.BooleanField() # Why do you want to come to X? description = models.TextField(max_length=500) # Explain a little bit what projects have you done lately projects = models.TextField(max_length=500, blank=True, null=True) # Reimbursement reimb = models.BooleanField(default=False) reimb_amount = models.FloatField(blank=True, null=True, validators=[ MinValueValidator(0, "Negative? Really? Please put a positive value")]) # Random lenny face lennyface = models.CharField(max_length=300, default='-.-') # Giv me a resume here! resume = models.FileField(upload_to='resumes', null=True, blank=True) # University graduation_year = models.IntegerField(choices=YEARS, default=DEFAULT_YEAR) university = models.CharField(max_length=300) degree = models.CharField(max_length=300) # URLs github = models.URLField(blank=True, null=True) devpost = models.URLField(blank=True, null=True) linkedin = models.URLField(blank=True, null=True) site = models.URLField(blank=True, null=True) # Info for swag and food diet = models.CharField(max_length=300, choices=DIETS, default=D_NONE) other_diet = models.CharField(max_length=600, blank=True, null=True) tshirt_size = models.CharField(max_length=3, default=DEFAULT_TSHIRT_SIZE, choices=TSHIRT_SIZES) @classmethod def annotate_vote(cls, qs): return qs.annotate(vote_avg=Avg('vote__calculated_vote')) @property def uuid_str(self): return str(self.uuid) def get_soft_status_display(self): text = self.get_status_display() if "Not" in text or 'Rejected' in text: return "Pending" return text def __str__(self): return self.user.email def save(self, **kwargs): self.status_update_date = timezone.now() super(Application, self).save(**kwargs) def invite(self, user): # We can re-invite someone invited if self.status in [APP_CONFIRMED, APP_ATTENDED]: raise ValidationError('Application has already answered invite. ' 'Current status: %s' % self.status) self.status = APP_INVITED if not self.invited_by: self.invited_by = user self.last_invite = timezone.now() self.last_reminder = None self.status_update_date = timezone.now() self.save() def last_reminder(self): if self.status != APP_INVITED: raise ValidationError('Reminder can\'t be sent to non-pending ' 'applications') self.status_update_date = timezone.now() self.status = APP_LAST_REMIDER self.save() def expire(self): self.status_update_date = timezone.now() self.status = APP_EXPIRED self.save() def reject(self, request): if self.status == APP_ATTENDED: raise ValidationError('Application has already attended. ' 'Current status: %s' % self.status) self.status = APP_REJECTED self.status_update_date = timezone.now() self.save() def confirm(self): if self.status == APP_CANCELLED: raise ValidationError('This invite has been cancelled.') elif self.status == APP_EXPIRED: raise ValidationError('Unfortunately your invite has expired.') elif self.status in [APP_INVITED, APP_LAST_REMIDER]: self.status = APP_CONFIRMED self.status_update_date = timezone.now() self.save() elif self.status in [APP_CONFIRMED, APP_ATTENDED]: return None else: raise ValidationError('Unfortunately his application hasn\'t been ' 'invited [yet]') def cancel(self): if not self.can_be_cancelled(): raise ValidationError('Application can\'t be cancelled. Current ' 'status: %s' % self.status) if self.status != APP_CANCELLED: self.status = APP_CANCELLED self.status_update_date = timezone.now() self.save() reimb = getattr(self.user, 'reimbursement', None) if reimb: reimb.delete() def check_in(self): self.status = APP_ATTENDED self.status_update_date = timezone.now() self.save() def is_confirmed(self): return self.status == APP_CONFIRMED def is_cancelled(self): return self.status == APP_CANCELLED def answered_invite(self): return self.status in [APP_CONFIRMED, APP_CANCELLED, APP_ATTENDED] def needs_action(self): return self.status == APP_INVITED def is_pending(self): return self.status == APP_PENDING def can_be_edit(self): return self.status == APP_PENDING and not self.vote_set.exists() and not utils.is_app_closed() def is_invited(self): return self.status == APP_INVITED def is_expired(self): return self.status == APP_EXPIRED def is_rejected(self): return self.status == APP_REJECTED def is_attended(self): return self.status == APP_ATTENDED def is_last_reminder(self): return self.status == APP_LAST_REMIDER def can_be_cancelled(self): return self.status == APP_CONFIRMED or self.status == APP_INVITED or self.status == APP_LAST_REMIDER def can_confirm(self): return self.status in [APP_INVITED, APP_LAST_REMIDER]
class MealItem(models.Model): ''' An item (component) of a meal ''' meal = models.ForeignKey(Meal, verbose_name=_('Nutrition plan'), editable=False, on_delete=models.CASCADE) ingredient = models.ForeignKey(Ingredient, verbose_name=_('Ingredient'), on_delete=models.CASCADE) weight_unit = models.ForeignKey(IngredientWeightUnit, verbose_name=_('Weight unit'), null=True, blank=True, on_delete=models.CASCADE) order = models.IntegerField(verbose_name=_('Order'), blank=True, editable=False) amount = models.DecimalField(decimal_places=2, max_digits=6, verbose_name=_('Amount'), validators=[MinValueValidator(1), MaxValueValidator(1000)]) def __str__(self): ''' Return a more human-readable representation ''' return u"{0}g ingredient {1}".format(self.amount, self.ingredient_id) def get_owner_object(self): ''' Returns the object that has owner information ''' return self.meal.plan def get_unit_type(self): ''' Returns the type of unit used: - a value in grams - a 'human' unit like 'a cup' or 'a slice' ''' if self.weight_unit: return MEALITEM_WEIGHT_UNIT else: return MEALITEM_WEIGHT_GRAM def get_nutritional_values(self, use_metric=True): ''' Sums the nutrional info for the ingredient in the MealItem :param use_metric Flag that controls the units used ''' nutritional_info = {'energy': 0, 'protein': 0, 'carbohydrates': 0, 'carbohydrates_sugar': 0, 'fat': 0, 'fat_saturated': 0, 'fibres': 0, 'sodium': 0} # Calculate the base weight of the item if self.get_unit_type() == MEALITEM_WEIGHT_GRAM: item_weight = self.amount else: item_weight = (self.amount * self.weight_unit.amount * self.weight_unit.gram) nutritional_info['energy'] += self.ingredient.energy * item_weight / 100 nutritional_info['protein'] += self.ingredient.protein * item_weight / 100 nutritional_info['carbohydrates'] += self.ingredient.carbohydrates * item_weight / 100 if self.ingredient.carbohydrates_sugar: nutritional_info['carbohydrates_sugar'] += self.ingredient.carbohydrates_sugar \ * item_weight / 100 nutritional_info['fat'] += self.ingredient.fat * item_weight / 100 if self.ingredient.fat_saturated: nutritional_info['fat_saturated'] += self.ingredient.fat_saturated * item_weight / 100 if self.ingredient.fibres: nutritional_info['fibres'] += self.ingredient.fibres * item_weight / 100 if self.ingredient.sodium: nutritional_info['sodium'] += self.ingredient.sodium * item_weight / 100 # If necessary, convert weight units if not use_metric: for key, value in nutritional_info.items(): # Energy is not a weight! if key == 'energy': continue # Everything else, to ounces nutritional_info[key] = AbstractWeight(value, 'g').oz # Only 2 decimal places, anything else doesn't make sense for i in nutritional_info: nutritional_info[i] = Decimal(nutritional_info[i]).quantize(TWOPLACES) return nutritional_info
class InfantBirthData(InfantCrfModel): """ A model completed by the user on the infant's birth exam. """ infant_gender = models.CharField( max_length=6, choices=GENDER, verbose_name="What is the gender of the infant?", help_text="") weight_kg = models.DecimalField( max_digits=3, decimal_places=2, verbose_name="What was the infant's birth weight? ", help_text="Measured in Kilograms (kg)") infant_length = models.DecimalField( max_digits=4, decimal_places=2, validators=[MinValueValidator(0), MaxValueValidator(90)], verbose_name="What was the infant's length at birth? ", help_text="Measured in centimeters, (cm)") head_circumference = models.DecimalField( max_digits=4, decimal_places=2, validators=[MinValueValidator(0), MaxValueValidator(41)], verbose_name="What was the head circumference in centimeters? ", help_text="Measured in centimeters, (cm)") apgar_score = models.CharField( max_length=3, choices=YES_NO, verbose_name="Was Apgar Score performed? ", help_text="If 'No' go to question 10. Otherwise continue") apgar_score_min_1 = models.IntegerField( verbose_name="At 1 minute: ", help_text="", blank=True, null=True, validators=[MaxValueValidator(10), MinValueValidator(0)]) apgar_score_min_5 = models.IntegerField( verbose_name="At 5 minutes: ", help_text="", blank=True, null=True, validators=[MaxValueValidator(10), MinValueValidator(0)]) apgar_score_min_10 = models.IntegerField( verbose_name="At 10 minutes: ", help_text="", blank=True, null=True, validators=[MaxValueValidator(10), MinValueValidator(0)]) congenital_anomalities = models.CharField( max_length=3, choices=YES_NO, verbose_name="Were any congenital anomalies identified? ", help_text="If 'Yes' please complete the Congenital Anomalies Form", ) other_birth_info = models.TextField( max_length=250, verbose_name="Other birth information ", blank=True, null=True) class Meta: app_label = 'td_infant' verbose_name = "Infant Birth: Data" verbose_name_plural = "Infant Birth: Data"
class OrderedItem(models.Model, ItemLine): delivery_group = models.ForeignKey(DeliveryGroup, related_name='items', editable=False, verbose_name=pgettext_lazy( 'Ordered item field', 'delivery group')) product = models.ForeignKey(Product, blank=True, null=True, related_name='+', on_delete=models.SET_NULL, verbose_name=pgettext_lazy( 'Ordered item field', 'product')) product_name = models.CharField(pgettext_lazy('Ordered item field', 'product name'), max_length=128) product_sku = models.CharField(pgettext_lazy('Ordered item field', 'sku'), max_length=32) stock_location = models.CharField(pgettext_lazy('OrderedItem field', 'stock location'), max_length=100, default='') stock = models.ForeignKey('product.Stock', on_delete=models.SET_NULL, null=True, verbose_name=pgettext_lazy( 'Ordered item field', 'stock')) quantity = models.IntegerField( pgettext_lazy('Ordered item field', 'quantity'), validators=[MinValueValidator(0), MaxValueValidator(999)]) unit_price_net = models.DecimalField(pgettext_lazy('Ordered item field', 'unit price (net)'), max_digits=12, decimal_places=4) unit_price_gross = models.DecimalField(pgettext_lazy( 'Ordered item field', 'unit price (gross)'), max_digits=12, decimal_places=4) objects = OrderedItemManager() class Meta: verbose_name = pgettext_lazy('Ordered item model', 'Ordered item') verbose_name_plural = pgettext_lazy('Ordered item model', 'Ordered items') def __str__(self): return self.product_name def get_price_per_item(self, **kwargs): return Price(net=self.unit_price_net, gross=self.unit_price_gross, currency=settings.DEFAULT_CURRENCY) def get_quantity(self): return self.quantity def change_quantity(self, new_quantity): order = self.delivery_group.order self.quantity = new_quantity self.save() if not self.delivery_group.get_total_quantity(): self.delivery_group.delete() if not order.get_items(): order.change_status('cancelled')
'apptemplates.Loader', 'django.template.loaders.eggs.Loader', ) #Engrade # http://ww7.engrade.com/api/key.php ENGRADE_APIKEY = '' ENGRADE_LOGIN = '' ENGRADE_PASSWORD = '' # School UID (admin must be connected to school) ENGRADE_SCHOOLID = '' # Global date validators, to help prevent data entry errors import datetime from django.core.validators import MinValueValidator # Could use MaxValueValidator too DATE_VALIDATORS = [MinValueValidator(datetime.date(1970, 1, 1))] # Unix epoch! TEMPLATE_CONTEXT_PROCESSORS = ( "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.core.context_processors.static", "django.contrib.messages.context_processors.messages", "django.core.context_processors.request", 'noticeapp.context_processors.processor', ) # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to # the site admins on every HTTP 500 error when DEBUG=False. # See http://docs.djangoproject.com/en/dev/topics/logging for
class URLInputForm(forms.Form, BaseFormFieldPluginForm): """Form for ``URLPlugin``.""" plugin_data_fields = [ ("label", ""), ("name", ""), ("help_text", ""), ("initial", ""), ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] label = forms.CharField( label=_("Question text"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) name = forms.CharField( label=_("Name"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) help_text = forms.CharField( label=_("Help text"), required=False, widget=forms.widgets.Textarea( attrs={'class': theme.form_element_html_class} ) ) initial = forms.URLField( label=_("Initial"), required=False, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) max_length = forms.IntegerField( label=_("Max length"), required=True, widget=NumberInput(attrs={'class': theme.form_element_html_class, 'min': str(DEFAULT_MIN_LENGTH)}), initial=DEFAULT_MAX_LENGTH, validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), required=False, widget=forms.widgets.CheckboxInput( attrs={'class': theme.form_element_checkbox_html_class} ) ) placeholder = forms.CharField( label=_("Placeholder"), required=False, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) ) def clean(self): super(URLInputForm, self).clean() max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) if self.cleaned_data['initial']: len_initial = len(self.cleaned_data['initial']) if len_initial > max_length: self.add_error( 'initial', _("Ensure this value has at most {0} characters " "(it has {1}).".format(max_length, len_initial)) )
class RegexInputForm(forms.Form, BaseFormFieldPluginForm): """Form for ``RegexInputPlugin``.""" plugin_data_fields = [ ("label", ""), ("name", ""), ("help_text", ""), ("initial", ""), ("regex", ""), ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] label = forms.CharField( label=_("Label"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class})) name = forms.CharField(label=_("Name"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class})) help_text = forms.CharField( label=_("Help text"), required=False, widget=forms.widgets.Textarea( attrs={'class': theme.form_element_html_class})) regex = forms.RegexField( label=_("Regex"), required=True, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class}), regex="", help_text=_("Enter a valid regular expression. A couple of common " "examples are listed below.<br/>" "- Allow a single digit from 1 to 9 (example value 6): " "<code>^[1-9]$</code><br/>" "- Allow any combination of characters from a to z, " "including capitals (example value abcXYZ):" "<code>^([a-zA-Z])+$</code><br/>" "- Allow a hex value (example value #a5c125:" "<code>^#?([a-f0-9]{6}|[a-f0-9]{3})$</code><br/>")) initial = forms.CharField( label=_("Initial"), required=False, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class})) max_length = forms.IntegerField( label=_("Max length"), required=True, widget=NumberInput(attrs={ 'class': theme.form_element_html_class, 'min': str(DEFAULT_MIN_LENGTH) }), initial=DEFAULT_MAX_LENGTH, validators=[MinValueValidator(DEFAULT_MIN_LENGTH)]) required = forms.BooleanField( label=_("Required"), required=False, widget=forms.widgets.CheckboxInput( attrs={'class': theme.form_element_checkbox_html_class})) placeholder = forms.CharField( label=_("Placeholder"), required=False, widget=forms.widgets.TextInput( attrs={'class': theme.form_element_html_class})) def clean(self): super(RegexInputForm, self).clean() max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) if self.cleaned_data['initial']: len_initial = len(self.cleaned_data['initial']) if len_initial > max_length: self.add_error( 'initial', _("Ensure this value has at most {0} characters " "(it has {1}).".format(max_length, len_initial)))
class User(AbstractUser): TYPE_VALUE_MAP = { "Doctor": 5, "Staff": 10, "Patient": 15, "Volunteer": 20, "DistrictLabAdmin": 25, "DistrictAdmin": 30, "StateLabAdmin": 35, } TYPE_CHOICES = [(value, name) for name, value in TYPE_VALUE_MAP.items()] user_type = models.IntegerField(choices=TYPE_CHOICES, blank=False) local_body = models.ForeignKey(LocalBody, on_delete=models.PROTECT, null=True, blank=True) district = models.ForeignKey(District, on_delete=models.PROTECT, null=True, blank=True) state = models.ForeignKey(State, on_delete=models.PROTECT, null=True, blank=True) phone_number = models.CharField(max_length=14, validators=[phone_number_regex]) gender = models.IntegerField(choices=GENDER_CHOICES, blank=False) age = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(100)]) skill = models.ForeignKey("Skill", on_delete=models.SET_NULL, null=True, blank=True) verified = models.BooleanField(default=False) deleted = models.BooleanField(default=False) REQUIRED_FIELDS = [ "user_type", "email", "phone_number", "age", "gender", "district", ] objects = CustomUserManager() @staticmethod def has_read_permission(request): return True def has_object_read_permission(self, request): return request.user.is_superuser or self == request.user @staticmethod def has_write_permission(request): try: return request.data["user_type"] <= User.TYPE_VALUE_MAP["Volunteer"] except TypeError: return User.TYPE_VALUE_MAP[request.data["user_type"]] <= User.TYPE_VALUE_MAP["Volunteer"] except KeyError: # No user_type passed, the view shall raise a 400 return True def has_object_write_permission(self, request): return request.user.is_superuser def has_object_update_permission(self, request): if request.user.is_superuser: return True if not self == request.user: return False if (request.data.get("district") or request.data.get("state")) and self.user_type >= User.TYPE_VALUE_MAP[ "DistrictLabAdmin" ]: # District/state admins shouldn't be able to edit their district/state, that'll practically give them # access to everything return False return True def delete(self, *args, **kwargs): self.deleted = True self.save() def get_absolute_url(self): return reverse("users:detail", kwargs={"username": self.username}) def save(self, *args, **kwargs) -> None: """ While saving, if the local body is not null, then district will be local body's district Overriding save will help in a collision where the local body's district and district fields are different. """ if self.local_body is not None: self.district = self.local_body.district if self.district is not None: self.state = self.district.state super().save(*args, **kwargs)
class Project(BaseStreamForm, AccessFormData, models.Model): lead = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL, related_name='lead_projects') submission = models.OneToOneField("funds.ApplicationSubmission", on_delete=models.CASCADE) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name='owned_projects') title = models.TextField() contact_legal_name = models.TextField(_('Person or Organisation name'), default='') contact_email = models.TextField(_('Email'), default='') contact_address = models.TextField(_('Address'), default='') contact_phone = models.TextField(_('Phone'), default='') value = models.DecimalField( default=0, max_digits=10, decimal_places=2, validators=[MinValueValidator(decimal.Decimal('0.01'))], ) proposed_start = models.DateTimeField(_('Proposed Start Date'), null=True) proposed_end = models.DateTimeField(_('Proposed End Date'), null=True) status = models.TextField(choices=PROJECT_STATUS_CHOICES, default=COMMITTED) form_data = JSONField(encoder=StreamFieldDataEncoder, default=dict) form_fields = StreamField(FormFieldsBlock(), null=True) # tracks read/write state of the Project is_locked = models.BooleanField(default=False) # tracks updates to the Projects fields via the Project Application Form. user_has_updated_details = models.BooleanField(default=False) activities = GenericRelation( 'activity.Activity', content_type_field='source_content_type', object_id_field='source_object_id', related_query_name='project', ) created_at = models.DateTimeField(auto_now_add=True) sent_to_compliance_at = models.DateTimeField(null=True) objects = ProjectQuerySet.as_manager() def __str__(self): return self.title @property def status_display(self): return self.get_status_display() def get_address_display(self): try: address = json.loads(self.contact_address) except json.JSONDecodeError: return '' else: return ', '.join( address.get(field) for field in ADDRESS_FIELDS_ORDER if address.get(field)) @classmethod def create_from_submission(cls, submission): """ Create a Project from the given submission. Returns a new Project or the given ApplicationSubmissions existing Project. """ if not settings.PROJECTS_ENABLED: logging.error( f'Tried to create a Project for Submission ID={submission.id} while projects are disabled' ) return None # OneToOne relations on the targetted model cannot be accessed without # an exception when the relation doesn't exist (is None). Since we # want to fail fast here, we can use hasattr instead. if hasattr(submission, 'project'): return submission.project return Project.objects.create( submission=submission, title=submission.title, user=submission.user, contact_email=submission.user.email, contact_legal_name=submission.user.full_name, contact_address=submission.form_data.get('address', ''), value=submission.form_data.get('value', 0), ) @property def start_date(self): # Assume project starts when OTF are happy with the first signed contract first_approved_contract = self.contracts.approved().order_by( 'approved_at').first() if not first_approved_contract: return None return first_approved_contract.approved_at.date() @property def end_date(self): # Aiming for the proposed end date as the last day of the project # If still ongoing assume today is the end return max( self.proposed_end.date(), timezone.now().date(), ) def paid_value(self): return self.payment_requests.paid_value() def unpaid_value(self): return self.payment_requests.unpaid_value() def clean(self): if self.proposed_start is None: return if self.proposed_end is None: return if self.proposed_start > self.proposed_end: raise ValidationError( _('Proposed End Date must be after Proposed Start Date')) def save(self, *args, **kwargs): creating = not self.pk if creating: files = self.extract_files() else: self.process_file_data(self.form_data) super().save(*args, **kwargs) if creating: self.process_file_data(files) def editable_by(self, user): if self.editable: return True # Approver can edit it when they are approving return user.is_approver and self.can_make_approval @property def editable(self): if self.status not in (CONTRACTING, COMMITTED): return True # Someone has approved the project - consider it locked while with contracting if self.approvals.exists(): return False # Someone must lead the project to make changes return self.lead and not self.is_locked def get_absolute_url(self): if settings.PROJECTS_ENABLED: return reverse('apply:projects:detail', args=[self.id]) return '#' @property def can_make_approval(self): return self.is_locked and self.status == COMMITTED def can_request_funding(self): """ Should we show this Project's funding block? """ return self.status in (CLOSING, IN_PROGRESS) @property def can_send_for_approval(self): """ Wrapper to expose the pending approval state We don't want to expose a "Sent for Approval" state to the end User so we infer it from the current status being "Comitted" and the Project being locked. """ correct_state = self.status == COMMITTED and not self.is_locked return correct_state and self.user_has_updated_details @property def requires_approval(self): return not self.approvals.exists() def get_missing_document_categories(self): """ Get the number of documents required to meet each DocumentCategorys minimum """ # Count the number of documents in each category currently existing_categories = DocumentCategory.objects.filter( packet_files__project=self) counter = collections.Counter(existing_categories) # Find the difference between the current count and recommended count for category in DocumentCategory.objects.all(): current_count = counter[category] difference = category.recommended_minimum - current_count if difference > 0: yield { 'category': category, 'difference': difference, } @property def is_in_progress(self): return self.status == IN_PROGRESS def send_to_compliance(self, request): """Notify Compliance about this Project.""" messenger( MESSAGES.SENT_TO_COMPLIANCE, request=request, user=request.user, source=self, ) self.sent_to_compliance_at = timezone.now() self.save(update_fields=['sent_to_compliance_at'])
class PaymentRequest(models.Model): project = models.ForeignKey("Project", on_delete=models.CASCADE, related_name="payment_requests") by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="payment_requests") requested_value = models.DecimalField( default=0, max_digits=10, decimal_places=2, validators=[MinValueValidator(decimal.Decimal('0.01'))], ) paid_value = models.DecimalField( max_digits=10, decimal_places=2, validators=[MinValueValidator(decimal.Decimal('0.01'))], null=True) invoice = models.FileField(upload_to=invoice_path, storage=PrivateStorage()) requested_at = models.DateTimeField(auto_now_add=True) date_from = models.DateTimeField() date_to = models.DateTimeField() comment = models.TextField(blank=True) status = models.TextField(choices=REQUEST_STATUS_CHOICES, default=SUBMITTED) objects = PaymentRequestQueryset.as_manager() def __str__(self): return f'Payment requested for {self.project}' @property def has_changes_requested(self): return self.status == CHANGES_REQUESTED @property def status_display(self): return self.get_status_display() def can_user_delete(self, user): if user.is_applicant: if self.status in (SUBMITTED, CHANGES_REQUESTED): return True if user.is_apply_staff: if self.status in {SUBMITTED}: return True return False def can_user_edit(self, user): if user.is_applicant: if self.status in {SUBMITTED, CHANGES_REQUESTED}: return True if user.is_apply_staff: if self.status in {SUBMITTED}: return True return False def can_user_change_status(self, user): if not user.is_apply_staff: return False # Users can't change status if self.status in {PAID, DECLINED}: return False return True @property def value(self): return self.paid_value or self.requested_value def get_absolute_url(self): return reverse('apply:projects:payments:detail', args=[self.pk])
from django.db import models from django.core.exceptions import ObjectDoesNotExist from django.core.validators import MaxValueValidator, MinValueValidator from django.db.models.signals import post_save, post_delete from .signals import ( post_reporting_signal, new_post_like_signal, inactive_post_like_signal ) min_max_range = [ MinValueValidator(0), MaxValueValidator(20) ] def uploads_path(instance, filename): ''' Function to organize the upload directory this way, every file is organized by username and management is a lot faster ''' return '/'.join(['uploads', 'posts', filename]) class UserLikesPost(models.Model): user = models.ForeignKey('users.User', related_name='user_likes') post = models.ForeignKey('posts.Post', related_name='user_likes') created_at = models.DateTimeField(auto_now_add=True) class Meta:
class SubmittedPriceList(models.Model): CONTRACTOR_SITE_CHOICES = [ ('Customer', 'Customer/Offsite'), ('Contractor', 'Contractor/Onsite'), ('Both', 'Both'), ] STATUS_UNREVIEWED = 0 STATUS_APPROVED = 1 STATUS_RETIRED = 2 STATUS_REJECTED = 3 STATUS_CHOICES = ( (STATUS_UNREVIEWED, 'unreviewed'), (STATUS_APPROVED, 'approved'), (STATUS_RETIRED, 'retired'), (STATUS_REJECTED, 'rejected'), ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) # This is the equivalent of Contract.idv_piid. contract_number = models.CharField( max_length=128, help_text='This should be the full contract number, e.g. GS-XXX-XXXX.', validators=[ RegexValidator( regex=r'^[a-zA-Z0-9-_]+$', message='Please use only letters, numbers, and dashes (-).') ], ) vendor_name = models.CharField(max_length=128) schedule = models.CharField(max_length=128) is_small_business = models.BooleanField() contractor_site = models.CharField(verbose_name='Worksite', choices=CONTRACTOR_SITE_CHOICES, max_length=128) contract_start = models.DateField( null=True, blank=True, ) contract_end = models.DateField( null=True, blank=True, ) escalation_rate = models.FloatField( verbose_name='escalation rate (%)', validators=[ MinValueValidator(MIN_ESCALATION_RATE), MaxValueValidator(MAX_ESCALATION_RATE) ]) submitter = models.ForeignKey(User) status = models.IntegerField(choices=STATUS_CHOICES, default=STATUS_UNREVIEWED) status_changed_by = models.ForeignKey(User, related_name='+') status_changed_at = models.DateTimeField() uploaded_filename = models.CharField( max_length=128, help_text=('Name of the file that was uploaded, as it was called on ' 'the uploader\'s system. For display purposes only.')) serialized_gleaned_data = models.TextField( help_text=('The JSON-serialized data from the upload, including ' 'information about any rows that failed validation.')) def add_row(self, **kwargs): row = SubmittedPriceListRow(**kwargs) row.price_list = self row.save() return row def get_schedule_title(self): # We're importing here to avoid a circular import. Kinda icky. from .schedules.registry import get_class return get_class(self.schedule).title def get_business_size_string(self): # 'S' means 'Small Business' and 'O' means 'Other' if self.is_small_business: return 'S' return 'O' def _change_status(self, status, user): self.status = status self.status_changed_at = timezone.now() self.status_changed_by = user status_name = self.STATUS_CHOICES[status][1] logger.info(f'Price list with id {self.id} has been set to ' f'{status_name} by user id {user.id} ({user.email})') def approve(self, user): ''' Approve this SubmittedPriceList. This causes its rows of pricing data to be converted to Contract models, which are then accessible via CALC's API and in the Data Explorer. ''' self._change_status(self.STATUS_APPROVED, user) for row in self.rows.filter(is_muted=False): if row.contract_model is not None: raise AssertionError() contract = Contract( idv_piid=self.contract_number, contract_start=self.contract_start, contract_end=self.contract_end, vendor_name=self.vendor_name, labor_category=row.labor_category, education_level=row.education_level, min_years_experience=row.min_years_experience, contractor_site=self.contractor_site, schedule=self.get_schedule_title(), business_size=self.get_business_size_string(), sin=row.sin, ) contract.adjust_contract_year() # Assuming the rate in the price list is the 'base rate' # Escalate the hourly_rate_yearX fields contract.escalate_hourly_rate_fields(row.base_year_rate, self.escalation_rate) # Update current/next/second year price fields contract.update_price_fields() contract.full_clean(exclude=['piid']) contract.save() row.contract_model = contract row.save() self.save() def unreview(self, user): ''' Mark this SubmittedPriceList as "unreviewed" and delete all associated Contract models. An "unreviewed" price list is one that has been either newly submitted or that has had modifications made to it and requires review (to approve or reject it) by an administrator. ''' self._change_status(self.STATUS_UNREVIEWED, user) self._delete_associated_contracts() self.save() def retire(self, user): ''' Mark this SubmittedPriceList as "retired" and delete all associated Contract models. Retiring a price list is for removing a once approved price list that is now either out-of-date or now otherwise invalid. ''' self._change_status(self.STATUS_RETIRED, user) self._delete_associated_contracts() self.save() def reject(self, user): ''' Reject this SubmittedPriceList. This method should be called on "unreviewed" price lists. It is the opposite of approving a price list. ''' if self.status is not self.STATUS_UNREVIEWED: raise AssertionError() self._change_status(self.STATUS_REJECTED, user) self.save() def _delete_associated_contracts(self): for row in self.rows.all(): if row.contract_model: row.contract_model.delete() self.save() def __str__(self): return "Price List for {}".format(self.contract_number) @classmethod def get_latest_by_contract_number(cls, contract_number): return cls.objects.filter(contract_number__iexact=contract_number ).latest('status_changed_at')
class Ingredient(AbstractSubmissionModel, AbstractLicenseModel, models.Model): ''' An ingredient, with some approximate nutrition values ''' ENERGY_APPROXIMATION = 15 ''' How much the calculated energy from protein, etc. can deviate from the energy amount given (in percent). ''' # Metaclass to set some other properties class Meta: ordering = ["name", ] language = models.ForeignKey(Language, verbose_name=_('Language'), editable=False, on_delete=models.CASCADE) creation_date = models.DateField(_('Date'), auto_now_add=True) update_date = models.DateField(_('Date'), auto_now=True, blank=True, editable=False) name = models.CharField(max_length=200, verbose_name=_('Name'),) energy = models.IntegerField(verbose_name=_('Energy'), help_text=_('In kcal per 100g')) protein = models.DecimalField(decimal_places=3, max_digits=6, verbose_name=_('Protein'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) carbohydrates = models.DecimalField(decimal_places=3, max_digits=6, verbose_name=_('Carbohydrates'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) carbohydrates_sugar = models.DecimalField(decimal_places=3, max_digits=6, blank=True, null=True, verbose_name=_('Sugar content in carbohydrates'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) fat = models.DecimalField(decimal_places=3, max_digits=6, verbose_name=_('Fat'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) fat_saturated = models.DecimalField(decimal_places=3, max_digits=6, blank=True, null=True, verbose_name=_('Saturated fat content in fats'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) fibres = models.DecimalField(decimal_places=3, max_digits=6, blank=True, null=True, verbose_name=_('Fibres'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) sodium = models.DecimalField(decimal_places=3, max_digits=6, blank=True, null=True, verbose_name=_('Sodium'), help_text=_('In g per 100g of product'), validators=[MinValueValidator(0), MaxValueValidator(100)]) # # Django methods # def get_absolute_url(self): ''' Returns the canonical URL to view this object ''' return reverse('nutrition:ingredient:view', kwargs={'id': self.id, 'slug': slugify(self.name)}) def clean(self): ''' Do a very broad sanity check on the nutritional values according to the following rules: - 1g of protein: 4kcal - 1g of carbohydrates: 4kcal - 1g of fat: 9kcal The sum is then compared to the given total energy, with ENERGY_APPROXIMATION percent tolerance. ''' # Note: calculations in 100 grams, to save us the '/100' everywhere energy_protein = 0 if self.protein: energy_protein = self.protein * ENERGY_FACTOR['protein']['kg'] energy_carbohydrates = 0 if self.carbohydrates: energy_carbohydrates = self.carbohydrates * ENERGY_FACTOR['carbohydrates']['kg'] energy_fat = 0 if self.fat: # TODO: for some reason, during the tests the fat value is not # converted to decimal (django 1.9) energy_fat = Decimal(self.fat * ENERGY_FACTOR['fat']['kg']) energy_calculated = energy_protein + energy_carbohydrates + energy_fat # Compare the values, but be generous if self.energy: energy_upper = self.energy * (1 + (self.ENERGY_APPROXIMATION / Decimal(100.0))) energy_lower = self.energy * (1 - (self.ENERGY_APPROXIMATION / Decimal(100.0))) if not ((energy_upper > energy_calculated) and (energy_calculated > energy_lower)): raise ValidationError(_('Total energy is not the approximate sum of the energy ' 'provided by protein, carbohydrates and fat.')) def save(self, *args, **kwargs): ''' Reset the cache ''' super(Ingredient, self).save(*args, **kwargs) cache.delete(cache_mapper.get_ingredient_key(self.id)) def __str__(self): ''' Return a more human-readable representation ''' return self.name def __eq__(self, other): ''' Compare ingredients based on their values, not like django on their PKs ''' logger.debug('Overwritten behaviour: comparing ingredients on values, not PK.') equal = True if isinstance(other, self.__class__): for i in self._meta.fields: if (hasattr(self, i.name) and hasattr(other, i.name) and (getattr(self, i.name, None) != getattr(other, i.name, None))): equal = False else: equal = False return equal def __hash__(self): """ Define a hash function This is rather unnecessary, but it seems that newer versions of django have a problem when the __eq__ function is implemented, but not the __hash__ one. Returning hash(pk) is also django's default. :return: hash(pk) """ return hash(self.pk) # # Own methods # def compare_with_database(self): ''' Compares the current ingredient with the version saved in the database. If the current object has no PK, returns false ''' if not self.pk: return False ingredient = Ingredient.objects.get(pk=self.pk) if self != ingredient: return False else: return True def send_email(self, request): ''' Sends an email after being successfully added to the database (for user submitted ingredients only) ''' try: user = User.objects.get(username=self.license_author) except User.DoesNotExist: return if self.license_author and user.email: translation.activate(user.userprofile.notification_language.short_name) url = request.build_absolute_uri(self.get_absolute_url()) subject = _('Ingredient was successfully added to the general database') context = { 'ingredient': self.name, 'url': url, 'site': Site.objects.get_current().domain } message = render_to_string('ingredient/email_new.tpl', context) mail.send_mail(subject, message, settings.WGER_SETTINGS['EMAIL_FROM'], [user.email], fail_silently=True) def set_author(self, request): if request.user.has_perm('nutrition.add_ingredient'): self.status = Ingredient.STATUS_ACCEPTED if not self.license_author: self.license_author = request.get_host().split(':')[0] else: if not self.license_author: self.license_author = request.user.username # Send email to administrator subject = _('New user submitted ingredient') message = _(u'''The user {0} submitted a new ingredient "{1}".'''.format( request.user.username, self.name)) mail.mail_admins(subject, message, fail_silently=True) def get_owner_object(self): ''' Ingredient has no owner information ''' return False
class Device(PrimaryModel, ConfigContextModel, StatusModel): """ A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType, DeviceRole, and (optionally) a Platform. Device names are not required, however if one is set it must be unique. Each Device must be assigned to a site, and optionally to a rack within that site. Associating a device with a particular rack face or unit is optional (for example, vertically mounted PDUs do not consume rack units). When a new Device is created, console/power/interface/device bay components are created along with it as dictated by the component templates assigned to its DeviceType. Components can also be added, modified, or deleted after the creation of a Device. """ device_type = models.ForeignKey(to="dcim.DeviceType", on_delete=models.PROTECT, related_name="instances") device_role = models.ForeignKey(to="dcim.DeviceRole", on_delete=models.PROTECT, related_name="devices") tenant = models.ForeignKey( to="tenancy.Tenant", on_delete=models.PROTECT, related_name="devices", blank=True, null=True, ) platform = models.ForeignKey( to="dcim.Platform", on_delete=models.SET_NULL, related_name="devices", blank=True, null=True, ) name = models.CharField(max_length=64, blank=True, null=True, db_index=True) _name = NaturalOrderingField(target_field="name", max_length=100, blank=True, null=True, db_index=True) serial = models.CharField(max_length=255, blank=True, verbose_name="Serial number", db_index=True) asset_tag = models.CharField( max_length=50, blank=True, null=True, unique=True, verbose_name="Asset tag", help_text="A unique tag used to identify this device", ) site = models.ForeignKey(to="dcim.Site", on_delete=models.PROTECT, related_name="devices") rack = models.ForeignKey( to="dcim.Rack", on_delete=models.PROTECT, related_name="devices", blank=True, null=True, ) position = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MinValueValidator(1)], verbose_name="Position (U)", help_text="The lowest-numbered unit occupied by the device", ) face = models.CharField(max_length=50, blank=True, choices=DeviceFaceChoices, verbose_name="Rack face") primary_ip4 = models.OneToOneField( to="ipam.IPAddress", on_delete=models.SET_NULL, related_name="primary_ip4_for", blank=True, null=True, verbose_name="Primary IPv4", ) primary_ip6 = models.OneToOneField( to="ipam.IPAddress", on_delete=models.SET_NULL, related_name="primary_ip6_for", blank=True, null=True, verbose_name="Primary IPv6", ) cluster = models.ForeignKey( to="virtualization.Cluster", on_delete=models.SET_NULL, related_name="devices", blank=True, null=True, ) virtual_chassis = models.ForeignKey( to="VirtualChassis", on_delete=models.SET_NULL, related_name="members", blank=True, null=True, ) vc_position = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MaxValueValidator(255)]) vc_priority = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MaxValueValidator(255)]) comments = models.TextField(blank=True) images = GenericRelation(to="extras.ImageAttachment") secrets_group = models.ForeignKey( to="extras.SecretsGroup", on_delete=models.SET_NULL, default=None, blank=True, null=True, ) objects = ConfigContextModelQuerySet.as_manager() csv_headers = [ "name", "device_role", "tenant", "manufacturer", "device_type", "platform", "serial", "asset_tag", "status", "site", "rack_group", "rack_name", "position", "face", "secrets_group", "primary_ip", "comments", ] clone_fields = [ "device_type", "device_role", "tenant", "platform", "site", "rack", "status", "cluster", "secrets_group", ] class Meta: ordering = ("_name", ) # Name may be null unique_together = ( ("site", "tenant", "name"), # See validate_unique below ("rack", "position", "face"), ("virtual_chassis", "vc_position"), ) def __str__(self): return self.display or super().__str__() def get_absolute_url(self): return reverse("dcim:device", args=[self.pk]) def validate_unique(self, exclude=None): # Check for a duplicate name on a device assigned to the same Site and no Tenant. This is necessary # because Django does not consider two NULL fields to be equal, and thus will not trigger a violation # of the uniqueness constraint without manual intervention. if self.name and hasattr(self, "site") and self.tenant is None: if Device.objects.exclude(pk=self.pk).filter(name=self.name, site=self.site, tenant__isnull=True): raise ValidationError( {"name": "A device with this name already exists."}) super().validate_unique(exclude) def clean(self): super().clean() # Validate site/rack combination if self.rack and self.site != self.rack.site: raise ValidationError({ "rack": f"Rack {self.rack} does not belong to site {self.site}.", }) if self.rack is None: if self.face: raise ValidationError({ "face": "Cannot select a rack face without assigning a rack.", }) if self.position: raise ValidationError({ "position": "Cannot select a rack position without assigning a rack.", }) # Validate position/face combination if self.position and not self.face: raise ValidationError({ "face": "Must specify rack face when defining rack position.", }) # Prevent 0U devices from being assigned to a specific position if self.position and self.device_type.u_height == 0: raise ValidationError({ "position": f"A U0 device type ({self.device_type}) cannot be assigned to a rack position." }) if self.rack: try: # Child devices cannot be assigned to a rack face/unit if self.device_type.is_child_device and self.face: raise ValidationError({ "face": "Child device types cannot be assigned to a rack face. This is an attribute of the " "parent device." }) if self.device_type.is_child_device and self.position: raise ValidationError({ "position": "Child device types cannot be assigned to a rack position. This is an attribute of " "the parent device." }) # Validate rack space rack_face = self.face if not self.device_type.is_full_depth else None exclude_list = [self.pk] if self.present_in_database else [] available_units = self.rack.get_available_units( u_height=self.device_type.u_height, rack_face=rack_face, exclude=exclude_list, ) if self.position and self.position not in available_units: raise ValidationError({ "position": f"U{self.position} is already occupied or does not have sufficient space to " f"accommodate this device type: {self.device_type} ({self.device_type.u_height}U)" }) except DeviceType.DoesNotExist: pass # Validate primary IP addresses vc_interfaces = self.vc_interfaces.all() if self.primary_ip4: if self.primary_ip4.family != 4: raise ValidationError({ "primary_ip4": f"{self.primary_ip4} is not an IPv4 address." }) if self.primary_ip4.assigned_object in vc_interfaces: pass elif (self.primary_ip4.nat_inside is not None and self.primary_ip4.nat_inside.assigned_object in vc_interfaces): pass else: raise ValidationError({ "primary_ip4": f"The specified IP address ({self.primary_ip4}) is not assigned to this device." }) if self.primary_ip6: if self.primary_ip6.family != 6: raise ValidationError({ "primary_ip6": f"{self.primary_ip6} is not an IPv6 address." }) if self.primary_ip6.assigned_object in vc_interfaces: pass elif (self.primary_ip6.nat_inside is not None and self.primary_ip6.nat_inside.assigned_object in vc_interfaces): pass else: raise ValidationError({ "primary_ip6": f"The specified IP address ({self.primary_ip6}) is not assigned to this device." }) # Validate manufacturer/platform if hasattr(self, "device_type") and self.platform: if self.platform.manufacturer and self.platform.manufacturer != self.device_type.manufacturer: raise ValidationError({ "platform": "The assigned platform is limited to {} device types, but this device's type belongs " "to {}.".format(self.platform.manufacturer, self.device_type.manufacturer) }) # A Device can only be assigned to a Cluster in the same Site (or no Site) if self.cluster and self.cluster.site is not None and self.cluster.site != self.site: raise ValidationError({ "cluster": "The assigned cluster belongs to a different site ({})".format( self.cluster.site) }) # Validate virtual chassis assignment if self.virtual_chassis and self.vc_position is None: raise ValidationError({ "vc_position": "A device assigned to a virtual chassis must have its position defined." }) # Validate device isn't being removed from a virtual chassis when it is the master if not self.virtual_chassis and self.present_in_database: existing_virtual_chassis = Device.objects.get( id=self.id).virtual_chassis if existing_virtual_chassis and existing_virtual_chassis.master == self: raise ValidationError({ "virtual_chassis": "The master device for the virtual chassis ({}) may not be removed" .format(existing_virtual_chassis) }) def save(self, *args, **kwargs): is_new = not self.present_in_database super().save(*args, **kwargs) # If this is a new Device, instantiate all of the related components per the DeviceType definition if is_new: ConsolePort.objects.bulk_create([ x.instantiate(self) for x in self.device_type.consoleporttemplates.all() ]) ConsoleServerPort.objects.bulk_create([ x.instantiate(self) for x in self.device_type.consoleserverporttemplates.all() ]) PowerPort.objects.bulk_create([ x.instantiate(self) for x in self.device_type.powerporttemplates.all() ]) PowerOutlet.objects.bulk_create([ x.instantiate(self) for x in self.device_type.poweroutlettemplates.all() ]) Interface.objects.bulk_create([ x.instantiate(self) for x in self.device_type.interfacetemplates.all() ]) RearPort.objects.bulk_create([ x.instantiate(self) for x in self.device_type.rearporttemplates.all() ]) FrontPort.objects.bulk_create([ x.instantiate(self) for x in self.device_type.frontporttemplates.all() ]) DeviceBay.objects.bulk_create([ x.instantiate(self) for x in self.device_type.devicebaytemplates.all() ]) # Update Site and Rack assignment for any child Devices devices = Device.objects.filter(parent_bay__device=self) for device in devices: device.site = self.site device.rack = self.rack device.save() def to_csv(self): return ( self.name or "", self.device_role.name, self.tenant.name if self.tenant else None, self.device_type.manufacturer.name, self.device_type.model, self.platform.name if self.platform else None, self.serial, self.asset_tag, self.get_status_display(), self.site.name, self.rack.group.name if self.rack and self.rack.group else None, self.rack.name if self.rack else None, self.position, self.get_face_display(), self.secrets_group.name if self.secrets_group else None, self.primary_ip if self.primary_ip else None, self.comments, ) @property def display(self): if self.name: return self.name elif self.virtual_chassis: return f"{self.virtual_chassis.name}:{self.vc_position} ({self.pk})" elif self.device_type: return f"{self.device_type.manufacturer} {self.device_type.model} ({self.pk})" else: return "" # Device has not yet been created @property def identifier(self): """ Return the device name if set; otherwise return the Device's primary key as {pk} """ if self.name is not None: return self.name return "{{{}}}".format(self.pk) @property def primary_ip(self): if get_settings_or_config("PREFER_IPV4") and self.primary_ip4: return self.primary_ip4 elif self.primary_ip6: return self.primary_ip6 elif self.primary_ip4: return self.primary_ip4 else: return None def get_vc_master(self): """ If this Device is a VirtualChassis member, return the VC master. Otherwise, return None. """ return self.virtual_chassis.master if self.virtual_chassis else None @property def vc_interfaces(self): """ Return a QuerySet matching all Interfaces assigned to this Device or, if this Device is a VC master, to another Device belonging to the same VirtualChassis. """ filter = Q(device=self) if self.virtual_chassis and self.virtual_chassis.master == self: filter |= Q(device__virtual_chassis=self.virtual_chassis, mgmt_only=False) return Interface.objects.filter(filter) def get_cables(self, pk_list=False): """ Return a QuerySet or PK list matching all Cables connected to a component of this Device. """ from .cables import Cable cable_pks = [] for component_model in [ ConsolePort, ConsoleServerPort, PowerPort, PowerOutlet, Interface, FrontPort, RearPort, ]: cable_pks += component_model.objects.filter( device=self, cable__isnull=False).values_list("cable", flat=True) if pk_list: return cable_pks return Cable.objects.filter(pk__in=cable_pks) def get_children(self): """ Return the set of child Devices installed in DeviceBays within this Device. """ return Device.objects.filter(parent_bay__device=self.pk)
class RefuelingStop(models.Model): equipment = models.ForeignKey(Equipment, verbose_name=_("equipment"), on_delete=models.CASCADE) datetime = models.DateTimeField(default=timezone.now, db_index=True) mileage = models.DecimalField( _("mileage"), max_digits=9, decimal_places=2, validators=[MinValueValidator(Decimal("0.01"))], ) distance = models.DecimalField( _("distance"), max_digits=9, decimal_places=2, blank=True, null=True, validators=[MinValueValidator(Decimal("0.01"))], ) liters = models.DecimalField( _("refueled liters"), max_digits=5, decimal_places=2, default=Decimal(0), validators=[MinValueValidator(Decimal("0.01"))], ) price_per_liter = models.DecimalField( _("price per liter"), max_digits=6, decimal_places=3, validators=[MinValueValidator(Decimal("0.001"))], ) average_consumption = models.DecimalField(_("average consumption"), max_digits=6, decimal_places=2, null=True, blank=True) def __str__(self): return "{}: {} {} {} {} {}".format( self.id, date_filter(self.datetime), self.liters, _("l"), self.mileage, _("km"), ) @cached_property def older_refueling_stop(self): older_refueling_stop = (RefuelingStop.objects.filter( equipment_id=self.equipment.id, mileage__lt=self.mileage).exclude( id=self.id).order_by("-mileage").first()) return older_refueling_stop @cached_property def younger_refueling_stop(self): younger_refueling_stop = (RefuelingStop.objects.filter( equipment_id=self.equipment.id, mileage__gt=self.mileage).exclude( id=self.id).order_by("mileage").first()) return younger_refueling_stop def save(self, *args, **kwargs): # Save average consumption if self.equipment: self.calc_average_consumption() # Update last_refueling_stop in equipment object/table if (not self.equipment.last_refueling_stop or not self.younger_refueling_stop): self.equipment.last_refueling_stop = self.datetime self.equipment.save() super(RefuelingStop, self).save(*args, **kwargs) def calc_average_consumption(self): if self.older_refueling_stop is None: last_mileage = Decimal(0) else: last_mileage = self.older_refueling_stop.mileage self.distance = self.mileage - last_mileage self.average_consumption = round(self.liters / self.distance * 100, 2)
class OrderLine(models.Model): order = models.ForeignKey(Order, related_name="lines", editable=False, on_delete=models.CASCADE) variant = models.ForeignKey( "product.ProductVariant", related_name="order_lines", on_delete=models.SET_NULL, blank=True, null=True, ) # max_length is as produced by ProductVariant's display_product method product_name = models.CharField(max_length=386) variant_name = models.CharField(max_length=255, default="", blank=True) translated_product_name = models.CharField(max_length=386, default="", blank=True) translated_variant_name = models.CharField(max_length=255, default="", blank=True) product_sku = models.CharField(max_length=255) is_shipping_required = models.BooleanField() quantity = models.IntegerField(validators=[MinValueValidator(1)]) quantity_fulfilled = models.IntegerField(validators=[MinValueValidator(0)], default=0) currency = models.CharField( max_length=settings.DEFAULT_CURRENCY_CODE_LENGTH, default=settings.DEFAULT_CURRENCY, ) unit_price_net_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, ) unit_price_net = MoneyField(amount_field="unit_price_net_amount", currency_field="currency") unit_price_gross_amount = models.DecimalField( max_digits=settings.DEFAULT_MAX_DIGITS, decimal_places=settings.DEFAULT_DECIMAL_PLACES, ) unit_price_gross = MoneyField(amount_field="unit_price_gross_amount", currency_field="currency") unit_price = TaxedMoneyField( net_amount_field="unit_price_net_amount", gross_amount_field="unit_price_gross_amount", currency="currency", ) tax_rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.0")) objects = OrderLineQueryset.as_manager() class Meta: ordering = ("pk", ) def __str__(self): return (f"{self.product_name} ({self.variant_name})" if self.variant_name else self.product_name) def get_total(self): return self.unit_price * self.quantity @property def quantity_unfulfilled(self): return self.quantity - self.quantity_fulfilled @property def is_digital(self) -> Optional[bool]: """Check if a variant is digital and contains digital content.""" if not self.variant: return None is_digital = self.variant.is_digital() has_digital = hasattr(self.variant, "digital_content") return is_digital and has_digital
class Hint(models.Model): """ A class to represent an hint """ class Meta: verbose_name_plural = "Hints" puzzle = models.ForeignKey( Puzzle, on_delete=models.CASCADE, help_text="The puzzle that this automated response is related to") text = models.CharField(max_length=400, help_text="The text to display") time = models.DurationField( verbose_name='Delay', help_text=('Time after anyone on the team first loads the puzzle'), validators=(MinValueValidator(timedelta(seconds=0)), ), ) number_eurekas = models.IntegerField( verbose_name='Number required', help_text=( 'How many Eurekas are reguired to trigger the shorter time'), default=1, ) eurekas = models.ManyToManyField( 'Eureka', verbose_name='Eureka conditions', blank=True, help_text="Eurekas that are a prerequisite for shorter time") short_time = models.DurationField( verbose_name='Shorter Delay', help_text=('Time after all the associated Eurekas were found'), validators=(MinValueValidator(timedelta(seconds=0)), ), ) def __str__(self): return str(self.time) + " => " + self.text @property def compact_id(self): return self.id def delay_for_team(self, team): """Returns how long until the hint unlocks for the given team. Parameters as for `unlocked_by`. """ if team is None: return self.time else: if self.eurekas.all().count() > 0: teams_eurekas = team.teameurekalink_set.all() start_time = self.starting_time_for_team(team) eureka_times = [] for eureka in self.eurekas.all(): for team_eureka in teams_eurekas: if eureka == team_eureka.eureka: eureka_times.append(team_eureka.time - start_time) if len(eureka_times) >= self.number_eurekas: return min(self.time, max(eureka_times) + self.short_time) else: return self.time else: return self.time def starting_time_for_team(self, team): return self.puzzle.starting_time_for_team(team)
class FilterBookForm(Form): author = ModelChoiceField(queryset=Author.objects.all()) notation = IntegerField(validators=[MaxValueValidator(5), MinValueValidator(0)])
class Repository(BaseModel): class Meta: unique_together = [ ('provider_namespace', 'name'), ('provider_namespace', 'original_name'), ] ordering = ('provider_namespace', 'name') # Foreign keys owners = models.ManyToManyField( settings.AUTH_USER_MODEL, related_name='repositories' ) provider_namespace = models.ForeignKey( ProviderNamespace, related_name='repositories', on_delete=models.CASCADE, ) readme = models.ForeignKey( 'Readme', null=True, on_delete=models.SET_NULL, related_name='+', ) # Fields name = models.CharField(max_length=256) original_name = models.CharField(max_length=256, null=False) format = models.CharField(max_length=16, null=True, choices=constants.RepositoryFormat.choices()) description = fields.TruncatingCharField( max_length=255, blank=True, default='') import_branch = models.CharField(max_length=256, null=True) is_enabled = models.BooleanField(default=False) # Repository attributes commit = models.CharField(max_length=256, blank=True, default='') commit_message = fields.TruncatingCharField( max_length=256, blank=True, default='') commit_url = models.CharField(max_length=256, blank=True, default='') commit_created = models.DateTimeField( null=True, verbose_name="Last Commit DateTime") stargazers_count = models.IntegerField(default=0) watchers_count = models.IntegerField(default=0) forks_count = models.IntegerField(default=0) open_issues_count = models.IntegerField(default=0) travis_status_url = models.CharField( max_length=256, blank=True, default='', verbose_name="Travis Build Status" ) travis_build_url = models.CharField( max_length=256, blank=True, default='', verbose_name="Travis Build URL" ) issue_tracker_url = models.CharField( max_length=256, blank=True, null=True, verbose_name="Issue Tracker URL", ) download_count = models.IntegerField( default=0 ) deprecated = models.BooleanField( default=False, ) community_score = models.FloatField( null=True ) community_survey_count = models.IntegerField( default=0 ) quality_score = models.FloatField( null=True, validators=[MinValueValidator(0.0), MaxValueValidator(5.0)], ) quality_score_date = models.DateTimeField( null=True, verbose_name="DateTime last scored", ) is_new = models.BooleanField( default=False, ) @property def clone_url(self): return "https://github.com/{user}/{repo}.git".format( user=self.provider_namespace.name, repo=self.original_name ) @property def github_user(self): return self.provider_namespace.name @property def github_repo(self): return self.original_name @property def content_counts(self): return Content.objects \ .filter(repository=self.pk) \ .values('content_type__name') \ .annotate(count=models.Count('content_type__name')) \ .order_by('content_type__name') def get_absolute_url(self): return reverse('api:repository_detail', args=(self.pk,)) def get_download_url(self, ref=None): download_url = self.provider_namespace.provider.download_url if ref is None: last_version = self.last_version() if last_version: ref = last_version.tag else: ref = self.import_branch return download_url.format( username=self.provider_namespace.name, repository=self.original_name, ref=ref, ) def all_versions(self): return sorted(self.versions.filter(version__isnull=False).all(), key=operator.attrgetter('version'), reverse=True) def last_version(self): versions = self.all_versions() if versions: return versions[0] return None
class Store(models.Model, CachedTreeItem, base.TranslationStore): """A model representing a translation store (i.e. a PO or XLIFF file).""" UnitClass = Unit Name = "Model Store" is_dir = False file = TranslationStoreField(max_length=255, storage=fs, db_index=True, null=False, editable=False) parent = models.ForeignKey('pootle_app.Directory', related_name='child_stores', db_index=True, editable=False) translation_project_fk = 'pootle_translationproject.TranslationProject' translation_project = models.ForeignKey(translation_project_fk, related_name='stores', db_index=True, editable=False) filetype = models.ForeignKey(Format, related_name='stores', null=True, blank=True, db_index=True) is_template = models.BooleanField(default=False) # any changes to the `pootle_path` field may require updating the schema # see migration 0007_case_sensitive_schema.py pootle_path = models.CharField(max_length=255, null=False, unique=True, db_index=True, verbose_name=_("Path")) # any changes to the `name` field may require updating the schema # see migration 0007_case_sensitive_schema.py name = models.CharField(max_length=128, null=False, editable=False, validators=[validate_no_slashes]) file_mtime = models.DateTimeField(default=datetime_min) state = models.IntegerField(null=False, default=NEW, editable=False, db_index=True) creation_time = models.DateTimeField(auto_now_add=True, db_index=True, editable=False, null=True) last_sync_revision = models.IntegerField(db_index=True, null=True, blank=True) obsolete = models.BooleanField(default=False) # this is calculated from virtualfolders if installed and linked priority = models.FloatField(db_index=True, default=1, validators=[MinValueValidator(0)]) objects = StoreManager() simple_objects = models.Manager() class Meta(object): ordering = ['pootle_path'] unique_together = ('parent', 'name') # # # # # # # # # # # # # # Properties # # # # # # # # # # # # # # # # # # @property def code(self): return self.name.replace('.', '-') @property def real_path(self): return self.file.name @property def has_terminology(self): """is this a project specific terminology store?""" # TODO: Consider if this should check if the store belongs to a # terminology project. Probably not, in case this might be called over # several files in a project. return self.name.startswith('pootle-terminology') @property def units(self): return self.unit_set.filter(state__gt=OBSOLETE).order_by('index') @units.setter def units(self, value): """Null setter to avoid tracebacks if :meth:`TranslationStore.__init__` is called. """ pass # # # # # # # # # # # # # # Methods # # # # # # # # # # # # # # # # # # # @cached_property def path(self): """Returns just the path part omitting language and project codes. If the `pootle_path` of a :cls:`Store` object `store` is `/af/project/dir1/dir2/file.po`, `store.path` will return `dir1/dir2/file.po`. """ return to_tp_relative_path(self.pootle_path) def __init__(self, *args, **kwargs): super(Store, self).__init__(*args, **kwargs) def __unicode__(self): return unicode(self.pootle_path) def __str__(self): return str(self.syncer.convert()) def save(self, *args, **kwargs): created = not self.id self.pootle_path = self.parent.pootle_path + self.name # Force validation of fields. self.full_clean() super(Store, self).save(*args, **kwargs) if created: store_log(user='******', action=STORE_ADDED, path=self.pootle_path, store=self.id) def delete(self, *args, **kwargs): store_log(user='******', action=STORE_DELETED, path=self.pootle_path, store=self.id) lang = self.translation_project.language.code for unit in self.unit_set.iterator(): action_log(user='******', action=UNIT_DELETED, lang=lang, unit=unit.id, translation='', path=self.pootle_path) super(Store, self).delete(*args, **kwargs) def calculate_priority(self): if not vfolders_installed(): return DEFAULT_PRIORITY from virtualfolder.models import VirtualFolder vfolders = VirtualFolder.objects priority = (vfolders.filter(stores=self).aggregate( priority=models.Max("priority"))["priority"]) if priority is None: return DEFAULT_PRIORITY return priority def set_priority(self, priority=None): priority = (self.calculate_priority() if priority is None else priority) if priority != self.priority: Store.objects.filter(pk=self.pk).update(priority=priority) def makeobsolete(self): """Make this store and all its units obsolete.""" store_log(user='******', action=STORE_OBSOLETE, path=self.pootle_path, store=self.id) lang = self.translation_project.language.code unit_query = self.unit_set.filter(state__gt=OBSOLETE) unit_ids = unit_query.values_list('id', flat=True) for unit_id in unit_ids: action_log(user='******', action=UNIT_OBSOLETE, lang=lang, unit=unit_id, translation='', path=self.pootle_path) unit_query.update(state=OBSOLETE, index=0) self.obsolete = True self.save() def get_absolute_url(self): return reverse('pootle-tp-store-browse', args=split_pootle_path(self.pootle_path)) def get_translate_url(self, **kwargs): return u''.join([ reverse("pootle-tp-store-translate", args=split_pootle_path(self.pootle_path)), get_editor_filter(**kwargs) ]) def findid_bulk(self, ids, unit_set=None): chunks = 200 for i in xrange(0, len(ids), chunks): units = (unit_set or self.unit_set).filter(id__in=ids[i:i + chunks]) for unit in units.iterator(): yield unit def get_file_mtime(self): disk_mtime = datetime.datetime.fromtimestamp(self.file.getpomtime()[0]) # set microsecond to 0 for comparing with a time value without # microseconds disk_mtime = make_aware(disk_mtime.replace(microsecond=0)) return disk_mtime def update_index(self, start, delta): with update_data_after(self): Unit.objects.filter( store_id=self.id, index__gte=start).update(index=operator.add(F('index'), delta)) def mark_units_obsolete(self, uids_to_obsolete, update_revision=None): """Marks a bulk of units as obsolete. :param uids_to_obsolete: UIDs of the units to be marked as obsolete. :return: The number of units marked as obsolete. """ obsoleted = 0 for unit in self.findid_bulk(uids_to_obsolete): # Use the same (parent) object since units will # accumulate the list of cache attributes to clear # in the parent Store object unit.store = self if not unit.isobsolete(): unit.makeobsolete() unit.save(revision=update_revision) obsoleted += 1 return obsoleted @cached_property def data_tool(self): return data_tool.get(self.__class__)(self) @cached_property def updater(self): updaters = format_updaters.gather() updater_class = (updaters.get(self.filetype.name) or updaters.get("default")) return updater_class(self) @cached_property def syncer(self): syncers = format_syncers.gather() syncer_class = (syncers.get(self.filetype.name) or syncers.get("default")) return syncer_class(self) def record_submissions(self, unit, old_target, old_state, current_time, user, submission_type=None, **kwargs): """Records all applicable submissions for `unit`. EXTREME HAZARD: this relies on implicit `._<field>_updated` members being available in `unit`. Let's look into replacing such members with something saner (#3895). """ state_updated = kwargs.get("state_updated") or unit._state_updated target_updated = kwargs.get("target_updated") or unit._target_updated comment_updated = kwargs.get( "comment_updated") or unit._comment_updated create_subs = OrderedDict() if state_updated: create_subs[SubmissionFields.STATE] = [old_state, unit.state] if target_updated: create_subs[SubmissionFields.TARGET] = [old_target, unit.target_f] if comment_updated: create_subs[SubmissionFields.COMMENT] = [ '', unit.translator_comment or '' ] if submission_type is None: submission_type = SubmissionTypes.SYSTEM subs_created = [] for field in create_subs: subs_created.append( Submission(creation_time=current_time, translation_project_id=self.translation_project_id, submitter=user, unit=unit, store_id=self.id, field=field, type=submission_type, old_value=create_subs[field][0], new_value=create_subs[field][1])) if subs_created: unit.submission_set.add(*subs_created, bulk=False) def update(self, store, user=None, store_revision=None, submission_type=None, resolve_conflict=POOTLE_WINS, allow_add_and_obsolete=True): """Update DB with units from a ttk Store. :param store: a source `Store` instance from TTK. :param store_revision: revision at which the source `Store` was last synced. :param user: User to attribute updates to. :param submission_type: Submission type of saved updates. :param allow_add_and_obsolete: allow to add new units and make obsolete existing units """ self.updater.update(store, user=user, store_revision=store_revision, submission_type=submission_type, resolve_conflict=resolve_conflict, allow_add_and_obsolete=allow_add_and_obsolete) def deserialize(self, data): return StoreDeserialization(self).deserialize(data) def serialize(self): return StoreSerialization(self).serialize() def sync(self, update_structure=False, conservative=True, user=None, skip_missing=False, only_newer=True): """Sync file with translations from DB.""" if skip_missing and not self.file.exists(): return self.syncer.sync(update_structure=update_structure, conservative=conservative, user=user, only_newer=only_newer) # # # # # # # # # # # # TranslationStore # # # # # # # # # # # # # suggestions_in_format = True def max_index(self): """Largest unit index""" return max_column(self.unit_set.all(), 'index', -1) def addunit(self, unit, index=None, user=None, update_revision=None): if index is None: index = self.max_index() + 1 newunit = self.UnitClass(store=self, index=index) newunit.update(unit, user=user) if self.id: newunit.save(revision=update_revision, user=user) return newunit def findunits(self, source, obsolete=False): if not obsolete and hasattr(self, "sourceindex"): return super(Store, self).findunits(source) # find using hash instead of index source_hash = md5(source.encode("utf-8")).hexdigest() units = self.unit_set.filter(source_hash=source_hash) if obsolete: units = units.filter(state=OBSOLETE) else: units = units.filter(state__gt=OBSOLETE) if units.count(): return units def findunit(self, source, obsolete=False): units = self.findunits(source, obsolete) if units: return units[0] def findid(self, id): if hasattr(self, "id_index"): return self.id_index.get(id, None) unitid_hash = md5(id.encode("utf-8")).hexdigest() try: return self.unit_set.get(unitid_hash=unitid_hash) except Unit.DoesNotExist: return None def header(self): # FIXME: we should store some metadata in db if self.file and hasattr(self.file.store, 'header'): return self.file.store.header() def get_max_unit_revision(self): return max_column(self.unit_set.all(), 'revision', 0) # # # TreeItem def get_parents(self): if self.parent.is_translationproject(): return [self.translation_project] return [self.parent]
class NTPServer(Model): ntp_address = models.CharField( verbose_name=_("Address"), max_length=120, ) ntp_burst = models.BooleanField( verbose_name=_("Burst"), default=False, help_text=_( "When the server is reachable, send a burst of eight " "packets instead of the usual one. This is designed to improve" " timekeeping quality with the server command and s addresses."), ) ntp_iburst = models.BooleanField( verbose_name=_("IBurst"), default=True, help_text=_( "When the server is unreachable, send a burst of eight" " packets instead of the usual one. This is designed to speed " "the initial synchronization acquisition with the server " "command and s addresses."), ) ntp_prefer = models.BooleanField( verbose_name=_("Prefer"), default=False, help_text=_( "Marks the server as preferred. All other things being" " equal, this host will be chosen for synchronization among a " "set of correctly operating hosts."), ) ntp_minpoll = models.IntegerField( verbose_name=_("Min. Poll"), default=6, validators=[MinValueValidator(4)], help_text=_("The minimum poll interval for NTP messages, as a " "power of 2 in seconds. Defaults to 6 (64 s), but can be " "decreased to a lower limit of 4 (16 s)"), ) ntp_maxpoll = models.IntegerField( verbose_name=_("Max. Poll"), default=10, validators=[MaxValueValidator(17)], help_text=_( "The maximum poll interval for NTP messages, as a " "power of 2 in seconds. Defaults to 10 (1,024 s), but can be " "increased to an upper limit of 17 (36.4 h)"), ) def __unicode__(self): return self.ntp_address def delete(self): super(NTPServer, self).delete() notifier().start("ix-ntpd") notifier().restart("ntpd") class Meta: verbose_name = _("NTP Server") verbose_name_plural = _("NTP Servers") ordering = ["ntp_address"] class FreeAdmin: icon_model = u"NTPServerIcon" icon_object = u"NTPServerIcon" icon_view = u"ViewNTPServerIcon" icon_add = u"AddNTPServerIcon"
class Student(models.Model): """ Represents a student with personal information such as student ID, email, ect. and class information, i.e courses currently enrolled in, ect. """ name = models.CharField(max_length=25) idnumber = models.IntegerField( primary_key=True, validators=[MaxValueValidator(40000000), MinValueValidator(30000000)]) phonenumber = models.CharField(max_length=100) address = models.CharField(max_length=60) gender = models.CharField(max_length=25) pronouns = models.CharField(max_length=25) emergency = models.CharField(max_length=25) relationships = models.ManyToManyField('self', through='Relationship', symmetrical=False, related_name='related_to+') coursestaken = models.ManyToManyField('CourseInstance') coursesnow = models.ManyToManyField("CourseInstance", related_name='coursesnow') shoppingcart = models.ManyToManyField('CourseInstance', related_name='shoppingcart') user = models.OneToOneField(User, on_delete=models.CASCADE, null=True) def __str__(self): return self.name def get_shoppingcart(self): return ", ".join(shoppingcart.name for shoppingcart in self.shoppingcart.all()) get_shoppingcart.short_description = "Shopping Cart" def get_coursestaken(self): return ", ".join(coursestaken.name for coursestaken in self.coursestaken.all()) get_coursestaken.short_description = "Courses Taken" def add_relationship(self, person, status): relationship, created = Relationship.objects.get_or_create( from_student=self, to_student=student) if symm: student.add_relationship(self, status, False) return relationship def remove_relationship(self, person, status): Relationship.objects.filter(from_student=self, to_student=student, status=status).delete() if symm: student.remove_relationship(self, status, False) return def get_relationships(self, status): return self.relationships.filter(to_students__status=status, to_students__from_student=self) class Meta: permissions = (("can_view_student_list", "Can view the list of student view"), )
class Email(Model): em_fromemail = models.CharField( max_length=120, verbose_name=_("From email"), help_text=_( "An email address that the system will use for the " "sending address for mail it sends, eg: [email protected]"), default='', ) em_outgoingserver = models.CharField( max_length=120, verbose_name=_("Outgoing mail server"), help_text=_("A hostname or ip that will accept our mail, for " "instance mail.example.org, or 192.168.1.1"), blank=True, ) em_port = models.IntegerField( default=25, validators=[MinValueValidator(1), MaxValueValidator(65535)], help_text=_("An integer from 1 - 65535, generally will be 25, " "465, or 587"), verbose_name=_("Port to connect to"), ) em_security = models.CharField(max_length=120, choices=choices.SMTPAUTH_CHOICES, default="plain", help_text=_("encryption of the connection"), verbose_name=_("TLS/SSL")) em_smtp = models.BooleanField(verbose_name=_("Use SMTP Authentication"), default=False) em_user = models.CharField( blank=True, null=True, max_length=120, verbose_name=_("Username"), help_text=_("A username to authenticate to the remote server"), ) em_pass = models.CharField( blank=True, null=True, max_length=120, verbose_name=_("Password"), help_text=_("A password to authenticate to the remote server"), ) class Meta: verbose_name = _("Email") class FreeAdmin: deletable = False def __init__(self, *args, **kwargs): super(Email, self).__init__(*args, **kwargs) if self.em_pass: try: self.em_pass = notifier().pwenc_decrypt(self.em_pass) except: log.debug('Failed to decrypt email password', exc_info=True) self.em_pass = '' self._em_pass_encrypted = False def save(self, *args, **kwargs): if self.em_pass and not self._em_pass_encrypted: self.em_pass = notifier().pwenc_encrypt(self.em_pass) self._em_pass_encrypted = True return super(Email, self).save(*args, **kwargs)
class Tileset(models.Model): # base name = models.CharField(max_length=255) created_by = models.CharField(max_length=256) created_at = models.DateTimeField(auto_now_add=True) source_type = models.CharField(max_length=10, choices=SOURCE_TYPES) # server server_url = models.URLField(blank=True, null=True) server_username = models.CharField(blank=True, null=True, max_length=30) server_password = models.CharField(blank=True, null=True, max_length=30) # layer layer_name = models.CharField(blank=True, null=True, max_length=200) layer_zoom_start = models.IntegerField(default=0) layer_zoom_stop = models.IntegerField(default=12) # area bbox_x0 = models.DecimalField( max_digits=19, decimal_places=15, default=-180, validators=[MinValueValidator(-180), MaxValueValidator(180)]) bbox_x1 = models.DecimalField( max_digits=19, decimal_places=15, default=180, validators=[MinValueValidator(-180), MaxValueValidator(180)]) bbox_y0 = models.DecimalField( max_digits=19, decimal_places=15, default=-89.9, validators=[MinValueValidator(-89.9), MaxValueValidator(89.9)]) bbox_y1 = models.DecimalField( max_digits=19, decimal_places=15, default=89.9, validators=[MinValueValidator(-89.9), MaxValueValidator(89.9)]) # cache cache_type = models.CharField(max_length=10, choices=CACHE_TYPES) # file cache params directory_layout = models.CharField(max_length=20, choices=DIR_LAYOUTS, blank=True, null=True) directory = models.CharField(max_length=256, default=TILESET_CACHE_DIRECTORY, blank=True, null=True) # gpkg cache params filename = models.CharField(max_length=256, blank=True, null=True) table_name = models.CharField(max_length=128, blank=True, null=True) # mapnik params mapfile = models.FileField(blank=True, null=True, upload_to='mapfiles') # geonode params layer_uuid = models.CharField(max_length=36, null=True, blank=True) # size size = models.CharField('Size (MB)', default='0', max_length=128) def __unicode__(self): return self.name # terminate the seeding of this tileset! def stop(self): log.debug('tileset.stop') res = {'status': 'not in progress'} pid_str = helpers.get_pid_from_lock_file(self) process = helpers.get_process_from_pid(pid_str) if process: log.debug('tileset.stop, will stop, pid: {}').format(pid_str) res = {'status': 'stopped'} children = process.children() for c in children: c.terminate() process.terminate() else: if pid_str == 'preparing_to_start': res = {'status': 'debug, prevent start!'} # TODO: prevent it from starting! log.debug('process not running but may be started shortly') elif helpers.is_int_str(pid_str): log.debug( 'tileset.stop, process not running but cleaned lock file') helpers.remove_lock_file(self.id) return res def seed(self): lock_file = helpers.get_lock_file(self) if lock_file: log.debug('generating tileset') try: pid = helpers.seed_process_spawn(self) lock_file.write("{}\n".format(pid)) res = {'status': 'started'} except (SeedConfigurationError, ConfigurationError) as e: log.error( 'Something went wrong when generating.. removing lock file' ) res = {'status': 'unable to start', 'error': e.message} finally: lock_file.flush() lock_file.close() helpers.remove_lock_file(self) else: log.debug( 'tileset.generate, will NOT generate. already running, pid: {}' .format(helpers.get_pid_from_lock_file(self))) res = {'status': 'already started'} return res def bbox_3857(self): inProj = Proj(init='epsg:4326') outProj = Proj(init='epsg:3857') sw = transform(inProj, outProj, self.bbox_x0, self.bbox_y0) ne = transform(inProj, outProj, self.bbox_x1, self.bbox_y1) return [sw[0], sw[1], ne[0], ne[1]] def bbox(self): return [self.bbox_x0, self.bbox_y0, self.bbox_x1, self.bbox_y1] def add_read_perm(self, user_or_group): return assign_perm('view_tileset', user_or_group, self) def set_up_permissions(self, user_or_group=None): # TODO(mvv): handle default anonymous permissions if user_or_group: self.add_read_perm(user_or_group) class Meta: permissions = (('view_tileset', 'View Tileset'), )
class Agrifield(models.Model, AgrifieldSWBMixin, AgrifieldSWBResultsMixin): owner = models.ForeignKey(User, on_delete=models.CASCADE) name = models.CharField(max_length=255, default="i.e. MyField1") is_virtual = models.NullBooleanField(choices=YES_OR_NO_OR_NULL, null=True, default=None) location = models.PointField() crop_type = models.ForeignKey(CropType, on_delete=models.CASCADE) irrigation_type = models.ForeignKey(IrrigationType, on_delete=models.CASCADE) area = models.FloatField() use_custom_parameters = models.BooleanField(default=False) custom_kc = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(1.50), MinValueValidator(0.10)], ) custom_root_depth_max = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(4.00), MinValueValidator(0.20)], ) custom_root_depth_min = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(2.00), MinValueValidator(0.1)], ) custom_max_allowed_depletion = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(0.99), MinValueValidator(0.00)], ) custom_efficiency = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(1.00), MinValueValidator(0.05)], ) custom_irrigation_optimizer = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(1.00), MinValueValidator(0.10)], ) custom_field_capacity = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(0.45), MinValueValidator(0.10)], ) custom_thetaS = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(0.55), MinValueValidator(0.30)], ) custom_wilting_point = models.FloatField( null=True, blank=True, validators=[MaxValueValidator(0.22), MinValueValidator(0.00)], ) soil_analysis = models.FileField(blank=True, storage=SoilAnalysisStorage(), upload_to="soil_analyses") @property def wilting_point(self): if self.use_custom_parameters and self.custom_wilting_point: return self.custom_wilting_point else: return self.default_wilting_point @property def default_wilting_point(self): if not self.in_covered_area: return None else: return extract_point_from_raster( self.location, gdal.Open(os.path.join(settings.AIRA_DATA_SOIL, "pwp.tif")), ) @property def theta_s(self): if self.use_custom_parameters and self.custom_thetaS: return self.custom_thetaS else: return self.default_theta_s @property def default_theta_s(self): if not self.in_covered_area: return None else: return extract_point_from_raster( self.location, gdal.Open(os.path.join(settings.AIRA_DATA_SOIL, "theta_s.tif")), ) @property def field_capacity(self): if self.use_custom_parameters and self.custom_field_capacity: return self.custom_field_capacity else: return self.default_field_capacity @property def default_field_capacity(self): if not self.in_covered_area: return None else: return extract_point_from_raster( self.location, gdal.Open(os.path.join(settings.AIRA_DATA_SOIL, "fc.tif")), ) @property def irrigation_efficiency(self): if self.use_custom_parameters and self.custom_efficiency: return self.custom_efficiency else: return self.irrigation_type.efficiency @property def p(self): if self.use_custom_parameters and self.custom_max_allowed_depletion: return self.custom_max_allowed_depletion else: return self.crop_type.max_allowed_depletion @property def root_depth_max(self): if self.use_custom_parameters and self.custom_root_depth_max: return self.custom_root_depth_max else: return self.crop_type.root_depth_max @property def root_depth_min(self): if self.use_custom_parameters and self.custom_root_depth_min: return self.custom_root_depth_min else: return self.crop_type.root_depth_min @property def root_depth(self): return (self.root_depth_max + self.root_depth_min) / 2.0 @property def irrigation_optimizer(self): if self.use_custom_parameters and self.custom_irrigation_optimizer: return self.custom_irrigation_optimizer else: return 0.5 @property def last_irrigation(self): try: result = self.irrigationlog_set.latest() except IrrigationLog.DoesNotExist: return None if result.applied_water is None: result.applied_water = ( float(self.p) * (self.field_capacity - self.wilting_point) * self.root_depth * self.area) result.message = _( "Irrigation water is estimated using system's default parameters." ) return result def can_edit(self, user): if (user == self.owner) or (user == self.owner.profile.supervisor): return True raise Http404 class Meta: ordering = ("name", "area") verbose_name_plural = "Agrifields" def __str__(self): return self.name def save(self, *args, **kwargs): super(Agrifield, self).save(*args, **kwargs) self._queue_for_calculation() self._delete_cached_point_timeseries() def _queue_for_calculation(self): from aira import tasks cache_key = "agrifield_{}_status".format(self.id) # If the agrifield is already in the Celery queue for calculation, # return without doing anything. if cache.get(cache_key) == "queued": return tasks.calculate_agrifield.delay(self) cache.set(cache_key, "queued", None) @property def status(self): return cache.get("agrifield_{}_status".format(self.id)) @property def in_covered_area(self): mask = os.path.join(settings.AIRA_DATA_SOIL, "fc.tif") try: tmp_check = extract_point_from_raster(self.location, gdal.Open(mask)) except (RuntimeError, ValueError): tmp_check = float("nan") return not math.isnan(tmp_check) def get_point_timeseries(self, variable): prefix = os.path.join(settings.AIRA_DATA_HISTORICAL, "daily_" + variable) dest = os.path.join( settings.AIRA_TIMESERIES_CACHE_DIR, "agrifield{}-{}.hts".format(self.id, variable), ) PointTimeseries(point=self.location, prefix=prefix, default_time=dt.time(23, 59)).get_cached(dest, version=2) return dest def _delete_cached_point_timeseries(self): filenamesglob = os.path.join(settings.AIRA_TIMESERIES_CACHE_DIR, "agrifield{}-*".format(self.id)) for filename in iglob(filenamesglob): os.remove(filename)
class Listing(models.Model): seller = models.ForeignKey(User, on_delete=CASCADE, related_name="sellers") product = models.CharField(max_length=64) description = models.CharField(max_length=256) price = models.DecimalField(max_digits=10 ,decimal_places=2, default=0, validators=[MinValueValidator(0)]) image = models.URLField(default="https://www.thermaxglobal.com/wp-content/uploads/2020/05/image-not-found.jpg") category = models.CharField(max_length=20) active = models.BooleanField(default=True) newOwner = models.ForeignKey(User, on_delete=CASCADE, related_name="newowner") watchlist = models.ManyToManyField(User) def __str__(self): return f"{self.seller} is selling {self.product} for a minimum price of {self.price} euro."