def message(self): if self.reason == self.ALL_FORMS_REQUIRE_CASE: return gettext_lazy('Not all forms in the module update a case.') elif self.reason == self.MODULE_IN_ROOT: return gettext_lazy("The module's 'Menu Mode' is not configured as 'Display module and then forms'") elif self.reason == self.PARENT_SELECT_ACTIVE: return gettext_lazy("The module has 'Parent Selection' configured.")
def _get_careplan_module_view_context(app, module): case_property_builder = _setup_case_property_builder(app) subcase_types = list(app.get_subcase_types(module.case_type)) return { 'parent_modules': _get_parent_modules(app, module, case_property_builder, CAREPLAN_GOAL), 'fixtures': _get_fixture_types(app.domain), 'details': [ { 'label': gettext_lazy('Goal List'), 'detail_label': gettext_lazy('Goal Detail'), 'type': 'careplan_goal', 'model': 'case', 'properties': sorted( case_property_builder.get_properties(CAREPLAN_GOAL)), 'sort_elements': module.goal_details.short.sort_elements, 'short': module.goal_details.short, 'long': module.goal_details.long, 'subcase_types': subcase_types, }, { 'label': gettext_lazy('Task List'), 'detail_label': gettext_lazy('Task Detail'), 'type': 'careplan_task', 'model': 'case', 'properties': sorted( case_property_builder.get_properties(CAREPLAN_TASK)), 'sort_elements': module.task_details.short.sort_elements, 'short': module.task_details.short, 'long': module.task_details.long, 'subcase_types': subcase_types, }, ], }
def clean(self, value): if not value: raise forms.ValidationError( gettext_lazy('This field is required.')) if value.lower() != 'no': raise forms.ValidationError( gettext_lazy('This field is required.')) return value
def title_i18n(self): """Return translated title.""" match = PATTERN_TITLE_VERSION.match(self.title) if match: # if the title is "Version x.y.z", translate only "Version" return "%s %s" % (str(gettext_lazy(match.group(1))).decode("utf-8"), match.group(2)) else: return gettext_lazy(self.title)
def __call__(self, field_data, all_data): try: content = field_data['content'] except TypeError: raise ValidationError, gettext_lazy("No file was submitted. Check the encoding type on the form.") if self.min_size is not None and len(content) < self.min_size: raise ValidationError, self.min_error_message if self.max_size is not None and len(content) > self.max_size: raise ValidationError, self.max_error_message
def to_python(self, value): if isinstance(value, basestring): return value if value is None: if self.null: return value else: raise validators.ValidationError, gettext_lazy("This field cannot be null.") return str(value)
def __init__(self, attrs=None): choices = ( ('1', '--------'), # Translators: Please leave this blank, it should be left for the base Django translations. ('2', gettext_lazy('Yes')), # Translators: Please leave this blank, it should be left for the base Django translations. ('3', gettext_lazy('No')) ) # skip the NullBooleanSelect constructor super(forms.NullBooleanSelect, self).__init__(attrs, choices)
def test_lazy_string_encoding(self): self.assertEqual( json.dumps({'lang': gettext_lazy("French")}, cls=DjangoJSONEncoder), '{"lang": "French"}' ) with override('fr'): self.assertEqual( json.dumps({'lang': gettext_lazy("French")}, cls=DjangoJSONEncoder), '{"lang": "Fran\\u00e7ais"}' )
def __init__(self, other_field, other_value, other_label=None, error_message=None): self.other_field = other_field self.other_value = other_value other_label = other_label or other_value self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is not %(value)s"), { 'field': other_field, 'value': other_label}) self.always_test = True
def __init__(self, validator_list=None, error_message=gettext_lazy("This field is invalid.")): if validator_list is None: validator_list = [] self.validator_list = validator_list self.error_message = error_message for v in validator_list: if hasattr(v, 'always_test'): self.always_test = True
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters, } all_reports = ReportConfiguration.by_domain(app.domain) all_report_ids = set([r._id for r in all_reports]) invalid_report_references = filter( lambda r: r.report_id not in all_report_ids, module.report_configs) warnings = [] if invalid_report_references: module.report_configs = filter(lambda r: r.report_id in all_report_ids, module.report_configs) warnings.append( gettext_lazy( 'Your app contains references to reports that are deleted. These will be removed on save.') ) return { 'all_reports': [_report_to_config(r) for r in all_reports], 'current_reports': [r.to_json() for r in module.report_configs], 'invalid_report_references': invalid_report_references, 'warnings': warnings, }
def popularity_img(self): """Return HTML code with image for popular script.""" if self.popularity == 0: return ' ' return '<img src="%simages/star.png" alt="*" title="%s" ' \ 'width="10" height="10" />' % (settings.MEDIA_URL, gettext_lazy('Popular script'))
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters_without_prefilters, } all_reports = ReportConfiguration.by_domain(app.domain) + \ StaticReportConfiguration.by_domain(app.domain) warnings = [] validity = module.check_report_validity() # We're now proactively deleting these references, so after that's been # out for a while, this can be removed (say June 2016 or later) if not validity.is_valid: module.report_configs = validity.valid_report_configs warnings.append( gettext_lazy('Your app contains references to reports that are ' 'deleted. These will be removed on save.') ) return { 'all_reports': [_report_to_config(r) for r in all_reports], 'current_reports': [r.to_json() for r in module.report_configs], 'warnings': warnings, }
def test_create_relation_with_gettext_lazy(self): reporter = Reporter.objects.create(first_name='John', last_name='Smith', email='*****@*****.**') lazy = gettext_lazy('test') reporter.article_set.create(headline=lazy, pub_date=datetime.date(2011, 6, 10)) notlazy = str(lazy) article = reporter.article_set.get() self.assertEqual(article.headline, notlazy)
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters, } all_reports = ReportConfiguration.by_domain(app.domain) warnings = [] validity = module.check_report_validity() if not validity.is_valid: module.report_configs = validity.valid_report_configs warnings.append( gettext_lazy( 'Your app contains references to reports that are deleted. These will be removed on save.') ) return { 'all_reports': [_report_to_config(r) for r in all_reports], 'current_reports': [r.to_json() for r in module.report_configs], 'warnings': warnings, }
def clean(self, value): if not value: raise forms.ValidationError( gettext_lazy('This field is required.')) if not re.search('^[a-z0-9_]+$', value): raise forms.ValidationError( gettext_lazy('This name is invalid.')) plugins = Plugin.objects.exclude(max_weechat='0.2.6') \ .filter(name=value) if plugins: raise forms.ValidationError( gettext_lazy('This name already exists, please choose another ' 'name (update script content accordingly).')) if len(value) > 20: raise forms.ValidationError( gettext_lazy('This name is too long (must be max 20 chars).')) return value
def test_add_lazy_translation(self): storage = self.get_storage() response = self.get_response() storage.add(constants.INFO, gettext_lazy('lazy message')) storage.update(response) storing = self.stored_messages_count(storage, response) self.assertEqual(storing, 1)
def get_manipulator_fields(self, opts, manipulator, change, name_prefix="", rel=False, follow=True): """ Returns a list of oldforms.FormField instances for this field. It calculates the choices at runtime, not at compile time. name_prefix is a prefix to prepend to the "field_name" argument. rel is a boolean specifying whether this field is in a related context. """ field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix) # Add the "unique" validator(s). for field_name_list in opts.unique_together: if field_name_list[0] == self.name: params["validator_list"].append(getattr(manipulator, "isUnique%s" % "_".join(field_name_list))) # Add the "unique for..." validator(s). if self.unique_for_date: params["validator_list"].append(getattr(manipulator, "isUnique%sFor%s" % (self.name, self.unique_for_date))) if self.unique_for_month: params["validator_list"].append( getattr(manipulator, "isUnique%sFor%s" % (self.name, self.unique_for_month)) ) if self.unique_for_year: params["validator_list"].append(getattr(manipulator, "isUnique%sFor%s" % (self.name, self.unique_for_year))) if self.unique or (self.primary_key and not rel): params["validator_list"].append(curry(manipulator_validator_unique, self, opts, manipulator)) # Only add is_required=True if the field cannot be blank. Primary keys # are a special case, and fields in a related context should set this # as False, because they'll be caught by a separate validator -- # RequiredIfOtherFieldGiven. params["is_required"] = not self.blank and not self.primary_key and not rel # BooleanFields (CheckboxFields) are a special case. They don't take # is_required. if isinstance(self, BooleanField): del params["is_required"] # If this field is in a related context, check whether any other fields # in the related object have core=True. If so, add a validator -- # RequiredIfOtherFieldsGiven -- to this FormField. if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField): # First, get the core fields, if any. core_field_names = [] for f in opts.fields: if f.core and f != self: core_field_names.extend(f.get_manipulator_field_names(name_prefix)) # Now, if there are any, add the validator to this FormField. if core_field_names: params["validator_list"].append( validators.RequiredIfOtherFieldsGiven(core_field_names, gettext_lazy("This field is required.")) ) # Finally, add the field_names. field_names = self.get_manipulator_field_names(name_prefix) return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
def test_smart_bytes(self): class Test: def __str__(self): return 'ŠĐĆŽćžšđ' lazy_func = gettext_lazy('x') self.assertIs(smart_bytes(lazy_func), lazy_func) self.assertEqual(smart_bytes(Test()), b'\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91') self.assertEqual(smart_bytes(1), b'1') self.assertEqual(smart_bytes('foo'), b'foo')
def __init__(self, verbose_name=None, name=None, primary_key=False, maxlength=None, unique=False, blank=False, null=False, db_index=None, core=False, rel=None, default=NOT_PROVIDED, editable=True, prepopulate_from=None, unique_for_date=None, unique_for_month=None, unique_for_year=None, validator_list=None, choices=None, radio_admin=None, help_text='', db_column=None): self.name = name self.verbose_name = verbose_name or (name and name.replace('_', ' ')) self.primary_key = primary_key self.maxlength, self.unique = maxlength, unique self.blank, self.null = blank, null self.core, self.rel, self.default = core, rel, default self.editable = editable self.validator_list = validator_list or [] self.prepopulate_from = prepopulate_from self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month self.unique_for_year = unique_for_year self.choices = choices or [] self.radio_admin = radio_admin self.help_text = help_text self.db_column = db_column if rel and isinstance(rel, ManyToMany): if rel.raw_id_admin: self.help_text = string_concat(self.help_text, gettext_lazy(' Separate multiple IDs with commas.')) else: self.help_text = string_concat(self.help_text, gettext_lazy(' Hold down "Control", or "Command" on a Mac, to select more than one.')) # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. if db_index is None: if isinstance(rel, OneToOne) or isinstance(rel, ManyToOne): self.db_index = True else: self.db_index = False else: self.db_index = db_index # Increase the creation counter, and save our local copy. self.creation_counter = Field.creation_counter Field.creation_counter += 1 self.attname, self.column = self.get_attname_column()
def test_smart_text(self): class Test: def __str__(self): return 'ŠĐĆŽćžšđ' lazy_func = gettext_lazy('x') self.assertIs(smart_text(lazy_func), lazy_func) self.assertEqual(smart_text(Test()), '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111') self.assertEqual(smart_text(1), '1') self.assertEqual(smart_text('foo'), 'foo')
def __init__(self, to, **kwargs): kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = ManyToManyRel(to, num_in_admin=kwargs.pop('num_in_admin', 0), related_name=kwargs.pop('related_name', None), filter_interface=kwargs.pop('filter_interface', None), limit_choices_to=kwargs.pop('limit_choices_to', None), raw_id_admin=kwargs.pop('raw_id_admin', False), symmetrical=kwargs.pop('symmetrical', True)) self.db_table = kwargs.pop('db_table', None) if kwargs["rel"].raw_id_admin: kwargs.setdefault("validator_list", []).append(self.isValidIDList) Field.__init__(self, **kwargs) if self.rel.raw_id_admin: msg = gettext_lazy('Separate multiple IDs with commas.') else: msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') self.help_text = string_concat(self.help_text, ' ', msg)
def _case_list_form_options(app, module, case_type_): options = OrderedDict() forms = [ form for mod in app.get_modules() if module.unique_id != mod.unique_id for form in mod.get_forms() if form.is_registration_form(case_type_) ] options['disabled'] = gettext_lazy("Don't Show") options.update({f.unique_id: trans(f.name, app.langs) for f in forms}) return options
def clean_credit(self): prefix = 'submit_manual_' if self.request.method == 'POST': for key in self.request.POST: if key.startswith(prefix): credit_id = int(key[len(prefix):]) if not self.credit_choices or credit_id not in next(zip(*self.credit_choices)): raise forms.ValidationError( gettext_lazy('That credit cannot be manually credited'), code='invalid' ) return credit_id
def validate_full(self, field_data, all_data): """ Returns a list of errors for this field. This is the main interface, as it encapsulates some basic validation logic used by all fields. Subclasses should implement validate(), not validate_full(). """ if not self.blank and not field_data: return [gettext_lazy('This field is required.')] try: self.validate(field_data, all_data) except validators.ValidationError, e: return e.messages
def get_theme_choices(): """Get list of themes for update form.""" try: theme_list = Theme.objects.filter(visible=1).order_by('name') theme_choices = [] theme_choices.append(('', gettext_lazy('Choose...'))) for theme in theme_list: theme_choices.append((theme.id, '%s (%s)' % (theme.name, theme.version))) return theme_choices except: return []
def test_lazy_objects(self): """ Format string interpolation should work with *_lazy objects. """ s = ugettext_lazy('Add %(name)s') d = {'name': 'Ringo'} self.assertEqual(u'Add Ringo', s % d) with translation.override('de', deactivate=True): self.assertEqual(u'Ringo hinzuf\xfcgen', s % d) with translation.override('pl'): self.assertEqual(u'Dodaj Ringo', s % d) # It should be possible to compare *_lazy objects. s1 = ugettext_lazy('Add %(name)s') self.assertEqual(True, s == s1) s2 = gettext_lazy('Add %(name)s') s3 = gettext_lazy('Add %(name)s') self.assertEqual(True, s2 == s3) self.assertEqual(True, s == s2) s4 = ugettext_lazy('Some other string') self.assertEqual(False, s == s4)
def test_lazy_objects(self): """ Format string interpolation should work with *_lazy objects. """ s = ugettext_lazy("Add %(name)s") d = {"name": "Ringo"} self.assertEqual(u"Add Ringo", s % d) with translation.override("de", deactivate=True): self.assertEqual(u"Ringo hinzuf\xfcgen", s % d) with translation.override("pl"): self.assertEqual(u"Dodaj Ringo", s % d) # It should be possible to compare *_lazy objects. s1 = ugettext_lazy("Add %(name)s") self.assertEqual(True, s == s1) s2 = gettext_lazy("Add %(name)s") s3 = gettext_lazy("Add %(name)s") self.assertEqual(True, s2 == s3) self.assertEqual(True, s == s2) s4 = ugettext_lazy("Some other string") self.assertEqual(False, s == s4)
def clean_themefile(self): """Check if theme file is valid.""" _file = self.cleaned_data['themefile'] if _file.size > 512*1024: raise forms.ValidationError(gettext_lazy('Theme file too big.')) props = Theme.get_props(_file.read()) if 'name' not in props or 'weechat' not in props: raise forms.ValidationError(gettext_lazy('Invalid theme file.')) themes = Theme.objects.filter(name=props['name']) if themes: raise forms.ValidationError( gettext_lazy('This name already exists.')) if not props['name'].endswith('.theme'): raise forms.ValidationError( gettext_lazy('Invalid name inside theme file.')) shortname = props['name'][0:-6] if not re.search('^[A-Za-z0-9_]+$', shortname): raise forms.ValidationError( gettext_lazy('Invalid name inside theme file.')) release_stable = Release.objects.get(version='stable') release_devel = Release.objects.get(version='devel') if props['weechat'] not in (release_stable.description, re.sub('-.*', '', release_devel.description)): raise forms.ValidationError( gettext_lazy('Invalid WeeChat version, too old!')) _file.seek(0) return _file
def _make_set_result_status(value, verbose_name): # noqa: N805 def _set_result_status(modeladmin, request, queryset): count = queryset.update(result_status=value) message = ngettext("%(count)d debate had its status set to %(status)s.", "%(count)d debates had their statuses set to %(status)s.", count) % { 'count': count, 'status': verbose_name} modeladmin.message_user(request, message) # so that they look different to DebateAdmin _set_result_status.__name__ = "set_result_status_%s" % verbose_name.lower() _set_result_status.short_description = gettext_lazy("Set result status to " "%(status)s") % {'status': verbose_name} return _set_result_status
def desc_i18n(self): """Return translated description.""" return gettext_lazy(self.desc_en.encode('utf-8'))
class Unit(models.Model, LoggerMixin): translation = models.ForeignKey("Translation", on_delete=models.deletion.CASCADE) id_hash = models.BigIntegerField() content_hash = models.BigIntegerField(db_index=True) location = models.TextField(default="", blank=True) context = models.TextField(default="", blank=True) note = models.TextField(default="", blank=True) flags = models.TextField(default="", blank=True) source = models.TextField() previous_source = models.TextField(default="", blank=True) target = models.TextField(default="", blank=True) state = models.IntegerField(default=STATE_EMPTY, db_index=True, choices=STATE_CHOICES) original_state = models.IntegerField(default=STATE_EMPTY, choices=STATE_CHOICES) position = models.IntegerField() num_words = models.IntegerField(default=0) priority = models.IntegerField(default=100) pending = models.BooleanField(default=False) timestamp = models.DateTimeField(auto_now_add=True) extra_flags = models.TextField( verbose_name=gettext_lazy("Translation flags"), default="", help_text=gettext_lazy( "Additional comma-separated flags to influence quality checks. " "Possible values can be found in the documentation."), validators=[validate_check_flags], blank=True, ) extra_context = models.TextField( verbose_name=gettext_lazy("Additional context"), default="", blank=True) variant = models.ForeignKey( "Variant", on_delete=models.deletion.SET_NULL, blank=True, null=True, default=None, ) labels = models.ManyToManyField("Label", verbose_name=gettext_lazy("Labels"), blank=True) objects = UnitQuerySet.as_manager() class Meta: app_label = "trans" unique_together = ("translation", "id_hash") index_together = [("translation", "pending"), ("priority", "position")] verbose_name = "string" verbose_name_plural = "strings" def __str__(self): if self.translation.is_template: return self.context if self.context: return "[{}] {}".format(self.context, self.source) return self.source def save( self, same_content=False, same_state=False, force_insert=False, force_update=False, using=None, update_fields=None, ): """Wrapper around save to run checks or update fulltext.""" # Store number of words if not same_content or not self.num_words: self.num_words = len(self.get_source_plurals()[0].split()) if update_fields and "num_words" not in update_fields: update_fields.append("num_words") # Actually save the unit super().save( force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields, ) # Update checks if content or fuzzy flag has changed if not same_content or not same_state: self.run_checks(same_content) def get_absolute_url(self): return "{0}?checksum={1}".format(self.translation.get_translate_url(), self.checksum) def __init__(self, *args, **kwargs): """Constructor to initialize some cache properties.""" super().__init__(*args, **kwargs) self.old_unit = copy(self) self.is_batch_update = False self.is_bulk_edit = False self.source_updated = False @property def approved(self): return self.state == STATE_APPROVED @property def translated(self): return self.state >= STATE_TRANSLATED @property def readonly(self): return self.state == STATE_READONLY @property def fuzzy(self): return self.state == STATE_FUZZY @property def has_failing_check(self): return bool(self.active_checks) @property def has_comment(self): return any(not comment.resolved and comment.unit_id == self.id for comment in self.all_comments) @property def has_suggestion(self): return bool(self.suggestions) @cached_property def full_slug(self): return "/".join(( self.translation.component.project.slug, self.translation.component.slug, self.translation.language.code, str(self.pk), )) def get_unit_state(self, unit, flags): """Calculate translated and fuzzy status.""" if (unit.is_readonly() or (flags is not None and "read-only" in self.get_all_flags(flags)) or (flags is not None and self.source_info != self and self.source_info.state < STATE_TRANSLATED)): return STATE_READONLY # We need to keep approved/fuzzy state for formats which do not # support saving it if unit.is_fuzzy(self.fuzzy): return STATE_FUZZY if not unit.is_translated(): return STATE_EMPTY if unit.is_approved(self.approved) and self.translation.enable_review: return STATE_APPROVED return STATE_TRANSLATED @staticmethod def check_valid(texts): for text in texts: if any(char in text for char in CONTROLCHARS): raise ValueError( "String contains control char: {!r}".format(text)) def update_from_unit(self, unit, pos, created): """Update Unit from ttkit unit.""" component = self.translation.component self.is_batch_update = True # Get unit attributes try: location = unit.locations flags = unit.flags target = unit.target self.check_valid(split_plural(target)) source = unit.source self.check_valid(split_plural(source)) context = unit.context self.check_valid([context]) note = unit.notes previous_source = unit.previous_source content_hash = unit.content_hash except Exception as error: report_error(cause="Unit update error") self.translation.component.handle_parse_error( error, self.translation) # Ensure we track source string for bilingual if not self.translation.is_source: source_info = component.get_source( self.id_hash, create={ "source": source, "target": source, "context": context, "content_hash": calculate_hash(source, context), "position": pos, "note": note, "location": location, "flags": flags, }, ) if (not component.has_template() and not source_info.source_updated and (pos != source_info.position or location != source_info.location or flags != source_info.flags or note != source_info.note)): source_info.position = pos source_info.source_updated = True source_info.location = location source_info.flags = flags source_info.note = note source_info.save( update_fields=["position", "location", "flags", "note"], same_content=True, same_state=True, ) self.extra_context = source_info.extra_context self.extra_flags = source_info.extra_flags self.__dict__["source_info"] = source_info # Calculate state state = self.get_unit_state(unit, flags) self.original_state = self.get_unit_state(unit, None) # Has source changed same_source = source == self.source and context == self.context # Monolingual files handling (without target change) if not created and unit.template is not None and target == self.target: if not same_source and state >= STATE_TRANSLATED: if self.previous_source == self.source and self.fuzzy: # Source change was reverted previous_source = "" state = STATE_TRANSLATED else: # Store previous source and fuzzy flag for monolingual if previous_source == "": previous_source = self.source state = STATE_FUZZY elif self.state in (STATE_FUZZY, STATE_APPROVED): # We should keep calculated flags if translation was # not changed outside previous_source = self.previous_source state = self.state # Update checks on fuzzy update or on content change same_target = target == self.target same_state = state == self.state and flags == self.flags # Check if we actually need to change anything # pylint: disable=too-many-boolean-expressions if (location == self.location and flags == self.flags and same_source and same_target and same_state and note == self.note and pos == self.position and content_hash == self.content_hash and previous_source == self.previous_source): return # Store updated values self.position = pos self.location = location self.flags = flags self.source = source self.target = target self.state = state self.context = context self.note = note self.content_hash = content_hash self.previous_source = previous_source self.update_priority(save=False) # Sanitize number of plurals if self.is_plural(): self.target = join_plural(self.get_target_plurals()) if created: unit_pre_create.send(sender=self.__class__, unit=self) # Save into database self.save( force_insert=created, same_content=same_source and same_target, same_state=same_state, ) # Track updated sources for source checks if self.translation.is_template: component.updated_sources[self.id_hash] = self # Update unit labels if not self.translation.is_source: self.labels.set(self.source_info.labels.all()) # Indicate source string change if not same_source and previous_source: Change.objects.create( unit=self, action=Change.ACTION_SOURCE_CHANGE, old=previous_source, target=self.source, ) def update_state(self): """ Updates state based on flags. Mark read only strings: * Flagged with 'read-only' * Where source string is not translated """ source_info = self.source_info if "read-only" in self.all_flags or ( source_info != self and source_info.state < STATE_TRANSLATED): if not self.readonly: self.state = STATE_READONLY self.save(same_content=True, same_state=True, update_fields=["state"]) elif self.readonly: self.state = self.original_state self.save(same_content=True, same_state=True, update_fields=["state"]) def update_priority(self, save=True): if self.all_flags.has_value("priority"): priority = self.all_flags.get_value("priority") else: priority = 100 if self.priority != priority: self.priority = priority if save: self.save(same_content=True, same_state=True, update_fields=["priority"]) def is_plural(self): """Check whether message is plural.""" return is_plural(self.source) or is_plural(self.target) def get_source_plurals(self): """Return source plurals in array.""" return split_plural(self.source) def get_target_plurals(self): """Return target plurals in array.""" # Is this plural? if not self.is_plural(): return [self.target] # Split plurals ret = split_plural(self.target) # Check if we have expected number of them plurals = self.translation.plural.number if len(ret) == plurals: return ret # Pad with empty translations while len(ret) < plurals: ret.append("") # Delete extra plurals while len(ret) > plurals: del ret[-1] return ret def propagate(self, user, change_action=None, author=None): """Propagate current translation to all others.""" result = False for unit in self.same_source_units: if not user.has_perm("unit.edit", unit): continue if unit.target == self.target and unit.state == self.state: continue unit.target = self.target unit.state = self.state unit.save_backend(user, False, change_action=change_action, author=None) result = True return result def save_backend(self, user, propagate=True, change_action=None, author=None): """Stores unit to backend. Optional user parameters defines authorship of a change. This should be always called in a transaction with updated unit locked for update. """ # For case when authorship specified, use user author = author or user # Commit possible previous changes on this unit if self.pending: change_author = self.get_last_content_change()[0] if change_author != author: self.translation.commit_pending("pending unit", user, force=True) # Propagate to other projects # This has to be done before changing source/content_hash for template if propagate: self.propagate(user, change_action, author=author) # Return if there was no change # We have to explicitly check for fuzzy flag change on monolingual # files, where we handle it ourselves without storing to backend if self.old_unit.state == self.state and self.old_unit.target == self.target: return False if self.translation.is_source and not self.translation.component.intermediate: self.source = self.target self.content_hash = calculate_hash(self.source, self.context) # Unit is pending for write self.pending = True # Update translated flag (not fuzzy and at least one translation) translation = bool(max(self.get_target_plurals())) if self.state >= STATE_TRANSLATED and not translation: self.state = STATE_EMPTY elif self.state == STATE_EMPTY and translation: self.state = STATE_TRANSLATED self.original_state = self.state # Save updated unit to database self.save() # Generate Change object for this change self.generate_change(user or author, author, change_action) if change_action not in ( Change.ACTION_UPLOAD, Change.ACTION_AUTO, Change.ACTION_BULK_EDIT, ): # Update translation stats self.translation.invalidate_cache() # Update user stats author.profile.translated += 1 author.profile.save() # Update related source strings if working on a template if self.translation.is_template and self.old_unit.target != self.target: self.update_source_units(self.old_unit.target, user or author, author) return True def update_source_units(self, previous_source, user, author): """Update source for units withing same component. This is needed when editing template translation for monolingual formats. """ # Find relevant units same_source = Unit.objects.filter( translation__component=self.translation.component, id_hash=self.id_hash).exclude(id=self.id) for unit in same_source.prefetch(): # Update source, number of words and content_hash unit.source = self.target unit.num_words = self.num_words unit.content_hash = self.content_hash # Find reverted units if unit.state == STATE_FUZZY and unit.previous_source == self.target: # Unset fuzzy on reverted unit.original_state = unit.state = STATE_TRANSLATED unit.previous_source = "" elif (unit.original_state == STATE_FUZZY and unit.previous_source == self.target): # Unset fuzzy on reverted unit.original_state = STATE_TRANSLATED unit.previous_source = "" elif unit.state >= STATE_TRANSLATED: # Set fuzzy on changed unit.original_state = STATE_FUZZY if unit.state < STATE_READONLY: unit.state = STATE_FUZZY unit.previous_source = previous_source # Save unit and change unit.save() Change.objects.create( unit=unit, action=Change.ACTION_SOURCE_CHANGE, user=user, author=author, old=previous_source, target=self.target, ) # Invalidate stats unit.translation.invalidate_cache() def generate_change(self, user, author, change_action): """Create Change entry for saving unit.""" # Notify about new contributor user_changes = Change.objects.filter(translation=self.translation, user=user) if not user_changes.exists(): Change.objects.create( unit=self, action=Change.ACTION_NEW_CONTRIBUTOR, user=user, author=author, ) # Action type to store if change_action is not None: action = change_action elif self.state == STATE_FUZZY: action = Change.ACTION_MARKED_EDIT elif self.old_unit.state >= STATE_FUZZY: if self.state == STATE_APPROVED: action = Change.ACTION_APPROVE else: action = Change.ACTION_CHANGE else: action = Change.ACTION_NEW # Create change object Change.objects.create( unit=self, action=action, user=user, author=author, target=self.target, old=self.old_unit.target, ) @cached_property def suggestions(self): """Return all suggestions for this unit.""" return self.suggestion_set.order() @cached_property def all_checks(self): result = self.check_set.all() # Force fetching list(result) return result @property def all_checks_names(self): return {check.check for check in self.all_checks} @property def dismissed_checks(self): return [check for check in self.all_checks if check.dismissed] @property def active_checks(self): """Return all active (not ignored) checks for this unit.""" return [check for check in self.all_checks if not check.dismissed] @cached_property def all_comments(self): """Return list of target comments.""" return Comment.objects.filter(Q(unit=self) | Q(unit=self.source_info)).order() def run_checks(self, same_content=True): """Update checks for this unit.""" run_propagate = False src = self.get_source_plurals() tgt = self.get_target_plurals() old_checks = self.all_checks_names create = [] if self.translation.is_source: checks = CHECKS.source.items() meth = "check_source" args = src, self else: checks = CHECKS.target.items() meth = "check_target" args = src, tgt, self # Run all checks for check, check_obj in checks: # Does the check fire? if getattr(check_obj, meth)(*args): if check in old_checks: # We already have this check old_checks.remove(check) else: # Create new check create.append( Check(unit=self, dismissed=False, check=check)) run_propagate |= check_obj.propagates if create: Check.objects.bulk_create(create, batch_size=500, ignore_conflicts=True) # Propagate checks which need it (for example consistency) if run_propagate: for unit in self.same_source_units: try: unit.run_checks() except Unit.DoesNotExist: # This can happen in some corner cases like changing # source language of a project - the source language is # changed first and then components are updated. But # not all are yet updated and this spans across them. continue # Trigger source checks on target check update (multiple failing checks) if not self.translation.is_source: self.source_info.is_batch_update = self.is_batch_update self.source_info.run_checks() # Delete no longer failing checks if old_checks: Check.objects.filter(unit=self, check__in=old_checks).delete() # This is always preset as it is used in top of this method del self.__dict__["all_checks"] def nearby(self): """Return list of nearby messages based on location.""" return (Unit.objects.prefetch().order_by("position").filter( translation=self.translation, position__gte=self.position - settings.NEARBY_MESSAGES, position__lte=self.position + settings.NEARBY_MESSAGES, )) def nearby_keys(self): # Do not show nearby keys on bilingual if not self.translation.component.has_template(): return [] key = self.translation.keys_cache_key key_list = cache.get(key) if key_list is None or self.pk not in key_list or True: key_list = list( Unit.objects.filter(translation=self.translation).order_by( "context").values_list("id", flat=True)) cache.set(key, key_list) offset = key_list.index(self.pk) nearby = key_list[max(offset - settings.NEARBY_MESSAGES, 0):offset + settings.NEARBY_MESSAGES] return (Unit.objects.filter( translation=self.translation, id__in=nearby).prefetch().order_by("context")) def variants(self): if not self.variant: return [] return (self.variant.unit_set.filter( translation=self.translation).prefetch().order_by("context")) @transaction.atomic def translate(self, user, new_target, new_state, change_action=None, propagate=True): """Store new translation of a unit.""" # Fetch current copy from database and lock it for update self.old_unit = Unit.objects.select_for_update().get(pk=self.pk) # Update unit and save it if isinstance(new_target, str): self.target = new_target not_empty = bool(new_target) else: self.target = join_plural(new_target) not_empty = bool(max(new_target)) # Newlines fixup if "dos-eol" in self.all_flags: self.target = NEWLINES.sub("\r\n", self.target) if not_empty: self.state = new_state else: self.state = STATE_EMPTY self.original_state = self.state saved = self.save_backend(user, change_action=change_action, propagate=propagate) # Enforced checks can revert the state to needs editing (fuzzy) if (self.state >= STATE_TRANSLATED and self.translation.component.enforced_checks and self.all_checks_names & set(self.translation.component.enforced_checks)): self.state = self.original_state = STATE_FUZZY self.save(same_state=True, same_content=True, update_fields=["state"]) if (propagate and user and self.target != self.old_unit.target and self.state >= STATE_TRANSLATED): update_memory(user, self) return saved def get_all_flags(self, override=None): """Return union of own and component flags.""" return Flags(self.translation.all_flags, self.extra_flags, override or self.flags) @cached_property def all_flags(self): return self.get_all_flags() @cached_property def source_info(self): """Return related source string object.""" if self.translation.is_source: return self return self.translation.component.get_source(self.id_hash) def get_secondary_units(self, user): """Return list of secondary units.""" secondary_langs = user.profile.secondary_languages.exclude( id=self.translation.language.id) return get_distinct_translations( Unit.objects.filter( id_hash=self.id_hash, state__gte=STATE_TRANSLATED, translation__component=self.translation.component, translation__language__in=secondary_langs, ).exclude(target="")) @property def checksum(self): """Return unique hex identifier. It's unsigned representation of id_hash in hex. """ return hash_to_checksum(self.id_hash) @cached_property def same_source_units(self): return (Unit.objects.same(self).prefetch().filter( translation__component__allow_translation_propagation=True)) def get_max_length(self): """Returns maximal translation length.""" if not self.pk: return 10000 if self.all_flags.has_value("max-length"): return self.all_flags.get_value("max-length") if settings.LIMIT_TRANSLATION_LENGTH_BY_SOURCE_LENGTH: # Fallback to reasonably big value return max(100, len(self.get_source_plurals()[0]) * 10) return 10000 def get_target_hash(self): return calculate_hash(None, self.target) def get_last_content_change(self, silent=False): """Wrapper to get last content change metadata. Used when commiting pending changes, needs to handle and report inconsistencies from past releases. """ from weblate.auth.models import get_anonymous try: change = self.change_set.content().order_by("-timestamp")[0] return change.author or get_anonymous(), change.timestamp except IndexError: if not silent: report_error(level="error") return get_anonymous(), timezone.now() def get_locations(self): """Returns list of location filenames.""" for location in self.location.split(","): location = location.strip() if location == "": continue location_parts = location.split(":") if len(location_parts) == 2: filename, line = location_parts else: filename = location_parts[0] line = 0 yield location, filename, line
<title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title> </head> <body> <h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1> <ul> {% if directory != "/" %} <li><a href="../">../</a></li> {% endif %} {% for f in file_list %} <li><a href="{{ f|urlencode }}">{{ f }}</a></li> {% endfor %} </ul> </body> </html> """ template_translatable = gettext_lazy("Index of %(directory)s") def directory_index(path, fullpath): try: t = loader.select_template([ 'static/directory_index.html', 'static/directory_index', ]) except TemplateDoesNotExist: t = Engine(libraries={ 'i18n': 'django.templatetags.i18n' }).from_string(DEFAULT_DIRECTORY_INDEX_TEMPLATE) c = Context() else: c = {}
class PluginFormAdd(forms.Form): """Form to add a script.""" languages = ( ('python', 'Python (.py)'), ('perl', 'Perl (.pl)'), ('ruby', 'Ruby (.rb)'), ('lua', 'Lua (.lua)'), ('tcl', 'Tcl (.tcl)'), ('guile', 'Scheme (.scm)'), ('javascript', 'Javascript (.js)'), ) required_css_class = 'required' language = forms.ChoiceField( choices=languages, label=pgettext_lazy(u'programming language', u'Language') ) name = NameField( max_length=MAX_LENGTH_NAME, label=gettext_lazy('Name'), widget=forms.TextInput(attrs={'size': str(MAX_LENGTH_NAME)}) ) version = forms.CharField( max_length=MAX_LENGTH_VERSION, label=gettext_lazy('Version'), help_text=gettext_lazy('version of script (only digits or dots)'), widget=forms.TextInput(attrs={'size': '7'}) ) license = forms.CharField( max_length=MAX_LENGTH_LICENSE, label=gettext_lazy('License'), help_text=gettext_lazy('license (for example: GPL3, BSD, ...)'), widget=forms.TextInput(attrs={'size': '7'}) ) file = forms.FileField( label=gettext_lazy('File'), help_text=gettext_lazy('the script') ) description = forms.CharField( max_length=MAX_LENGTH_DESC, label=gettext_lazy('Description'), widget=forms.TextInput(attrs={'size': '75'}) ) requirements = forms.CharField( required=False, max_length=MAX_LENGTH_REQUIRE, label=gettext_lazy('Requirements'), help_text=gettext_lazy('optional'), widget=forms.TextInput(attrs={'size': '30'}) ) min_max = forms.ChoiceField( choices=[], label=gettext_lazy('Min/max WeeChat') ) author = forms.CharField( max_length=MAX_LENGTH_AUTHOR, label=gettext_lazy('Your name or nick'), help_text=gettext_lazy('used for scripts page and git commit') ) mail = forms.EmailField( max_length=MAX_LENGTH_MAIL, label=gettext_lazy('Your e-mail'), help_text=gettext_lazy('used for scripts page and git commit'), widget=Html5EmailInput(attrs={'size': '40'}) ) comment = forms.CharField( required=False, max_length=1024, label=gettext_lazy('Comments'), help_text=gettext_lazy('optional, not displayed'), widget=forms.Textarea(attrs={'rows': '3'}) ) test = TestField( max_length=64, label=gettext_lazy('Are you a spammer?'), help_text=gettext_lazy('enter "no" if you are not a spammer'), widget=forms.TextInput(attrs={'size': '10'}) ) def __init__(self, *args, **kwargs): super(PluginFormAdd, self).__init__(*args, **kwargs) self.fields['min_max'].choices = get_min_max_choices() self.fields['name'].help_text = gettext_lazy( 'short name of script (max {max_chars} chars, ' 'only lower case letters, digits or "_")').format( max_chars=MAX_LENGTH_NAME)
class InteractionCSVForm(BaseCSVImportForm): """Form used for loading a CSV file to import interactions.""" csv_file_field_label = gettext_lazy('Interaction list (CSV file)') csv_file_field_help_text = gettext_lazy( 'Maximum file size: {max_file_size}. Use the CSV (UTF-8) format when using Microsoft ' 'Excel.', ).format(max_file_size=filesizeformat( settings.INTERACTION_ADMIN_CSV_IMPORT_MAX_SIZE), ) required_columns = InteractionCSVRowForm.get_required_field_names() def are_all_rows_valid(self): """Check if all of the rows in the CSV pass validation.""" return all(row_form.is_valid() for row_form in self._get_row_form_iterator()) def get_row_error_iterator(self): """Get a generator of CSVRowError instances.""" for row_form in self._get_row_form_iterator(): yield from row_form.get_flat_error_list_iterator() def get_matching_summary(self, max_rows): """ Get a summary of the contact matching results of the rows. This is used as part of the preview page displayed once a file has been uploaded. :returns: dict of counts by `ContactMatchingStatus` and list of matched rows as serializer dicts """ matching_counts = {status: 0 for status in ContactMatchingStatus} matched_rows = [] for row_form in self._get_row_form_iterator( raise_error_if_invalid=True): contact_matching_status = row_form.cleaned_data[ 'contact_matching_status'] matching_counts[contact_matching_status] += 1 is_row_matched = contact_matching_status == ContactMatchingStatus.matched if is_row_matched and len(matched_rows) < max_rows: matched_rows.append(row_form.cleaned_data_as_serializer_dict()) return matching_counts, matched_rows @reversion.create_revision() def save(self, user): """Saves all loaded rows matched with contacts.""" reversion.set_comment(REVISION_COMMENT) csv_file = self.cleaned_data['csv_file'] sha256 = _sha256_for_file(csv_file) source = { 'file': { 'name': csv_file.name, 'size': csv_file.size, 'sha256': sha256.hexdigest(), }, } matching_counts = {status: 0 for status in ContactMatchingStatus} unmatched_row_collector = UnmatchedRowCollector() for row_form in self._get_row_form_iterator( raise_error_if_invalid=True): if row_form.is_matched(): row_form.save(user, source) else: unmatched_row_collector.append_row(row_form) matching_counts[ row_form.cleaned_data['contact_matching_status']] += 1 return matching_counts, unmatched_row_collector def save_to_cache(self): """ Generate a token and store the file in the configured cache with a timeout. Can only be called on a validated form. """ token = token_urlsafe() csv_file = self.cleaned_data['csv_file'] csv_file.seek(0) contents = csv_file.read() save_file_contents_and_name(token, contents, csv_file.name) return token @classmethod def from_token(cls, token): """ Create a InteractionCSVForm instance using a token. Returns None if serialised data for the token can't be found in the cache. """ file_contents_and_name = load_file_contents_and_name(token) if not file_contents_and_name: return None contents, name = file_contents_and_name csv_file = SimpleUploadedFile(name=name, content=contents) return cls(files={ 'csv_file': csv_file, }, ) def _get_row_form_iterator(self, raise_error_if_invalid=False): """ Get a generator over InteractionCSVRowForm instances. This should only be called if the rows have previously been validated. """ duplicate_tracker = DuplicateTracker() with self.open_file_as_dict_reader() as dict_reader: for index, row in enumerate(dict_reader): row_form = InteractionCSVRowForm( row_index=index, data=row, duplicate_tracker=duplicate_tracker, ) if not row_form.is_valid() and raise_error_if_invalid: # We are not expecting this to happen. Raise an exception to alert us if # it does. raise DataHubError( 'CSV row unexpectedly failed revalidation') yield row_form
class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView): model = Submission paginate_by = 50 show_problem = True title = gettext_lazy('All submissions') content_title = gettext_lazy('All submissions') tab = 'all_submissions_list' template_name = 'submission/list.html' context_object_name = 'submissions' first_page_href = None def get_result_data(self): result = self._get_result_data() for category in result['categories']: category['name'] = _(category['name']) return result def _get_result_data(self): return get_result_data(self.get_queryset().order_by()) def access_check(self, request): pass @cached_property def in_contest(self): return self.request.user.is_authenticated and self.request.profile.current_contest is not None @cached_property def contest(self): return self.request.profile.current_contest.contest def _get_queryset(self): queryset = Submission.objects.all() use_straight_join(queryset) queryset = submission_related(queryset.order_by('-id')) if self.show_problem: queryset = queryset.prefetch_related(Prefetch('problem__translations', queryset=ProblemTranslation.objects.filter( language=self.request.LANGUAGE_CODE), to_attr='_trans')) if self.in_contest: queryset = queryset.filter(contest__participation__contest_id=self.contest.id) if self.contest.hide_scoreboard and self.contest.is_in_contest(self.request.user): queryset = queryset.filter(contest__participation__user=self.request.profile) else: queryset = queryset.select_related('contest_object').defer('contest_object__description') if not self.request.user.has_perm('judge.see_private_contest'): # Show submissions for any contest you can edit or visible scoreboard contest_queryset = Contest.objects.filter(Q(organizers=self.request.profile) | Q(hide_scoreboard=False)) queryset = queryset.filter(Q(contest_object_id__in=contest_queryset) | Q(contest_object__isnull=True)) if self.selected_languages: queryset = queryset.filter(language_id__in=Language.objects.filter(key__in=self.selected_languages)) if self.selected_statuses: queryset = queryset.filter(result__in=self.selected_statuses) return queryset def get_queryset(self): queryset = self._get_queryset() if not self.in_contest: if not self.request.user.has_perm('judge.see_private_problem'): queryset = queryset.filter(problem__is_public=True) if not self.request.user.has_perm('judge.see_organization_problem'): filter = Q(problem__is_organization_private=False) if self.request.user.is_authenticated: filter |= Q(problem__organizations__in=self.request.profile.organizations.all()) queryset = queryset.filter(filter) return queryset def get_my_submissions_page(self): return None def get_all_submissions_page(self): return reverse('all_submissions') def get_searchable_status_codes(self): hidden_codes = ['SC'] if not self.request.user.is_superuser and not self.request.user.is_staff: hidden_codes += ['IE'] return [(key, value) for key, value in Submission.RESULT if key not in hidden_codes] def get_context_data(self, **kwargs): context = super(SubmissionsListBase, self).get_context_data(**kwargs) authenticated = self.request.user.is_authenticated context['dynamic_update'] = False context['show_problem'] = self.show_problem context['completed_problem_ids'] = user_completed_ids(self.request.profile) if authenticated else [] context['authored_problem_ids'] = user_authored_ids(self.request.profile) if authenticated else [] context['editable_problem_ids'] = user_editable_ids(self.request.profile) if authenticated else [] context['all_languages'] = Language.objects.all().values_list('key', 'name') context['selected_languages'] = self.selected_languages context['all_statuses'] = self.get_searchable_status_codes() context['selected_statuses'] = self.selected_statuses context['results_json'] = mark_safe(json.dumps(self.get_result_data())) context['results_colors_json'] = mark_safe(json.dumps(settings.DMOJ_STATS_SUBMISSION_RESULT_COLORS)) context['page_suffix'] = suffix = ('?' + self.request.GET.urlencode()) if self.request.GET else '' context['first_page_href'] = (self.first_page_href or '.') + suffix context['my_submissions_link'] = self.get_my_submissions_page() context['all_submissions_link'] = self.get_all_submissions_page() context['tab'] = self.tab return context def get(self, request, *args, **kwargs): check = self.access_check(request) if check is not None: return check self.selected_languages = set(request.GET.getlist('language')) self.selected_statuses = set(request.GET.getlist('status')) if 'results' in request.GET: return JsonResponse(self.get_result_data()) return super(SubmissionsListBase, self).get(request, *args, **kwargs)
class OTPForm(forms.Form): otp = forms.CharField(required=True, label=gettext_lazy("Code"))
return get_component( self.request, self.kwargs["project"], self.kwargs["component"] ) class ProjectViewMixin: project = None # This should be done in setup once we drop support for older Django def dispatch(self, request, *args, **kwargs): self.project = get_project(self.request, self.kwargs["project"]) return super().dispatch(request, *args, **kwargs) SORT_CHOICES = { "-priority,position": gettext_lazy("Position and priority"), "position": gettext_lazy("Position"), "priority": gettext_lazy("Priority"), "labels": gettext_lazy("Labels"), "timestamp": gettext_lazy("Age of string"), "num_words": gettext_lazy("Number of words"), "num_comments": gettext_lazy("Number of comments"), "num_failing_checks": gettext_lazy("Number of failing checks"), "context": pgettext_lazy("Translation key", "Key"), } SORT_LOOKUP = {key.replace("-", ""): value for key, value in SORT_CHOICES.items()} def get_sort_name(request): """Gets sort name."""
class IProjectSerializer(PermittedFieldsModelSerializer, NoteAwareModelSerializer): """Serialiser for investment project endpoints.""" default_error_messages = { 'only_pm_or_paa_can_move_to_verify_win': gettext_lazy( 'Only the Project Manager or Project Assurance Adviser can move the project' ' to the ‘Verify win’ stage.', ), 'only_ivt_can_move_to_won': gettext_lazy( 'Only the Investment Verification Team can move the project to the ‘Won’ stage.', ), } incomplete_fields = serializers.SerializerMethodField() project_code = serializers.CharField(read_only=True) investment_type = NestedRelatedField(meta_models.InvestmentType) stage = NestedRelatedField(meta_models.InvestmentProjectStage, required=False) country_lost_to = NestedRelatedField(meta_models.Country, required=False, allow_null=True) country_investment_originates_from = NestedRelatedField( meta_models.Country, required=False, allow_null=True, ) investor_company = NestedRelatedField(Company, required=True, allow_null=False) investor_company_country = NestedRelatedField(meta_models.Country, read_only=True) investor_type = NestedRelatedField(InvestorType, required=False, allow_null=True) intermediate_company = NestedRelatedField(Company, required=False, allow_null=True) level_of_involvement = NestedRelatedField(Involvement, required=False, allow_null=True) likelihood_to_land = NestedRelatedField(LikelihoodToLand, required=False, allow_null=True) specific_programme = NestedRelatedField(SpecificProgramme, required=False, allow_null=True) client_contacts = NestedRelatedField( Contact, many=True, required=True, allow_null=False, allow_empty=False, ) client_relationship_manager = NestedAdviserField(required=True, allow_null=False) client_relationship_manager_team = NestedRelatedField(meta_models.Team, read_only=True) referral_source_adviser = NestedAdviserField(required=True, allow_null=False) referral_source_activity = NestedRelatedField( meta_models.ReferralSourceActivity, required=True, allow_null=False, ) referral_source_activity_website = NestedRelatedField( meta_models.ReferralSourceWebsite, required=False, allow_null=True, ) referral_source_activity_marketing = NestedRelatedField( meta_models.ReferralSourceMarketing, required=False, allow_null=True, ) fdi_type = NestedRelatedField(meta_models.FDIType, required=False, allow_null=True) sector = NestedRelatedField(meta_models.Sector, required=True, allow_null=False) business_activities = NestedRelatedField( meta_models.InvestmentBusinessActivity, many=True, required=True, allow_null=False, allow_empty=False, ) archived_by = NestedAdviserField(read_only=True) project_manager_request_status = NestedRelatedField( ProjectManagerRequestStatus, required=False, allow_null=True, ) # Value fields fdi_value = NestedRelatedField(meta_models.FDIValue, required=False, allow_null=True) average_salary = NestedRelatedField( meta_models.SalaryRange, required=False, allow_null=True, ) value_complete = serializers.SerializerMethodField() associated_non_fdi_r_and_d_project = NestedRelatedField( InvestmentProject, required=False, allow_null=True, extra_fields=('name', 'project_code'), ) # Requirements fields competitor_countries = NestedRelatedField(meta_models.Country, many=True, required=False) # Note: uk_region_locations is the possible UK regions at the start of the project (not the # actual/final UK regions at the end of the project) uk_region_locations = NestedRelatedField(meta_models.UKRegion, many=True, required=False) actual_uk_regions = NestedRelatedField(meta_models.UKRegion, many=True, required=False) delivery_partners = NestedRelatedField(InvestmentDeliveryPartner, many=True, required=False) strategic_drivers = NestedRelatedField( meta_models.InvestmentStrategicDriver, many=True, required=False, ) uk_company = NestedRelatedField(Company, required=False, allow_null=True) requirements_complete = serializers.SerializerMethodField() # Team fields project_manager = NestedAdviserField(required=False, allow_null=True) project_assurance_adviser = NestedAdviserField(required=False, allow_null=True) project_manager_team = NestedRelatedField(meta_models.Team, read_only=True) project_assurance_team = NestedRelatedField(meta_models.Team, read_only=True) team_members = NestedIProjectTeamMemberSerializer(many=True, read_only=True) team_complete = serializers.SerializerMethodField() # SPI fields project_arrived_in_triage_on = serializers.DateField(required=False, allow_null=True) proposal_deadline = serializers.DateField(required=False, allow_null=True) stage_log = NestedInvestmentProjectStageLogSerializer(many=True, read_only=True) def save(self, **kwargs): """Saves when and who assigned a project manager for the first time.""" if ( 'project_manager' in self.validated_data and (self.instance is None or self.instance.project_manager is None) ): kwargs['project_manager_first_assigned_on'] = now() kwargs['project_manager_first_assigned_by'] = self.context['current_user'] super().save(**kwargs) def validate_estimated_land_date(self, value): """Validate estimated land date.""" if value or (self.instance and self.instance.allow_blank_estimated_land_date): return value raise serializers.ValidationError(REQUIRED_MESSAGE) def validate(self, data): """Validates the object after individual fields have been validated. Performs stage-dependent validation of the different sections. When transitioning stage, all fields required for the new stage are validated. In other cases, only the fields being modified are validated. If a project ends up in an invalid state, this avoids the user being unable to rectify the situation. """ if not self.instance: # Required for validation as DRF does not allow defaults for read-only fields data['allow_blank_possible_uk_regions'] = False self._check_if_investment_project_can_be_moved_to_verify_win(data) self._check_if_investment_project_can_be_moved_to_won(data) self._validate_for_stage(data) self._update_status(data) self._track_project_manager_request(data) return data def _track_project_manager_request(self, data): """ If a project manager has been requested track the request by setting the project_manager_requested_on timestamp. """ pm_requested = ProjectManagerRequestStatusValue.requested.value.id if ( 'project_manager_request_status' in data and str(data['project_manager_request_status'].pk) == pm_requested and (self.instance is None or self.instance.project_manager_requested_on is None) ): data['project_manager_requested_on'] = now() def _check_if_investment_project_can_be_moved_to_verify_win(self, data): # only project manager or project assurance adviser can move a project to verify win if self.instance and 'stage' in data: current_user_id = self.context['current_user'].id allowed_users_ids = ( self.instance.project_manager_id, self.instance.project_assurance_adviser_id, ) if ( str(data['stage'].id) == InvestmentProjectStage.verify_win.value.id and self.instance.stage.order < data['stage'].order and current_user_id not in allowed_users_ids ): errors = { 'stage': self.default_error_messages['only_pm_or_paa_can_move_to_verify_win'], } raise serializers.ValidationError(errors) def _check_if_investment_project_can_be_moved_to_won(self, data): # Investment Verification Team can only move a project to won if self.instance and 'stage' in data: current_user = self.context['current_user'] permission_name = f'investment.{InvestmentProjectPermission.change_stage_to_won}' if ( str(data['stage'].id) == InvestmentProjectStage.won.value.id and self.instance.stage.order < data['stage'].order and not current_user.has_perm(permission_name) ): errors = { 'stage': self.default_error_messages['only_ivt_can_move_to_won'], } raise serializers.ValidationError(errors) def _validate_for_stage(self, data): fields = None if self.partial and 'stage' not in data: fields = data.keys() errors = validate(self.instance, data, fields=fields) if errors: raise serializers.ValidationError(errors) def get_incomplete_fields(self, instance): """Returns the names of the fields that still need to be completed in order to move to the next stage. """ return tuple(validate(instance=instance, next_stage=True)) def get_value_complete(self, instance): """Whether the value fields required to move to the next stage are complete.""" return not validate( instance=instance, fields=VALUE_FIELDS, next_stage=True, ) def get_requirements_complete(self, instance): """Whether the requirements fields required to move to the next stage are complete.""" return not validate( instance=instance, fields=REQUIREMENTS_FIELDS, next_stage=True, ) def get_team_complete(self, instance): """Whether the team fields required to move to the next stage are complete.""" return not validate( instance=instance, fields=TEAM_FIELDS, next_stage=True, ) def _update_status(self, data): """Updates the project status when the stage changes to or from Won.""" old_stage = self.instance.stage if self.instance else None new_stage = data.get('stage') if not new_stage or new_stage == old_stage: return combiner = DataCombiner(instance=self.instance, update_data=data) new_status = combiner.get_value('status') if str(new_stage.id) == InvestmentProjectStage.won.value.id: data['status'] = InvestmentProject.Status.WON elif ( old_stage and str(old_stage.id) == InvestmentProjectStage.won.value.id and new_status == InvestmentProject.Status.WON ): data['status'] = InvestmentProject.Status.ONGOING class Meta: model = InvestmentProject fields = ALL_FIELDS permissions = { f'investment.{InvestmentProjectPermission.view_investmentproject_document}': 'archived_documents_url_path', } read_only_fields = ( 'allow_blank_estimated_land_date', 'allow_blank_possible_uk_regions', 'archived', 'archived_on', 'archived_reason', 'archived_documents_url_path', 'comments', 'project_manager_requested_on', 'gross_value_added', )
class ThemeFormAdd(forms.Form): """Form to add a theme.""" required_css_class = 'required' themefile = forms.FileField(label=gettext_lazy('File'), help_text=gettext_lazy('the theme'), widget=forms.FileInput(attrs={'size': '50'})) description = forms.CharField(required=False, max_length=MAX_LENGTH_DESC, label=gettext_lazy('Description'), help_text=gettext_lazy('optional'), widget=forms.TextInput(attrs={'size': '60'})) author = forms.CharField(max_length=MAX_LENGTH_AUTHOR, label=gettext_lazy('Your name or nick')) mail = forms.EmailField( max_length=MAX_LENGTH_MAIL, label=gettext_lazy('Your e-mail'), help_text=gettext_lazy('no spam, never displayed on site'), widget=forms.TextInput(attrs={'size': '40'})) comment = forms.CharField( required=False, max_length=1024, label=gettext_lazy('Comments'), help_text=gettext_lazy('optional, not displayed'), widget=forms.Textarea(attrs={'rows': '3'})) test = TestField( max_length=64, label=gettext_lazy('Are you a spammer?'), help_text=gettext_lazy('enter "no" if you are not a spammer'), widget=forms.TextInput(attrs={'size': '10'})) def clean_themefile(self): """Check if theme file is valid.""" _file = self.cleaned_data['themefile'] if _file.size > 512 * 1024: raise forms.ValidationError(gettext_lazy('Theme file too big.')) props = Theme.get_props(_file.read()) if 'name' not in props or 'weechat' not in props: raise forms.ValidationError(gettext_lazy('Invalid theme file.')) themes = Theme.objects.filter(name=props['name']) if themes: raise forms.ValidationError( gettext_lazy('This name already exists.')) if not props['name'].endswith('.theme'): raise forms.ValidationError( gettext_lazy('Invalid name inside theme file.')) shortname = props['name'][0:-6] if not re.search('^[A-Za-z0-9_]+$', shortname): raise forms.ValidationError( gettext_lazy('Invalid name inside theme file.')) release_stable = Release.objects.get(version='stable') release_devel = Release.objects.get(version='devel') if props['weechat'] not in (release_stable.description, re.sub('-.*', '', release_devel.description)): raise forms.ValidationError( gettext_lazy('Invalid WeeChat version, too old!')) _file.seek(0) return _file
class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView): model = Problem title = gettext_lazy('Problems') context_object_name = 'problems' template_name = 'problem/list.html' paginate_by = 50 sql_sort = frozenset(('points', 'ac_rate', 'user_count', 'code')) manual_sort = frozenset(('name', 'group', 'solved', 'type', 'editorial')) all_sorts = sql_sort | manual_sort default_desc = frozenset(('points', 'ac_rate', 'user_count')) default_sort = 'code' def get_paginator(self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs): paginator = DiggPaginator(queryset, per_page, body=6, padding=2, orphans=orphans, allow_empty_first_page=allow_empty_first_page, **kwargs) if not self.in_contest: # Get the number of pages and then add in this magic. # noinspection PyStatementEffect paginator.num_pages queryset = queryset.add_i18n_name(self.request.LANGUAGE_CODE) sort_key = self.order.lstrip('-') if sort_key in self.sql_sort: queryset = queryset.order_by(self.order, 'id') elif sort_key == 'name': queryset = queryset.order_by(self.order.replace('name', 'i18n_name'), 'id') elif sort_key == 'group': queryset = queryset.order_by(self.order + '__name', 'id') elif sort_key == 'editorial': queryset = queryset.order_by(self.order.replace('editorial', 'has_public_editorial'), 'id') elif sort_key == 'solved': if self.request.user.is_authenticated: profile = self.request.profile solved = user_completed_ids(profile) attempted = user_attempted_ids(profile) def _solved_sort_order(problem): if problem.id in solved: return 1 if problem.id in attempted: return 0 return -1 queryset = list(queryset) queryset.sort(key=_solved_sort_order, reverse=self.order.startswith('-')) elif sort_key == 'type': if self.show_types: queryset = list(queryset) queryset.sort(key=lambda problem: problem.types_list[0] if problem.types_list else '', reverse=self.order.startswith('-')) paginator.object_list = queryset return paginator @cached_property def profile(self): if not self.request.user.is_authenticated: return None return self.request.profile def get_contest_queryset(self): queryset = self.profile.current_contest.contest.contest_problems.select_related('problem__group') \ .defer('problem__description').order_by('problem__code') \ .annotate(user_count=Count('submission__participation', distinct=True)) \ .order_by('order') queryset = TranslatedProblemForeignKeyQuerySet.add_problem_i18n_name(queryset, 'i18n_name', self.request.LANGUAGE_CODE, 'problem__name') return [{ 'id': p['problem_id'], 'code': p['problem__code'], 'name': p['problem__name'], 'i18n_name': p['i18n_name'], 'group': {'full_name': p['problem__group__full_name']}, 'points': p['points'], 'partial': p['partial'], 'user_count': p['user_count'], } for p in queryset.values('problem_id', 'problem__code', 'problem__name', 'i18n_name', 'problem__group__full_name', 'points', 'partial', 'user_count')] @staticmethod def apply_full_text(queryset, query): if recjk.search(query): # MariaDB can't tokenize CJK properly, fallback to LIKE '%term%' for each term. for term in query.split(): queryset = queryset.filter(Q(code__icontains=term) | Q(name__icontains=term) | Q(description__icontains=term)) return queryset return queryset.search(query, queryset.BOOLEAN).extra(order_by=['-relevance']) def get_normal_queryset(self): filter = Q(is_public=True) if not self.request.user.has_perm('see_organization_problem'): org_filter = Q(is_organization_private=False) if self.profile is not None: org_filter |= Q(organizations__in=self.profile.organizations.all()) filter &= org_filter if self.profile is not None: filter |= Q(authors=self.profile) filter |= Q(curators=self.profile) filter |= Q(testers=self.profile) queryset = Problem.objects.filter(filter).select_related('group').defer('description', 'summary') if self.profile is not None and self.hide_solved: queryset = queryset.exclude(id__in=Submission.objects.filter(user=self.profile, points=F('problem__points')) .values_list('problem__id', flat=True)) if self.show_types: queryset = queryset.prefetch_related('types') queryset = queryset.annotate(has_public_editorial=Case( When(solution__is_public=True, solution__publish_on__lte=timezone.now(), then=True), default=False, output_field=BooleanField(), )) if self.has_public_editorial: queryset = queryset.filter(has_public_editorial=True) if self.category is not None: queryset = queryset.filter(group__id=self.category) if self.selected_types: queryset = queryset.filter(types__in=self.selected_types) if 'search' in self.request.GET: self.search_query = query = ' '.join(self.request.GET.getlist('search')).strip() if query: if settings.ENABLE_FTS and self.full_text: queryset = self.apply_full_text(queryset, query) else: queryset = queryset.filter( Q(code__icontains=query) | Q(name__icontains=query) | Q(translations__name__icontains=query, translations__language=self.request.LANGUAGE_CODE)) self.prepoint_queryset = queryset if self.point_start is not None: queryset = queryset.filter(points__gte=self.point_start) if self.point_end is not None: queryset = queryset.filter(points__lte=self.point_end) return queryset.distinct() def get_queryset(self): if self.in_contest: return self.get_contest_queryset() else: return self.get_normal_queryset() def get_context_data(self, **kwargs): context = super(ProblemList, self).get_context_data(**kwargs) context['hide_solved'] = 0 if self.in_contest else int(self.hide_solved) context['show_types'] = 0 if self.in_contest else int(self.show_types) context['has_public_editorial'] = 0 if self.in_contest else int(self.has_public_editorial) context['full_text'] = 0 if self.in_contest else int(self.full_text) context['category'] = self.category context['categories'] = ProblemGroup.objects.all() if self.show_types: context['selected_types'] = self.selected_types context['problem_types'] = ProblemType.objects.all() context['has_fts'] = settings.ENABLE_FTS context['search_query'] = self.search_query context['completed_problem_ids'] = self.get_completed_problems() context['attempted_problems'] = self.get_attempted_problems() context.update(self.get_sort_paginate_context()) if not self.in_contest: context.update(self.get_sort_context()) context['hot_problems'] = hot_problems(timedelta(days=1), settings.DMOJ_PROBLEM_HOT_PROBLEM_COUNT) context['point_start'], context['point_end'], context['point_values'] = self.get_noui_slider_points() else: context['hot_problems'] = None context['point_start'], context['point_end'], context['point_values'] = 0, 0, {} context['hide_contest_scoreboard'] = self.contest.scoreboard_visibility in ( self.contest.SCOREBOARD_AFTER_CONTEST, self.contest.SCOREBOARD_AFTER_PARTICIPATION, self.contest.SCOREBOARD_HIDDEN, ) return context def get_noui_slider_points(self): points = sorted(self.prepoint_queryset.values_list('points', flat=True).distinct()) if not points: return 0, 0, {} if len(points) == 1: return points[0], points[0], { 'min': points[0] - 1, 'max': points[0] + 1, } start, end = points[0], points[-1] if self.point_start is not None: start = self.point_start if self.point_end is not None: end = self.point_end points_map = {0.0: 'min', 1.0: 'max'} size = len(points) - 1 return start, end, {points_map.get(i / size, '%.2f%%' % (100 * i / size,)): j for i, j in enumerate(points)} def GET_with_session(self, request, key): if not request.GET: return request.session.get(key, False) return request.GET.get(key, None) == '1' def setup_problem_list(self, request): self.hide_solved = self.GET_with_session(request, 'hide_solved') self.show_types = self.GET_with_session(request, 'show_types') self.full_text = self.GET_with_session(request, 'full_text') self.has_public_editorial = self.GET_with_session(request, 'has_public_editorial') self.search_query = None self.category = None self.selected_types = [] # This actually copies into the instance dictionary... self.all_sorts = set(self.all_sorts) if not self.show_types: self.all_sorts.discard('type') self.category = safe_int_or_none(request.GET.get('category')) if 'type' in request.GET: try: self.selected_types = list(map(int, request.GET.getlist('type'))) except ValueError: pass self.point_start = safe_float_or_none(request.GET.get('point_start')) self.point_end = safe_float_or_none(request.GET.get('point_end')) def get(self, request, *args, **kwargs): self.setup_problem_list(request) try: return super(ProblemList, self).get(request, *args, **kwargs) except ProgrammingError as e: return generic_message(request, 'FTS syntax error', e.args[1], status=400) def post(self, request, *args, **kwargs): to_update = ('hide_solved', 'show_types', 'full_text') for key in to_update: if key in request.GET: val = request.GET.get(key) == '1' request.session[key] = val else: request.session.pop(key, None) return HttpResponseRedirect(request.get_full_path())
def create(self, validated_data): fees_data = validated_data.pop('fees') if 'fees' in validated_data else [] positions_data = validated_data.pop('positions') if 'positions' in validated_data else [] payment_provider = validated_data.pop('payment_provider', None) payment_info = validated_data.pop('payment_info', '{}') payment_date = validated_data.pop('payment_date', now()) force = validated_data.pop('force', False) simulate = validated_data.pop('simulate', False) self._send_mail = validated_data.pop('send_mail', False) if 'invoice_address' in validated_data: iadata = validated_data.pop('invoice_address') name = iadata.pop('name', '') if name and not iadata.get('name_parts'): iadata['name_parts'] = { '_legacy': name } ia = InvoiceAddress(**iadata) else: ia = None lockfn = self.context['event'].lock if simulate: lockfn = NoLockManager with lockfn() as now_dt: free_seats = set() seats_seen = set() consume_carts = validated_data.pop('consume_carts', []) delete_cps = [] quota_avail_cache = {} v_budget = {} voucher_usage = Counter() if consume_carts: for cp in CartPosition.objects.filter( event=self.context['event'], cart_id__in=consume_carts, expires__gt=now() ): quotas = (cp.variation.quotas.filter(subevent=cp.subevent) if cp.variation else cp.item.quotas.filter(subevent=cp.subevent)) for quota in quotas: if quota not in quota_avail_cache: quota_avail_cache[quota] = list(quota.availability()) if quota_avail_cache[quota][1] is not None: quota_avail_cache[quota][1] += 1 if cp.voucher: voucher_usage[cp.voucher] -= 1 if cp.expires > now_dt: if cp.seat: free_seats.add(cp.seat) delete_cps.append(cp) errs = [{} for p in positions_data] for i, pos_data in enumerate(positions_data): if pos_data.get('voucher'): v = pos_data['voucher'] if pos_data.get('addon_to'): errs[i]['voucher'] = ['Vouchers are currently not supported for add-on products.'] continue if not v.applies_to(pos_data['item'], pos_data.get('variation')): errs[i]['voucher'] = [error_messages['voucher_invalid_item']] continue if v.subevent_id and pos_data.get('subevent').pk != v.subevent_id: errs[i]['voucher'] = [error_messages['voucher_invalid_subevent']] continue if v.valid_until is not None and v.valid_until < now_dt: errs[i]['voucher'] = [error_messages['voucher_expired']] continue voucher_usage[v] += 1 if voucher_usage[v] > 0: redeemed_in_carts = CartPosition.objects.filter( Q(voucher=pos_data['voucher']) & Q(event=self.context['event']) & Q(expires__gte=now_dt) ).exclude(pk__in=[cp.pk for cp in delete_cps]) v_avail = v.max_usages - v.redeemed - redeemed_in_carts.count() if v_avail < voucher_usage[v]: errs[i]['voucher'] = [ 'The voucher has already been used the maximum number of times.' ] if v.budget is not None: price = pos_data.get('price') if price is None: price = get_price( item=pos_data.get('item'), variation=pos_data.get('variation'), voucher=v, custom_price=None, subevent=pos_data.get('subevent'), addon_to=pos_data.get('addon_to'), invoice_address=ia, ).gross pbv = get_price( item=pos_data['item'], variation=pos_data.get('variation'), voucher=None, custom_price=None, subevent=pos_data.get('subevent'), addon_to=pos_data.get('addon_to'), invoice_address=ia, ) if v not in v_budget: v_budget[v] = v.budget - v.budget_used() disc = pbv.gross - price if disc > v_budget[v]: new_disc = v_budget[v] v_budget[v] -= new_disc if new_disc == Decimal('0.00') or pos_data.get('price') is not None: errs[i]['voucher'] = [ 'The voucher has a remaining budget of {}, therefore a discount of {} can not be ' 'given.'.format(v_budget[v] + new_disc, disc) ] continue pos_data['price'] = price + (disc - new_disc) else: v_budget[v] -= disc seated = pos_data.get('item').seat_category_mappings.filter(subevent=pos_data.get('subevent')).exists() if pos_data.get('seat'): if not seated: errs[i]['seat'] = ['The specified product does not allow to choose a seat.'] try: seat = self.context['event'].seats.get(seat_guid=pos_data['seat'], subevent=pos_data.get('subevent')) except Seat.DoesNotExist: errs[i]['seat'] = ['The specified seat does not exist.'] else: pos_data['seat'] = seat if (seat not in free_seats and not seat.is_available(sales_channel=validated_data.get('sales_channel', 'web'))) or seat in seats_seen: errs[i]['seat'] = [gettext_lazy('The selected seat "{seat}" is not available.').format(seat=seat.name)] seats_seen.add(seat) elif seated: errs[i]['seat'] = ['The specified product requires to choose a seat.'] if not force: for i, pos_data in enumerate(positions_data): if pos_data.get('voucher'): if pos_data['voucher'].allow_ignore_quota or pos_data['voucher'].block_quota: continue new_quotas = (pos_data.get('variation').quotas.filter(subevent=pos_data.get('subevent')) if pos_data.get('variation') else pos_data.get('item').quotas.filter(subevent=pos_data.get('subevent'))) if len(new_quotas) == 0: errs[i]['item'] = [gettext_lazy('The product "{}" is not assigned to a quota.').format( str(pos_data.get('item')) )] else: for quota in new_quotas: if quota not in quota_avail_cache: quota_avail_cache[quota] = list(quota.availability()) if quota_avail_cache[quota][1] is not None: quota_avail_cache[quota][1] -= 1 if quota_avail_cache[quota][1] < 0: errs[i]['item'] = [ gettext_lazy('There is not enough quota available on quota "{}" to perform the operation.').format( quota.name ) ] if any(errs): raise ValidationError({'positions': errs}) if validated_data.get('locale', None) is None: validated_data['locale'] = self.context['event'].settings.locale order = Order(event=self.context['event'], **validated_data) order.set_expires(subevents=[p.get('subevent') for p in positions_data]) order.meta_info = "{}" order.total = Decimal('0.00') if simulate: order = WrappedModel(order) order.last_modified = now() order.code = 'PREVIEW' else: order.save() if ia: if not simulate: ia.order = order ia.save() else: order.invoice_address = ia ia.last_modified = now() pos_map = {} for pos_data in positions_data: answers_data = pos_data.pop('answers', []) addon_to = pos_data.pop('addon_to', None) attendee_name = pos_data.pop('attendee_name', '') if attendee_name and not pos_data.get('attendee_name_parts'): pos_data['attendee_name_parts'] = { '_legacy': attendee_name } pos = OrderPosition(**pos_data) if simulate: pos.order = order._wrapped else: pos.order = order if addon_to: pos.addon_to = pos_map[addon_to] if pos.price is None: price = get_price( item=pos.item, variation=pos.variation, voucher=pos.voucher, custom_price=None, subevent=pos.subevent, addon_to=pos.addon_to, invoice_address=ia, ) pos.price = price.gross pos.tax_rate = price.rate pos.tax_value = price.tax pos.tax_rule = pos.item.tax_rule else: pos._calculate_tax() pos.price_before_voucher = get_price( item=pos.item, variation=pos.variation, voucher=None, custom_price=None, subevent=pos.subevent, addon_to=pos.addon_to, invoice_address=ia, ).gross if simulate: pos = WrappedModel(pos) pos.id = 0 answers = [] for answ_data in answers_data: options = answ_data.pop('options', []) answ = WrappedModel(QuestionAnswer(**answ_data)) answ.options = WrappedList(options) answers.append(answ) pos.answers = answers pos.pseudonymization_id = "PREVIEW" else: if pos.voucher: Voucher.objects.filter(pk=pos.voucher.pk).update(redeemed=F('redeemed') + 1) pos.save() for answ_data in answers_data: options = answ_data.pop('options', []) answ = pos.answers.create(**answ_data) answ.options.add(*options) pos_map[pos.positionid] = pos if not simulate: for cp in delete_cps: cp.delete() order.total = sum([p.price for p in pos_map.values()]) fees = [] for fee_data in fees_data: is_percentage = fee_data.pop('_treat_value_as_percentage', False) if is_percentage: fee_data['value'] = round_decimal(order.total * (fee_data['value'] / Decimal('100.00')), self.context['event'].currency) is_split_taxes = fee_data.pop('_split_taxes_like_products', False) if is_split_taxes: d = defaultdict(lambda: Decimal('0.00')) trz = TaxRule.zero() for p in pos_map.values(): tr = p.tax_rule d[tr] += p.price - p.tax_value base_values = sorted([tuple(t) for t in d.items()], key=lambda t: (t[0] or trz).rate) sum_base = sum(t[1] for t in base_values) fee_values = [(t[0], round_decimal(fee_data['value'] * t[1] / sum_base, self.context['event'].currency)) for t in base_values] sum_fee = sum(t[1] for t in fee_values) # If there are rounding differences, we fix them up, but always leaning to the benefit of the tax # authorities if sum_fee > fee_data['value']: fee_values[0] = (fee_values[0][0], fee_values[0][1] + (fee_data['value'] - sum_fee)) elif sum_fee < fee_data['value']: fee_values[-1] = (fee_values[-1][0], fee_values[-1][1] + (fee_data['value'] - sum_fee)) for tr, val in fee_values: fee_data['tax_rule'] = tr fee_data['value'] = val f = OrderFee(**fee_data) f.order = order._wrapped if simulate else order f._calculate_tax() fees.append(f) if not simulate: f.save() else: f = OrderFee(**fee_data) f.order = order._wrapped if simulate else order f._calculate_tax() fees.append(f) if not simulate: f.save() order.total += sum([f.value for f in fees]) if simulate: order.fees = fees order.positions = pos_map.values() return order # ignore payments else: order.save(update_fields=['total']) if order.total == Decimal('0.00') and validated_data.get('status') == Order.STATUS_PAID and not payment_provider: payment_provider = 'free' if order.total == Decimal('0.00') and validated_data.get('status') != Order.STATUS_PAID: order.status = Order.STATUS_PAID order.save() order.payments.create( amount=order.total, provider='free', state=OrderPayment.PAYMENT_STATE_CONFIRMED, payment_date=now() ) elif payment_provider == "free" and order.total != Decimal('0.00'): raise ValidationError('You cannot use the "free" payment provider for non-free orders.') elif validated_data.get('status') == Order.STATUS_PAID: if not payment_provider: raise ValidationError('You cannot create a paid order without a payment provider.') order.payments.create( amount=order.total, provider=payment_provider, info=payment_info, payment_date=payment_date, state=OrderPayment.PAYMENT_STATE_CONFIRMED ) elif payment_provider: order.payments.create( amount=order.total, provider=payment_provider, info=payment_info, state=OrderPayment.PAYMENT_STATE_CREATED ) return order
class Project(models.Model, URLMixin, PathMixin): ACCESS_PUBLIC = 0 ACCESS_PROTECTED = 1 ACCESS_PRIVATE = 100 ACCESS_CUSTOM = 200 ACCESS_CHOICES = ( (ACCESS_PUBLIC, gettext_lazy("Public")), (ACCESS_PROTECTED, gettext_lazy("Protected")), (ACCESS_PRIVATE, gettext_lazy("Private")), (ACCESS_CUSTOM, gettext_lazy("Custom")), ) name = models.CharField( verbose_name=gettext_lazy("Project name"), max_length=PROJECT_NAME_LENGTH, unique=True, help_text=gettext_lazy("Display name"), ) slug = models.SlugField( verbose_name=gettext_lazy("URL slug"), unique=True, max_length=PROJECT_NAME_LENGTH, help_text=gettext_lazy("Name used in URLs and filenames."), ) web = models.URLField( verbose_name=gettext_lazy("Project website"), help_text=gettext_lazy("Main website of translated project."), ) mail = models.EmailField( verbose_name=gettext_lazy("Mailing list"), blank=True, max_length=254, help_text=gettext_lazy("Mailing list for translators."), ) instructions = models.TextField( verbose_name=gettext_lazy("Translation instructions"), blank=True, help_text=_("You can use Markdown and mention users by @username."), ) set_language_team = models.BooleanField( verbose_name=gettext_lazy('Set "Language-Team" header'), default=True, help_text=gettext_lazy( 'Lets Anuvad update the "Language-Team" file header ' "of your project."), ) use_shared_tm = models.BooleanField( verbose_name=gettext_lazy("Use shared translation memory"), default=settings.DEFAULT_SHARED_TM, help_text=gettext_lazy( "Uses the pool of shared translations between projects."), ) contribute_shared_tm = models.BooleanField( verbose_name=gettext_lazy("Contribute to shared translation memory"), default=settings.DEFAULT_SHARED_TM, help_text=gettext_lazy( "Contributes to the pool of shared translations between projects." ), ) access_control = models.IntegerField( default=settings.DEFAULT_ACCESS_CONTROL, choices=ACCESS_CHOICES, verbose_name=gettext_lazy("Access control"), help_text=gettext_lazy( "How to restrict access to this project is detailed " "in the documentation."), ) enable_review = models.BooleanField( verbose_name=gettext_lazy("Enable reviews"), default=False, help_text=gettext_lazy( "Requires dedicated reviewers to approve translations."), ) enable_hooks = models.BooleanField( verbose_name=gettext_lazy("Enable hooks"), default=True, help_text=gettext_lazy( "Whether to allow updating this repository by remote hooks."), ) source_language = models.ForeignKey( Language, verbose_name=gettext_lazy("Source language"), help_text=gettext_lazy( "Language used for source strings in all components"), default=get_english_lang, on_delete=models.deletion.CASCADE, ) is_lockable = True _reverse_url_name = "project" objects = ProjectQuerySet.as_manager() class Meta: app_label = "trans" verbose_name = gettext_lazy("Project") verbose_name_plural = gettext_lazy("Projects") def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.old_access_control = self.access_control self.stats = ProjectStats(self) def add_user(self, user, group=None): """Add user based on username or email address.""" if group is None: if self.access_control != self.ACCESS_PUBLIC: group = "@Translate" else: group = "@Administration" group = self.group_set.get(name="{0}{1}".format(self.name, group)) user.groups.add(group) user.profile.watched.add(self) def remove_user(self, user, group=None): """Add user based on username or email address.""" if group is None: groups = self.group_set.filter(internal=True, name__contains="@") user.groups.remove(*groups) else: group = self.group_set.get(name="{0}{1}".format(self.name, group)) user.groups.remove(group) def get_reverse_url_kwargs(self): """Return kwargs for URL reversing.""" return {"project": self.slug} def get_widgets_url(self): """Return absolute URL for widgets.""" return get_site_url(reverse("widgets", kwargs={"project": self.slug})) def get_share_url(self): """Return absolute URL usable for sharing.""" return get_site_url(reverse("engage", kwargs={"project": self.slug})) @cached_property def locked(self): return (self.component_set.exists() and not self.component_set.filter(locked=False).exists()) def _get_path(self): return os.path.join(data_dir("vcs"), self.slug) def __str__(self): return self.name def save(self, *args, **kwargs): update_tm = self.contribute_shared_tm # Renaming detection old = None if self.id: old = Project.objects.get(pk=self.id) # Detect slug changes and rename directory self.check_rename(old) # Rename linked repos if old.slug != self.slug: for component in old.component_set.iterator(): new_component = self.component_set.get(pk=component.pk) new_component.project = self component.linked_childs.update( repo=new_component.get_repo_link_url()) update_tm = self.contribute_shared_tm and not old.contribute_shared_tm self.create_path() super().save(*args, **kwargs) # Reload components after source language change if old is not None and old.source_language != self.source_language: from weblate.trans.tasks import perform_load for component in self.component_set.iterator(): perform_load.delay(component.pk) # Update translation memory on enabled sharing if update_tm: transaction.on_commit(lambda: import_memory.delay(self.id)) @cached_property def languages(self): """Return list of all languages used in project.""" return (Language.objects.filter( translation__component__project=self).distinct().order()) def needs_commit(self): """Check whether there are any uncommitted changes.""" return any(component.needs_commit() for component in self.component_set.iterator()) def on_repo_components(self, default, call, *args, **kwargs): """Wrapper for operations on repository.""" ret = default for component in self.all_repo_components(): res = getattr(component, call)(*args, **kwargs) if default: ret = ret & res else: ret = ret | res return ret def commit_pending(self, reason, user): """Commit any pending changes.""" return self.on_repo_components(True, "commit_pending", reason, user) def repo_needs_merge(self): return self.on_repo_components(False, "repo_needs_merge") def repo_needs_push(self): return self.on_repo_components(False, "repo_needs_push") def do_update(self, request=None, method=None): """Update all Git repos.""" return self.on_repo_components(True, "do_update", request, method=method) def do_push(self, request=None): """Push all Git repos.""" return self.on_repo_components(True, "do_push", request) def do_reset(self, request=None): """Push all Git repos.""" return self.on_repo_components(True, "do_reset", request) def do_cleanup(self, request=None): """Push all Git repos.""" return self.on_repo_components(True, "do_cleanup", request) def can_push(self): """Check whether any suprojects can push.""" return self.on_repo_components(False, "can_push") def all_repo_components(self): """Return list of all unique VCS components.""" result = list(self.component_set.with_repo()) included = {component.get_repo_link_url() for component in result} linked = self.component_set.filter(repo__startswith="weblate:") for other in linked: if other.repo in included: continue included.add(other.repo) result.append(other) return result @cached_property def paid(self): return ("weblate.billing" not in settings.INSTALLED_APPS or not self.billing_set.exists() or self.billing_set.filter(paid=True).exists()) def run_batch_checks(self, attr_name): """Run batch executed checks.""" from weblate.trans.models import Unit create = [] meth_name = "check_{}_project".format(attr_name) for check, check_obj in CHECKS.items(): if not getattr(check_obj, attr_name) or not check_obj.batch_update: continue self.log_info("running batch check: %s", check) # List of triggered checks data = getattr(check_obj, meth_name)(self) # Fetch existing check instances existing = set( Check.objects.filter( unit__translation__component__project=self, check=check).values_list("unit__content_hash", "unit__translation__language_id")) # Create new check instances for item in data: if "translation__language" not in item: item["translation__language"] = self.source_language.id key = (item["content_hash"], item["translation__language"]) if key in existing: existing.discard(key) else: units = Unit.objects.filter( translation__component__project=self, translation__language_id=item["translation__language"], content_hash=item["content_hash"], ) for unit in units: create.append( Check(unit=unit, check=check, ignore=False)) # Remove stale instances if existing: query = functools.reduce( lambda q, value: q | (Q(unit__content_hash=value[0]) & Q(unit__translation__language_id=value[1])), existing, Q(), ) Check.objects.filter(check=check).filter(query).delete() # Create new checks if create: Check.objects.bulk_create(create, batch_size=500, ignore_conflicts=True) def run_target_checks(self): """Run batch executed target checks.""" self.run_batch_checks("target") def run_source_checks(self): """Run batch executed source checks.""" self.run_batch_checks("source") def update_unit_flags(self): from weblate.trans.models import Unit units = Unit.objects.filter(translation__component__project=self) self.log_debug("updating unit flags: has_failing_check") units.filter(has_failing_check=False).filter( check__ignore=False).update(has_failing_check=True) units.filter(has_failing_check=True).exclude( check__ignore=False).update(has_failing_check=False) self.log_debug("all unit flags updated") def invalidate_stats_deep(self): self.log_info("updating stats caches") from weblate.trans.models import Translation translations = Translation.objects.filter(component__project=self) for translation in translations.iterator(): translation.invalidate_cache() def get_stats(self): """Return stats dictionary.""" return { "name": self.name, "total": self.stats.all, "total_words": self.stats.all_words, "last_change": self.stats.last_changed, "recent_changes": self.stats.recent_changes, "translated": self.stats.translated, "translated_words": self.stats.translated_words, "translated_percent": self.stats.translated_percent, "fuzzy": self.stats.fuzzy, "fuzzy_percent": self.stats.fuzzy_percent, "failing": self.stats.allchecks, "failing_percent": self.stats.allchecks_percent, "url": self.get_share_url(), "url_translate": get_site_url(self.get_absolute_url()), } def post_create(self, user, billing=None): from weblate.trans.models import Change if billing: billing.projects.add(self) self.access_control = Project.ACCESS_PRIVATE self.save() if not user.is_superuser: self.add_user(user, "@Administration") Change.objects.create(action=Change.ACTION_CREATE_PROJECT, project=self, user=user, author=user) @cached_property def all_alerts(self): from weblate.trans.models import Alert result = Alert.objects.filter(component__project=self) list(result) return result
class Meta: app_label = "trans" verbose_name = gettext_lazy("Project") verbose_name_plural = gettext_lazy("Projects")
class SubmissionsListView(SpreadsheetExportMixin, SafePaginateListView): """Lists submissions for the provided form page""" template_name = "wagtailforms/submissions_index.html" context_object_name = "submissions" form_page = None ordering = ("-submit_time", ) ordering_csv = ("submit_time", ) # keep legacy CSV ordering orderable_fields = ( "id", "submit_time", ) # used to validate ordering in URL page_title = gettext_lazy("Form data") select_date_form = None def dispatch(self, request, *args, **kwargs): """Check permissions and set the form page""" self.form_page = kwargs.get("form_page") if not get_forms_for_user( request.user).filter(pk=self.form_page.id).exists(): raise PermissionDenied self.is_export = self.request.GET.get("export") in self.FORMATS if self.is_export: self.paginate_by = None data_fields = self.form_page.get_data_fields() # Set the export fields and the headings for spreadsheet export self.list_export = [field for field, label in data_fields] self.export_headings = dict(data_fields) return super().dispatch(request, *args, **kwargs) def get_queryset(self): """Return queryset of form submissions with filter and order_by applied""" submission_class = self.form_page.get_submission_class() queryset = submission_class._default_manager.filter( page=self.form_page) filtering = self.get_filtering() if filtering and isinstance(filtering, dict): queryset = queryset.filter(**filtering) ordering = self.get_ordering() if ordering: if isinstance(ordering, str): ordering = (ordering, ) queryset = queryset.order_by(*ordering) return queryset def get_paginate_by(self, queryset): """Get the number of items to paginate by, or ``None`` for no pagination""" if self.is_export: return None return self.paginate_by def get_validated_ordering(self): """Return a dict of field names with ordering labels if ordering is valid""" orderable_fields = self.orderable_fields or () ordering = {} if self.is_export: # Revert to CSV order_by submit_time ascending for backwards compatibility default_ordering = self.ordering_csv or () else: default_ordering = self.ordering or () if isinstance(default_ordering, str): default_ordering = (default_ordering, ) ordering_strs = self.request.GET.getlist("order_by") or list( default_ordering) for order in ordering_strs: try: _, prefix, field_name = order.rpartition("-") if field_name in orderable_fields: ordering[field_name] = ( prefix, "descending" if prefix == "-" else "ascending", ) except (IndexError, ValueError): continue # invalid ordering specified, skip it return ordering def get_ordering(self): """Return the field or fields to use for ordering the queryset""" ordering = self.get_validated_ordering() return [values[0] + name for name, values in ordering.items()] def get_filtering(self): """Return filering as a dict for submissions queryset""" self.select_date_form = SelectDateForm(self.request.GET) result = {} if self.select_date_form.is_valid(): date_from = self.select_date_form.cleaned_data.get("date_from") date_to = self.select_date_form.cleaned_data.get("date_to") if date_to: # careful: date_to must be increased by 1 day # as submit_time is a time so will always be greater date_to += datetime.timedelta(days=1) if date_from: result["submit_time__range"] = [date_from, date_to] else: result["submit_time__lte"] = date_to elif date_from: result["submit_time__gte"] = date_from return result def get_filename(self): """Returns the base filename for the generated spreadsheet data file""" return "{}-export-{}".format( self.form_page.slug, datetime.datetime.today().strftime("%Y-%m-%d")) def render_to_response(self, context, **response_kwargs): if self.is_export: return self.as_spreadsheet(context["submissions"], self.request.GET.get("export")) return super().render_to_response(context, **response_kwargs) def to_row_dict(self, item): """Orders the submission dictionary for spreadsheet writing""" row_dict = OrderedDict( (field, item.get_data().get(field)) for field in self.list_export) return row_dict def get_context_data(self, **kwargs): """Return context for view""" context = super().get_context_data(**kwargs) submissions = context[self.context_object_name] data_fields = self.form_page.get_data_fields() data_rows = [] context["submissions"] = submissions context["page_title"] = self.page_title if not self.is_export: # Build data_rows as list of dicts containing model_id and fields for submission in submissions: form_data = submission.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ", ".join(val) data_row.append(val) data_rows.append({ "model_id": submission.id, "fields": data_row }) # Build data_headings as list of dicts containing model_id and fields ordering_by_field = self.get_validated_ordering() orderable_fields = self.orderable_fields data_headings = [] for name, label in data_fields: order_label = None if name in orderable_fields: order = ordering_by_field.get(name) if order: order_label = order[1] # 'ascending' or 'descending' else: order_label = "orderable" # not ordered yet but can be data_headings.append({ "name": name, "label": label, "order": order_label, }) context.update({ "form_page": self.form_page, "select_date_form": self.select_date_form, "data_headings": data_headings, "data_rows": data_rows, }) return context
class ECOOContestFormat(DefaultContestFormat): name = gettext_lazy('ECOO') config_defaults = {'cumtime': False, 'first_ac_bonus': 10, 'time_bonus': 5} config_validators = {'cumtime': lambda x: True, 'first_ac_bonus': lambda x: x >= 0, 'time_bonus': lambda x: x >= 0} ''' cumtime: Specify True if cumulative time is to be used in breaking ties. Defaults to False. first_ac_bonus: The number of points to award if a solution gets AC on its first non-IE/CE run. Defaults to 10. time_bonus: Number of minutes to award an extra point for submitting before the contest end. Specify 0 to disable. Defaults to 5. ''' @classmethod def validate(cls, config): if config is None: return if not isinstance(config, dict): raise ValidationError('ECOO-styled contest expects no config or dict as config') for key, value in config.items(): if key not in cls.config_defaults: raise ValidationError('unknown config key "%s"' % key) if not isinstance(value, type(cls.config_defaults[key])): raise ValidationError('invalid type for config key "%s"' % key) if not cls.config_validators[key](value): raise ValidationError('invalid value "%s" for config key "%s"' % (value, key)) def __init__(self, contest, config): self.config = self.config_defaults.copy() self.config.update(config or {}) self.contest = contest def update_participation(self, participation): cumtime = 0 score = 0 format_data = {} submissions = participation.submissions.exclude(submission__result__in=('IE', 'CE')) submission_counts = { data['problem_id']: data['count'] for data in submissions.values('problem_id').annotate(count=Count('id')) } queryset = ( submissions .values('problem_id') .filter( submission__date=Subquery( submissions .filter(problem_id=OuterRef('problem_id')) .order_by('-submission__date') .values('submission__date')[:1], ), ) .annotate(points=Max('points')) .values_list('problem_id', 'problem__points', 'points', 'submission__date') ) for problem_id, problem_points, points, date in queryset: sub_cnt = submission_counts.get(problem_id, 0) dt = (date - participation.start).total_seconds() bonus = 0 if points > 0: # First AC bonus if sub_cnt == 1 and points == problem_points: bonus += self.config['first_ac_bonus'] # Time bonus if self.config['time_bonus']: bonus += (participation.end_time - date).total_seconds() // 60 // self.config['time_bonus'] format_data[str(problem_id)] = {'time': dt, 'points': points, 'bonus': bonus} for data in format_data.values(): if self.config['cumtime']: cumtime += data['time'] score += data['points'] + data['bonus'] participation.cumtime = cumtime participation.score = round(score, self.contest.points_precision) participation.tiebreaker = 0 participation.format_data = format_data participation.save() def display_user_problem(self, participation, contest_problem): format_data = (participation.format_data or {}).get(str(contest_problem.id)) if format_data: bonus = format_html('<small> +{bonus}</small>', bonus=floatformat(format_data['bonus'])) if format_data['bonus'] else '' return format_html( '<td class="{state}"><a href="{url}">{points}{bonus}<div class="solving-time">{time}</div></a></td>', state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') + self.best_solution_state(format_data['points'], contest_problem.points)), url=reverse('contest_user_submissions', args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]), points=floatformat(format_data['points']), bonus=bonus, time=nice_repr(timedelta(seconds=format_data['time']), 'noday'), ) else: return mark_safe('<td></td>') def display_participation_result(self, participation): return format_html( '<td class="user-points"><a href="{url}">{points}<div class="solving-time">{cumtime}</div></a></td>', url=reverse('contest_all_user_submissions', args=[self.contest.key, participation.user.user.username]), points=floatformat(participation.score, -self.contest.points_precision), cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday') if self.config['cumtime'] else '', ) def get_short_form_display(self): yield _('The score on your **last** non-CE submission for each problem will be used.') first_ac_bonus = self.config['first_ac_bonus'] if first_ac_bonus: yield _( 'There is a **%d bonus** for fully solving on your first non-CE submission.', ) % first_ac_bonus time_bonus = self.config['time_bonus'] if time_bonus: yield ungettext( 'For every **%d minute** you submit before the end of your window, there will be a **1** point bonus.', 'For every **%d minutes** you submit before the end of your window, there will be a **1** point bonus.', time_bonus, ) % time_bonus if self.config['cumtime']: yield _('Ties will be broken by the sum of the last submission time on **all** problems.') else: yield _('Ties by score will **not** be broken.')
rating, mean, performance = recalculate_ratings(ranking, old_mean, times_ranked, historical_p) now = timezone.now() ratings = [Rating(user_id=i, contest=contest, rating=r, mean=m, performance=perf, last_rated=now, participation_id=pid, rank=z) for i, pid, r, m, perf, z in zip(user_ids, participation_ids, rating, mean, performance, ranking)] with transaction.atomic(): Rating.objects.bulk_create(ratings) Profile.objects.filter(contest_history__contest=contest, contest_history__virtual=0).update( rating=Subquery(Rating.objects.filter(user=OuterRef('id')) .order_by('-contest__end_time').values('rating')[:1])) RATING_LEVELS = [ gettext_lazy('Newbie'), gettext_lazy('Amateur'), gettext_lazy('Expert'), gettext_lazy('Candidate Master'), gettext_lazy('Master'), gettext_lazy('Grandmaster'), gettext_lazy('Target'), ] RATING_VALUES = [1000, 1300, 1600, 1900, 2400, 3000] RATING_CLASS = ['rate-newbie', 'rate-amateur', 'rate-expert', 'rate-candidate-master', 'rate-master', 'rate-grandmaster', 'rate-target'] def rating_level(rating): return bisect(RATING_VALUES, rating)
class PluginFormUpdate(forms.Form): """Form to update a script.""" required_css_class = 'required' plugin = forms.ChoiceField( choices=[], label=gettext_lazy('Script') ) version = forms.CharField( max_length=MAX_LENGTH_VERSION, label=gettext_lazy('New version'), widget=forms.TextInput(attrs={'size': '10'}) ) file = forms.FileField( label=gettext_lazy('File'), help_text=gettext_lazy('the script') ) author = forms.CharField( max_length=MAX_LENGTH_AUTHOR, label=gettext_lazy('Your name or nick'), help_text=gettext_lazy('used for git commit') ) mail = forms.EmailField( max_length=MAX_LENGTH_MAIL, label=gettext_lazy('Your e-mail'), help_text=gettext_lazy('used for git commit'), widget=Html5EmailInput(attrs={'size': '40'}) ) comment = forms.CharField( max_length=1024, label=gettext_lazy('Comments'), help_text=gettext_lazy('changes in this release'), widget=forms.Textarea(attrs={'rows': '3'}) ) test = TestField( max_length=64, label=gettext_lazy('Are you a spammer?'), help_text=gettext_lazy('enter "no" if you are not a spammer'), widget=forms.TextInput(attrs={'size': '10'}) ) def __init__(self, *args, **kwargs): super(PluginFormUpdate, self).__init__(*args, **kwargs) self.fields['plugin'].choices = get_plugin_choices()
class NaturalTimeFormatter: time_strings = { # Translators: delta will contain a string like '2 months' or '1 month, 2 weeks' "past-day": gettext_lazy("%(delta)s ago"), # Translators: please keep a non-breaking space (U+00A0) between count # and time unit. "past-hour": ngettext_lazy("an hour ago", "%(count)s hours ago", "count"), # Translators: please keep a non-breaking space (U+00A0) between count # and time unit. "past-minute": ngettext_lazy("a minute ago", "%(count)s minutes ago", "count"), # Translators: please keep a non-breaking space (U+00A0) between count # and time unit. "past-second": ngettext_lazy("a second ago", "%(count)s seconds ago", "count"), "now": gettext_lazy("now"), # Translators: please keep a non-breaking space (U+00A0) between count # and time unit. "future-second": ngettext_lazy("a second from now", "%(count)s seconds from now", "count"), # Translators: please keep a non-breaking space (U+00A0) between count # and time unit. "future-minute": ngettext_lazy("a minute from now", "%(count)s minutes from now", "count"), # Translators: please keep a non-breaking space (U+00A0) between count # and time unit. "future-hour": ngettext_lazy("an hour from now", "%(count)s hours from now", "count"), # Translators: delta will contain a string like '2 months' or '1 month, 2 weeks' "future-day": gettext_lazy("%(delta)s from now"), } past_substrings = { # Translators: 'naturaltime-past' strings will be included in '%(delta)s ago' "year": npgettext_lazy("naturaltime-past", "%d year", "%d years"), "month": npgettext_lazy("naturaltime-past", "%d month", "%d months"), "week": npgettext_lazy("naturaltime-past", "%d week", "%d weeks"), "day": npgettext_lazy("naturaltime-past", "%d day", "%d days"), "hour": npgettext_lazy("naturaltime-past", "%d hour", "%d hours"), "minute": npgettext_lazy("naturaltime-past", "%d minute", "%d minutes"), } future_substrings = { # Translators: 'naturaltime-future' strings will be included in '%(delta)s from now' "year": npgettext_lazy("naturaltime-future", "%d year", "%d years"), "month": npgettext_lazy("naturaltime-future", "%d month", "%d months"), "week": npgettext_lazy("naturaltime-future", "%d week", "%d weeks"), "day": npgettext_lazy("naturaltime-future", "%d day", "%d days"), "hour": npgettext_lazy("naturaltime-future", "%d hour", "%d hours"), "minute": npgettext_lazy("naturaltime-future", "%d minute", "%d minutes"), } @classmethod def string_for(cls, value): if not isinstance(value, date): # datetime is a subclass of date return value now = datetime.now(utc if is_aware(value) else None) if value < now: delta = now - value if delta.days != 0: # The only change being done is here and in the else clausule: # It splits the string returned by timesince filter and gets only first element # to shorten the string so e.g '1 days, 5 hours' becomes '1 days' return cls.time_strings["past-day"] % { "delta": defaultfilters.timesince( value, now, time_strings=cls.past_substrings).split(",")[0] } elif delta.seconds == 0: return cls.time_strings["now"] elif delta.seconds < 60: return cls.time_strings["past-second"] % { "count": delta.seconds } elif delta.seconds // 60 < 60: count = delta.seconds // 60 return cls.time_strings["past-minute"] % {"count": count} else: count = delta.seconds // 60 // 60 return cls.time_strings["past-hour"] % {"count": count} else: delta = value - now if delta.days != 0: return cls.time_strings["future-day"] % { "delta": defaultfilters.timeuntil( value, now, time_strings=cls.future_substrings).split(",")[0] } elif delta.seconds == 0: return cls.time_strings["now"] elif delta.seconds < 60: return cls.time_strings["future-second"] % { "count": delta.seconds } elif delta.seconds // 60 < 60: count = delta.seconds // 60 return cls.time_strings["future-minute"] % {"count": count} else: count = delta.seconds // 60 // 60 return cls.time_strings["future-hour"] % {"count": count}
from zerver.lib.email_validation import ( get_realm_email_validator, validate_email_is_valid, validate_email_not_already_in_realm, ) from zerver.lib.exceptions import JsonableError, RateLimited from zerver.lib.i18n import get_available_language_codes from zerver.lib.request import REQ, has_request_variables from zerver.lib.response import json_success from zerver.lib.send_email import FromAddress, send_email from zerver.lib.upload import upload_avatar_image from zerver.lib.validator import check_bool, check_int, check_int_in, check_string_in from zerver.models import UserProfile, avatar_changes_disabled, name_changes_disabled from zproject.backends import check_password_strength, email_belongs_to_ldap AVATAR_CHANGES_DISABLED_ERROR = gettext_lazy( "Avatar changes are disabled in this organization.") def confirm_email_change(request: HttpRequest, confirmation_key: str) -> HttpResponse: try: email_change_object = get_object_from_key(confirmation_key, Confirmation.EMAIL_CHANGE) except ConfirmationKeyException as exception: return render_confirmation_key_error(request, exception) new_email = email_change_object.new_email old_email = email_change_object.old_email user_profile = email_change_object.user_profile if user_profile.realm.email_changes_disabled and not user_profile.is_realm_admin:
class AtCoderContestFormat(DefaultContestFormat): name = gettext_lazy('AtCoder') config_defaults = {'penalty': 5} config_validators = {'penalty': lambda x: x >= 0} ''' penalty: Number of penalty minutes each incorrect submission adds. Defaults to 5. ''' @classmethod def validate(cls, config): if config is None: return if not isinstance(config, dict): raise ValidationError( 'AtCoder-styled contest expects no config or dict as config') for key, value in config.items(): if key not in cls.config_defaults: raise ValidationError('unknown config key "%s"' % key) if not isinstance(value, type(cls.config_defaults[key])): raise ValidationError('invalid type for config key "%s"' % key) if not cls.config_validators[key](value): raise ValidationError( 'invalid value "%s" for config key "%s"' % (value, key)) def __init__(self, contest, config): self.config = self.config_defaults.copy() self.config.update(config or {}) self.contest = contest def update_participation(self, participation): cumtime = 0 penalty = 0 points = 0 format_data = {} with connection.cursor() as cursor: cursor.execute( ''' SELECT MAX(cs.points) as `score`, ( SELECT MIN(csub.date) FROM judge_contestsubmission ccs LEFT OUTER JOIN judge_submission csub ON (csub.id = ccs.submission_id) WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points) ) AS `time`, cp.id AS `prob` FROM judge_contestproblem cp INNER JOIN judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN judge_submission sub ON (sub.id = cs.submission_id) GROUP BY cp.id ''', (participation.id, participation.id)) for score, time, prob in cursor.fetchall(): time = from_database_time(time) dt = (time - participation.start).total_seconds() # Compute penalty if self.config['penalty']: # An IE can have a submission result of `None` subs = participation.submissions.exclude(submission__result__isnull=True) \ .exclude(submission__result__in=['IE', 'CE']) \ .filter(problem_id=prob) if score: prev = subs.filter( submission__date__lte=time).count() - 1 penalty += prev * self.config['penalty'] * 60 else: # We should always display the penalty, even if the user has a score of 0 prev = subs.count() if score: cumtime = max(cumtime, dt) format_data[str(prob)] = { 'time': dt, 'points': score, 'penalty': prev } points += score participation.cumtime = cumtime + penalty participation.score = points participation.format_data = format_data participation.save() def display_user_problem(self, participation, contest_problem): format_data = (participation.format_data or {}).get(str(contest_problem.id)) if format_data: penalty = format_html( '<small style="color:red"> ({penalty})</small>', penalty=floatformat( format_data['penalty'])) if format_data['penalty'] else '' return format_html( '<td class="{state}"><a href="{url}">{points}{penalty}<div class="solving-time">{time}</div></a></td>', state=('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') + self.best_solution_state(format_data['points'], contest_problem.points), url=reverse('contest_user_submissions', args=[ self.contest.key, participation.user.user.username, contest_problem.problem.code ]), points=floatformat(format_data['points']), penalty=penalty, time=nice_repr(timedelta(seconds=format_data['time']), 'noday'), ) else: return mark_safe('<td></td>')
class DeviceLogCommCareVersionFilter(BaseTagsFilter): slug = "commcare_version" label = gettext_lazy("Filter Logs by CommCareVersion") placeholder = gettext_lazy("Enter the CommCare Version you want e.g '2.28.1'")
class GroupstudentsappConfig(AppConfig): name = 'groupstudentsapp' verbose_name = gettext_lazy('Группы студентов')
from datahub.core.admin import max_upload_size from datahub.core.csv import CSV_CONTENT_TYPE from datahub.core.exceptions import DataHubException from datahub.interaction.admin_csv_import.cache_utils import ( CACHE_VALUE_TIMEOUT, load_result_counts_by_status, load_unmatched_rows_csv_contents, save_result_counts_by_status, save_unmatched_rows_csv_contents, ) from datahub.interaction.admin_csv_import.file_form import InteractionCSVForm from datahub.interaction.models import Interaction, InteractionPermission MAX_ERRORS_TO_DISPLAY = 50 MAX_PREVIEW_ROWS_TO_DISPLAY = 100 PAGE_TITLE = gettext_lazy('Import interactions') INVALID_TOKEN_MESSAGE_DURING_SAVE = gettext_lazy( 'The CSV file referenced is no longer available and may have expired. Please upload ' 'the file again.', ) INVALID_TOKEN_MESSAGE_POST_SAVE = gettext_lazy( 'Sorry, we could not find the results for that import operation. They may have expired.', ) interaction_change_all_permission_required = method_decorator( permission_required( f'interaction.{InteractionPermission.change_all}', raise_exception=True, ),
class DeviceLogUsersFilter(BaseDeviceLogFilter): slug = "loguser" label = gettext_lazy("Filter Logs by Username") field = 'username' endpoint = 'device_log_users'
class Announcement(models.Model): message = models.TextField( verbose_name=gettext_lazy("Message"), help_text=gettext_lazy( "You can use Markdown and mention users by @username."), ) project = models.ForeignKey( "Project", verbose_name=gettext_lazy("Project"), null=True, blank=True, on_delete=models.deletion.CASCADE, ) component = models.ForeignKey( "Component", verbose_name=gettext_lazy("Component"), null=True, blank=True, on_delete=models.deletion.CASCADE, ) language = models.ForeignKey( Language, verbose_name=gettext_lazy("Language"), null=True, blank=True, on_delete=models.deletion.CASCADE, ) category = models.CharField( max_length=25, verbose_name=gettext_lazy("Category"), help_text=gettext_lazy("Category defines color used for the message."), choices=( ("info", gettext_lazy("Info (light blue)")), ("warning", gettext_lazy("Warning (yellow)")), ("danger", gettext_lazy("Danger (red)")), ("success", gettext_lazy("Success (green)")), ), default="info", ) expiry = models.DateField( null=True, blank=True, db_index=True, verbose_name=gettext_lazy("Expiry date"), help_text=gettext_lazy( "The message will be not shown after this date. " "Use it to announce string freeze and translation " "deadline for next release."), ) notify = models.BooleanField( blank=True, default=True, verbose_name=gettext_lazy("Notify users"), ) objects = AnnouncementManager() class Meta: app_label = "trans" verbose_name = gettext_lazy("Announcement") verbose_name_plural = gettext_lazy("Announcements") def __str__(self): return self.message def clean(self): if self.project and self.component and self.component.project != self.project: raise ValidationError( _("Do not specify both component and project!")) if not self.project and self.component: self.project = self.component.project
def index(request): output = gettext_lazy("test_message") return HttpResponse(output)
'NAME': 'django.contrib.auth' '.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth' '.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.10/topics/i18n/ LANGUAGE_CODE = 'en' LANGUAGES = ( ('en', gettext_lazy('English')), ('de', gettext_lazy('German')), ('pt', gettext_lazy('Portuguese')), ('es', gettext_lazy('Spanish')), ('fr', gettext_lazy('French')), ('nl', gettext_lazy('Dutch')), ('pl', gettext_lazy('Polish')), ) TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale'),
HIGHLIGTH_SPACE = '<span class="hlspace">{}</span>{}' SPACE_TEMPLATE = '<span class="{}"><span class="sr-only">{}</span></span>' SPACE_SPACE = SPACE_TEMPLATE.format("space-space", " ") SPACE_NL = HIGHLIGTH_SPACE.format(SPACE_TEMPLATE.format("space-nl", ""), "<br />") SPACE_TAB = HIGHLIGTH_SPACE.format(SPACE_TEMPLATE.format("space-tab", "\t"), "") HL_CHECK = ( '<span class="hlcheck">' '<span class="highlight-number"></span>' "{0}" "</span>" ) WHITESPACE_RE = re.compile(r"( +| $|^ )") NEWLINES_RE = re.compile(r"\r\n|\r|\n") TYPE_MAPPING = {True: "yes", False: "no", None: "unknown"} # Mapping of status report flags to names NAME_MAPPING = { True: gettext_lazy("Good configuration"), False: gettext_lazy("Bad configuration"), None: gettext_lazy("Possible configuration"), } FLAG_TEMPLATE = '<span title="{0}" class="{1}">{2}</span>' BADGE_TEMPLATE = '<span class="badge pull-right flip {1}">{0}</span>' PERM_TEMPLATE = """ <td> <input type="checkbox" class="set-group" data-placement="bottom" data-username="******" data-group="{1}" data-name="{2}"
class Meta: app_label = "trans" verbose_name = gettext_lazy("Announcement") verbose_name_plural = gettext_lazy("Announcements")