class ObjectViewsSerializerAdmixer(serializers.Serializer):
    object = serializers.CharField(max_length=1024)
    views = serializers.IntegerField()
    date = serializers.DateField(required=False)
class CartItemSerializer(serializers.ModelSerializer):
    quantity = serializers.IntegerField(min_value=1, max_value=100)

    class Meta:
        model = ShoppingCartItem
        fields = ('product', 'quantity')
Exemple #3
0
class AvailabilitySerializer(serializers.Serializer):  # pylint: disable=abstract-method
    is_available_to_buy = serializers.BooleanField()
    num_available = serializers.IntegerField(required=False)
    message = serializers.CharField()
class EnrollmentSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    name = serializers.CharField()
    phone = serializers.CharField()
    club = ClubSerializer()
Exemple #5
0
class InterfaceSerializer(PrimaryModelSerializer, CableTerminationSerializer,
                          ConnectedEndpointSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='dcim-api:interface-detail')
    device = NestedDeviceSerializer()
    type = ChoiceField(choices=InterfaceTypeChoices)
    parent = NestedInterfaceSerializer(required=False, allow_null=True)
    lag = NestedInterfaceSerializer(required=False, allow_null=True)
    mode = ChoiceField(choices=InterfaceModeChoices,
                       allow_blank=True,
                       required=False)
    untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
    tagged_vlans = SerializedPKRelatedField(queryset=VLAN.objects.all(),
                                            serializer=NestedVLANSerializer,
                                            required=False,
                                            many=True)
    cable = NestedCableSerializer(read_only=True)
    count_ipaddresses = serializers.IntegerField(read_only=True)

    class Meta:
        model = Interface
        fields = [
            'id',
            'url',
            'display',
            'device',
            'name',
            'label',
            'type',
            'enabled',
            'parent',
            'lag',
            'mtu',
            'mac_address',
            'mgmt_only',
            'description',
            'mode',
            'untagged_vlan',
            'tagged_vlans',
            'mark_connected',
            'cable',
            'cable_peer',
            'cable_peer_type',
            'connected_endpoint',
            'connected_endpoint_type',
            'connected_endpoint_reachable',
            'tags',
            'custom_fields',
            'created',
            'last_updated',
            'count_ipaddresses',
            '_occupied',
        ]

    def validate(self, data):

        # Validate many-to-many VLAN assignments
        device = self.instance.device if self.instance else data.get('device')
        for vlan in data.get('tagged_vlans', []):
            if vlan.site not in [device.site, None]:
                raise serializers.ValidationError({
                    'tagged_vlans':
                    f"VLAN {vlan} must belong to the same site as the interface's parent device, or "
                    f"it must be global."
                })

        return super().validate(data)
Exemple #6
0
 class Request(serializers.Serializer):
     description = serializers.ChoiceField(choices=DESCRIPTION_CHOICES)
     location = serializers.ChoiceField(choices=LOCATION_CHOICES)
     page = serializers.IntegerField(default=1, min_value=1)
     search_from = serializers.IPAddressField(write_only=True)
class BuildingTrainingDirectionConstraintSerializer(serializers.Serializer):
    training_direction_id = serializers.IntegerField(required=False)
    id = serializers.IntegerField(required=False)
    building_id = serializers.IntegerField()
    ordering = serializers.IntegerField()
    remove = serializers.BooleanField(default=False)
Exemple #8
0
class TPMVisitApproveSerializer(serializers.Serializer):
    mark_as_programmatic_visit = serializers.ListField(
        child=serializers.IntegerField(), required=False)
    approval_comment = serializers.CharField(required=False)
    notify_focal_point = serializers.BooleanField(required=False)
    notify_tpm_partner = serializers.BooleanField(required=False)
Exemple #9
0
class TestSuiteHealthSerializer(serializers.Serializer):
    test = serializers.CharField()
    suite = serializers.CharField()
    platforms = CommaSeparatedField()
    repositories = CommaSeparatedField()
    total_alerts = serializers.IntegerField()
Exemple #10
0
class ActorMovieSerializer(serializers.Serializer):
    idmovies = serializers.IntegerField()
    title = serializers.CharField()
    year = serializers.IntegerField()
Exemple #11
0
class MovieGenreSerializer(serializers.Serializer):
    idmovies = serializers.IntegerField()
    title = serializers.CharField()
class ReviewSerializer(serializers.Serializer):
    title = serializers.CharField()
    comment = serializers.CharField()
    rating = serializers.IntegerField()
    reviewer = CustomerSerializer()
    to_game = GameSerializer()
Exemple #13
0
class GetUsersSerializer(serializers.Serializer):
    query = serializers.CharField(
        max_length=settings.SEARCH_QUERIES_MAX_LENGTH, required=True)
    count = serializers.IntegerField(required=False, max_value=10)
class ThemeCompanySdViewsSerializer(serializers.Serializer):
    key_word = serializers.CharField(max_length=1024)
    views = serializers.IntegerField()
    date = serializers.DateField(required=False)
    sex = serializers.DictField(required=False,
                                child=serializers.IntegerField(min_value=0))
    age = serializers.DictField(required=False,
                                child=serializers.IntegerField(min_value=0))
    education = serializers.DictField(
        required=False, child=serializers.IntegerField(min_value=0))
    children_lt_16 = serializers.DictField(
        required=False, child=serializers.IntegerField(min_value=0))
    marital_status = serializers.DictField(
        required=False, child=serializers.IntegerField(min_value=0))
    occupation = serializers.DictField(
        required=False, child=serializers.IntegerField(min_value=0))
    group = serializers.DictField(required=False,
                                  child=serializers.IntegerField(min_value=0))
    income = serializers.DictField(required=False,
                                   child=serializers.IntegerField(min_value=0))
    region = serializers.DictField(required=False,
                                   child=serializers.IntegerField(min_value=0))
    typeNP = serializers.DictField(required=False,
                                   child=serializers.IntegerField(min_value=0))

    def to_internal_value(self, data):
        date = data.pop("upload_info__title")
        try:
            start_period = datetime.strptime(date, "%m-%Y")
            end_period = start_period + timedelta(
                calendar.monthrange(start_period.year, start_period.month)[1])
        except ValueError:
            try:
                start_period = datetime.strptime(date, "%w-%W-%Y")
                end_period = start_period + timedelta(days=6)
            except ValueError:
                raise ValidationError(
                    {"title": ["Title should be in format %m-%Y or %w-%W-%Y"]})

        data["date"] = end_period.strftime("%Y-%m-%d")
        data["key_word"] = data.pop("title__title")
        return super(ThemeCompanySdViewsSerializer,
                     self).to_internal_value(data=data)
Exemple #15
0
class AlertRuleTriggerActionSerializer(CamelSnakeModelSerializer):
    """
    Serializer for creating/updating a trigger action. Required context:
     - `trigger`: The trigger related to this action.
     - `alert_rule`: The alert_rule related to this action.
     - `organization`: The organization related to this action.
     - `access`: An access object (from `request.access`)
     - `user`: The user from `request.user`
    """

    id = serializers.IntegerField(required=False)
    type = serializers.CharField()
    target_type = serializers.CharField()
    sentry_app_config = serializers.JSONField(required=False)  # array of dicts
    sentry_app_installation_uuid = serializers.CharField(required=False)

    class Meta:
        model = AlertRuleTriggerAction
        fields = [
            "id",
            "type",
            "target_type",
            "target_identifier",
            "integration",
            "sentry_app",
            "sentry_app_config",
            "sentry_app_installation_uuid",
        ]
        extra_kwargs = {
            "target_identifier": {
                "required": True
            },
            "target_display": {
                "required": False
            },
            "integration": {
                "required": False,
                "allow_null": True
            },
            "sentry_app": {
                "required": False,
                "allow_null": True
            },
            "sentry_app_config": {
                "required": False,
                "allow_null": True
            },
            "sentry_app_installation_uuid": {
                "required": False,
                "allow_null": True
            },
        }

    def validate_type(self, type):
        if type not in STRING_TO_ACTION_TYPE:
            raise serializers.ValidationError(
                "Invalid type, valid values are [%s]" %
                ", ".join(STRING_TO_ACTION_TYPE.keys()))
        return STRING_TO_ACTION_TYPE[type]

    def validate_target_type(self, target_type):
        if target_type not in STRING_TO_ACTION_TARGET_TYPE:
            raise serializers.ValidationError(
                "Invalid targetType, valid values are [%s]" %
                ", ".join(STRING_TO_ACTION_TARGET_TYPE.keys()))
        return STRING_TO_ACTION_TARGET_TYPE[target_type]

    def validate(self, attrs):
        if ("type" in attrs) != ("target_type"
                                 in attrs) != ("target_identifier" in attrs):
            raise serializers.ValidationError(
                "type, targetType and targetIdentifier must be passed together"
            )
        type = attrs.get("type")
        target_type = attrs.get("target_type")
        access = self.context["access"]
        identifier = attrs.get("target_identifier")

        if type is not None:
            type_info = AlertRuleTriggerAction.get_registered_type(type)
            if target_type not in type_info.supported_target_types:
                allowed_target_types = ",".join(
                    ACTION_TARGET_TYPE_TO_STRING[type_name]
                    for type_name in type_info.supported_target_types)
                raise serializers.ValidationError({
                    "target_type":
                    "Invalid target type for %s. Valid types are [%s]" %
                    (type_info.slug, allowed_target_types)
                })

        if attrs.get("type") == AlertRuleTriggerAction.Type.EMAIL:
            if target_type == AlertRuleTriggerAction.TargetType.TEAM:
                try:
                    team = Team.objects.get(id=identifier)
                except Team.DoesNotExist:
                    raise serializers.ValidationError("Team does not exist")
                if not access.has_team(team):
                    raise serializers.ValidationError("Team does not exist")
            elif target_type == AlertRuleTriggerAction.TargetType.USER:
                try:
                    user = User.objects.get(id=identifier)
                except User.DoesNotExist:
                    raise serializers.ValidationError("User does not exist")

                if not OrganizationMember.objects.filter(
                        organization=self.context["organization"],
                        user=user).exists():
                    raise serializers.ValidationError(
                        "User does not belong to this organization")
        elif attrs.get("type") == AlertRuleTriggerAction.Type.SLACK:
            if not attrs.get("integration"):
                raise serializers.ValidationError(
                    {"integration": "Integration must be provided for slack"})

        elif attrs.get("type") == AlertRuleTriggerAction.Type.SENTRY_APP:
            if not attrs.get("sentry_app"):
                raise serializers.ValidationError({
                    "sentry_app":
                    "SentryApp must be provided for sentry_app"
                })
            if attrs.get("sentry_app_config"):
                if attrs.get("sentry_app_installation_uuid") is None:
                    raise serializers.ValidationError({
                        "sentry_app":
                        "Missing parameter: sentry_app_installation_uuid"
                    })

                try:
                    install = SentryAppInstallation.objects.get(
                        uuid=attrs.get("sentry_app_installation_uuid"))
                except SentryAppInstallation.DoesNotExist:
                    raise serializers.ValidationError(
                        {"sentry_app": "The installation does not exist."})
                # Check response from creator and bubble up errors from providers as a ValidationError
                result = alert_rule_actions.AlertRuleActionCreator.run(
                    install=install,
                    fields=attrs.get("sentry_app_config"),
                )

                if not result["success"]:
                    raise serializers.ValidationError(
                        {"sentry_app": result["message"]})

                del attrs["sentry_app_installation_uuid"]

        attrs["use_async_lookup"] = self.context.get("use_async_lookup")
        attrs["input_channel_id"] = self.context.get("input_channel_id")
        should_validate_channel_id = self.context.get("validate_channel_id",
                                                      True)
        # validate_channel_id is assumed to be true unless explicitly passed as false
        if attrs["input_channel_id"] and should_validate_channel_id:
            validate_channel_id(identifier, attrs["integration"].id,
                                attrs["input_channel_id"])
        return attrs

    def create(self, validated_data):
        try:
            action = create_alert_rule_trigger_action(
                trigger=self.context["trigger"], **validated_data)
        except InvalidTriggerActionError as e:
            raise serializers.ValidationError(force_text(e))
        except ApiRateLimitedError as e:
            raise serializers.ValidationError(force_text(e))
        else:
            analytics.record(
                "metric_alert_with_ui_component.created",
                user_id=getattr(self.context["user"], "id", None),
                alert_rule_id=getattr(self.context["alert_rule"], "id"),
                organization_id=getattr(self.context["organization"], "id"),
            )
            return action

    def update(self, instance, validated_data):
        if "id" in validated_data:
            validated_data.pop("id")
        try:
            return update_alert_rule_trigger_action(instance, **validated_data)
        except InvalidTriggerActionError as e:
            raise serializers.ValidationError(force_text(e))
        except ApiRateLimitedError as e:
            raise serializers.ValidationError(force_text(e))
class OrganizationSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=64)
    slug = serializers.RegexField(r"^[a-z0-9_\-]+$", max_length=50)
    accountRateLimit = EmptyIntegerField(
        min_value=0, max_value=1000000, required=False, allow_null=True
    )
    projectRateLimit = EmptyIntegerField(
        min_value=50, max_value=100, required=False, allow_null=True
    )
    avatar = AvatarField(required=False, allow_null=True)
    avatarType = serializers.ChoiceField(
        choices=(("upload", "upload"), ("letter_avatar", "letter_avatar")),
        required=False,
        allow_null=True,
    )

    openMembership = serializers.BooleanField(required=False)
    allowSharedIssues = serializers.BooleanField(required=False)
    enhancedPrivacy = serializers.BooleanField(required=False)
    dataScrubber = serializers.BooleanField(required=False)
    dataScrubberDefaults = serializers.BooleanField(required=False)
    sensitiveFields = ListField(child=serializers.CharField(), required=False)
    safeFields = ListField(child=serializers.CharField(), required=False)
    storeCrashReports = serializers.IntegerField(min_value=-1, max_value=20, required=False)
    attachmentsRole = serializers.CharField(required=True)
    scrubIPAddresses = serializers.BooleanField(required=False)
    scrapeJavaScript = serializers.BooleanField(required=False)
    isEarlyAdopter = serializers.BooleanField(required=False)
    require2FA = serializers.BooleanField(required=False)
    trustedRelays = ListField(child=serializers.CharField(), required=False)
    allowJoinRequests = serializers.BooleanField(required=False)

    @memoize
    def _has_legacy_rate_limits(self):
        org = self.context["organization"]
        return OrganizationOption.objects.filter(
            organization=org, key__in=LEGACY_RATE_LIMIT_OPTIONS
        ).exists()

    def _has_sso_enabled(self):
        org = self.context["organization"]
        return AuthProvider.objects.filter(organization=org).exists()

    def validate_slug(self, value):
        # Historically, the only check just made sure there was more than 1
        # character for the slug, but since then, there are many slugs that
        # fit within this new imposed limit. We're not fixing existing, but
        # just preventing new bad values.
        if len(value) < 3:
            raise serializers.ValidationError(
                'This slug "%s" is too short. Minimum of 3 characters.' % (value,)
            )
        if value in RESERVED_ORGANIZATION_SLUGS:
            raise serializers.ValidationError(
                'This slug "%s" is reserved and not allowed.' % (value,)
            )
        qs = Organization.objects.filter(slug=value).exclude(id=self.context["organization"].id)
        if qs.exists():
            raise serializers.ValidationError('The slug "%s" is already in use.' % (value,))
        return value

    def validate_sensitiveFields(self, value):
        if value and not all(value):
            raise serializers.ValidationError("Empty values are not allowed.")
        return value

    def validate_safeFields(self, value):
        if value and not all(value):
            raise serializers.ValidationError("Empty values are not allowed.")
        return value

    def validate_attachmentsRole(self, value):
        try:
            roles.get(value)
        except KeyError:
            raise serializers.ValidationError("Invalid role")
        return value

    def validate_require2FA(self, value):
        user = self.context["user"]
        has_2fa = Authenticator.objects.user_has_2fa(user)
        if value and not has_2fa:
            raise serializers.ValidationError(ERR_NO_2FA)

        if value and self._has_sso_enabled():
            raise serializers.ValidationError(ERR_SSO_ENABLED)
        return value

    def validate_trustedRelays(self, value):
        from sentry import features

        organization = self.context["organization"]
        request = self.context["request"]
        has_relays = features.has("organizations:relay", organization, actor=request.user)
        if not has_relays:
            raise serializers.ValidationError(
                "Organization does not have the relay feature enabled"
            )
        return value

    def validate_accountRateLimit(self, value):
        if not self._has_legacy_rate_limits:
            raise serializers.ValidationError(
                "The accountRateLimit option cannot be configured for this organization"
            )
        return value

    def validate_projectRateLimit(self, value):
        if not self._has_legacy_rate_limits:
            raise serializers.ValidationError(
                "The accountRateLimit option cannot be configured for this organization"
            )
        return value

    def validate(self, attrs):
        attrs = super(OrganizationSerializer, self).validate(attrs)
        if attrs.get("avatarType") == "upload":
            has_existing_file = OrganizationAvatar.objects.filter(
                organization=self.context["organization"], file__isnull=False
            ).exists()
            if not has_existing_file and not attrs.get("avatar"):
                raise serializers.ValidationError(
                    {"avatarType": "Cannot set avatarType to upload without avatar"}
                )
        return attrs

    def save(self):
        org = self.context["organization"]
        changed_data = {}

        for key, option, type_, default_value in ORG_OPTIONS:
            if key not in self.initial_data:
                continue
            try:
                option_inst = OrganizationOption.objects.get(organization=org, key=option)
            except OrganizationOption.DoesNotExist:
                OrganizationOption.objects.set_value(
                    organization=org, key=option, value=type_(self.initial_data[key])
                )

                if self.initial_data[key] != default_value:
                    changed_data[key] = u"to {}".format(self.initial_data[key])
            else:
                option_inst.value = self.initial_data[key]
                # check if ORG_OPTIONS changed
                if option_inst.has_changed("value"):
                    old_val = option_inst.old_value("value")
                    changed_data[key] = u"from {} to {}".format(old_val, option_inst.value)
                option_inst.save()

        if "openMembership" in self.initial_data:
            org.flags.allow_joinleave = self.initial_data["openMembership"]
        if "allowSharedIssues" in self.initial_data:
            org.flags.disable_shared_issues = not self.initial_data["allowSharedIssues"]
        if "enhancedPrivacy" in self.initial_data:
            org.flags.enhanced_privacy = self.initial_data["enhancedPrivacy"]
        if "isEarlyAdopter" in self.initial_data:
            org.flags.early_adopter = self.initial_data["isEarlyAdopter"]
        if "require2FA" in self.initial_data:
            org.flags.require_2fa = self.initial_data["require2FA"]
        if "name" in self.initial_data:
            org.name = self.initial_data["name"]
        if "slug" in self.initial_data:
            org.slug = self.initial_data["slug"]

        org_tracked_field = {
            "name": org.name,
            "slug": org.slug,
            "default_role": org.default_role,
            "flag_field": {
                "allow_joinleave": org.flags.allow_joinleave.is_set,
                "enhanced_privacy": org.flags.enhanced_privacy.is_set,
                "disable_shared_issues": org.flags.disable_shared_issues.is_set,
                "early_adopter": org.flags.early_adopter.is_set,
                "require_2fa": org.flags.require_2fa.is_set,
            },
        }

        # check if fields changed
        for f, v in six.iteritems(org_tracked_field):
            if f != "flag_field":
                if org.has_changed(f):
                    old_val = org.old_value(f)
                    changed_data[f] = u"from {} to {}".format(old_val, v)
            else:
                # check if flag fields changed
                for f, v in six.iteritems(org_tracked_field["flag_field"]):
                    if org.flag_has_changed(f):
                        changed_data[f] = u"to {}".format(v)

        org.save()

        if "avatar" in self.initial_data or "avatarType" in self.initial_data:
            OrganizationAvatar.save_avatar(
                relation={"organization": org},
                type=self.initial_data.get("avatarType", "upload"),
                avatar=self.initial_data.get("avatar"),
                filename=u"{}.png".format(org.slug),
            )
        if "require2FA" in self.initial_data and self.initial_data["require2FA"] is True:
            org.handle_2fa_required(self.context["request"])
        return org, changed_data
Exemple #17
0
class BaseFileSerializer(JSONAPISerializer):
    filterable_fields = frozenset([
        'id',
        'name',
        'kind',
        'path',
        'materialized_path',
        'size',
        'provider',
        'last_touched',
        'tags',
    ])
    id = IDField(source='_id', read_only=True)
    type = TypeField()
    guid = ser.SerializerMethodField(read_only=True,
                                     method_name='get_file_guid',
                                     help_text='OSF GUID for this file (if one has been assigned)')
    checkout = CheckoutField()
    name = ser.CharField(read_only=True, help_text='Display name used in the general user interface')
    kind = ser.CharField(read_only=True, help_text='Either folder or file')
    path = ser.CharField(read_only=True, help_text='The unique path used to reference this object')
    size = ser.SerializerMethodField(read_only=True, help_text='The size of this file at this version')
    provider = ser.CharField(read_only=True, help_text='The Add-on service this file originates from')
    materialized_path = ser.CharField(
        read_only=True, help_text='The Unix-style path of this object relative to the provider root')
    last_touched = VersionedDateTimeField(read_only=True, help_text='The last time this file had information fetched about it via the OSF')
    date_modified = ser.SerializerMethodField(read_only=True, help_text='Timestamp when the file was last modified')
    date_created = ser.SerializerMethodField(read_only=True, help_text='Timestamp when the file was created')
    extra = ser.SerializerMethodField(read_only=True, help_text='Additional metadata about this file')
    tags = JSONAPIListField(child=FileTagField(), required=False)
    current_user_can_comment = ser.SerializerMethodField(help_text='Whether the current user is allowed to post comments')
    current_version = ser.IntegerField(help_text='Latest file version', read_only=True, source='current_version_number')
    delete_allowed = ser.BooleanField(read_only=True, required=False)

    files = NodeFileHyperLinkField(
        related_view='nodes:node-files',
        related_view_kwargs={'node_id': '<target._id>', 'path': '<path>', 'provider': '<provider>'},
        kind='folder'
    )
    versions = NodeFileHyperLinkField(
        related_view='files:file-versions',
        related_view_kwargs={'file_id': '<_id>'},
        kind='file'
    )
    comments = FileCommentRelationshipField(related_view='nodes:node-comments',
                                            related_view_kwargs={'node_id': '<target._id>'},
                                            related_meta={'unread': 'get_unread_comments_count'},
                                            filter={'target': 'get_file_guid'}
                                            )

    links = LinksField({
        'info': Link('files:file-detail', kwargs={'file_id': '<_id>'}),
        'move': WaterbutlerLink(),
        'upload': WaterbutlerLink(),
        'delete': WaterbutlerLink(),
        'download': 'get_download_link',
        'new_folder': WaterbutlerLink(must_be_folder=True, kind='folder'),
    })

    def get_download_link(self, obj):
        if obj.is_file:
            return get_file_download_link(obj, view_only=self.context['request'].query_params.get('view_only'))

    class Meta:
        type_ = 'files'

    def get_size(self, obj):
        if obj.versions.exists():
            self.size = obj.versions.first().size
            return self.size
        return None

    def get_date_modified(self, obj):
        mod_dt = None
        if obj.provider == 'osfstorage' and obj.versions.exists():
            # Each time an osfstorage file is added or uploaded, a new version object is created with its
            # date_created equal to the time of the update.  The external_modified is the modified date
            # from the backend the file is stored on.  This field refers to the modified date on osfstorage,
            # so prefer to use the created of the latest version.
            mod_dt = obj.versions.first().created
        elif obj.provider != 'osfstorage' and obj.history:
            mod_dt = obj.history[-1].get('modified', None)

        if self.context['request'].version >= '2.2' and obj.is_file and mod_dt:
            return datetime.strftime(mod_dt, '%Y-%m-%dT%H:%M:%S.%fZ')

        return mod_dt and mod_dt.replace(tzinfo=pytz.utc)

    def get_date_created(self, obj):
        creat_dt = None
        if obj.provider == 'osfstorage' and obj.versions.exists():
            creat_dt = obj.versions.last().created
        elif obj.provider != 'osfstorage' and obj.history:
            # Non-osfstorage files don't store a created date, so instead get the modified date of the
            # earliest entry in the file history.
            creat_dt = obj.history[0].get('modified', None)

        if self.context['request'].version >= '2.2' and obj.is_file and creat_dt:
            return datetime.strftime(creat_dt, '%Y-%m-%dT%H:%M:%S.%fZ')

        return creat_dt and creat_dt.replace(tzinfo=pytz.utc)

    def get_extra(self, obj):
        metadata = {}
        if obj.provider == 'osfstorage' and obj.versions.exists():
            metadata = obj.versions.first().metadata
        elif obj.provider != 'osfstorage' and obj.history:
            metadata = obj.history[-1].get('extra', {})

        extras = {}
        extras['hashes'] = {  # mimic waterbutler response
            'md5': metadata.get('md5', None),
            'sha256': metadata.get('sha256', None),
        }
        if obj.provider == 'osfstorage' and obj.is_file:
            extras['downloads'] = obj.get_download_count()
        return extras

    def get_current_user_can_comment(self, obj):
        user = self.context['request'].user
        auth = Auth(user if not user.is_anonymous else None)
        return obj.target.can_comment(auth)

    def get_unread_comments_count(self, obj):
        user = self.context['request'].user
        if user.is_anonymous:
            return 0
        return Comment.find_n_unread(user=user, node=obj.target, page='files', root_id=obj.get_guid()._id)

    def user_id(self, obj):
        # NOTE: obj is the user here, the meta field for
        # Hyperlinks is weird
        if obj:
            return obj._id
        return None

    def update(self, instance, validated_data):
        assert isinstance(instance, BaseFileNode), 'Instance must be a BaseFileNode'
        if instance.provider != 'osfstorage' and 'tags' in validated_data:
            raise Conflict('File service provider {} does not support tags on the OSF.'.format(instance.provider))
        auth = get_user_auth(self.context['request'])
        old_tags = set(instance.tags.values_list('name', flat=True))
        if 'tags' in validated_data:
            current_tags = set(validated_data.pop('tags', []))
        else:
            current_tags = set(old_tags)

        for new_tag in (current_tags - old_tags):
            instance.add_tag(new_tag, auth=auth)
        for deleted_tag in (old_tags - current_tags):
            instance.remove_tag(deleted_tag, auth=auth)

        for attr, value in validated_data.items():
            if attr == 'checkout':
                user = self.context['request'].user
                instance.check_in_or_out(user, value)
            else:
                setattr(instance, attr, value)
        instance.save()
        return instance

    def is_valid(self, **kwargs):
        return super(BaseFileSerializer, self).is_valid(clean_html=False, **kwargs)

    def get_file_guid(self, obj):
        if obj:
            guid = obj.get_guid()
            if guid:
                return guid._id
        return None

    def get_absolute_url(self, obj):
        return api_v2_url('files/{}/'.format(obj._id))
class ProjectCodeOwnerSerializer(CamelSnakeModelSerializer):
    code_mapping_id = serializers.IntegerField(required=True)
    raw = serializers.CharField(required=True)
    organization_integration_id = serializers.IntegerField(required=False)

    class Meta:
        model = ProjectCodeOwners
        fields = ["raw", "code_mapping_id", "organization_integration_id"]

    def validate(self, attrs):
        # If it already exists, set default attrs with existing values
        if self.instance:
            attrs = {
                "raw": self.instance.raw,
                "code_mapping_id": self.instance.repository_project_path_config,
                **attrs,
            }

        if not attrs.get("raw", "").strip():
            return attrs
        external_association_err = []
        # Get list of team/user names from CODEOWNERS file
        teamnames, usernames, emails = parse_code_owners(attrs["raw"])

        # Check if there exists Sentry users with the emails listed in CODEOWNERS
        user_emails = UserEmail.objects.filter(email__in=emails)
        user_emails_diff = self._validate_association(emails, user_emails, "emails")

        external_association_err.extend(user_emails_diff)

        # Check if the usernames have an association
        external_users = ExternalUser.objects.filter(
            external_name__in=usernames,
            organizationmember__organization=self.context["project"].organization,
        )

        external_users_diff = self._validate_association(usernames, external_users, "usernames")

        external_association_err.extend(external_users_diff)

        # Check if the team names have an association
        external_teams = ExternalTeam.objects.filter(
            external_name__in=teamnames,
            team__organization=self.context["project"].organization,
        )

        external_teams_diff = self._validate_association(teamnames, external_teams, "team names")

        external_association_err.extend(external_teams_diff)

        if len(external_association_err):
            raise serializers.ValidationError({"raw": "\n".join(external_association_err)})

        # Convert CODEOWNERS into IssueOwner syntax
        users_dict = {
            user.external_name: user.organizationmember.user.email for user in external_users
        }
        teams_dict = {team.external_name: f"#{team.team.slug}" for team in external_teams}
        emails_dict = {email: email for email in emails}
        associations = {**users_dict, **teams_dict, **emails_dict}

        issue_owner_rules = convert_codeowners_syntax(
            attrs["raw"], associations, attrs["code_mapping_id"]
        )

        # Convert IssueOwner syntax into schema syntax
        validated_data = ProjectOwnershipSerializer(context=self.context).validate(
            {"raw": issue_owner_rules}
        )

        return {**validated_data, **attrs}

    def _validate_association(self, raw_items, associations, type):
        if type == "emails":
            # associations are UserEmail objects
            sentry_items = [item.email for item in associations]
        else:
            # associations can be ExternalUser or ExternalTeam objects
            sentry_items = [item.external_name for item in associations]

        diff = [item for item in raw_items if item not in sentry_items]

        if len(diff):
            return [
                f'The following {type} do not have an association in Sentry: {", ".join(diff)}.'
            ]

        return []

    def validate_code_mapping_id(self, code_mapping_id):
        try:
            return RepositoryProjectPathConfig.objects.get(
                id=code_mapping_id, project=self.context["project"]
            )
        except RepositoryProjectPathConfig.DoesNotExist:
            raise serializers.ValidationError("This code mapping does not exist.")

    def create(self, validated_data):
        # Save projectcodeowners record
        repository_project_path_config = validated_data.pop("code_mapping_id", None)
        project = self.context["project"]
        return ProjectCodeOwners.objects.create(
            repository_project_path_config=repository_project_path_config,
            project=project,
            **validated_data,
        )

    def update(self, instance, validated_data):
        if "id" in validated_data:
            validated_data.pop("id")
        for key, value in validated_data.items():
            setattr(self.instance, key, value)
        self.instance.save()
        return self.instance
class SubmissionCountSerializer(serializers.Serializer):
    submission_count = serializers.IntegerField()
class BulkOperationSerializer(serializers.Serializer):
    id = serializers.IntegerField()
class LessonTrainingDirectionConstraintSerializer(serializers.Serializer):
    training_direction_id = serializers.IntegerField(required=False)
    id = serializers.IntegerField(required=False)
    lesson = serializers.IntegerField()
    day_of_week = serializers.IntegerField()
    remove = serializers.BooleanField(default=False)
Exemple #22
0
class AppSerializer(serializers.ModelSerializer):
    app_type = serializers.ChoiceField(
        choices=amo.ADDON_WEBAPP_TYPES_LOOKUP.items(), read_only=True)
    author = serializers.CharField(source='developer_name', read_only=True)
    banner_message = TranslationSerializerField(read_only=True,
        source='geodata.banner_message')
    banner_regions = serializers.Field(source='geodata.banner_regions_slugs')
    categories = serializers.SlugRelatedField(source='categories',
        many=True, slug_field='slug', required=True,
        queryset=Category.objects.filter(type=amo.ADDON_WEBAPP))
    content_ratings = serializers.SerializerMethodField('get_content_ratings')
    created = serializers.DateField(read_only=True)
    current_version = serializers.CharField(
        source='current_version.version',
        read_only=True)
    default_locale = serializers.CharField(read_only=True)
    device_types = SemiSerializerMethodField('get_device_types')
    description = TranslationSerializerField(required=False)
    homepage = TranslationSerializerField(required=False)
    icons = serializers.SerializerMethodField('get_icons')
    id = serializers.IntegerField(source='pk', required=False)
    is_packaged = serializers.BooleanField(read_only=True)
    manifest_url = serializers.CharField(source='get_manifest_url',
                                         read_only=True)
    name = TranslationSerializerField(required=False)
    payment_account = serializers.HyperlinkedRelatedField(
        view_name='payment-account-detail', source='app_payment_account',
        required=False)
    payment_required = serializers.SerializerMethodField(
        'get_payment_required')
    premium_type = ReverseChoiceField(
        choices_dict=amo.ADDON_PREMIUM_API, required=False)
    previews = PreviewSerializer(many=True, required=False,
                                 source='all_previews')
    price = SemiSerializerMethodField('get_price')
    price_locale = serializers.SerializerMethodField('get_price_locale')
    privacy_policy = LargeTextField(view_name='app-privacy-policy-detail',
                                    required=False)
    public_stats = serializers.BooleanField(read_only=True)
    ratings = serializers.SerializerMethodField('get_ratings_aggregates')
    regions = RegionSerializer(read_only=True, source='get_regions')
    release_notes = TranslationSerializerField(read_only=True,
        source='current_version.releasenotes')
    resource_uri = serializers.HyperlinkedIdentityField(view_name='app-detail')
    slug = serializers.CharField(source='app_slug', required=False)
    status = serializers.IntegerField(read_only=True)
    support_email = TranslationSerializerField(required=False)

    support_url = TranslationSerializerField(required=False)
    supported_locales = serializers.SerializerMethodField(
        'get_supported_locales')
    tags = serializers.SerializerMethodField('get_tags')
    upsell = serializers.SerializerMethodField('get_upsell')
    upsold = serializers.HyperlinkedRelatedField(
        view_name='app-detail', source='upsold.free',
        required=False, queryset=Webapp.objects.all())
    user = serializers.SerializerMethodField('get_user_info')
    versions = serializers.SerializerMethodField('get_versions')
    weekly_downloads = serializers.SerializerMethodField(
        'get_weekly_downloads')

    class Meta:
        model = Webapp
        fields = [
            'app_type', 'author', 'banner_message', 'banner_regions',
            'categories', 'content_ratings', 'created', 'current_version',
            'default_locale', 'description', 'device_types', 'homepage',
            'icons', 'id', 'is_packaged', 'manifest_url', 'name',
            'payment_account', 'payment_required', 'premium_type', 'previews',
            'price', 'price_locale', 'privacy_policy', 'public_stats',
            'release_notes', 'ratings', 'regions', 'resource_uri', 'slug',
            'status', 'support_email', 'support_url', 'supported_locales',
            'tags', 'upsell', 'upsold', 'user', 'versions', 'weekly_downloads']

    def _get_region_id(self):
        request = self.context.get('request')
        REGION = getattr(request, 'REGION', None)
        return REGION.id if REGION else None

    def _get_region_slug(self):
        request = self.context.get('request')
        REGION = getattr(request, 'REGION', None)
        return REGION.slug if REGION else None

    def get_content_ratings(self, app):
        return filter_content_ratings_by_region({
            'ratings': app.get_content_ratings_by_body() or None,
            'descriptors': app.get_descriptors() or None,
            'interactive_elements': app.get_interactives() or None,
            'regions': mkt.regions.REGION_TO_RATINGS_BODY()
        }, region=self._get_region_slug())

    def get_icons(self, app):
        return dict([(icon_size, app.get_icon_url(icon_size))
                     for icon_size in (16, 48, 64, 128)])

    def get_payment_required(self, app):
        if app.has_premium():
            tier = app.get_tier()
            return bool(tier and tier.price)
        return False

    def get_price(self, app):
        if app.has_premium():
            region = self._get_region_id()
            if region in app.get_price_region_ids():
                return app.get_price(region=region)
        return None

    def get_price_locale(self, app):
        if app.has_premium():
            region = self._get_region_id()
            if region in app.get_price_region_ids():
                return app.get_price_locale(region=region)
        return None

    def get_ratings_aggregates(self, app):
        return {'average': app.average_rating,
                'count': app.total_reviews}

    def get_supported_locales(self, app):
        locs = getattr(app.current_version, 'supported_locales', '')
        if locs:
            return locs.split(',') if isinstance(locs, basestring) else locs
        else:
            return []

    def get_tags(self, app):
        return [t.tag_text for t in app.tags.all()]

    def get_upsell(self, app):
        upsell = False
        if app.upsell:
            upsell = app.upsell.premium
        # Only return the upsell app if it's public and we are not in an
        # excluded region.
        if (upsell and upsell.is_public() and self._get_region_id()
                not in upsell.get_excluded_region_ids()):
            return {
                'id': upsell.id,
                'app_slug': upsell.app_slug,
                'icon_url': upsell.get_icon_url(128),
                'name': unicode(upsell.name),
                'resource_uri': reverse('app-detail', kwargs={'pk': upsell.pk})
            }
        else:
            return False

    def get_user_info(self, app):
        user = getattr(self.context.get('request'), 'amo_user', None)
        if user:
            return {
                'developed': app.addonuser_set.filter(
                    user=user, role=amo.AUTHOR_ROLE_OWNER).exists(),
                'installed': app.has_installed(user),
                'purchased': app.pk in user.purchase_ids(),
            }

    def get_versions(self, app):
        # Disable transforms, we only need two fields: version and pk.
        # Unfortunately, cache-machine gets in the way so we can't use .only()
        # (.no_transforms() is ignored, defeating the purpose), and we can't use
        # .values() / .values_list() because those aren't cached :(
        return dict((v.version, reverse('version-detail', kwargs={'pk': v.pk}))
                    for v in app.versions.all().no_transforms())

    def get_weekly_downloads(self, app):
        if app.public_stats:
            return app.weekly_downloads

    def validate_categories(self, attrs, source):
        if not attrs.get('categories'):
            raise serializers.ValidationError('This field is required.')
        set_categories = set(attrs[source])
        total = len(set_categories)
        max_cat = amo.MAX_CATEGORIES

        if total > max_cat:
            # L10n: {0} is the number of categories.
            raise serializers.ValidationError(ngettext(
                'You can have only {0} category.',
                'You can have only {0} categories.',
                max_cat).format(max_cat))

        return attrs

    def get_device_types(self, app):
        with no_translation():
            return [n.api_name for n in app.device_types]

    def save_device_types(self, obj, new_types):
        new_types = [amo.DEVICE_LOOKUP[d].id for d in new_types]
        old_types = [x.id for x in obj.device_types]

        added_devices = set(new_types) - set(old_types)
        removed_devices = set(old_types) - set(new_types)

        for d in added_devices:
            obj.addondevicetype_set.create(device_type=d)
        for d in removed_devices:
            obj.addondevicetype_set.filter(device_type=d).delete()

        # Send app to re-review queue if public and new devices are added.
        if added_devices and obj.status in amo.WEBAPPS_APPROVED_STATUSES:
            mark_for_rereview(obj, added_devices, removed_devices)

    def save_categories(self, obj, categories):
        before = set(obj.categories.values_list('id', flat=True))
        # Add new categories.
        to_add = set(c.id for c in categories) - before
        for c in to_add:
            AddonCategory.objects.create(addon=obj, category_id=c)

        # Remove old categories.
        to_remove = before - set(categories)
        for c in to_remove:
            obj.addoncategory_set.filter(category=c).delete()

    def save_upsold(self, obj, upsold):
        current_upsell = obj.upsold
        if upsold and upsold != obj.upsold.free:
            if not current_upsell:
                log.debug('[1@%s] Creating app upsell' % obj.pk)
                current_upsell = AddonUpsell(premium=obj)
            current_upsell.free = upsold
            current_upsell.save()

        elif current_upsell:
            # We're deleting the upsell.
            log.debug('[1@%s] Deleting the app upsell' % obj.pk)
            current_upsell.delete()

    def save_price(self, obj, price):
        premium = obj.premium
        if not premium:
            premium = AddonPremium()
            premium.addon = obj
        premium.price = Price.objects.active().get(price=price)
        premium.save()

    def validate_device_types(self, attrs, source):
        if attrs.get('device_types') is None:
            raise serializers.ValidationError('This field is required.')
        for v in attrs['device_types']:
            if v not in amo.DEVICE_LOOKUP.keys():
                raise serializers.ValidationError(
                    str(v) + ' is not one of the available choices.')
        return attrs

    def validate_price(self, attrs, source):
        if attrs.get('premium_type', None) not in (amo.ADDON_FREE,
                                                   amo.ADDON_FREE_INAPP):
            valid_prices = Price.objects.exclude(
                price='0.00').values_list('price', flat=True)
            price = attrs.get('price')
            if not (price and Decimal(price) in valid_prices):
                raise serializers.ValidationError(
                    'Premium app specified without a valid price. Price can be'
                    ' one of %s.' % (', '.join('"%s"' % str(p)
                                               for p in valid_prices),))
        return attrs

    def restore_object(self, attrs, instance=None):
        # restore_object creates or updates a model instance, during
        # input validation.
        extras = []
        # Upsell bits are handled here because we need to remove it
        # from the attrs dict before deserializing.
        upsold = attrs.pop('upsold.free', None)
        if upsold is not None:
            extras.append((self.save_upsold, upsold))
        price = attrs.pop('price', None)
        if price is not None:
            extras.append((self.save_price, price))
        device_types = attrs['device_types']
        if device_types:
            extras.append((self.save_device_types, device_types))
            del attrs['device_types']
        if attrs.get('app_payment_account') is None:
            attrs.pop('app_payment_account')
        instance = super(AppSerializer, self).restore_object(
            attrs, instance=instance)
        for f, v in extras:
            f(instance, v)
        return instance

    def save_object(self, obj, **kwargs):
        # this only gets called if validation succeeds.
        m2m = getattr(obj, '_m2m_data', {})
        cats = m2m.pop('categories', None)
        super(AppSerializer, self).save_object(obj, **kwargs)
        # Categories are handled here because we can't look up
        # existing ones until the initial save is done.
        self.save_categories(obj, cats)
Exemple #23
0
class RackSerializer(PrimaryModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='dcim-api:rack-detail')
    site = NestedSiteSerializer()
    location = NestedLocationSerializer(required=False,
                                        allow_null=True,
                                        default=None)
    tenant = NestedTenantSerializer(required=False, allow_null=True)
    status = ChoiceField(choices=RackStatusChoices, required=False)
    role = NestedRackRoleSerializer(required=False, allow_null=True)
    type = ChoiceField(choices=RackTypeChoices,
                       allow_blank=True,
                       required=False)
    width = ChoiceField(choices=RackWidthChoices, required=False)
    outer_unit = ChoiceField(choices=RackDimensionUnitChoices,
                             allow_blank=True,
                             required=False)
    device_count = serializers.IntegerField(read_only=True)
    powerfeed_count = serializers.IntegerField(read_only=True)

    class Meta:
        model = Rack
        fields = [
            'id',
            'url',
            'display',
            'name',
            'facility_id',
            'site',
            'location',
            'tenant',
            'status',
            'role',
            'serial',
            'asset_tag',
            'type',
            'width',
            'u_height',
            'desc_units',
            'outer_width',
            'outer_depth',
            'outer_unit',
            'comments',
            'tags',
            'custom_fields',
            'created',
            'last_updated',
            'device_count',
            'powerfeed_count',
        ]
        # Omit the UniqueTogetherValidator that would be automatically added to validate (location, facility_id). This
        # prevents facility_id from being interpreted as a required field.
        validators = [
            UniqueTogetherValidator(queryset=Rack.objects.all(),
                                    fields=('location', 'name'))
        ]

    def validate(self, data):

        # Validate uniqueness of (location, facility_id) since we omitted the automatically-created validator from Meta.
        if data.get('facility_id', None):
            validator = UniqueTogetherValidator(queryset=Rack.objects.all(),
                                                fields=('location',
                                                        'facility_id'))
            validator(data, self)

        # Enforce model validation
        super().validate(data)

        return data
Exemple #24
0
class QuizMarkSerializer(serializers.ModelSerializer):
    mark = serializers.IntegerField(max_value=200, min_value=0)

    class Meta:
        model = Language
        fields = ['mark']
Exemple #25
0
class DataStreamSerializer(ResourceSerializer):
    title = serializers.CharField(help_text=_(u'Título del conjunto de datos'))
    description = serializers.CharField(
        help_text=_(u'Descripción del conjunto de datos'))
    category = serializers.ChoiceField(
        tuple(),
        help_text=
        _(u'Nombre de la categoría para clasificar los recursos. Debe coincidir con alguna de las categorías de la cuenta'
          ))
    notes = serializers.CharField(
        required=False,
        allow_null=True,
        help_text=_(u'Texto de la nota del conjunto de datos'))
    table_id = serializers.IntegerField(
        required=False,
        allow_null=True,
        default=0,
        help_text=_(
            u'Indice de la tabla en el conjunto de datos, comenzando de cero.')
    )
    header_row = serializers.IntegerField(
        required=False,
        allow_null=True,
        help_text=
        _(u'Indice de la fila a usar como cabecera de la tabla comenzando de cero. Por defecto es vacio'
          ))
    dataset = serializers.CharField(
        required=False,
        help_text=_(u'GUID del conjunto de datos asociado a la vista'))

    def __init__(self, *args, **kwargs):
        super(DataStreamSerializer, self).__init__(*args, **kwargs)

        self.fields['category'] = serializers.ChoiceField(
            self.getAccountCategoriesChoices(),
            help_text=self.fields['category'].help_text)

    def to_representation(self, obj):
        answer = super(DataStreamSerializer, self).to_representation(obj)
        self.tryKeysOnDict(answer, 'parameters', obj, ['parameters'])
        return answer

    def validate(self, data):
        guid = data.pop('dataset', None)
        if guid:
            try:
                self.dataset = DatasetDBDAO().get(
                    self.context['request'].auth['language'],
                    guid=guid,
                    published=False)
                data['dataset'] = Dataset.objects.get(
                    id=self.dataset['dataset_id'])
            except ObjectDoesNotExist:
                # TODO: mejorar errores
                raise exceptions.ValidationError(
                    {'dataset': 'Dataset no existe'})

            if data['dataset'].last_revision.impl_type not in DATASTREAM_IMPL_VALID_CHOICES:
                # TODO: mejorar errores
                raise exceptions.ValidationError({
                    'dataset':
                    'El tipo de archivo no permite creacion de vistas'
                })

            if 'table_id' in data:
                table_id = data.pop('table_id')
                data['select_statement'] = SelectStatementBuilder().build(
                    table_id)
                data['data_source'] = DataSourceBuilder().build(
                    table_id, data['dataset'].last_revision_id, 'microsites')

        if 'category' in data and data['category']:
            data['category'] = self.getCategory(data['category']).id

        data['status'] = StatusChoices.PENDING_REVIEW

        data['language'] = self.context['request'].auth['language']

        return data

    def getDao(self, datastream_revision):
        return DataStreamDBDAO().get(
            datastream_revision_id=datastream_revision.id,
            language=self.context['request'].auth['language'],
            published=False)

    def create(self, validated_data):
        if 'dataset' not in validated_data:
            raise exceptions.ValidationError({'dataset': 'No hay dataset'})

        return self.getDao(
            DatastreamLifeCycleManager(
                self.context['request'].user).create(**validated_data))

    def update(self, instance, validated_data):
        lcycle = DatastreamLifeCycleManager(
            self.context['request'].user,
            datastream_id=instance['datastream_id'])
        instance.update(validated_data)
        instance.pop('datastream', None)
        instance.pop('dataset', None)
        instance.pop('user', None)
        instance.pop('status', None)
        instance.pop('parameters', None)
        if 'category' not in instance:
            instance['category'] = instance['category_id']
        return self.getDao(
            lcycle.edit(changed_fields=validated_data.keys(), **instance))
Exemple #26
0
class SwSerializer(serializers.Serializer):
    BargainDate = serializers.IntegerField(required=False)
    PB = serializers.FloatField(read_only=True)
    PE = serializers.FloatField(read_only=True)
class ProductStatSerializer(serializers.Serializer):
    stats = serializers.DictField(
        child=serializers.ListField(
            child=serializers.IntegerField()
        )
    )
Exemple #28
0
class StockSerializer(serializers.Serializer):
    code = serializers.CharField(required=False)
    close = serializers.FloatField(read_only=True)
    volume = serializers.FloatField(read_only=True)
    timestamp = serializers.IntegerField(read_only=True)
    turn_rate = serializers.FloatField(read_only=True)
Exemple #29
0
class MarkNotificationsAsReadSerializer(serializers.Serializer):
    topic = serializers.IntegerField(required=False, allow_null=True)
Exemple #30
0
class LevelSerializer(OptionFieldsFilter, serializers.ModelSerializer):
    '''
    @class LevelSerializer
    @brief
        Serializer class for Level
    '''

    member_count = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=255)
    remit_limit = serializers.CharField(required=False, max_length=255, allow_null=True)
    online_limit = serializers.CharField(required=False, max_length=255, allow_null=True)
    withdraw_limit = serializers.CharField(required=False, max_length=255, allow_null=True)
    # withdraw_fee = serializers.FloatField()
    withdraw_fee = serializers.CharField(max_length=100)
    reg_present = serializers.CharField(required=False, max_length=100, allow_null=True)
    remit_check = serializers.CharField(max_length=100, allow_null=True)
    service_rate = serializers.IntegerField()
    memo = serializers.CharField(required=False, allow_blank=True)
    status = serializers.IntegerField(default=1, allow_null=True)
    cdt_deposit_num = serializers.IntegerField(required=False, allow_null=True)
    cdt_deposit_amount = serializers.IntegerField(required=False, allow_null=True)
    cdt_deposit_max = serializers.IntegerField(required=False, allow_null=True)
    cdt_withdraw_num = serializers.IntegerField(required=False, allow_null=True)
    cdt_withdraw_amount = serializers.IntegerField(required=False, allow_null=True)
    remit_discounts = DiscountSerializer(required=False, source='level_remit_discount', many=True)
    online_discounts = DiscountSerializer(required=False, source='level_online_discount', many=True)
    __fields_to_validate = [
                            'remit_limit',
                            'online_limit',
                            'withdraw_limit',
                            'withdraw_fee',
                            'reg_present',
                            'remit_check',
                            ]


    class Meta:
        model = Level
        depth = 2
        fields = (
                'member_count',
                'id',
                'name',
                'remit_limit',
                'online_limit',
                'withdraw_limit',
                'withdraw_fee',
                'reg_present',
                'remit_check',
                'service_rate',
                'memo',
                'status',
                'cdt_deposit_num',
                'cdt_deposit_amount',
                'cdt_deposit_max',
                'cdt_withdraw_num',
                'cdt_withdraw_amount',
                'remit_discounts',
                'online_discounts',)

    def to_internal_value(self, data):
        ret = super(LevelSerializer, self).to_internal_value(data)
        remit_discount = data.get('remit_discounts')
        online_discount = data.get('online_discounts')
        if remit_discount:
            ret['level_remit_discount'] = remit_discount
        if online_discount:
            ret['level_online_discount'] = online_discount
        return ret

    def validate(self, data):
        '''
        @fn validate
        @brief
            Validates the data of the serializer.
            Specified field names needs to be a string convertible
            to python dictionary in order to be valid.
        '''

        validated_data = dict()
        try:
            for key, value in data.iteritems():
                if key in self.__fields_to_validate:
                    # check if can be converted to dictionary
                    if ast.literal_eval(value):
                        pass # value is a valid string dictionary
                validated_data[key] = value
        except:
            raise serializers.ValidationError('Invalid data')
        return validated_data

    def create(self, validated_data):
        '''
        '''

        remit_discount = validated_data.get('level_remit_discount')
        online_discount = validated_data.get('level_online_discount')
        validated_data.pop('level_remit_discount', None)
        validated_data.pop('level_online_discount', None)

        level = Level(**validated_data)
        level.save()

        if remit_discount:
            self.__create_update_discount(level.level_remit_discount, remit_discount)
        if online_discount:
            self.__create_update_discount(level.level_online_discount, online_discount)

        level.save()
        return level

    def update(self, instance, validated_data):
        '''
        '''

        remit_discount = validated_data.get('level_remit_discount')
        online_discount = validated_data.get('level_online_discount')
        validated_data.pop('level_remit_discount', None)
        validated_data.pop('level_online_discount', None)

        for key, val in validated_data.iteritems():
            setattr(instance, key, val)
        instance.save()

        if remit_discount:
            self.__create_update_discount(instance.level_remit_discount, remit_discount)
        if online_discount:
            self.__create_update_discount(instance.level_online_discount, online_discount)

        instance.save()
        return instance

    def __create_update_discount(self, instance, discount_details={}):
        '''
        @fn __create_update_discount
        @brief
            Creates or updates discount details then adds the discount to the given level.
        '''

        # clear the relationship for the level discount instance
        instance.clear()

        # process new relationships

        for discount in discount_details:
            # check if every field exists
            vailded = [(key in discount and discount.get(key) != '' ) for key in ['rate', 'check_rate', 'threshold']]

            if False in vailded:
                continue

            # check if discout had id
            if not discount.get('id'):
                # create discount
                discount_inst = instance.create(**discount)
                discount_inst.save()
                continue

            # update existing discount
            to_update = Discount.objects.get(pk=discount.get('id'))

            for key, value in discount.iteritems():
                setattr(to_update, key, value)
            to_update.save()

            # add to level
            instance.add(to_update)
        return

    def to_representation(self, instance):
        '''
        '''

        request = self.context['request']
        ret = super(LevelSerializer, self).to_representation(instance)

        to_display = collections.OrderedDict()
        for key, val in ret.iteritems():
            if key in self.__fields_to_validate:
                val = collections.OrderedDict(ast.literal_eval(val))
            to_display[key] = val
        return to_display