class CommentSerializer(JSONAPISerializer): filterable_fields = frozenset( ['deleted', 'date_created', 'date_modified', 'target']) id = IDField(source='_id', read_only=True) type = TypeField() content = AuthorizedCharField(source='get_content') target = TargetField(link_type='related', meta={'type': 'get_target_type'}) user = RelationshipField(related_view='users:user-detail', related_view_kwargs={'user_id': '<user._id>'}) node = RelationshipField(related_view='nodes:node-detail', related_view_kwargs={'node_id': '<node._id>'}) replies = RelationshipField(self_view='comments:comment-replies', self_view_kwargs={'comment_id': '<pk>'}) reports = RelationshipField(related_view='comments:comment-reports', related_view_kwargs={'comment_id': '<pk>'}) date_created = ser.DateTimeField(read_only=True) date_modified = ser.DateTimeField(read_only=True) modified = ser.BooleanField(read_only=True, default=False) deleted = ser.BooleanField(read_only=True, source='is_deleted', default=False) # LinksField.to_representation adds link to "self" links = LinksField({}) class Meta: type_ = 'comments' def update(self, comment, validated_data): assert isinstance(comment, Comment), 'comment must be a Comment' auth = Auth(self.context['request'].user) if validated_data: if 'get_content' in validated_data: comment.edit(validated_data['get_content'], auth=auth, save=True) if validated_data.get('is_deleted', None) is True: comment.delete(auth, save=True) elif comment.is_deleted: comment.undelete(auth, save=True) return comment def get_target_type(self, obj): if isinstance(obj, Node): return 'nodes' elif isinstance(obj, Comment): return 'comments' else: raise InvalidModelValueError(source={ 'pointer': '/data/relationships/target/links/related/meta/type' }, detail='Invalid comment target type.')
class CommentSerializer(JSONAPISerializer): filterable_fields = frozenset( ['deleted', 'date_created', 'date_modified', 'page', 'target']) id = IDField(source='_id', read_only=True) type = TypeField() content = AuthorizedCharField(source='get_content', required=True) page = ser.CharField(read_only=True) target = TargetField(link_type='related', meta={'type': 'get_target_type'}) user = RelationshipField(related_view='users:user-detail', related_view_kwargs={'user_id': '<user._id>'}) reports = RelationshipField(related_view='comments:comment-reports', related_view_kwargs={'comment_id': '<pk>'}) date_created = DateByVersion(read_only=True) date_modified = DateByVersion(read_only=True) modified = ser.BooleanField(read_only=True, default=False) deleted = ser.BooleanField(read_only=True, source='is_deleted', default=False) is_abuse = ser.SerializerMethodField( help_text='If the comment has been reported or confirmed.') is_ham = ser.SerializerMethodField( help_text='Comment has been confirmed as ham.') has_report = ser.SerializerMethodField( help_text='If the user reported this comment.') has_children = ser.SerializerMethodField( help_text='Whether this comment has any replies.') can_edit = ser.SerializerMethodField( help_text='Whether the current user can edit this comment.') # LinksField.to_representation adds link to "self" links = LinksField({}) class Meta: type_ = 'comments' def get_is_ham(self, obj): if obj.spam_status == SpamStatus.HAM: return True return False def get_has_report(self, obj): user = self.context['request'].user if user.is_anonymous(): return False return user._id in obj.reports and not obj.reports[user._id].get( 'retracted', True) def get_is_abuse(self, obj): if obj.spam_status == SpamStatus.FLAGGED or obj.spam_status == SpamStatus.SPAM: return True return False def get_can_edit(self, obj): user = self.context['request'].user if user.is_anonymous(): return False return obj.user._id == user._id and obj.node.can_comment(Auth(user)) def get_has_children(self, obj): return Comment.find(Q('target', 'eq', Guid.load(obj._id))).count() > 0 def get_absolute_url(self, obj): return absolute_reverse( 'comments:comment-detail', kwargs={ 'comment_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] }) def update(self, comment, validated_data): assert isinstance(comment, Comment), 'comment must be a Comment' auth = Auth(self.context['request'].user) if validated_data: if validated_data.get('is_deleted', None) is False and comment.is_deleted: try: comment.undelete(auth, save=True) except PermissionsError: raise PermissionDenied( 'Not authorized to undelete this comment.') elif validated_data.get('is_deleted', None) is True and not comment.is_deleted: try: comment.delete(auth, save=True) except PermissionsError: raise PermissionDenied( 'Not authorized to delete this comment.') elif 'get_content' in validated_data: content = validated_data.pop('get_content') try: comment.edit(content, auth=auth, save=True) except PermissionsError: raise PermissionDenied( 'Not authorized to edit this comment.') except ValidationValueError as err: raise ValidationError(err.args[0]) return comment def get_target_type(self, obj): if not getattr(obj.referent, 'target_type', None): raise InvalidModelValueError(source={ 'pointer': '/data/relationships/target/links/related/meta/type' }, detail='Invalid comment target type.') return obj.referent.target_type def sanitize_data(self): ret = super(CommentSerializer, self).sanitize_data() content = self.validated_data.get('get_content', None) if content: ret['get_content'] = bleach.clean(content) return ret
class CommentSerializer(JSONAPISerializer): filterable_fields = frozenset([ 'deleted', 'date_created', 'date_modified', 'target' ]) id = IDField(source='_id', read_only=True) type = TypeField() content = AuthorizedCharField(source='get_content', required=True, max_length=osf_settings.COMMENT_MAXLENGTH) target = TargetField(link_type='related', meta={'type': 'get_target_type'}) user = RelationshipField(related_view='users:user-detail', related_view_kwargs={'user_id': '<user._id>'}) node = RelationshipField(related_view='nodes:node-detail', related_view_kwargs={'node_id': '<node._id>'}) replies = RelationshipField(self_view='comments:comment-replies', self_view_kwargs={'comment_id': '<pk>'}) reports = RelationshipField(related_view='comments:comment-reports', related_view_kwargs={'comment_id': '<pk>'}) date_created = ser.DateTimeField(read_only=True) date_modified = ser.DateTimeField(read_only=True) modified = ser.BooleanField(read_only=True, default=False) deleted = ser.BooleanField(read_only=True, source='is_deleted', default=False) is_abuse = ser.SerializerMethodField(help_text='Whether the current user reported this comment.') has_children = ser.SerializerMethodField(help_text='Whether this comment has any replies.') can_edit = ser.SerializerMethodField(help_text='Whether the current user can edit this comment.') # LinksField.to_representation adds link to "self" links = LinksField({}) class Meta: type_ = 'comments' def validate_content(self, value): if value is None or not value.strip(): raise ValidationError('Comment cannot be empty.') return value def get_is_abuse(self, obj): user = self.context['request'].user if user.is_anonymous(): return False return user._id in obj.reports def get_can_edit(self, obj): user = self.context['request'].user if user.is_anonymous(): return False return obj.user._id == user._id def get_has_children(self, obj): return bool(getattr(obj, 'commented', [])) def update(self, comment, validated_data): assert isinstance(comment, Comment), 'comment must be a Comment' auth = Auth(self.context['request'].user) if validated_data: if 'get_content' in validated_data: content = validated_data.pop('get_content') try: comment.edit(content, auth=auth, save=True) except PermissionsError: raise PermissionDenied('Not authorized to edit this comment.') if validated_data.get('is_deleted', None) is True: try: comment.delete(auth, save=True) except PermissionsError: raise PermissionDenied('Not authorized to delete this comment.') elif comment.is_deleted: try: comment.undelete(auth, save=True) except PermissionsError: raise PermissionDenied('Not authorized to undelete this comment.') return comment def get_target_type(self, obj): if isinstance(obj, Node): return 'nodes' elif isinstance(obj, Comment): return 'comments' else: raise InvalidModelValueError( source={'pointer': '/data/relationships/target/links/related/meta/type'}, detail='Invalid comment target type.' )
class CommentSerializer(JSONAPISerializer): filterable_fields = frozenset( ['deleted', 'date_created', 'date_modified', 'page', 'target']) id = IDField(source='_id', read_only=True) type = TypeField() content = AuthorizedCharField(source='get_content', required=True, max_length=osf_settings.COMMENT_MAXLENGTH) page = ser.CharField(read_only=True) target = TargetField(link_type='related', meta={'type': 'get_target_type'}) user = RelationshipField(related_view='users:user-detail', related_view_kwargs={'user_id': '<user._id>'}) node = RelationshipField(related_view='nodes:node-detail', related_view_kwargs={'node_id': '<node._id>'}) replies = RelationshipField(self_view='nodes:node-comments', self_view_kwargs={'node_id': '<node._id>'}, filter={'target': '<pk>'}) reports = RelationshipField(related_view='comments:comment-reports', related_view_kwargs={'comment_id': '<pk>'}) date_created = ser.DateTimeField(read_only=True) date_modified = ser.DateTimeField(read_only=True) modified = ser.BooleanField(read_only=True, default=False) deleted = ser.BooleanField(read_only=True, source='is_deleted', default=False) is_abuse = ser.SerializerMethodField( help_text='Whether the current user reported this comment.') has_children = ser.SerializerMethodField( help_text='Whether this comment has any replies.') can_edit = ser.SerializerMethodField( help_text='Whether the current user can edit this comment.') # LinksField.to_representation adds link to "self" links = LinksField({}) class Meta: type_ = 'comments' def get_is_abuse(self, obj): user = self.context['request'].user if user.is_anonymous(): return False return user._id in obj.reports and not obj.reports[user._id].get( 'retracted', True) def get_can_edit(self, obj): user = self.context['request'].user if user.is_anonymous(): return False return obj.user._id == user._id and obj.node.can_comment(Auth(user)) def get_has_children(self, obj): return Comment.find(Q('target', 'eq', Guid.load(obj._id))).count() > 0 def get_absolute_url(self, obj): return absolute_reverse('comments:comment-detail', kwargs={'comment_id': obj._id}) # return self.data.get_absolute_url() def update(self, comment, validated_data): assert isinstance(comment, Comment), 'comment must be a Comment' auth = Auth(self.context['request'].user) if validated_data: if validated_data.get('is_deleted', None) is False and comment.is_deleted: try: comment.undelete(auth, save=True) except PermissionsError: raise PermissionDenied( 'Not authorized to undelete this comment.') elif 'get_content' in validated_data: content = validated_data.pop('get_content') try: comment.edit(content, auth=auth, save=True) except PermissionsError: raise PermissionDenied( 'Not authorized to edit this comment.') return comment def get_target_type(self, obj): if isinstance(obj.referent, Node): return 'nodes' elif isinstance(obj.referent, Comment): return 'comments' elif isinstance(obj.referent, StoredFileNode): return 'files' else: raise InvalidModelValueError(source={ 'pointer': '/data/relationships/target/links/related/meta/type' }, detail='Invalid comment target type.') def sanitize_data(self): ret = super(CommentSerializer, self).sanitize_data() content = self.validated_data.get('get_content', None) if content: ret['get_content'] = bleach.clean(content) return ret