Esempio n. 1
0
 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.")
Esempio n. 2
0
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,
            },
        ],
    }
Esempio n. 3
0
 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
Esempio n. 4
0
 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)
Esempio n. 5
0
 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
Esempio n. 6
0
 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)
Esempio n. 7
0
 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)
Esempio n. 8
0
 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"}'
         )
Esempio n. 9
0
 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
Esempio n. 10
0
 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
Esempio n. 11
0
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,
    }
Esempio n. 12
0
 def popularity_img(self):
     """Return HTML code with image for popular script."""
     if self.popularity == 0:
         return '&nbsp;'
     return '<img src="%simages/star.png" alt="*" title="%s" ' \
         'width="10" height="10" />' % (settings.MEDIA_URL,
                                        gettext_lazy('Popular script'))
Esempio n. 13
0
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,
    }
Esempio n. 14
0
 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)
Esempio n. 15
0
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,
    }
Esempio n. 16
0
 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
Esempio n. 17
0
    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)
Esempio n. 18
0
    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)]
Esempio n. 19
0
    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')
Esempio n. 20
0
    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')
Esempio n. 22
0
    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)
Esempio n. 23
0
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
Esempio n. 25
0
 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
Esempio n. 26
0
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 []
Esempio n. 27
0
    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)
Esempio n. 28
0
    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)
Esempio n. 29
0
 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
Esempio n. 30
0
        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
Esempio n. 31
0
 def desc_i18n(self):
     """Return translated description."""
     return gettext_lazy(self.desc_en.encode('utf-8'))
Esempio n. 32
0
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
Esempio n. 33
0
    <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 = {}
Esempio n. 34
0
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)
Esempio n. 35
0
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
Esempio n. 36
0
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)
Esempio n. 37
0
class OTPForm(forms.Form):
    otp = forms.CharField(required=True, label=gettext_lazy("Code"))
Esempio n. 38
0
        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."""
Esempio n. 39
0
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',
        )
Esempio n. 40
0
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
Esempio n. 41
0
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())
Esempio n. 42
0
    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
Esempio n. 43
0
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
Esempio n. 44
0
 class Meta:
     app_label = "trans"
     verbose_name = gettext_lazy("Project")
     verbose_name_plural = gettext_lazy("Projects")
Esempio n. 45
0
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
Esempio n. 46
0
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.')
Esempio n. 47
0
    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)
Esempio n. 48
0
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()
Esempio n. 49
0
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}
Esempio n. 50
0
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:
Esempio n. 51
0
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>')
Esempio n. 52
0
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'")
Esempio n. 53
0
class GroupstudentsappConfig(AppConfig):
    name = 'groupstudentsapp'
    verbose_name = gettext_lazy('Группы студентов')
Esempio n. 54
0
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,
    ),
Esempio n. 55
0
class DeviceLogUsersFilter(BaseDeviceLogFilter):
    slug = "loguser"
    label = gettext_lazy("Filter Logs by Username")
    field = 'username'
    endpoint = 'device_log_users'
Esempio n. 56
0
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
Esempio n. 57
0
def index(request):
    output = gettext_lazy("test_message")
    return HttpResponse(output)
Esempio n. 58
0
        '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'),
Esempio n. 59
0
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}"
Esempio n. 60
0
 class Meta:
     app_label = "trans"
     verbose_name = gettext_lazy("Announcement")
     verbose_name_plural = gettext_lazy("Announcements")