Пример #1
0
    def validate_bulk_tasks(self, attrs, source):
        filters = {
            "project__id": attrs["project_id"],
            "id__in": [task["task_id"] for task in attrs[source]]
        }

        if models.Task.objects.filter(**filters).count() != len(
                filters["id__in"]):
            raise ValidationError(
                _("All the tasks must be from the same project"))

        return attrs
    def validate_bulk_stories(self, attrs, source):
        filters = {
            "project__id": attrs["project_id"],
            "id__in": [us["us_id"] for us in attrs[source]],
        }

        if UserStory.objects.filter(**filters).count() != len(filters["id__in"]):
            raise ValidationError(
                _("All the user stories must be from the same project")
            )

        return attrs
Пример #3
0
    def validate_assigned_to(self, attrs, source):
        assigned_to = attrs[source]
        project = (attrs.get("project", None)
                   or getattr(self.object, "project", None))

        if assigned_to and project:
            filters = {"project_id": project.id, "user_id": assigned_to.id}

            if not Membership.objects.filter(**filters).exists():
                raise ValidationError(_("The user must be a project member."))

        return attrs
Пример #4
0
    def validate_source_project_slug(self, attrs, source):
        if source in attrs and attrs[
                source] is not None and attrs[source] != "":
            msg = _(
                "An Epic has a related story from an external project (%(project)s) and cannot be imported"
            ) % {
                "project": attrs[source]
            }
            raise ValidationError(msg)

        attrs.pop(source, None)
        return attrs
Пример #5
0
    def validate_us_id(self, attrs, source):
        filters = {"project__id": attrs["project_id"]}

        if "milestone_id" in attrs:
            filters["milestone__id"] = attrs["milestone_id"]

        filters["id"] = attrs["us_id"]

        if not UserStory.objects.filter(**filters).exists():
            raise ValidationError(_("Invalid user story id."))

        return attrs
Пример #6
0
    def validate_role(self, attrs, source):
        project = attrs.get(
            "project", None if self.object is None else self.object.project)
        if project is None:
            return attrs

        role = attrs[source]

        if project.roles.filter(id=role.id).count() == 0:
            raise ValidationError(_("Invalid role for the project"))

        return attrs
Пример #7
0
    def field_from_native(self, data, files, field_name, into):
        """
        Override default so that the serializer can be used as a writable
        nested field across relationships.
        """
        if self.read_only:
            return

        try:
            value = data[field_name]
        except KeyError:
            if self.default is not None and not self.partial:
                # Note: partial updates shouldn't set defaults
                value = copy.deepcopy(self.default)
            else:
                if self.required:
                    raise ValidationError(self.error_messages["required"])
                return

        # Set the serializer object if it exists
        obj = get_component(self.parent.object, self.source or field_name) if self.parent.object else None

        # If we have a model manager or similar object then we need
        # to iterate through each instance.
        if (self.many and
            not hasattr(obj, "__iter__") and
            is_simple_callable(getattr(obj, "all", None))):
            obj = obj.all()

        if self.source == "*":
            if value:
                reverted_data = self.restore_fields(value, {})
                if not self._errors:
                    into.update(reverted_data)
        else:
            if value in (None, ""):
                into[(self.source or field_name)] = None
            else:
                kwargs = {
                    "instance": obj,
                    "data": value,
                    "context": self.context,
                    "partial": self.partial,
                    "many": self.many,
                    "allow_add_remove": self.allow_add_remove
                }
                serializer = self.__class__(**kwargs)

                if serializer.is_valid():
                    into[self.source or field_name] = serializer.object
                else:
                    # Propagate errors up to our parent
                    raise NestedValidationError(serializer.errors)
Пример #8
0
    def from_native(self, data):
        if data in validators.EMPTY_VALUES:
            return None

        # UploadedFile objects should have name and size attributes.
        try:
            file_name = data.name
            file_size = data.size
        except AttributeError:
            raise ValidationError(self.error_messages["invalid"])

        if self.max_length is not None and len(file_name) > self.max_length:
            error_values = {"max": self.max_length, "length": len(file_name)}
            raise ValidationError(self.error_messages["max_length"] %
                                  error_values)
        if not file_name:
            raise ValidationError(self.error_messages["invalid"])
        if not self.allow_empty_file and not file_size:
            raise ValidationError(self.error_messages["empty"])

        return data
Пример #9
0
    def validate_bulk_stories(self, attrs, source):
        filters = {"project__id": attrs["project_id"]}
        if "milestone_id" in attrs:
            filters["milestone__id"] = attrs["milestone_id"]

        filters["id__in"] = [us["us_id"] for us in attrs[source]]

        if models.UserStory.objects.filter(**filters).count() != len(filters["id__in"]):
            raise ValidationError(_("Invalid user story ids. All stories must belong to the same project "
                                    "and, if it exists, to the same status and milestone."))

        return attrs
    def validate_bulk_tasks(self, attrs, source):
        filters = {
            "project__id": attrs["project_id"],
            "id__in": [issue["issue_id"] for issue in attrs[source]],
        }

        if models.Issue.objects.filter(**filters).count() != len(
                filters["id__in"]):
            raise ValidationError(
                _("All the issues must be from the same project"))

        return attrs
Пример #11
0
    def validate_username(self, attrs, source):
        username = attrs.get(source)
        try:
            validate_user_email_allowed_domains(username)
        except InvalidEmailValidationError:
            # If the validation comes from a request let's check the user is a valid contact
            request = self.context.get("request", None)
            if request is not None and request.user.is_authenticated:
                valid_usernames = set(request.user.contacts_visible_by_user(request.user).values_list("username", flat=True))
                if username not in valid_usernames:
                    raise ValidationError(_("The user must be a valid contact"))

        return attrs
Пример #12
0
    def validate_username(self, attrs, source):
        value = attrs[source]
        validator = core_validators.RegexValidator(re.compile(r'^[\w.-]+$'),
                                                   _("invalid username"),
                                                   "invalid")

        try:
            validator(value)
        except ValidationError:
            raise ValidationError(
                _("Required. 255 characters or fewer. Letters, numbers "
                  "and /./-/_ characters'"))
        return attrs
Пример #13
0
    def validate_bulk_memberships(self, attrs, source):
        filters = {
            "project__id": attrs["project_id"],
            "id__in": [r["role_id"] for r in attrs["bulk_memberships"]]
        }

        if Role.objects.filter(**filters).count() != len(set(
                filters["id__in"])):
            raise ValidationError(
                _("Invalid role ids. All roles must belong to the same project."
                  ))

        return attrs
Пример #14
0
    def validate(self, value):
        super(DecimalField, self).validate(value)
        if value in validators.EMPTY_VALUES:
            return
        # Check for NaN, Inf and -Inf values. We can't compare directly for NaN,
        # since it is never equal to itself. However, NaN is the only value that
        # isn't equal to itself, so we can use this to identify NaN
        if value != value or value == Decimal("Inf") or value == Decimal("-Inf"):
            raise ValidationError(self.error_messages["invalid"])
        sign, digittuple, exponent = value.as_tuple()
        decimals = abs(exponent)
        # digittuple doesn't include any leading zeros.
        digits = len(digittuple)
        if decimals > digits:
            # We have leading zeros up to or past the decimal point.  Count
            # everything past the decimal point as a digit.  We do not count
            # 0 before the decimal point as a digit since that would mean
            # we would not allow max_digits = decimal_places.
            digits = decimals
        whole_digits = digits - decimals

        if self.max_digits is not None and digits > self.max_digits:
            raise ValidationError(self.error_messages["max_digits"] % self.max_digits)
        if self.decimal_places is not None and decimals > self.decimal_places:
            raise ValidationError(
                self.error_messages["max_decimal_places"] % self.decimal_places
            )
        if (
            self.max_digits is not None
            and self.decimal_places is not None
            and whole_digits > (self.max_digits - self.decimal_places)
        ):
            raise ValidationError(
                self.error_messages["max_whole_digits"]
                % (self.max_digits - self.decimal_places)
            )
        return value
Пример #15
0
        def _validate_tag_field(value):
            # Valid field:
            #    - ["tag1", "tag2", "tag3"...]
            #    - ["tag1", ["tag2", None], ["tag3", "#ccc"], [tag4, #cccccc]...]
            for tag in value:
                if isinstance(tag, str):
                    continue

                if isinstance(tag, (list, tuple)) and len(tag) == 2:
                    name = tag[0]
                    color = tag[1]

                    if isinstance(name, str):
                        if color is None or color == "":
                            continue

                        if isinstance(color, str) and re.match('^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$', color):
                            continue

                        raise ValidationError(_("Invalid tag '{value}'. The color is not a "
                                                "valid HEX color or null.").format(value=tag))

                raise ValidationError(_("Invalid tag '{value}'. it must be the name or a pair "
                                        "'[\"name\", \"hex color/\" | null]'.").format(value=tag))
Пример #16
0
    def validate(self, attrs):
        if "ref" in attrs:
            if "epic" in attrs:
                raise ValidationError(
                    "'epic' param is incompatible with 'ref' in the same request"
                )
            if "us" in attrs:
                raise ValidationError(
                    "'us' param is incompatible with 'ref' in the same request"
                )
            if "task" in attrs:
                raise ValidationError(
                    "'task' param is incompatible with 'ref' in the same request"
                )
            if "issue" in attrs:
                raise ValidationError(
                    "'issue' param is incompatible with 'ref' in the same request"
                )
            if "wikipage" in attrs:
                raise ValidationError(
                    "'wikipage' param is incompatible with 'ref' in the same request"
                )

        return attrs
Пример #17
0
 def from_native(self, value):
     """
     Validates that the input is a decimal number. Returns a Decimal
     instance. Returns None for empty values. Ensures that there are no more
     than max_digits in the number, and no more than decimal_places digits
     after the decimal point.
     """
     if value in validators.EMPTY_VALUES:
         return None
     value = smart_text(value).strip()
     try:
         value = Decimal(value)
     except DecimalException:
         raise ValidationError(self.error_messages["invalid"])
     return value
Пример #18
0
    def validate(self, data):
        filters = {"project__id": data["project_id"]}
        if "status_id" in data:
            filters["status__id"] = data["status_id"]
        if "milestone_id" in data:
            filters["milestone__id"] = data["milestone_id"]

        filters["id__in"] = [us["us_id"] for us in data["bulk_stories"]]

        if models.UserStory.objects.filter(**filters).count() != len(
                filters["id__in"]):
            raise ValidationError(
                _("Invalid user story ids. All stories must belong to the same project and, "
                  "if it exists, to the same status and milestone."))

        return data
Пример #19
0
    def validate_bulk_attachments(self, attrs, source):
        if (attrs.get("content_type_id", None) is not None
                and attrs.get("object_id", None) is not None):
            filters = {
                "content_type__id": attrs["content_type_id"],
                "object_id": attrs["object_id"],
                "id__in": attrs[source]
            }

            if models.Attachment.objects.filter(**filters).count() != len(
                    filters["id__in"]):
                raise ValidationError(
                    _("Invalid attachment ids. All attachments must belong to the same "
                      "item (epic, userstory, task, issue or wiki page)."))

        return attrs
Пример #20
0
    def from_native(self, data):
        """
        Checks that the file-upload field data contains a valid image (GIF, JPG,
        PNG, possibly others -- whatever the Python Imaging Library supports).
        """
        f = super(ImageField, self).from_native(data)
        if f is None:
            return None

        # Try to import PIL in either of the two ways it can end up installed.
        try:
            from PIL import Image
        except ImportError:
            try:
                import Image
            except ImportError:
                Image = None

        assert (
            Image is not None
        ), "Either Pillow or PIL must be installed for ImageField support."

        # We need to get a file object for PIL. We might have a path or we might
        # have to read the data into memory.
        if hasattr(data, "temporary_file_path"):
            file = data.temporary_file_path()
        else:
            if hasattr(data, "read"):
                file = six.BytesIO(data.read())
            else:
                file = six.BytesIO(data["content"])

        try:
            # load() could spot a truncated JPEG, but it loads the entire
            # image in memory, which is a DoS vector. See #3848 and #18520.
            # verify() must be called immediately after the constructor.
            Image.open(file).verify()
        except ImportError:
            # Under PyPy, it is possible to import PIL. However, the underlying
            # _imaging C module isn't available, so an ImportError will be
            # raised. Catch and re-raise.
            raise
        except Exception:  # Python Imaging Library doesn't recognize it as an image
            raise ValidationError(self.error_messages["invalid_image"])
        if hasattr(f, "seek") and callable(f.seek):
            f.seek(0)
        return f
Пример #21
0
 def run_validators(self, value):
     if value in validators.EMPTY_VALUES:
         return
     errors = []
     for v in self.validators:
         try:
             v(value)
         except ValidationError as e:
             if hasattr(e, "code") and e.code in self.error_messages:
                 message = self.error_messages[e.code]
                 if e.params:
                     message = message % e.params
                 errors.append(message)
             else:
                 errors.extend(e.messages)
     if errors:
         raise ValidationError(errors)
Пример #22
0
    def validate_after_attachment_id(self, attrs, source):
        if (attrs.get(source, None) is not None
                and attrs.get("content_type_id", None) is not None
                and attrs.get("object_id", None) is not None):
            filters = {
                "content_type__id": attrs["content_type_id"],
                "object_id": attrs["object_id"],
                "id": attrs[source]
            }

            if not models.Attachment.objects.filter(**filters).exists():
                raise ValidationError(
                    _("Invalid attachment id to move after. The attachment must belong "
                      "to the same item (epic, userstory, task, issue or wiki page)."
                      ))

        return attrs
Пример #23
0
    def _validate_member_doesnt_exist(self, attrs, email):
        project = attrs.get("project", None if self.object is None else self.object.project)
        if project is None:
            return attrs

        qs = models.Membership.objects.all()

        # If self.object is not None, the serializer is in update
        # mode, and for it, it should exclude self.
        if self.object:
            qs = qs.exclude(pk=self.object.pk)

        qs = qs.filter(Q(project_id=project.id, user__email=email) |
                       Q(project_id=project.id, email=email))

        if qs.count() > 0:
            raise ValidationError(_("The user yet exists in the project"))
Пример #24
0
    def validate_after_userstory_id(self, attrs, source):
        if attrs.get(source, None) is not None:
            filters = {
                "project__id": attrs["project_id"],
                "status__id": attrs["status_id"],
                "id": attrs[source]
            }
            swimlane_id = attrs.get("swimlane_id", None)
            if swimlane_id:
                filters["swimlane__id"] = swimlane_id
            else:
                filters["swimlane__isnull"] = True

            if not UserStory.objects.filter(**filters).exists():
                raise ValidationError(
                    _("Invalid user story id to move after. The user story must belong "
                      "to the same project, status and swimlane."))

        return attrs
Пример #25
0
    def validate_bulk_tasks(self, attrs, source):
        filters = {"project__id": attrs["project_id"]}
        if "status_id" in attrs:
            filters["status__id"] = attrs["status_id"]
        if "us_id" in attrs:
            filters["user_story__id"] = attrs["us_id"]
        if "milestone_id" in attrs:
            filters["milestone__id"] = attrs["milestone_id"]

        filters["id__in"] = [t["task_id"] for t in attrs[source]]

        if models.Task.objects.filter(**filters).count() != len(
                filters["id__in"]):
            raise ValidationError(
                _("Invalid task ids. All tasks must belong to the same project and, "
                  "if it exists, to the same status, user story and/or milestone."
                  ))

        return attrs
Пример #26
0
    def from_native(self, value):
        if value in validators.EMPTY_VALUES:
            return None

        if isinstance(value, datetime.datetime):
            return value
        if isinstance(value, datetime.date):
            value = datetime.datetime(value.year, value.month, value.day)
            if settings.USE_TZ:
                # For backwards compatibility, interpret naive datetimes in
                # local time. This won't work during DST change, but we can"t
                # do much about it, so we let the exceptions percolate up the
                # call stack.
                warnings.warn(
                    "DateTimeField received a naive datetime (%s)"
                    " while time zone support is active." % value,
                    RuntimeWarning,
                )
                default_timezone = timezone.get_default_timezone()
                value = timezone.make_aware(value, default_timezone)
            return value

        for format in self.input_formats:
            if format.lower() == ISO_8601:
                try:
                    parsed = parse_datetime(value)
                except (ValueError, TypeError):
                    pass
                else:
                    if parsed is not None:
                        return parsed
            else:
                try:
                    parsed = datetime.datetime.strptime(value, format)
                except (ValueError, TypeError):
                    pass
                else:
                    return parsed

        msg = self.error_messages["invalid"] % readable_datetime_formats(
            self.input_formats
        )
        raise ValidationError(msg)
Пример #27
0
    def validate_name(self, attrs, source):
        """
        Check the points name is not duplicated in the project on creation
        """
        model = self.opts.model
        qs = None
        # If the object exists:
        if self.object and attrs.get(source, None):
            qs = model.objects.filter(
                project=self.object.project,
                name=attrs[source]).exclude(id=self.object.id)

        if not self.object and attrs.get("project", None) and attrs.get(source, None):
            qs = model.objects.filter(project=attrs["project"], name=attrs[source])

        if qs and qs.exists():
            raise ValidationError(_("Name duplicated for the project"))

        return attrs
Пример #28
0
    def validate_email(self, attrs, source):
        project = attrs.get("project", None)
        if project is None:
            project = self.object.project

        email = attrs[source]

        qs = models.Membership.objects.all()

        # If self.object is not None, the serializer is in update
        # mode, and for it, it should exclude self.
        if self.object:
            qs = qs.exclude(pk=self.object.pk)

        qs = qs.filter(Q(project_id=project.id, user__email=email) |
                       Q(project_id=project.id, email=email))

        if qs.count() > 0:
            raise ValidationError(_("Email address is already taken"))

        return attrs
Пример #29
0
    def _validate_integrity_between_project_and_name(self, attrs, source):
        """
        Check the name is not duplicated in the project. Check when:
          - create a new one
          - update the name
          - update the project (move to another project)
        """
        data_id = attrs.get("id", None)
        data_name = attrs.get("name", None)
        data_project = attrs.get("project", None)

        if self.object:
            data_id = data_id or self.object.id
            data_name = data_name or self.object.name
            data_project = data_project or self.object.project

        model = self.Meta.model
        qs = (model.objects.filter(project=data_project,
                                   name=data_name).exclude(id=data_id))
        if qs.exists():
            raise ValidationError(_("Already exists one with the same name."))

        return attrs
Пример #30
0
    def validate_username(self, attrs, source):
        username = attrs.get(source, None)
        try:
            validate_user_email_allowed_domains(username)

        except ValidationError:
            # If the validation comes from a request let's check the user is a valid contact
            request = self.context.get("request", None)
            if request is not None and request.user.is_authenticated:
                valid_usernames = request.user.contacts_visible_by_user(request.user).values_list("username", flat=True)
                if username not in valid_usernames:
                    raise ValidationError(_("The user must be a valid contact"))

        user = User.objects.filter(Q(username=username) | Q(email=username)).first()
        if user is not None:
            email = user.email
            self.user = user

        else:
            email = username

        self.email = email
        self._validate_member_doesnt_exist(attrs, email)
        return attrs