def restore_object(self, attrs, instance=None): if instance: metadata = JsonField.to_json(attrs.get('metadata')) if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) attrs['metadata'] = instance.metadata return super(ProjectSerializer, self).restore_object(attrs, instance) if 'request' in self.context: created_by = self.context['request'].user return Project( name=attrs.get('name'), organization=attrs.get('organization'), created_by=created_by, metadata=attrs.get('metadata'), ) return attrs
def restore_object(self, attrs, instance=None): if instance: metadata = JsonField.to_json(attrs.get('metadata')) owner = attrs.get('organization') if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) attrs['metadata'] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) # clear cache safe_delete('{}{}'.format(PROJ_PERM_CACHE, self.object.pk)) return super(ProjectSerializer, self).restore_object(attrs, instance) if 'request' in self.context: created_by = self.context['request'].user return Project( name=attrs.get('name'), organization=attrs.get('organization'), created_by=created_by, metadata=attrs.get('metadata'), ) return attrs
def restore_object(self, attrs, instance=None): if instance: metadata = JsonField.to_json(attrs.get("metadata")) owner = attrs.get("organization") if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) attrs["metadata"] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) # clear cache safe_delete("{}{}".format(PROJ_PERM_CACHE, self.object.pk)) return super(ProjectSerializer, self).restore_object(attrs, instance) if "request" in self.context: created_by = self.context["request"].user return Project( name=attrs.get("name"), organization=attrs.get("organization"), created_by=created_by, metadata=attrs.get("metadata"), ) return attrs
def update(self, instance, validated_data): metadata = JsonField.to_json(validated_data.get('metadata')) if metadata is None: metadata = dict() owner = validated_data.get('organization') if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) validated_data['metadata'] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) if is_organization(owner.profile): owners_team = get_or_create_organization_owners_team( owner.profile) members_team = get_organization_members_team(owner.profile) OwnerRole.add(owners_team, instance) ReadOnlyRole.add(members_team, instance) # clear cache safe_delete('{}{}'.format(PROJ_PERM_CACHE, instance.pk)) project = super(ProjectSerializer, self)\ .update(instance, validated_data) project.xform_set.exclude(shared=project.shared)\ .update(shared=project.shared, shared_data=project.shared) return instance
def update(self, instance, validated_data): metadata = JsonField.to_json(validated_data.get('metadata')) if metadata is None: metadata = dict() owner = validated_data.get('organization') if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) validated_data['metadata'] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) if is_organization(owner.profile): owners_team = get_organization_owners_team(owner.profile) members_team = get_organization_members_team(owner.profile) OwnerRole.add(owners_team, instance) ReadOnlyRole.add(members_team, instance) # clear cache safe_delete('{}{}'.format(PROJ_PERM_CACHE, instance.pk)) project = super(ProjectSerializer, self)\ .update(instance, validated_data) project.xform_set.exclude(shared=project.shared)\ .update(shared=project.shared, shared_data=project.shared) return instance
class BaseProjectSerializer(serializers.HyperlinkedModelSerializer): projectid = serializers.ReadOnlyField(source='id') url = serializers.HyperlinkedIdentityField(view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField( view_name='user-detail', source='organization', lookup_field='username', queryset=User.objects.exclude( username__iexact=settings.ANONYMOUS_DEFAULT_USERNAME)) created_by = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) starred = serializers.SerializerMethodField() users = serializers.SerializerMethodField() forms = serializers.SerializerMethodField() public = serializers.BooleanField(source='shared') tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField() last_submission_date = serializers.SerializerMethodField() teams = serializers.SerializerMethodField() class Meta: model = Project exclude = ('shared', 'organization', 'user_stars') def get_starred(self, obj): return get_starred(obj, self.context['request']) def get_users(self, obj): owner_query_param_in_request = \ 'request' in self.context and "owner" in self.context['request'].GET return get_users(obj, self.context, owner_query_param_in_request) @check_obj def get_forms(self, obj): forms = cache.get('{}{}'.format(PROJ_BASE_FORMS_CACHE, obj.pk)) if forms: return forms xforms = get_obj_xforms(obj) request = self.context.get('request') serializer = BaseProjectXFormSerializer(xforms, context={'request': request}, many=True) forms = list(serializer.data) cache.set('{}{}'.format(PROJ_BASE_FORMS_CACHE, obj.pk), forms) return forms def get_num_datasets(self, obj): return get_num_datasets(obj) def get_last_submission_date(self, obj): return get_last_submission_date(obj) def get_teams(self, obj): return get_teams(obj)
class DataViewMinimalSerializer(serializers.HyperlinkedModelSerializer): dataviewid = serializers.ReadOnlyField(source='id') name = serializers.CharField(max_length=255) url = serializers.HyperlinkedIdentityField(view_name='dataviews-detail', lookup_field='pk') xform = serializers.HyperlinkedRelatedField(view_name='xform-detail', lookup_field='pk', queryset=XForm.objects.all()) project = serializers.HyperlinkedRelatedField( view_name='project-detail', lookup_field='pk', queryset=Project.objects.all()) columns = JsonField() query = JsonField(required=False) matches_parent = serializers.BooleanField(default=True) class Meta: model = DataView
def validate_metadata(self, value): msg = serializers.ValidationError(_("Invaid value for metadata")) try: json_val = JsonField.to_json(value) except ValueError: raise serializers.ValidationError(msg) else: if json_val is None: raise serializers.ValidationError(msg) return value
def update(self, instance, validated_data): metadata = JsonField.to_json(validated_data.get('metadata')) if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) validated_data['metadata'] = instance.metadata return super(ProjectSerializer, self).update(instance, validated_data)
class BaseProjectSerializer(serializers.HyperlinkedModelSerializer): projectid = serializers.ReadOnlyField(source='id') url = serializers.HyperlinkedIdentityField( view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField( view_name='user-detail', source='organization', lookup_field='username', queryset=User.objects.exclude( username__iexact=settings.ANONYMOUS_DEFAULT_USERNAME ) ) created_by = serializers.HyperlinkedRelatedField( view_name='user-detail', lookup_field='username', read_only=True ) metadata = JsonField(required=False) starred = serializers.SerializerMethodField() users = serializers.SerializerMethodField() forms = serializers.SerializerMethodField() public = serializers.BooleanField(source='shared') tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField() last_submission_date = serializers.SerializerMethodField() teams = serializers.SerializerMethodField() class Meta: model = Project exclude = ('shared', 'organization', 'user_stars') def get_starred(self, obj): return get_starred(obj, self.context['request']) def get_users(self, obj): return get_users(obj, self.context, False) @profile("get_project_forms.prof") @check_obj def get_forms(self, obj): xforms = get_obj_xforms(obj) request = self.context.get('request') serializer = BaseProjectXFormSerializer( xforms, context={'request': request}, many=True ) return list(serializer.data) def get_num_datasets(self, obj): return get_num_datasets(obj) def get_last_submission_date(self, obj): return get_last_submission_date(obj) def get_teams(self, obj): return get_teams(obj)
class InstanceHistorySerializer(serializers.ModelSerializer): json = JsonField() class Meta: model = InstanceHistory fields = ('json', ) def to_representation(self, instance): ret = super(InstanceHistorySerializer, self).to_representation(instance) return ret['json'] if 'json' in ret else ret
def validate_metadata(self, value): # pylint: disable=no-self-use """ Validate metadaata is a valid JSON value. """ msg = serializers.ValidationError(_("Invaid value for metadata")) try: json_val = JsonField.to_json(value) except ValueError: raise serializers.ValidationError(msg) else: if json_val is None: raise serializers.ValidationError(msg) return value
class DataInstanceSerializer(serializers.ModelSerializer): json = JsonField() class Meta: model = Instance fields = ('json', ) def to_representation(self, instance): ret = super(DataInstanceSerializer, self).to_representation(instance) if 'json' in ret: ret = ret['json'] return ret
class DataInstanceSerializer(serializers.ModelSerializer): """ DataInstanceSerializer class - for json field data representation on the Instance (submission) model. """ json = JsonField() class Meta: model = Instance fields = ('json', ) def to_representation(self, instance): ret = super(DataInstanceSerializer, self).to_representation(instance) if 'json' in ret: ret = ret['json'] return ret
class UserProfileSerializer(serializers.Serializer): id = serializers.ReadOnlyField(source='user.id') username = serializers.ReadOnlyField(source='user.username') name = serializers.ReadOnlyField() email = serializers.ReadOnlyField(source='user.email') city = serializers.ReadOnlyField() country = serializers.ReadOnlyField() organization = serializers.ReadOnlyField() website = serializers.ReadOnlyField(source='home_page') twitter = serializers.ReadOnlyField() gravatar = serializers.ReadOnlyField() require_auth = serializers.ReadOnlyField() metadata = JsonField(read_only=True) class Meta: model = UserProfile fields = ( 'id', 'username', 'name', 'email', 'city', 'country', 'organization', 'website', 'twitter', 'gravatar', 'require_auth', 'metadata', ) def to_representation(self, obj): """ Serialize objects -> primitives. """ ret = super(UserProfileSerializer, self).to_representation(obj) request = self.context['request'] \ if 'request' in self.context else None if 'email' in ret and request is None or request.user \ and not request.user.has_perm(CAN_VIEW_PROFILE, obj): del ret['email'] return ret
class TableauDataSerializer(serializers.ModelSerializer): """ TableauDataSerializer class - cleans out instance fields. """ json = JsonField() class Meta: model = Instance fields = ('json', ) def to_representation(self, instance): ret = super(TableauDataSerializer, self).to_representation(instance) if 'json' in ret: ret = ret['json'] # Remove metadata fields from the instance remove_metadata_fields(ret) return ret
def restore_object(self, attrs, instance=None): if instance: metadata = JsonField.to_json(attrs.get('metadata')) if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) attrs['metadata'] = instance.metadata return super(ProjectSerializer, self).restore_object( attrs, instance) if 'request' in self.context: created_by = self.context['request'].user return Project( name=attrs.get('name'), organization=attrs.get('organization'), created_by=created_by, metadata=attrs.get('metadata'),) return attrs
class UserProfileSerializer(serializers.HyperlinkedModelSerializer): is_org = serializers.SerializerMethodField('is_organization') username = serializers.WritableField(source='user.username') email = serializers.WritableField(source='user.email') website = serializers.WritableField(source='home_page', required=False) gravatar = serializers.Field(source='gravatar') password = serializers.WritableField( source='user.password', widget=widgets.PasswordInput(), required=False) user = serializers.HyperlinkedRelatedField( view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(source='metadata', required=False) id = serializers.Field(source='user.id') joined_on = serializers.Field(source='user.date_joined') class Meta: model = UserProfile fields = ('id', 'is_org', 'url', 'username', 'name', 'password', 'email', 'city', 'country', 'organization', 'website', 'twitter', 'gravatar', 'require_auth', 'user', 'metadata', 'joined_on') lookup_field = 'user' def is_organization(self, obj): return is_organization(obj) def to_native(self, obj): """ Serialize objects -> primitives. """ ret = super(UserProfileSerializer, self).to_native(obj) if 'password' in ret: del ret['password'] request = self.context['request'] \ if 'request' in self.context else None if 'email' in ret and request is None or request.user \ and not request.user.has_perm(CAN_VIEW_PROFILE, obj): del ret['email'] return ret def restore_object(self, attrs, instance=None): params = copy.deepcopy(attrs) username = attrs.get('user.username', None) password = attrs.get('user.password', None) name = attrs.get('name', None) email = attrs.get('user.email', None) if username: params['username'] = username if email: params['email'] = email if password: params.update({'password1': password, 'password2': password}) if instance: form = UserProfileForm(params, instance=instance) # form.is_valid affects instance object for partial updates [PATCH] # so only use it for full updates [PUT], i.e shallow copy effect if not self.partial and form.is_valid(): instance = form.save() # get user if email: instance.user.email = form.cleaned_data['email'] if name: first_name, last_name = _get_first_last_names(name) instance.user.first_name = first_name instance.user.last_name = last_name if email or name: instance.user.save() return super( UserProfileSerializer, self).restore_object(attrs, instance) form = RegistrationFormUserProfile(params) # does not require captcha form.REGISTRATION_REQUIRE_CAPTCHA = False if form.is_valid(): site = Site.objects.get(pk=settings.SITE_ID) new_user = RegistrationProfile.objects.create_inactive_user( username=username, password=password, email=email, site=site, send_email=True) new_user.is_active = True new_user.save() created_by = self.context['request'].user created_by = None if created_by.is_anonymous() else created_by profile = UserProfile( user=new_user, name=attrs.get('name', u''), created_by=created_by, city=attrs.get('city', u''), country=attrs.get('country', u''), organization=attrs.get('organization', u''), home_page=attrs.get('home_page', u''), twitter=attrs.get('twitter', u'')) return profile else: self.errors.update(form.errors) return attrs def validate_username(self, attrs, source): request_method = self.context['request'].method if request_method == 'PATCH' and source not in attrs: return attrs current_username = self.object.user.username if self.object else None username = attrs[source].lower() is_edit = current_username is not None and current_username != username form = RegistrationFormUserProfile if username in form._reserved_usernames and is_edit: raise ValidationError( u"%s is a reserved name, please choose another" % username) elif not form.legal_usernames_re.search(username): raise ValidationError( u'username may only contain alpha-numeric characters and ' u'underscores') try: User.objects.get(username=username) except User.DoesNotExist: attrs[source] = username else: if not current_username or is_edit: raise ValidationError(u'%s already exists' % username) return attrs
class UserProfileSerializer(serializers.HyperlinkedModelSerializer): is_org = serializers.SerializerMethodField('is_organization') username = serializers.WritableField(source='user.username') name = serializers.CharField(required=False) first_name = serializers.WritableField(source='user.first_name', required=False) last_name = serializers.WritableField(source='user.last_name', required=False) email = serializers.EmailField(source='user.email') website = serializers.WritableField(source='home_page', required=False) twitter = serializers.WritableField(required=False) gravatar = serializers.Field(source='gravatar') password = serializers.WritableField(source='user.password', widget=widgets.PasswordInput(), required=False) user = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(source='metadata', required=False) id = serializers.Field(source='user.id') joined_on = serializers.Field(source='user.date_joined') class Meta: model = UserProfile fields = ('id', 'is_org', 'url', 'username', 'password', 'first_name', 'last_name', 'email', 'city', 'country', 'organization', 'website', 'twitter', 'gravatar', 'require_auth', 'user', 'metadata', 'joined_on', 'name') lookup_field = 'user' def is_organization(self, obj): if obj: is_org = cache.get('{}{}'.format(IS_ORG, obj.pk)) if is_org: return is_org is_org = is_organization(obj) cache.set('{}{}'.format(IS_ORG, obj.pk), is_org) return is_org def to_native(self, obj): """ Serialize objects -> primitives. """ ret = super(UserProfileSerializer, self).to_native(obj) if 'password' in ret: del ret['password'] request = self.context['request'] \ if 'request' in self.context else None if 'email' in ret and request is None or request.user \ and not request.user.has_perm(CAN_VIEW_PROFILE, obj): del ret['email'] if 'first_name' in ret: ret['name'] = u' '.join( [ret.get('first_name'), ret.get('last_name', "")]) return ret def restore_object(self, attrs, instance=None): params = copy.deepcopy(attrs) username = attrs.get('user.username', None) password = attrs.get('user.password', None) first_name = attrs.get('user.first_name', None) last_name = attrs.get('user.last_name', None) email = attrs.get('user.email', None) name = attrs.get('name', None) if username: params['username'] = username if email: params['email'] = email if password: params.update({'password1': password, 'password2': password}) if first_name: params['first_name'] = first_name if last_name: params['last_name'] = last_name # For backward compatibility, Users who still use only name if name: first_name, last_name = \ _get_first_last_names(name) params['first_name'] = first_name params['last_name'] = last_name if instance: form = UserProfileForm(params, instance=instance) # form.is_valid affects instance object for partial updates [PATCH] # so only use it for full updates [PUT], i.e shallow copy effect if not self.partial and form.is_valid(): instance = form.save() # get user if email: instance.user.email = email if first_name: instance.user.first_name = first_name if last_name: instance.user.last_name = last_name (email or first_name or last_name) and instance.user.save() return super(UserProfileSerializer, self).restore_object(attrs, instance) form = RegistrationFormUserProfile(params) # does not require captcha form.REGISTRATION_REQUIRE_CAPTCHA = False if form.is_valid(): site = Site.objects.get(pk=settings.SITE_ID) new_user = RegistrationProfile.objects.create_inactive_user( username=username, password=password, email=email, site=site, send_email=settings.SEND_EMAIL_ACTIVATION_API) new_user.is_active = True new_user.first_name = first_name new_user.last_name = last_name new_user.save() created_by = self.context['request'].user created_by = None if created_by.is_anonymous() else created_by profile = UserProfile(user=new_user, name=first_name, created_by=created_by, city=attrs.get('city', u''), country=attrs.get('country', u''), organization=attrs.get('organization', u''), home_page=attrs.get('home_page', u''), twitter=attrs.get('twitter', u'')) return profile else: self.errors.update(form.errors) return attrs def validate_username(self, attrs, source): request_method = self.context['request'].method if request_method == 'PATCH' and source not in attrs: return attrs current_username = self.object.user.username if self.object else None username = attrs[source].lower() is_edit = current_username is not None and current_username != username form = RegistrationFormUserProfile if username in form._reserved_usernames and is_edit: raise ValidationError( u"%s is a reserved name, please choose another" % username) elif not form.legal_usernames_re.search(username): raise ValidationError( u'username may only contain alpha-numeric characters and ' u'underscores') try: User.objects.get(username=username) except User.DoesNotExist: attrs[source] = username else: if not current_username or is_edit: raise ValidationError(u'%s already exists' % username) return attrs def validate_name(self, attrs, source): if (attrs.get('name') is None) and\ (attrs.get('user.first_name') is None): raise ValidationError( u"Either name or first_name should be provided") return attrs def validate_email(self, attrs, source): request_method = self.context['request'].method if request_method == 'PUT' and source in attrs: return attrs if User.objects.filter(email=attrs.get('user.email')).exists(): raise ValidationError("This email address is already in use. ") return attrs def validate_twitter(self, attrs, source): if isinstance(attrs.get('twitter'), basestring): if attrs.get('twitter'): match = re.search(r"^[A-Za-z0-9_]{1,15}$", attrs.get('twitter')) if not match: raise ValidationError("Invalid twitter username") else: attrs['twitter'] = '' return attrs
class ProjectSerializer(serializers.HyperlinkedModelSerializer): projectid = serializers.Field(source='id') url = serializers.HyperlinkedIdentityField(view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField(view_name='user-detail', source='organization', lookup_field='username') created_by = serializers.HyperlinkedRelatedField(view_name='user-detail', source='created_by', lookup_field='username', read_only=True) metadata = JsonField(source='metadata', required=False) starred = serializers.SerializerMethodField('is_starred_project') users = serializers.SerializerMethodField('get_project_permissions') forms = serializers.SerializerMethodField('get_project_forms') public = BooleanField(source='shared', widget=widgets.CheckboxInput()) tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField('get_num_datasets') last_submission_date = serializers.SerializerMethodField( 'get_last_submission_date') class Meta: model = Project exclude = ('organization', 'user_stars') def restore_object(self, attrs, instance=None): if instance: metadata = JsonField.to_json(attrs.get('metadata')) owner = attrs.get('organization') if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) attrs['metadata'] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) # clear cache safe_delete('{}{}'.format(PROJ_PERM_CACHE, self.object.pk)) return super(ProjectSerializer, self).restore_object(attrs, instance) if 'request' in self.context: created_by = self.context['request'].user return Project( name=attrs.get('name'), organization=attrs.get('organization'), created_by=created_by, metadata=attrs.get('metadata'), ) return attrs def save_object(self, obj, **kwargs): super(ProjectSerializer, self).save_object(obj, **kwargs) obj.xform_set.exclude(shared=obj.shared)\ .update(shared=obj.shared, shared_data=obj.shared) def get_project_permissions(self, obj): if obj: users = cache.get('{}{}'.format(PROJ_PERM_CACHE, obj.pk)) if users: return users user = get_object_users_with_permissions(obj) cache.set('{}{}'.format(PROJ_PERM_CACHE, obj.pk), user) return user return [] @check_obj def get_project_forms(self, obj): if obj: forms = cache.get('{}{}'.format(PROJ_FORMS_CACHE, obj.pk)) if forms: return forms xforms_details = obj.xform_set.values('pk', 'title') forms = [{ 'name': form['title'], 'id': form['pk'] } for form in xforms_details] cache.set('{}{}'.format(PROJ_FORMS_CACHE, obj.pk), forms) return forms return [] @check_obj def get_num_datasets(self, obj): """Return the number of datasets attached to the object. :param obj: The project to find datasets for. """ if obj: count = cache.get('{}{}'.format(PROJ_NUM_DATASET_CACHE, obj.pk)) if count: return count count = obj.xform_set.count() cache.set('{}{}'.format(PROJ_NUM_DATASET_CACHE, obj.pk), count) return count return None @check_obj def get_last_submission_date(self, obj): """Return the most recent submission date to any of the projects datasets. :param obj: The project to find the last submission date for. """ if obj: last_submission = cache.get('{}{}'.format(PROJ_SUB_DATE_CACHE, obj.pk)) if last_submission: return last_submission xform_ids = obj.xform_set.values_list('pk', flat=True) last_submission = Instance.objects.\ order_by('-date_created').\ filter(xform_id__in=xform_ids).values_list('date_created', flat=True) cache.set('{}{}'.format(PROJ_SUB_DATE_CACHE, obj.pk), last_submission and last_submission[0]) return last_submission and last_submission[0] return None def is_starred_project(self, obj): request = self.context['request'] user = request.user user_stars = obj.user_stars.all() if user in user_stars: return True return False
class ProjectSerializer(serializers.HyperlinkedModelSerializer): """ ProjectSerializer class - creates and updates a project. """ projectid = serializers.ReadOnlyField(source='id') url = serializers.HyperlinkedIdentityField(view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField( view_name='user-detail', source='organization', lookup_field='username', queryset=User.objects.exclude( username__iexact=settings.ANONYMOUS_DEFAULT_USERNAME)) created_by = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) starred = serializers.SerializerMethodField() users = serializers.SerializerMethodField() forms = serializers.SerializerMethodField() public = serializers.BooleanField(source='shared') tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField() last_submission_date = serializers.SerializerMethodField() teams = serializers.SerializerMethodField() data_views = serializers.SerializerMethodField() class Meta: model = Project exclude = ('shared', 'user_stars', 'deleted_by') extra_kwargs = { 'organization': { 'write_only': True, 'required': False, 'lookup_field': 'username' } } def validate(self, attrs): name = attrs.get('name') organization = attrs.get('organization') if not self.instance and organization: project_w_same_name = Project.objects.filter( name__iexact=name, organization=organization) if project_w_same_name: raise serializers.ValidationError( {'name': _(u"Project {} already exists.".format(name))}) else: organization = organization or self.instance.organization request = self.context['request'] try: has_perm = can_add_project_to_profile(request.user, organization) except OrganizationProfile.DoesNotExist: # most likely when transfering a project to an individual account # A user does not require permissions to the user's account forms. has_perm = False if not has_perm: raise serializers.ValidationError({ 'owner': _("You do not have permission to create a project " "in the organization %(organization)s." % {'organization': organization}) }) return attrs def validate_public(self, value): # pylint: disable=no-self-use """ Validate the public field """ if not settings.ALLOW_PUBLIC_DATASETS and value: raise serializers.ValidationError( _('Public projects are currently disabled.')) return value def validate_metadata(self, value): # pylint: disable=no-self-use """ Validate metadaata is a valid JSON value. """ msg = serializers.ValidationError(_("Invaid value for metadata")) try: json_val = JsonField.to_json(value) except ValueError: raise serializers.ValidationError(msg) else: if json_val is None: raise serializers.ValidationError(msg) return value def update(self, instance, validated_data): metadata = JsonField.to_json(validated_data.get('metadata')) if metadata is None: metadata = dict() owner = validated_data.get('organization') if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) validated_data['metadata'] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) if is_organization(owner.profile): owners_team = get_or_create_organization_owners_team( owner.profile) members_team = get_organization_members_team(owner.profile) OwnerRole.add(owners_team, instance) ReadOnlyRole.add(members_team, instance) # clear cache safe_delete('{}{}'.format(PROJ_PERM_CACHE, instance.pk)) project = super(ProjectSerializer, self)\ .update(instance, validated_data) project.xform_set.exclude(shared=project.shared)\ .update(shared=project.shared, shared_data=project.shared) return instance def create(self, validated_data): metadata = validated_data.get('metadata', dict()) if metadata is None: metadata = dict() created_by = self.context['request'].user try: project = Project.objects.create( # pylint: disable=E1101 name=validated_data.get('name'), organization=validated_data.get('organization'), created_by=created_by, shared=validated_data.get('shared', False), metadata=metadata) except IntegrityError: raise serializers.ValidationError( "The fields name, organization must make a unique set.") else: project.xform_set.exclude(shared=project.shared)\ .update(shared=project.shared, shared_data=project.shared) request = self.context.get('request') serializer = ProjectSerializer(project, context={'request': request}) response = serializer.data cache.set(f'{PROJ_OWNER_CACHE}{project.pk}', response) return project def get_users(self, obj): # pylint: disable=no-self-use """ Return a list of users and organizations that have access to the project. """ return get_users(obj, self.context) @check_obj def get_forms(self, obj): # pylint: disable=no-self-use """ Return list of xforms in the project. """ forms = cache.get('{}{}'.format(PROJ_FORMS_CACHE, obj.pk)) if forms: return forms xforms = get_project_xforms(obj) request = self.context.get('request') serializer = ProjectXFormSerializer(xforms, context={'request': request}, many=True) forms = list(serializer.data) cache.set('{}{}'.format(PROJ_FORMS_CACHE, obj.pk), forms) return forms def get_num_datasets(self, obj): # pylint: disable=no-self-use """ Return the number of datasets attached to the project. """ return get_num_datasets(obj) def get_last_submission_date(self, obj): # pylint: disable=no-self-use """ Return the most recent submission date to any of the projects datasets. """ return get_last_submission_date(obj) def get_starred(self, obj): # pylint: disable=no-self-use """ Return True if request user has starred this project. """ return is_starred(obj, self.context['request']) def get_teams(self, obj): # pylint: disable=no-self-use """ Return the teams with access to the project. """ return get_teams(obj) @check_obj def get_data_views(self, obj): """ Return a list of filtered datasets. """ data_views = cache.get('{}{}'.format(PROJECT_LINKED_DATAVIEWS, obj.pk)) if data_views: return data_views data_views_obj = obj.dataview_prefetch if \ hasattr(obj, 'dataview_prefetch') else\ obj.dataview_set.filter(deleted_at__isnull=True) serializer = DataViewMinimalSerializer(data_views_obj, many=True, context=self.context) data_views = list(serializer.data) cache.set('{}{}'.format(PROJECT_LINKED_DATAVIEWS, obj.pk), data_views) return data_views
class BaseProjectSerializer(serializers.HyperlinkedModelSerializer): """ BaseProjectSerializer class. """ projectid = serializers.ReadOnlyField(source='id') url = serializers.HyperlinkedIdentityField(view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField( view_name='user-detail', source='organization', lookup_field='username', queryset=User.objects.exclude( username__iexact=settings.ANONYMOUS_DEFAULT_USERNAME)) created_by = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) starred = serializers.SerializerMethodField() users = serializers.SerializerMethodField() forms = serializers.SerializerMethodField() public = serializers.BooleanField(source='shared') tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField() last_submission_date = serializers.SerializerMethodField() teams = serializers.SerializerMethodField() class Meta: model = Project fields = [ 'url', 'projectid', 'owner', 'created_by', 'metadata', 'starred', 'users', 'forms', 'public', 'tags', 'num_datasets', 'last_submission_date', 'teams', 'name', 'date_created', 'date_modified', 'deleted_at' ] def get_starred(self, obj): """ Return True if request user has starred this project. """ return is_starred(obj, self.context['request']) def get_users(self, obj): """ Return a list of users and organizations that have access to the project. """ owner_query_param_in_request = 'request' in self.context and\ "owner" in self.context['request'].GET return get_users(obj, self.context, owner_query_param_in_request) @check_obj def get_forms(self, obj): """ Return list of xforms in the project. """ forms = cache.get('{}{}'.format(PROJ_BASE_FORMS_CACHE, obj.pk)) if forms: return forms xforms = get_project_xforms(obj) request = self.context.get('request') serializer = BaseProjectXFormSerializer(xforms, context={'request': request}, many=True) forms = list(serializer.data) cache.set('{}{}'.format(PROJ_BASE_FORMS_CACHE, obj.pk), forms) return forms def get_num_datasets(self, obj): # pylint: disable=no-self-use """ Return the number of datasets attached to the project. """ return get_num_datasets(obj) def get_last_submission_date(self, obj): # pylint: disable=no-self-use """ Return the most recent submission date to any of the projects datasets. """ return get_last_submission_date(obj) def get_teams(self, obj): # pylint: disable=no-self-use """ Return the teams with access to the project. """ return get_teams(obj)
class OrganizationSerializer(serializers.HyperlinkedModelSerializer): """ Organization profile serializer """ url = serializers.HyperlinkedIdentityField( view_name='organizationprofile-detail', lookup_field='user') org = serializers.CharField(source='user.username', max_length=30) user = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) creator = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) users = serializers.SerializerMethodField() metadata = JsonField(required=False) name = serializers.CharField(max_length=30) class Meta: model = OrganizationProfile exclude = ('created_by', 'is_organization', 'organization') owner_only_fields = ('metadata', ) def __init__(self, *args, **kwargs): super(OrganizationSerializer, self).__init__(*args, **kwargs) if self.instance and hasattr(self.Meta, 'owner_only_fields'): request = self.context.get('request') is_permitted = (request and request.user and request.user.has_perm( 'api.view_organizationprofile', self.instance)) if isinstance(self.instance, QuerySet) or not is_permitted or \ not request: for field in getattr(self.Meta, 'owner_only_fields'): self.fields.pop(field) def update(self, instance, validated_data): # update the user model if 'name' in validated_data: first_name, last_name = \ _get_first_last_names(validated_data.get('name')) instance.user.first_name = first_name instance.user.last_name = last_name instance.user.save() return super(OrganizationSerializer, self).update(instance, validated_data) def create(self, validated_data): org = validated_data.get('user') if org: org = org.get('username') org_name = validated_data.get('name', None) creator = None if 'request' in self.context: creator = self.context['request'].user validated_data['organization'] = org_name profile = tools.create_organization_object(org, creator, validated_data) profile.save() return profile def validate_org(self, value): # pylint: disable=no-self-use """ Validate organization name. """ org = value.lower() if isinstance(value, basestring) else value if org in RegistrationFormUserProfile.RESERVED_USERNAMES: raise serializers.ValidationError( _(u"%s is a reserved name, please choose another" % org)) elif not RegistrationFormUserProfile.legal_usernames_re.search(org): raise serializers.ValidationError( _(u"Organization may only contain alpha-numeric characters and " u"underscores")) try: User.objects.get(username=org) except User.DoesNotExist: return org raise serializers.ValidationError( _(u"Organization %s already exists." % org)) def get_users(self, obj): # pylint: disable=no-self-use """ Return organization members. """ members = get_organization_members(obj) if obj else [] return [{ 'user': u.username, 'role': get_role_in_org(u, obj), 'first_name': u.first_name, 'last_name': u.last_name, 'gravatar': u.profile.gravatar, } for u in members]
class OrganizationSerializer(serializers.HyperlinkedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name='organizationprofile-detail', lookup_field='user') org = serializers.CharField(source='user.username', max_length=30) user = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) creator = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) users = serializers.SerializerMethodField() metadata = JsonField(required=False) name = serializers.CharField(max_length=30) class Meta: model = OrganizationProfile exclude = ('created_by', 'is_organization', 'organization') def update(self, instance, validated_data): # update the user model if 'name' in validated_data: first_name, last_name = \ _get_first_last_names(validated_data.get('name')) instance.user.first_name = first_name instance.user.last_name = last_name instance.user.save() return super(OrganizationSerializer, self).update(instance, validated_data) def create(self, validated_data): org = validated_data.get('user') if org: org = org.get('username') org_name = validated_data.get('name', None) creator = None if 'request' in self.context: creator = self.context['request'].user validated_data['organization'] = org_name profile = tools.create_organization_object(org, creator, validated_data) profile.save() return profile def validate_org(self, value): org = value.lower() if isinstance(value, basestring) else value if org in RegistrationFormUserProfile._reserved_usernames: raise serializers.ValidationError( _(u"%s is a reserved name, please choose another" % org)) elif not RegistrationFormUserProfile.legal_usernames_re.search(org): raise serializers.ValidationError( _(u"Organization may only contain alpha-numeric characters and " u"underscores")) try: User.objects.get(username=org) except User.DoesNotExist: return org raise serializers.ValidationError( _(u"Organization %s already exists." % org)) def get_users(self, obj): members = get_organization_members(obj) if obj else [] return [{ 'user': u.username, 'role': get_role_in_org(u, obj), 'first_name': u.first_name, 'last_name': u.last_name, 'gravatar': u.profile.gravatar, 'metadata': u.profile.metadata, } for u in members]
class WidgetSerializer(serializers.HyperlinkedModelSerializer): id = serializers.ReadOnlyField() url = serializers.HyperlinkedIdentityField( view_name='widgets-detail', lookup_field='pk' ) content_object = GenericRelatedField() key = serializers.CharField(read_only=True) data = serializers.SerializerMethodField() order = serializers.IntegerField(required=False) metadata = JsonField(required=False) class Meta: model = Widget fields = ('id', 'url', 'key', 'title', 'description', 'widget_type', 'order', 'view_type', 'column', 'group_by', 'content_object', 'data', 'aggregation', 'metadata') def get_data(self, obj): # Get the request obj request = self.context.get('request') # Check if data flag is present data_flag = request.GET.get('data') key = request.GET.get('key') if (str2bool(data_flag) or key) and obj: data = Widget.query_data(obj) else: data = [] return data def validate(self, attrs): column = attrs.get('column') # Get the form if 'content_object' in attrs: content_object = attrs.get('content_object') if isinstance(content_object, XForm): xform = content_object elif isinstance(content_object, DataView): # must be a dataview xform = content_object.xform try: # Check if column exists in xform get_field_from_field_xpath(column, xform) except Http404: raise serializers.ValidationError({ 'column': (u"'{}' not in the form.".format(column)) }) order = attrs.get('order') # Set the order if order: self.instance.to(order) return attrs def validate_content_object(self, value): request = self.context.get('request') users = get_users_with_perms( value.project, attach_perms=False, with_group_users=False ) profile = value.project.organization.profile # Shared or an admin in the organization if request.user not in users and not\ is_organization(profile) and not\ OwnerRole.user_has_role(request.user, profile): raise serializers.ValidationError(_( u"You don't have permission to the Project." )) return value
class ProjectSerializer(serializers.HyperlinkedModelSerializer): projectid = serializers.Field(source='id') url = serializers.HyperlinkedIdentityField(view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField(view_name='user-detail', source='organization', lookup_field='username') created_by = serializers.HyperlinkedRelatedField(view_name='user-detail', source='created_by', lookup_field='username', read_only=True) metadata = JsonField(source='metadata', required=False) starred = serializers.SerializerMethodField('is_starred_project') users = serializers.SerializerMethodField('get_project_permissions') forms = serializers.SerializerMethodField('get_project_forms') public = BooleanField(source='shared', widget=widgets.CheckboxInput()) tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField('get_num_datasets') last_submission_date = serializers.SerializerMethodField( 'get_last_submission_date') class Meta: model = Project exclude = ('organization', 'user_stars') def restore_object(self, attrs, instance=None): if instance: metadata = JsonField.to_json(attrs.get('metadata')) if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) attrs['metadata'] = instance.metadata return super(ProjectSerializer, self).restore_object(attrs, instance) if 'request' in self.context: created_by = self.context['request'].user return Project( name=attrs.get('name'), organization=attrs.get('organization'), created_by=created_by, metadata=attrs.get('metadata'), ) return attrs def get_project_permissions(self, obj): return get_object_users_with_permissions(obj) @check_obj def get_project_forms(self, obj): xforms_details = obj.projectxform_set.values('xform__pk', 'xform__title') return [{ 'name': form['xform__title'], 'id': form['xform__pk'] } for form in xforms_details] @check_obj def get_num_datasets(self, obj): """Return the number of datasets attached to the object. :param obj: The project to find datasets for. """ return obj.projectxform_set.count() @check_obj def get_last_submission_date(self, obj): """Return the most recent submission date to any of the projects datasets. :param obj: The project to find the last submission date for. """ xform_ids = obj.projectxform_set.values_list('xform', flat=True) last_submission = Instance.objects.\ order_by('-date_created').\ filter(xform_id__in=xform_ids).values_list('date_created', flat=True) return last_submission and last_submission[0] def is_starred_project(self, obj): request = self.context['request'] user = request.user user_stars = obj.user_stars.all() if user in user_stars: return True return False
class ProjectSerializer(serializers.HyperlinkedModelSerializer): projectid = serializers.ReadOnlyField(source='id') url = serializers.HyperlinkedIdentityField(view_name='project-detail', lookup_field='pk') owner = serializers.HyperlinkedRelatedField( view_name='user-detail', source='organization', lookup_field='username', queryset=User.objects.exclude( username__iexact=settings.ANONYMOUS_DEFAULT_USERNAME)) created_by = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) starred = serializers.SerializerMethodField() users = serializers.SerializerMethodField() forms = serializers.SerializerMethodField() public = serializers.BooleanField(source='shared') tags = TagListSerializer(read_only=True) num_datasets = serializers.SerializerMethodField() last_submission_date = serializers.SerializerMethodField() teams = serializers.SerializerMethodField() data_views = serializers.SerializerMethodField() class Meta: model = Project exclude = ('shared', 'organization', 'user_stars') def validate(self, attrs): name = attrs.get('name') organization = attrs.get('organization') if not self.instance and \ Project.objects.filter(name__iexact=name, organization=organization): raise serializers.ValidationError( {'name': _(u"Project {} already exists.".format(name))}) return attrs def update(self, instance, validated_data): metadata = JsonField.to_json(validated_data.get('metadata')) owner = validated_data.get('organization') if self.partial and metadata: if not isinstance(instance.metadata, dict): instance.metadata = {} instance.metadata.update(metadata) validated_data['metadata'] = instance.metadata if self.partial and owner: # give the new owner permissions set_owners_permission(owner, instance) if is_organization(owner.profile): owners_team = get_organization_owners_team(owner.profile) members_team = get_organization_members_team(owner.profile) OwnerRole.add(owners_team, instance) ReadOnlyRole.add(members_team, instance) # clear cache safe_delete('{}{}'.format(PROJ_PERM_CACHE, instance.pk)) project = super(ProjectSerializer, self)\ .update(instance, validated_data) project.xform_set.exclude(shared=project.shared)\ .update(shared=project.shared, shared_data=project.shared) return instance def create(self, validated_data): created_by = self.context['request'].user project = Project.objects.create( name=validated_data.get('name'), organization=validated_data.get('organization'), created_by=created_by, shared=validated_data.get('shared', False), metadata=validated_data.get('metadata', dict())) project.xform_set.exclude(shared=project.shared)\ .update(shared=project.shared, shared_data=project.shared) return project def get_users(self, obj): return get_users(obj, self.context) @check_obj def get_forms(self, obj): forms = cache.get('{}{}'.format(PROJ_FORMS_CACHE, obj.pk)) if forms: return forms xforms = get_obj_xforms(obj) request = self.context.get('request') serializer = ProjectXFormSerializer(xforms, context={'request': request}, many=True) forms = list(serializer.data) cache.set('{}{}'.format(PROJ_FORMS_CACHE, obj.pk), forms) return forms def get_num_datasets(self, obj): return get_num_datasets(obj) def get_last_submission_date(self, obj): return get_last_submission_date(obj) def get_starred(self, obj): return get_starred(obj, self.context['request']) def get_teams(self, obj): return get_teams(obj) @check_obj def get_data_views(self, obj): data_views = cache.get('{}{}'.format(PROJECT_LINKED_DATAVIEWS, obj.pk)) if data_views: return data_views data_views_obj = obj.dataview_prefetch if \ hasattr(obj, 'dataview_prefetch') else obj.dataview_set.all() serializer = DataViewMinimalSerializer(data_views_obj, many=True, context=self.context) data_views = list(serializer.data) cache.set('{}{}'.format(PROJECT_LINKED_DATAVIEWS, obj.pk), data_views) return data_views
class UserProfileSerializer(serializers.HyperlinkedModelSerializer): is_org = serializers.SerializerMethodField('is_organization') username = serializers.CharField(source='user.username') # Added this field so it's required in the API in a clean way # and triggers validatino name = serializers.CharField(required=True) email = serializers.CharField(source='user.email') website = serializers.CharField(source='home_page', required=False) gravatar = serializers.ReadOnlyField() password = serializers.CharField( source='user.password', style={'input_type': 'password'}, required=False) user = serializers.HyperlinkedRelatedField( view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) id = serializers.ReadOnlyField(source='user.id') class Meta: model = UserProfile fields = ('id', 'is_org', 'url', 'username', 'name', 'password', 'email', 'city', 'country', 'organization', 'website', 'twitter', 'gravatar', 'require_auth', 'user', 'metadata') extra_kwargs = { 'url': {'lookup_field': 'user'} } def is_organization(self, obj): return is_organization(obj) def to_representation(self, obj): """ Serialize objects -> primitives. """ ret = super(UserProfileSerializer, self).to_representation(obj) if 'password' in ret: del ret['password'] request = self.context['request'] \ if 'request' in self.context else None if 'email' in ret and request is None or request.user \ and not request.user.has_perm(CAN_VIEW_PROFILE, obj): del ret['email'] return ret # Those 2 validations methods where embeded in the same code as # the create() method but DRF3 needs it to be separted now. # It uses to fill merge the form.errors and self._errors, # but you can't do it anymore so we validate the username, catch # the validation exception and reraise it in an exception DRF will # understand def validate_name(self, value): try: RegistrationFormUserProfile.validate_username(value) except FormValidationError as e: raise serializers.ValidationError(list(e)) return value def validate_username(self, value): return self.validate_name(value) def create(self, validated_data): user = validated_data.get('user', {}) username = user.get('username', None) password = user.get('password', None) email = user.get('email', None) site = Site.objects.get(pk=settings.SITE_ID) new_user = RegistrationProfile.objects.create_inactive_user( site, username=username, password=password, email=email, send_email=True) new_user.is_active = True new_user.save() created_by = self.context['request'].user created_by = None if created_by.is_anonymous() else created_by profile = UserProfile.objects.create( user=new_user, name=validated_data.get('name', u''), created_by=created_by, city=validated_data.get('city', u''), country=validated_data.get('country', u''), organization=validated_data.get('organization', u''), # home_page=validated_data.get('home_page', u''), # twitter=validated_data.get('twitter', u'') ) return profile def update(self, instance, validated_data): params = copy.deepcopy(validated_data) username = validated_data.get('user.username', None) password = validated_data.get('user.password', None) name = validated_data.get('name', None) email = validated_data.get('user.email', None) if username: params['username'] = username if email: params['email'] = email if password: params.update({'password1': password, 'password2': password}) form = UserProfileForm(params, instance=instance) # form.is_valid affects instance object for partial updates [PATCH] # so only use it for full updates [PUT], i.e shallow copy effect if not self.partial and form.is_valid(): instance = form.save() # get user if email: instance.user.email = form.cleaned_data['email'] if name: first_name, last_name = _get_first_last_names(name) instance.user.first_name = first_name instance.user.last_name = last_name if email or name: instance.user.save() return super(UserProfileSerializer, self).update(instance, validated_data)
class UserProfileSerializer(serializers.HyperlinkedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='userprofile-detail', lookup_field='user') is_org = serializers.SerializerMethodField() username = serializers.CharField(source='user.username', min_length=3, max_length=30) name = serializers.CharField(required=False, allow_blank=True) first_name = serializers.CharField(source='user.first_name', required=False, allow_blank=True, max_length=30) last_name = serializers.CharField(source='user.last_name', required=False, allow_blank=True, max_length=30) email = serializers.EmailField(source='user.email') website = serializers.CharField(source='home_page', required=False, allow_blank=True) twitter = serializers.CharField(required=False, allow_blank=True) gravatar = serializers.ReadOnlyField() password = serializers.CharField(source='user.password', allow_blank=True, required=False) user = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) id = serializers.ReadOnlyField(source='user.id') joined_on = serializers.ReadOnlyField(source='user.date_joined') class Meta: model = UserProfile fields = ('id', 'is_org', 'url', 'username', 'password', 'first_name', 'last_name', 'email', 'city', 'country', 'organization', 'website', 'twitter', 'gravatar', 'require_auth', 'user', 'metadata', 'joined_on', 'name') def get_is_org(self, obj): if obj: is_org = cache.get('{}{}'.format(IS_ORG, obj.pk)) if is_org: return is_org is_org = is_organization(obj) cache.set('{}{}'.format(IS_ORG, obj.pk), is_org) return is_org def to_representation(self, obj): """ Serialize objects -> primitives. """ ret = super(UserProfileSerializer, self).to_representation(obj) if 'password' in ret: del ret['password'] request = self.context['request'] \ if 'request' in self.context else None if 'email' in ret and request is None or request.user \ and not request.user.has_perm(CAN_VIEW_PROFILE, obj): del ret['email'] if 'first_name' in ret: ret['name'] = u' '.join( [ret.get('first_name'), ret.get('last_name', "")]) ret['name'] = ret['name'].strip() return ret def _get_params(self, attrs): params = copy.deepcopy(attrs) name = params.get('name', None) user = params.pop('user', None) if user: username = user.pop('username', None) password = user.pop('password', None) first_name = user.pop('first_name', None) last_name = user.pop('last_name', None) email = user.pop('email', None) if username: params['username'] = username if email: params['email'] = email if password: params.update({'password1': password, 'password2': password}) if first_name: params['first_name'] = first_name params['last_name'] = last_name or '' # For backward compatibility, Users who still use only name if name: first_name, last_name = \ _get_first_last_names(name) params['first_name'] = first_name params['last_name'] = last_name return params def update(self, instance, validated_data): params = validated_data password = params.get("password1") email = params.get('email') # Check password if email is being updated if email and not password: raise serializers.ValidationError( _(u'Your password is required when updating your email ' u'address.')) if password and not instance.user.check_password(password): raise serializers.ValidationError(_(u'Invalid password')) # get user instance.user.email = email or instance.user.email instance.user.first_name = params.get('first_name', instance.user.first_name) instance.user.last_name = params.get('last_name', instance.user.last_name) instance.user.username = params.get('username', instance.user.username) instance.user.save() if password: # force django-digest to regenerate its stored partial digests update_partial_digests(instance.user, password) return super(UserProfileSerializer, self).update(instance, params) def create(self, validated_data): params = validated_data site = Site.objects.get(pk=settings.SITE_ID) new_user = RegistrationProfile.objects.create_inactive_user( username=params.get('username'), password=params.get('password1'), email=params.get('email'), site=site, send_email=settings.SEND_EMAIL_ACTIVATION_API) new_user.is_active = True new_user.first_name = params.get('first_name') new_user.last_name = params.get('last_name') new_user.save() created_by = self.context['request'].user created_by = None if created_by.is_anonymous() else created_by profile = UserProfile(user=new_user, name=params.get('first_name'), created_by=created_by, city=params.get('city', u''), country=params.get('country', u''), organization=params.get('organization', u''), home_page=params.get('home_page', u''), twitter=params.get('twitter', u'')) profile.save() return profile def validate_username(self, value): username = value.lower() if isinstance(value, basestring) else value if username in RESERVED_NAMES: raise serializers.ValidationError( _(u"%s is a reserved name, please choose another" % username)) elif not LEGAL_USERNAMES_REGEX.search(username): raise serializers.ValidationError( _(u"username may only contain alpha-numeric characters and " u"underscores")) elif len(username) < 3: raise serializers.ValidationError( _(u"Username must have 3 or more characters")) users = User.objects.filter(username=username) if self.instance: users = users.exclude(pk=self.instance.user.pk) if users.exists(): raise serializers.ValidationError( _(u"%s already exists" % username)) return username def validate_email(self, value): users = User.objects.filter(email=value) if self.instance: users = users.exclude(pk=self.instance.user.pk) if users.exists(): raise serializers.ValidationError( _(u"This email address is already in use. ")) return value def validate_twitter(self, value): if isinstance(value, basestring) and len(value) > 0: match = re.search(r"^[A-Za-z0-9_]{1,15}$", value) if not match: raise serializers.ValidationError( _(u"Invalid twitter username {}".format(value))) return value def validate(self, attrs): params = self._get_params(attrs) if not self.instance and params.get('name') is None and \ params.get('first_name') is None: raise serializers.ValidationError( {'name': _(u"Either name or first_name should be provided")}) return params
class UserProfileSerializer(serializers.HyperlinkedModelSerializer): """ UserProfile serializer. """ url = serializers.HyperlinkedIdentityField(view_name='userprofile-detail', lookup_field='user') is_org = serializers.SerializerMethodField() username = serializers.CharField(source='user.username', min_length=3, max_length=30) name = serializers.CharField(required=False, allow_blank=True) first_name = serializers.CharField(source='user.first_name', required=False, allow_blank=True, max_length=30) last_name = serializers.CharField(source='user.last_name', required=False, allow_blank=True, max_length=30) email = serializers.EmailField(source='user.email') website = serializers.CharField(source='home_page', required=False, allow_blank=True) twitter = serializers.CharField(required=False, allow_blank=True) gravatar = serializers.ReadOnlyField() password = serializers.CharField(source='user.password', allow_blank=True, required=False) user = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) metadata = JsonField(required=False) id = serializers.ReadOnlyField(source='user.id') # pylint: disable=C0103 joined_on = serializers.ReadOnlyField(source='user.date_joined') class Meta: model = UserProfile fields = ('id', 'is_org', 'url', 'username', 'password', 'first_name', 'last_name', 'email', 'city', 'country', 'organization', 'website', 'twitter', 'gravatar', 'require_auth', 'user', 'metadata', 'joined_on', 'name') owner_only_fields = ('metadata', ) def __init__(self, *args, **kwargs): super(UserProfileSerializer, self).__init__(*args, **kwargs) if self.instance and hasattr(self.Meta, 'owner_only_fields'): request = self.context.get('request') if isinstance(self.instance, QuerySet) or \ (request and request.user != self.instance.user) or \ not request: for field in getattr(self.Meta, 'owner_only_fields'): self.fields.pop(field) def get_is_org(self, obj): # pylint: disable=no-self-use """ Returns True if it is an organization profile. """ if obj: is_org = cache.get('{}{}'.format(IS_ORG, obj.pk)) if is_org: return is_org is_org = is_organization(obj) cache.set('{}{}'.format(IS_ORG, obj.pk), is_org) return is_org def to_representation(self, instance): """ Serialize objects -> primitives. """ ret = super(UserProfileSerializer, self).to_representation(instance) if 'password' in ret: del ret['password'] request = self.context['request'] \ if 'request' in self.context else None if 'email' in ret and request is None or request.user \ and not request.user.has_perm(CAN_VIEW_PROFILE, instance): del ret['email'] if 'first_name' in ret: ret['name'] = u' '.join( [ret.get('first_name'), ret.get('last_name', "")]) ret['name'] = ret['name'].strip() return ret def update(self, instance, validated_data): params = validated_data password = params.get("password1") email = params.get('email') # Check password if email is being updated if email and not password: raise serializers.ValidationError( _(u'Your password is required when updating your email ' u'address.')) if password and not instance.user.check_password(password): raise serializers.ValidationError(_(u'Invalid password')) # get user instance.user.email = email or instance.user.email instance.user.first_name = params.get('first_name', instance.user.first_name) instance.user.last_name = params.get('last_name', instance.user.last_name) instance.user.username = params.get('username', instance.user.username) instance.user.save() if email: instance.metadata.update({"is_email_verified": False}) instance.save() request = self.context.get('request') redirect_url = params.get('redirect_url') _send_verification_email(redirect_url, instance.user, request) if password: # force django-digest to regenerate its stored partial digests update_partial_digests(instance.user, password) return super(UserProfileSerializer, self).update(instance, params) def create(self, validated_data): params = validated_data request = self.context.get('request') metadata = {} site = Site.objects.get(pk=settings.SITE_ID) try: new_user = RegistrationProfile.objects.create_inactive_user( username=params.get('username'), password=params.get('password1'), email=params.get('email'), site=site, send_email=settings.SEND_EMAIL_ACTIVATION_API) except IntegrityError: raise serializers.ValidationError( _(u"User account {} already exists".format( params.get('username')))) new_user.is_active = True new_user.first_name = params.get('first_name') new_user.last_name = params.get('last_name') new_user.save() if getattr(settings, 'ENABLE_EMAIL_VERIFICATION', False): redirect_url = params.get('redirect_url') _send_verification_email(redirect_url, new_user, request) created_by = request.user created_by = None if created_by.is_anonymous else created_by metadata['last_password_edit'] = timezone.now().isoformat() profile = UserProfile(user=new_user, name=params.get('first_name'), created_by=created_by, city=params.get('city', u''), country=params.get('country', u''), organization=params.get('organization', u''), home_page=params.get('home_page', u''), twitter=params.get('twitter', u''), metadata=metadata) profile.save() # cache user profile object cache.set(f'{USER_PROFILE_PREFIX}{new_user.username}', profile) return profile def validate_username(self, value): """ Validate username. """ username = value.lower() if isinstance(value, basestring) else value if username in RESERVED_NAMES: raise serializers.ValidationError( _(u"%s is a reserved name, please choose another" % username)) elif not LEGAL_USERNAMES_REGEX.search(username): raise serializers.ValidationError( _(u"username may only contain alpha-numeric characters and " u"underscores")) elif len(username) < 3: raise serializers.ValidationError( _(u"Username must have 3 or more characters")) users = User.objects.filter(username=username) if self.instance: users = users.exclude(pk=self.instance.user.pk) if users.exists(): raise serializers.ValidationError( _(u"%s already exists" % username)) return username def validate_email(self, value): """ Checks if user with the same email has already been registered. """ users = User.objects.filter(email=value) if self.instance: users = users.exclude(pk=self.instance.user.pk) if users.exists(): raise serializers.ValidationError( _(u"This email address is already in use. ")) return value def validate_twitter(self, value): # pylint: disable=no-self-use """ Checks if the twitter handle is valid. """ if isinstance(value, basestring) and value: match = re.search(r"^[A-Za-z0-9_]{1,15}$", value) if not match: raise serializers.ValidationError( _(u"Invalid twitter username {}".format(value))) return value def validate(self, attrs): params = _get_registration_params(attrs) if not self.instance and params.get('name') is None and \ params.get('first_name') is None: raise serializers.ValidationError( {'name': _(u"Either name or first_name should be provided")}) return params
class DataViewSerializer(serializers.HyperlinkedModelSerializer): dataviewid = serializers.ReadOnlyField(source='id') name = serializers.CharField(max_length=255) url = serializers.HyperlinkedIdentityField(view_name='dataviews-detail', lookup_field='pk') xform = serializers.HyperlinkedRelatedField(view_name='xform-detail', lookup_field='pk', queryset=XForm.objects.all()) project = serializers.HyperlinkedRelatedField( view_name='project-detail', lookup_field='pk', queryset=Project.objects.all()) columns = JsonField() query = JsonField(required=False) count = serializers.SerializerMethodField() instances_with_geopoints = serializers.SerializerMethodField() matches_parent = serializers.BooleanField(default=True) last_submission_time = serializers.SerializerMethodField() has_hxl_support = serializers.SerializerMethodField() class Meta: model = DataView def create(self, validated_data): validated_data = match_columns(validated_data) return super(DataViewSerializer, self).create(validated_data) def update(self, instance, validated_data): validated_data = match_columns(validated_data, instance) return super(DataViewSerializer, self).update(instance, validated_data) def validate_query(self, value): if value: for q in value: if 'column' not in q: raise serializers.ValidationError( _(u"`column` not set in query")) if 'filter' not in q: raise serializers.ValidationError( _(u"`filter` not set in query")) if 'value' not in q: raise serializers.ValidationError( _(u"`value` not set in query")) comp = q.get('filter') if comp not in SUPPORTED_FILTERS: raise serializers.ValidationError( _(u"Filter not supported")) return value def validate_columns(self, value): if not isinstance(value, list): raise serializers.ValidationError( _(u"`columns` should be a list of columns")) return value def validate(self, attrs): if 'xform' in attrs and attrs.get('xform'): xform = attrs.get('xform') know_dates = [ e.name for e in xform.get_survey_elements_of_type('date') ] know_dates.append('_submission_time') for q in attrs.get('query', []): column = q.get('column') value = q.get('value') if column in know_dates and not \ (validate_datetime(value) or validate_date(value)): raise serializers.ValidationError( _(u"Date value in {} should be yyyy-mm-ddThh:m:s or " u"yyyy-mm-dd".format(column))) return super(DataViewSerializer, self).validate(attrs) def get_count(self, obj): if obj: count_dict = cache.get('{}{}'.format(DATAVIEW_COUNT, obj.xform.pk)) if count_dict: if obj.pk in count_dict: return count_dict.get(obj.pk) else: count_dict = {} count_rows = DataView.query_data(obj, count=True) if 'error' in count_rows: raise ParseError(count_rows.get('error')) count_row = count_rows[0] if 'count' in count_row: count = count_row.get('count') count_dict.setdefault(obj.pk, count) cache.set('{}{}'.format(DATAVIEW_COUNT, obj.xform.pk), count_dict) return count return None def get_last_submission_time(self, obj): if obj: last_submission_time = cache.get('{}{}'.format( DATAVIEW_LAST_SUBMISSION_TIME, obj.xform.pk)) if last_submission_time: return last_submission_time last_submission_rows = DataView.query_data( obj, last_submission_time=True) # data is returned as list if 'error' in last_submission_rows: raise ParseError(last_submission_rows.get('error')) if len(last_submission_rows): last_submission_row = last_submission_rows[0] if LAST_SUBMISSION_TIME in last_submission_row: last_submission_time = last_submission_row.get( LAST_SUBMISSION_TIME) cache.set( '{}{}'.format(DATAVIEW_LAST_SUBMISSION_TIME, obj.xform.pk), last_submission_time) return last_submission_time return None def get_instances_with_geopoints(self, obj): if obj: check_geo = obj.has_geo_columnn_n_data() if obj.instances_with_geopoints != check_geo: obj.instances_with_geopoints = check_geo obj.save() return obj.instances_with_geopoints return False def get_has_hxl_support(self, obj): columns_with_hxl = get_columns_with_hxl( obj.xform.survey.get('children')) return include_hxl_row(obj.columns, columns_with_hxl.keys())
class OrganizationSerializer(serializers.HyperlinkedModelSerializer): org = serializers.WritableField(source='user.username') user = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) creator = serializers.HyperlinkedRelatedField(view_name='user-detail', lookup_field='username', read_only=True) users = serializers.SerializerMethodField('get_org_permissions') metadata = JsonField(source='metadata', required=False) class Meta: model = OrganizationProfile lookup_field = 'user' exclude = ('created_by', 'is_organization', 'organization') def restore_object(self, attrs, instance=None): if instance: return super(OrganizationSerializer, self)\ .restore_object(attrs, instance) org = attrs.get('user.username', None) org_name = attrs.get('name', None) org_exists = False creator = None try: User.objects.get(username=org) except User.DoesNotExist: pass else: self.errors['org'] = u'Organization %s already exists.' % org org_exists = True if 'request' in self.context: creator = self.context['request'].user if org and org_name and creator and not org_exists: attrs['organization'] = org_name orgprofile = tools.create_organization_object(org, creator, attrs) return orgprofile if not org: self.errors['org'] = u'org is required!' if not org_name: self.errors['name'] = u'name is required!' return attrs def validate_org(self, attrs, source): org = attrs[source].lower() if org in RegistrationFormUserProfile._reserved_usernames: raise ValidationError( u"%s is a reserved name, please choose another" % org) elif not RegistrationFormUserProfile.legal_usernames_re.search(org): raise ValidationError( u'organization may only contain alpha-numeric characters and ' u'underscores') try: User.objects.get(username=org) except User.DoesNotExist: attrs[source] = org return attrs raise ValidationError(u'%s already exists' % org) def get_org_permissions(self, obj): members = get_organization_members(obj) if obj else [] return [{ 'user': u.username, 'role': get_role_in_org(u, obj), 'first_name': u.first_name, 'last_name': u.last_name, 'gravatar': u.profile.gravatar, 'metadata': u.profile.metadata, } for u in members]