class CategorySerializer(serializers.ModelSerializer): id = serializers.CharField(source='slug', read_only=True) title = serializers.CharField() description = serializers.CharField() image = ImageSerializer(required=False) image_logo = ImageSerializer(required=False) contents = CategoryContentSerializer(many=True, read_only=True) class Meta: model = Category fields = ('id', 'title', 'description', 'image', 'image_logo', 'contents')
class OrganizationSerializer(NoCommitMixin, ModelSerializer): description = serializers.CharField(required=False, allow_blank=True) slug = serializers.SlugField(allow_null=True, required=False) name = serializers.CharField(required=True) website = serializers.CharField(allow_blank=True, required=False) logo = ImageSerializer(required=False, allow_null=True) permissions = ResourcePermissionField('organization_detail', view_args=('pk',)) errors = ValidationErrorsField() required = RequiredErrorsField() included_serializers = { 'owner': 'bluebottle.initiatives.serializers.MemberSerializer', } class Meta(object): model = Organization fields = ( 'id', 'name', 'slug', 'description', 'website', 'owner', 'logo', 'required', 'errors', ) meta_fields = ['created', 'updated', 'errors', 'required', 'permissions'] class JSONAPIMeta(object): resource_name = 'organizations' included_resources = ['owner', ]
class BaseFundraiserSerializer(serializers.ModelSerializer): """ Serializer to view/create fundraisers """ owner = UserProfileSerializer(read_only=True) project = serializers.SlugRelatedField(slug_field='slug', queryset=Project.objects) image = ImageSerializer() video_html = OEmbedField(source='video_url', maxwidth='560', maxheight='315') amount = MoneySerializer() amount_donated = MoneySerializer(read_only=True) validators = [ProjectCurrencyValidator()] class Meta: model = Fundraiser fields = ('id', 'owner', 'project', 'title', 'description', 'image', 'created', 'video_html', 'video_url', 'amount', 'amount_donated', 'deadline') def validate(self, data): if not data.get( 'deadline') or data['deadline'] > data['project'].deadline: raise serializers.ValidationError({ 'deadline': [_("Fundraiser deadline exceeds project deadline.")] }) return data
class ProjectWallpostPhotoSerializer(serializers.ModelSerializer): photo = ImageSerializer(read_only=True) created = serializers.DateTimeField(source='mediawallpost.created', read_only=True) class Meta: model = MediaWallpostPhoto fields = ('id', 'photo', 'created', 'results_page')
class ProjectImageSerializer(serializers.ModelSerializer): """ Members that wrote a wallpost """ image = ImageSerializer(source='file') class Meta(object): model = ProjectImage fields = ('id', 'image')
class ProjectImageSerializer(serializers.ModelSerializer): """ Members that wrote a wallpost """ image = ImageSerializer(source='file') project = serializers.SlugRelatedField(slug_field='slug', queryset=Project.objects) class Meta: model = ProjectImage fields = ('id', 'image', 'project')
class ProjectCreateTemplateSerializer(serializers.ModelSerializer): default_amount_asked = MoneySerializer(min_amount=5.0) image = ImageSerializer() default_image = ImageSerializer() default_story = serializers.CharField(source='default_description') class Meta: model = ProjectCreateTemplate fields = ( 'name', 'sub_name', 'image', 'description', 'default_amount_asked', 'default_title', 'default_pitch', 'default_story', 'default_image', )
class CategoryContentSerializer(serializers.ModelSerializer): title = serializers.CharField(required=True) description = serializers.CharField(required=False) image = ImageSerializer(required=False) video_url = serializers.URLField(required=False) link_text = serializers.CharField(required=False) link_url = serializers.URLField(required=False) sequence = serializers.IntegerField(read_only=True) class Meta: model = CategoryContent fields = ('title', 'description', 'image', 'video_url', 'link_text', 'link_url', 'sequence')
class PictureItemSerializer(ItemSerializer): image = ImageSerializer() item_type = 'image' class Meta(object): model = PictureItem fields = ( 'id', 'align', 'image', 'type', )
class ImageTextRoundItemSerializer(ItemSerializer): image = ImageSerializer() item_type = 'image-text-round' class Meta(object): model = ImageTextItem fields = ( 'id', 'text', 'image', 'type', )
class ResultPageSerializer(serializers.ModelSerializer): blocks = BlockSerializer(source='content.contentitems.all.translated', many=True) image = ImageSerializer() share_image = SorlImageField( '1200x600', source='image', crop='center', ) class Meta(object): model = ResultPage fields = ('id', 'title', 'slug', 'start_date', 'image', 'share_image', 'end_date', 'description', 'blocks')
class ImageTextItemSerializer(ItemSerializer): image = ImageSerializer() item_type = 'image-text' class Meta(object): model = ImageTextItem fields = ( 'id', 'text', 'image', 'ratio', 'align', 'type', )
class ProjectPreviewSerializer(ProjectSerializer): categories = serializers.SlugRelatedField(many=True, read_only=True, slug_field='slug') image = ImageSerializer(required=False) owner = UserProfileSerializer() skills = serializers.SerializerMethodField() project_location = ProjectLocationSerializer(read_only=True, source='projectlocation') theme = ProjectThemeSerializer() project_location = ProjectLocationSerializer(read_only=True, source='projectlocation') def get_skills(self, obj): return set(task.skill.id for task in obj.task_set.all() if task.skill) class Meta: model = Project fields = ('id', 'allow_overfunding', 'amount_asked', 'amount_donated', 'amount_extra', 'amount_needed', 'amount_cancelled', 'categories', 'celebrate_results', 'country', 'deadline', 'full_task_count', 'image', 'is_campaign', 'is_funding', 'latitude', 'location', 'project_location', 'longitude', 'open_task_count', 'owner', 'people_needed', 'people_registered', 'pitch', 'place', 'project_type', 'realized_task_count', 'skills', 'status', 'task_count', 'theme', 'title', 'vote_count', 'voting_deadline', )
class UserProfileSerializer(PrivateProfileMixin, serializers.ModelSerializer): """ Serializer for a member's public profile. """ url = serializers.HyperlinkedIdentityField(view_name='user-profile-detail', lookup_field='pk') picture = ImageSerializer(required=False) date_joined = serializers.DateTimeField(read_only=True) full_name = serializers.CharField(source='get_full_name', read_only=True) short_name = serializers.CharField(source='get_short_name', read_only=True) primary_language = serializers.CharField(required=False, default=properties.LANGUAGE_CODE) location = serializers.PrimaryKeyRelatedField(required=False, allow_null=True, queryset=Location.objects) avatar = SorlImageField('133x133', source='picture', crop='center', required=False) skill_ids = serializers.PrimaryKeyRelatedField(many=True, source='skills', required=False, queryset=Skill.objects) favourite_theme_ids = serializers.PrimaryKeyRelatedField( many=True, source='favourite_themes', queryset=ProjectTheme.objects) project_count = serializers.ReadOnlyField() donation_count = serializers.ReadOnlyField() fundraiser_count = serializers.ReadOnlyField() task_count = serializers.ReadOnlyField() time_spent = serializers.ReadOnlyField() tasks_performed = serializers.ReadOnlyField() partner_organization = OrganizationPreviewSerializer(allow_null=True, read_only=True, required=False) is_active = serializers.BooleanField(read_only=True) class Meta: model = BB_USER_MODEL fields = ( 'id', 'url', 'full_name', 'short_name', 'initials', 'picture', 'primary_language', 'about_me', 'location', 'avatar', 'project_count', 'donation_count', 'date_joined', 'fundraiser_count', 'task_count', 'time_spent', 'is_active', 'tasks_performed', 'website', 'twitter', 'facebook', 'skypename', 'skill_ids', 'favourite_theme_ids', 'partner_organization', )
class OrganizationPreviewSerializer(serializers.ModelSerializer): description = serializers.CharField(required=False, allow_blank=True) slug = serializers.SlugField(allow_null=True, required=False) name = serializers.CharField(required=True) website = URLField(allow_blank=True, required=False) logo = ImageSerializer(allow_null=True, required=False) members = serializers.SlugRelatedField( many=True, read_only=True, slug_field='full_name', source='partner_organization_members') projects = serializers.SlugRelatedField(many=True, read_only=True, slug_field='title') class Meta: model = Organization fields = ('id', 'name', 'slug', 'website', 'logo', 'members', 'projects', 'description')
class LocationSerializer(serializers.ModelSerializer): latitude = serializers.DecimalField(source='position.latitude', required=False, max_digits=10, decimal_places=3) longitude = serializers.DecimalField(source='position.longitude', required=False, max_digits=10, decimal_places=3) image = ImageSerializer(required=False) static_map_url = StaticMapsField(source='position') class Meta(object): model = Location fields = ('id', 'name', 'description', 'image', 'latitude', 'longitude', 'static_map_url') class JSONAPIMeta(object): resource_name = 'locations'
class OrganizationSerializer(serializers.ModelSerializer): description = serializers.CharField(required=False, allow_blank=True) slug = serializers.SlugField(allow_null=True, required=False) name = serializers.CharField(required=True) website = URLField(allow_blank=True, required=False) email = serializers.EmailField(allow_blank=True, required=False) contacts = serializers.SerializerMethodField() logo = ImageSerializer(allow_null=True, required=False) members = serializers.SlugRelatedField( many=True, read_only=True, slug_field='full_name', source='partner_organization_members') projects = serializers.SlugRelatedField(many=True, read_only=True, slug_field='title') def get_contacts(self, obj): owner = self.context['request'].user try: contacts = OrganizationContact.objects.filter( owner=owner, organization=obj).order_by('-created') except TypeError: contacts = [] return OrganizationContactSerializer( contacts, many=True, required=True).to_representation(contacts) class Meta: model = Organization fields = ('id', 'name', 'slug', 'address_line1', 'address_line2', 'city', 'state', 'country', 'postal_code', 'phone_number', 'website', 'email', 'contacts', 'partner_organizations', 'created', 'updated', 'logo', 'members', 'projects', 'description')
class ProjectImageSerializer(serializers.ModelSerializer): photo = ImageSerializer(source='image') class Meta: model = Project fields = ('id', 'photo', 'title', 'slug')
class ProjectSerializer(serializers.ModelSerializer): id = serializers.CharField(source='slug', read_only=True) addons = ProjectAddOnSerializer(many=True) amount_asked = MoneySerializer() amount_donated = MoneySerializer() amount_extra = MoneySerializer() amount_needed = MoneySerializer() amount_cancelled = MoneySerializer(read_only=True) budget_lines = BasicProjectBudgetLineSerializer(many=True, source='projectbudgetline_set', read_only=True) categories = serializers.SlugRelatedField(slug_field='slug', many=True, queryset=Category.objects) country = ProjectCountrySerializer() currencies = serializers.JSONField(read_only=True) has_voted = serializers.SerializerMethodField() image = ImageSerializer(required=False) is_funding = serializers.ReadOnlyField() location = serializers.PrimaryKeyRelatedField(required=False, queryset=Location.objects) organization = OrganizationPreviewSerializer(read_only=True) owner = UserProfileSerializer() people_needed = serializers.ReadOnlyField() people_registered = serializers.ReadOnlyField() permissions = ResourcePermissionField('project_detail', view_args=('slug',)) promoter = UserProfileSerializer(read_only=True) related_permissions = ProjectPermissionsSerializer(read_only=True) story = SafeField() supporter_count = serializers.IntegerField() task_manager = UserProfileSerializer(read_only=True) video_html = OEmbedField(source='video_url', maxwidth='560', maxheight='315') vote_count = serializers.IntegerField() latitude = serializers.FloatField(source='projectlocation.latitude') longitude = serializers.FloatField(source='projectlocation.longitude') project_location = ProjectLocationSerializer(read_only=True, source='projectlocation') supporters_export_url = PrivateFileSerializer( 'project-supporters-export', url_args=('slug', ), permission=CanExportSupportersPermission, read_only=True ) def __init__(self, *args, **kwargs): super(ProjectSerializer, self).__init__(*args, **kwargs) def get_has_voted(self, obj): return Vote.has_voted(self.context['request'].user, obj) class Meta: model = Project fields = ('id', 'addons', 'allow_overfunding', 'amount_asked', 'amount_donated', 'amount_extra', 'amount_needed', 'amount_cancelled', 'budget_lines', 'categories', 'celebrate_results', 'country', 'created', 'currencies', 'deadline', 'description', 'full_task_count', 'has_voted', 'image', 'is_funding', 'language', 'latitude', 'location', 'longitude', 'project_location', 'open_task_count', 'organization', 'owner', 'people_needed', 'people_registered', 'permissions', 'pitch', 'place', 'project_type', 'promoter', 'realized_task_count', 'related_permissions', 'status', 'status', 'story', 'supporter_count', 'task_count', 'task_manager', 'theme', 'title', 'video_html', 'video_url', 'vote_count', 'voting_deadline', 'supporters_export_url', )
class ManageProjectSerializer(serializers.ModelSerializer): id = serializers.CharField(source='slug', read_only=True) account_bic = serializers.CharField(required=False, allow_blank=True, allow_null=True) account_details = serializers.CharField(required=False, allow_blank=True, allow_null=True) amount_asked = MoneySerializer(required=False, allow_null=True) amount_donated = MoneySerializer(read_only=True) amount_needed = MoneySerializer(read_only=True) amount_cancelled = MoneySerializer(read_only=True) budget_lines = ProjectBudgetLineSerializer(many=True, source='projectbudgetline_set', read_only=True) currencies = serializers.JSONField(read_only=True) categories = serializers.SlugRelatedField(many=True, read_only=True, slug_field='slug') documents = ProjectDocumentSerializer(many=True, read_only=True) editable = serializers.BooleanField(read_only=True) image = ImageSerializer(required=False, allow_null=True) is_funding = serializers.ReadOnlyField() location = serializers.PrimaryKeyRelatedField(required=False, allow_null=True, queryset=Location.objects) people_needed = serializers.IntegerField(read_only=True) people_registered = serializers.IntegerField(read_only=True) pitch = serializers.CharField(required=False, allow_null=True) promoter = UserProfileSerializer(read_only=True) slug = serializers.CharField(read_only=True) status = serializers.PrimaryKeyRelatedField(required=False, allow_null=True, queryset=ProjectPhase.objects) story = SafeField(required=False, allow_blank=True) task_manager = UserProfileSerializer(read_only=True) owner = UserProfileSerializer(read_only=True) tasks = ManageTaskSerializer(many=True, source='task_set', read_only=True) url = serializers.HyperlinkedIdentityField(view_name='project_manage_detail', lookup_field='slug') video_html = OEmbedField(source='video_url', maxwidth='560', maxheight='315') viewable = serializers.BooleanField(read_only=True) permissions = ResourcePermissionField('project_manage_detail', view_args=('slug', )) related_permissions = ProjectPermissionsSerializer(read_only=True) latitude = serializers.FloatField(source='projectlocation.latitude', required=False, allow_null=True) longitude = serializers.FloatField(source='projectlocation.longitude', required=False, allow_null=True) project_location = ProjectLocationSerializer(read_only=True, source='projectlocation') editable_fields = ('pitch', 'story', 'image', 'video_url', 'projectlocation') @staticmethod def validate_account_number(value): if value: country_code = value[:2] digits_regex = re.compile('\d{2}') check_digits = value[2:4] # Only try iban validaton when the field matches start of # iban format as the field can also contain non-iban # account numbers. # Expecting something like: NL18xxxxxxxxxx iban_validator = IBANValidator() if country_code in iban_validator.validation_countries.keys() and \ digits_regex.match(check_digits): iban_validator(value) return value def validate_status(self, value): if not value: value = ProjectPhase.objects.order_by('sequence').all()[0] else: """ Don't let the owner set a status with a sequence number higher than 2 They can set 1: plan-new or 2: plan-submitted TODO: This needs work. Maybe we could use a FSM for the project status transitions, e.g.: https://pypi.python.org/pypi/django-fsm/1.2.0 TODO: what to do if the expected status (plan-submitted) is not found?! Hard fail? """ submit_status = ProjectPhase.objects.get(slug='plan-submitted') new_status = ProjectPhase.objects.get(slug='plan-new') needs_work_status = ProjectPhase.objects.get( slug='plan-needs-work') proposed_status = value current_status = None # Get the current status or the first if not found try: current_status = Project.objects.get(slug=self.initial_data['slug']).status except (Project.DoesNotExist, KeyError): current_status = ProjectPhase.objects.order_by( 'sequence').all()[0] if current_status and proposed_status: """ These are possible combinations of current v. proposed status which are permitted: 1) the current status is the same as the proposed status 2) the current is new or needs work and the proposed is submitted """ if proposed_status == current_status: return value if proposed_status != submit_status or current_status not in [new_status, needs_work_status]: raise serializers.ValidationError(_("You can not change the project state.")) return value def validate(self, data): if self.instance and self.instance.status.slug in ('campaign', 'voting'): # When project is running, only a subset of the fields canb be changed for field, value in data.items(): current = getattr(self.instance, field) if field not in self.editable_fields: try: # If we check a many to many field, make convert both sides to a set current = set(current.all()) value = set(value) except (AttributeError, TypeError): # normal field: do nothing pass if value != current: raise serializers.ValidationError( _('Not allowed to edit {} when project is running').format(field) ) self.instance.campaign_edited = timezone.now() return data def update(self, instance, validated_data): if 'projectlocation' in validated_data: location = validated_data.pop('projectlocation') for field, value in location.items(): setattr(instance.projectlocation, field, value) instance.projectlocation.save() return super(ManageProjectSerializer, self).update(instance, validated_data) def create(self, validated_data): location_data = None if 'projectlocation' in validated_data: location_data = validated_data.pop('projectlocation') instance = super(ManageProjectSerializer, self).create(validated_data) if location_data: for field, value in location_data.items(): setattr(instance.projectlocation, field, value) instance.projectlocation.save() return instance class Meta: model = Project fields = ('id', 'account_bank_country', 'account_details', 'account_bic', 'account_holder_address', 'account_holder_city', 'account_holder_country', 'account_holder_name', 'account_holder_postal_code', 'account_number', 'amount_asked', 'amount_donated', 'amount_needed', 'amount_cancelled', 'budget_lines', 'categories', 'country', 'created', 'currencies', 'deadline', 'description', 'documents', 'editable', 'image', 'is_funding', 'language', 'latitude', 'location', 'longitude', 'project_location', 'organization', 'people_needed', 'people_registered', 'pitch', 'place', 'project_type', 'promoter', 'slug', 'status', 'story', 'task_manager', 'owner', 'tasks', 'theme', 'title', 'url', 'video_html', 'video_url', 'permissions', 'related_permissions', 'viewable',)
def field_to_native(self, obj, field_name): """ Get the parts of the meta dict """ # set defaults value = { "title": None, "fb_title": None, "tweet": None, "description": None, "image": None, "keywords": None, "url": None, } # get the meta title from object callable or object property if self.title: title = self._get_callable(obj, self.title) if title is None: title = self._get_field(obj, self.title) value["title"] = title # try to get the facebook title if self.fb_title is not None: fb_title = self._get_callable(obj, self.fb_title) if fb_title is None: fb_title = self._get_field(obj, self.fb_title) value["fb_title"] = fb_title elif self.title: value["fb_title"] = value["title"] if self.tweet is not None: tweet = self._get_callable(obj, self.tweet) if tweet is None: tweet = self._get_field(obj, self.tweet) value["tweet"] = tweet elif self.title: value["tweet"] = "{URL}" # get the meta description from object callable or object property if self.description: description = self._get_callable(obj, self.description) if description is None: description = self._get_field(obj, self.description) description = truncatechars(description, 200) value["description"] = description # keywords: either from object callable or property, if property, # check if we are referring to taggit tags. if self.keywords: keywords = self._get_callable(obj, self.keywords) if keywords is None: # Get the keywords keywords = self._get_field(obj, self.keywords) # usually tags as keywords if isinstance(keywords, _TaggableManager): keywords = [tag.name.lower() for tag in keywords.all()] else: # try to split the keywords try: keywords = keywords.lower().split() except AttributeError: keywords = "" value["keywords"] = ", ".join(keywords) else: value["keywords"] = keywords # special case with images, use the ImageSerializer to get cropped formats if self.image_source: """ Sometimes, direct urls can be returned, and then we don't want to serialize the 'image'. It's also possible that only an image is returned without is_url (e.g. directly from model attribute). """ image_source = self._get_callable(obj, self.image_source) if image_source is None: image, is_url = self._get_field(obj, self.image_source), False else: try: image, is_url = image_source[0], image_source[1] except TypeError: # no indexing, so not a tupple that was returned image, is_url = image_source, False if is_url: # the callable returned a direct url, instead of a serializable image value["image"] = image else: serializer = ImageSerializer() serializer.context = self.context images = serializer.to_native(image) if images: # always take the full image for facebook, they consume it and # resize/store the images themselve value["image"] = images.get("full", None) if self.url: url = self._get_callable(obj, self.url) if url is None: url = self._get_field(obj, self.url) value["url"] = url return self.to_native(value)