示例#1
0
    def post(self, **kwargs):
        """Create a record.

        :returns: The created record.
        """
        # import deposit dependencies here in order to avoid recursive imports
        from b2share.modules.deposit.links import deposit_links_factory
        if request.content_type not in self.loaders:
            abort(415)
        version_of = request.args.get('version_of')
        previous_record = None
        data = None
        if version_of:
            try:
                _, previous_record = Resolver(
                    pid_type='b2rec',
                    object_type='rec',
                    getter=B2ShareRecord.get_record,
                ).resolve(version_of)
            # if the pid doesn't exist
            except PIDDoesNotExistError as e:
                raise RecordNotFoundVersioningError()
            # if it is the parent pid
            except PIDRedirectedError as e:
                raise IncorrectRecordVersioningError(version_of)
            # Copy the metadata from a previous version if this version is
            # specified and no data was provided.
            if request.content_length == 0:
                data = copy_data_from_previous(previous_record.model.json)

        if data is None:
            data = self.loaders[request.content_type]()

        if data is None:
            abort(400)

        # Check permissions
        permission_factory = self.create_permission_factory
        if permission_factory:
            verify_record_permission(permission_factory, data,
                                     previous_record=previous_record)

        # Create uuid for record
        record_uuid = uuid.uuid4()
        # Create persistent identifier
        pid = self.minter(record_uuid, data=data)

        # Create record
        record = self.record_class.create(data, id_=record_uuid,
                                          version_of=version_of)
        db.session.commit()

        response = self.make_response(
            pid, record, 201, links_factory=deposit_links_factory)

        # Add location headers
        endpoint = 'b2share_deposit_rest.{0}_item'.format(pid.pid_type)
        location = url_for(endpoint, pid_value=pid.pid_value, _external=True)
        response.headers.extend(dict(location=location))
        return response
def test_deposit_copy_data_from_previous(app, test_records, test_users):
    """Test copying of metadata from previous version."""
    with app.app_context():
        prev_record = test_records[0]
        _prev_record = B2ShareRecord.get_record(prev_record.record_id)
        copied_data = copy_data_from_previous(_prev_record.model.json)
        for field in copy_data_from_previous.extra_removed_fields:
            del prev_record.data[field]
        data = {k: v for k, v in prev_record.data.items() if not k.startswith('_')}
        assert copied_data == data
def test_new_deposit_versions_preserve_schema(app, test_records, test_users):
    """Creating new versions of existing records."""
    with app.app_context():
        # Retrieve a record which will be the first version, and its deposit
        v1_rec = B2ShareRecord.get_record(test_records[0].record_id)
        _, v1_id = pid_of(test_records[0].data)

        # update the community's schema
        community_id = v1_rec.model.json['community']
        old_schema = CommunitySchema.get_community_schema(community_id)
        json_schema = json.loads(old_schema.model.community_schema)
        new_schema = CommunitySchema.create_version(community_id, json_schema)
        assert new_schema.version > old_schema.version

        # create new, unversioned, draft and records
        data = copy_data_from_previous(v1_rec.model.json)
        unver_dep = create_deposit(data, test_users['deposits_creator'])
        unver_dep.submit()
        unver_dep.publish()
        _, unver_rec = unver_dep.fetch_published()

        # the unversioned draft or record in a version chain have the updated schema
        assert unver_dep['$schema'] != Deposit._build_deposit_schema(
            v1_rec.model.json)
        assert unver_rec.model.json['$schema'] != v1_rec.model.json['$schema']

        # create new draft and record in the version chain of v1
        data = copy_data_from_previous(v1_rec.model.json)
        v2_dep = create_deposit(data,
                                test_users['deposits_creator'],
                                version_of=v1_id)
        v2_dep.submit()
        v2_dep.publish()
        _, v2_rec = v2_dep.fetch_published()

        # the new draft and record in a version chain preserve the version of the schema
        assert v2_dep['$schema'] == Deposit._build_deposit_schema(
            v1_rec.model.json)
        assert v2_rec.model.json['$schema'] == v1_rec.model.json['$schema']
def test_deposit_copy_data_from_previous(app, test_records, test_users):
    """Test copying of metadata from previous version."""
    with app.app_context():
        prev_record = test_records[0]
        _prev_record = B2ShareRecord.get_record(prev_record.record_id)
        copied_data = copy_data_from_previous(_prev_record.model.json)
        for field in copy_data_from_previous.extra_removed_fields:
            del prev_record.data[field]
        data = {
            k: v
            for k, v in prev_record.data.items() if not k.startswith('_')
        }
        assert copied_data == data
def test_deposit_delete(app, draft_deposits, test_records, test_users,
                        test_communities):
    """Test deposit deletion."""
    with app.app_context():
        # create a deposit with a parent pid which has no other children
        first_deposit = create_deposit(
            {'community': str(test_communities['MyTestCommunity1'])},
            test_users['deposits_creator'])
        parent_pid = first_deposit['_pid'][0]['value']
        deposit_pid_value = first_deposit['_deposit']['id']
        # delete the deposit
        first_deposit.delete()
        deposit = PersistentIdentifier.query.filter_by(
            pid_value=deposit_pid_value).first()
        parent = PersistentIdentifier.query.filter_by(
            pid_value=parent_pid).one_or_none()
        # check that deleting it deletes parent from the db because there are
        # no remaining published versions and draft.
        assert not parent
        assert deposit.status == PIDStatus.DELETED

        # check that the buckets are removed
        assert not db.session.query(
            Bucket.query.join(RecordsBuckets).filter(
                RecordsBuckets.bucket_id == Bucket.id, RecordsBuckets.record_id
                == first_deposit.id).exists()).scalar()

        # create a deposit with a parent which has other children
        v1 = test_records[0].data
        v1_rec = B2ShareRecord.get_record(test_records[0].record_id)
        v1_pid, v1_id = pid_of(v1)
        data = copy_data_from_previous(v1_rec.model.json)
        v2 = create_deposit(data,
                            test_users['deposits_creator'],
                            version_of=v1_id)
        deposit_pid_value = v2['_deposit']['id']
        parent_pid = v2['_pid'][0]['value']

        v2.delete()
        deposit = PersistentIdentifier.query.filter_by(
            pid_value=deposit_pid_value).first()
        parent = PersistentIdentifier.query.filter_by(
            pid_value=parent_pid).first()
        # check that the parent status is not changed after deleting
        assert parent.status != PIDStatus.DELETED
        assert parent.get_redirect() == v1_pid
        assert deposit.status == PIDStatus.DELETED
def test_deposit_delete(app, draft_deposits, test_records,
                        test_users, test_communities):
    """Test deposit deletion."""
    with app.app_context():
        # create a deposit with a parent pid which has no other children
        first_deposit = create_deposit(
            {'community': str(test_communities['MyTestCommunity1'])},
            test_users['deposits_creator'])
        parent_pid = first_deposit['_pid'][0]['value']
        deposit_pid_value = first_deposit['_deposit']['id']
        # delete the deposit
        first_deposit.delete()
        deposit = PersistentIdentifier.query.filter_by(pid_value=deposit_pid_value).first()
        parent = PersistentIdentifier.query.filter_by(pid_value=parent_pid).one_or_none()
        # check that deleting it deletes parent from the db because there are
        # no remaining published versions and draft.
        assert not parent
        assert deposit.status == PIDStatus.DELETED

        # check that the buckets are removed
        assert not db.session.query(
            Bucket.query.join(RecordsBuckets).
            filter(RecordsBuckets.bucket_id == Bucket.id,
                   RecordsBuckets.record_id == first_deposit.id).exists()
        ).scalar()

        # create a deposit with a parent which has other children
        v1 = test_records[0].data
        v1_rec = B2ShareRecord.get_record(test_records[0].record_id)
        v1_pid, v1_id = pid_of(v1)
        data = copy_data_from_previous(v1_rec.model.json)
        v2 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v1_id)
        deposit_pid_value = v2['_deposit']['id']
        parent_pid = v2['_pid'][0]['value']

        v2.delete()
        deposit = PersistentIdentifier.query.filter_by(pid_value=deposit_pid_value).first()
        parent = PersistentIdentifier.query.filter_by(pid_value=parent_pid).first()
        # check that the parent status is not changed after deleting
        assert parent.status != PIDStatus.DELETED
        assert parent.get_redirect() == v1_pid
        assert deposit.status == PIDStatus.DELETED
def test_deposit_versions_create(app, test_records, test_users):
    """Creating new versions of existing records."""
    with app.app_context():
        # Retrieve a record which will be the first version
        v1 = test_records[0].data
        v1_rec = B2ShareRecord.get_record(test_records[0].record_id)
        v1_pid, v1_id = pid_of(v1)
        assert list_published_pids(v1_pid) == [v1_pid]

        # create draft in version chain:
        # version chain becomes: [v1] -- [v2 draft]
        # v2 = create_deposit({}, version_of=v1_id)
        data = copy_data_from_previous(v1_rec.model.json)
        v2 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v1_id)
        assert filenames(v2) == []
        ObjectVersion.create(v2.files.bucket, 'myfile1',
                             stream=BytesIO(b'mycontent'))
        assert filenames(v2) == ['myfile1']

        assert list_published_pids(v1_pid) == [v1_pid]

        # cannot create another draft if one exists
        # not possible: [v1] -- [v2 draft]
        #                    `- [new draft]
        with pytest.raises(DraftExistsVersioningError):
            data = copy_data_from_previous(v1_rec.model.json)
            create_deposit(data, test_users['deposits_creator'],
                           version_of=v1_id)

        # cannot create a version from a draft pid
        # not possible: [v1] -- [v2 draft] -- [new draft]
        with pytest.raises(IncorrectRecordVersioningError): # record pid not created yet
            data = copy_data_from_previous(v1_rec.model.json)
            create_deposit(data, test_users['deposits_creator'],
                           version_of=v2['_deposit']['id'])

        # publish previous draft
        # version chain becomes: [v1] -- [v2]
        v2.submit()
        v2.publish()
        v2_pid, v2_id = pid_of(v2)
        assert list_published_pids(v1_pid) == [v1_pid, v2_pid]

        # cannot create draft based on the first version in a chain
        # not possible: [v1] -- [v2]
        #                    `- [new draft]
        with pytest.raises(IncorrectRecordVersioningError):
            data = copy_data_from_previous(v1_rec.model.json)
            create_deposit(data, test_users['deposits_creator'],
                           version_of=v1_id)

        # create and publish other versions:
        # version chain becomes: [v1] -- [v2] -- [v3]
        data = copy_data_from_previous(v1_rec.model.json)
        v3 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v2_id)
        # assert files are imported from v2
        assert filenames(v3) == ['myfile1']
        ObjectVersion.create(v3.files.bucket, 'myfile2',
                                stream=BytesIO(b'mycontent'))
        assert filenames(v3) == ['myfile1', 'myfile2']

        assert list_published_pids(v1_pid) == [v1_pid, v2_pid]

        v3.submit()
        v3.publish()
        v3_pid, v3_id = pid_of(v3)
        v3_rec = Record.get_record(v3_id)
        assert filenames(v3_rec) == ['myfile1', 'myfile2']
        assert list_published_pids(v1_pid) == [v1_pid, v2_pid, v3_pid]

        # cannot create draft based on an intermediate version in a chain
        # not possible: [v1] -- [v2] -- [v3]
        #                            `- [new draft]
        with pytest.raises(IncorrectRecordVersioningError):
            create_deposit({}, test_users['deposits_creator'],
                           version_of=v2_id)

        # Create yet another version
        # Version chain becomes: [v1] -- [v2] -- [v3] -- [v4]
        data = copy_data_from_previous(v1_rec.model.json)
        v4 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v3_id)
        v4.submit()
        v4.publish()
        assert filenames(v4) == ['myfile1', 'myfile2']
        v4_pid, v4_id = pid_of(v4)
        assert list_published_pids(v1_pid) == [
            v1_pid, v2_pid, v3_pid, v4_pid]

        # assert that creating a new version from a deleted pid is not allowed
        resolver = Resolver(pid_type=v4_pid.pid_type, object_type='rec',
                            getter=partial(B2ShareRecord.get_record,
                                           with_deleted=True))
        v4_pid, v4_rec = LazyPIDValue(resolver, v4_pid.pid_value).data
        # delete [v4]
        v4_rec.delete()
        with pytest.raises(RecordNotFoundVersioningError):
            v5 = create_deposit(data, test_users['deposits_creator'],
                                version_of=v4_id)
def test_deposit_create_versions(app, test_records_data, test_users,
                                 login_user):
    """Test the creation of new record version draft."""
    # Use admin user in order to publish easily the records.
    login = lambda c: login_user(test_users['admin'], c)

    data = test_records_data

    # create and publish first record in a chain
    v1_draft = create_ok(app, login, data[0])
    assert 'versions' in v1_draft['links']
    check_links(app, v1_draft, [])

    v1_rec = publish(app, login, v1_draft)
    assert 'versions' in v1_rec['links']
    check_links(app, v1_rec, [v1_rec])

    # try to create a new version from an unknown pid
    res, json_data = create(app, login, data[1], version_of=uuid.uuid4().hex)
    assert res.status_code == 400

    # try to create a new version from a parent pid
    with app.app_context():
        v1_pid = PersistentIdentifier.get(pid_value=v1_rec['id'],
                                          pid_type='b2rec')
        parent_pid = PIDVersioning(child=v1_pid).parent
    res, json_data = create(app,
                            login,
                            data[1],
                            version_of=parent_pid.pid_value)
    assert res.status_code == 400

    # create and publish second record in a chain
    v2_draft = create_ok(app, login, data[1], version_of=v1_rec['id'])
    check_links(app, v2_draft, [v1_rec])
    v2_rec = publish(app, login, v2_draft)
    check_links(app, v2_rec, [v1_rec, v2_rec])

    # test error if trying to create a non-linear version chain
    res, json_data = create(app, login, data[1], version_of=v1_rec['id'])
    assert res.status_code == 400
    assert json_data['use_record'] == v2_rec['id']

    # create third record draft in a chain
    v3_draft = create_ok(app, login, data[2], version_of=v2_rec['id'])
    check_links(app, v3_draft, [v1_rec, v2_rec])

    # test error when a draft already exists in a version chain
    res, json_data = create(app, login, data[1], version_of=v2_rec['id'])
    assert res.status_code == 400
    assert json_data['goto_draft'] == v3_draft['id']

    # publish third record in a chain
    v3_rec = publish(app, login, v3_draft)
    check_links(app, v3_rec, [v1_rec, v2_rec, v3_rec])

    # create a new version without data
    # assert that data is copied from the previous version
    v4_draft = create_ok(app, login, None, v3_rec['id'])
    with app.app_context():
        record_resolver = Resolver(
            pid_type='b2rec',
            object_type='rec',
            getter=B2ShareRecord.get_record,
        )
        deposit_resolver = Resolver(
            pid_type='b2dep',
            object_type='rec',
            getter=Deposit.get_record,
        )
        v4_metadata = deposit_resolver.resolve(v4_draft['id'])[1].model.json
        v3_metadata = record_resolver.resolve(v3_rec['id'])[1].model.json

        assert copy_data_from_previous(v4_metadata) == \
            copy_data_from_previous(v3_metadata)
def test_deposit_versions_create(app, test_records, test_users):
    """Creating new versions of existing records."""
    with app.app_context():
        # Retrieve a record which will be the first version
        v1 = test_records[0].data
        v1_rec = B2ShareRecord.get_record(test_records[0].record_id)
        v1_pid, v1_id = pid_of(v1)
        assert list_published_pids(v1_pid) == [v1_pid]

        # create draft in version chain:
        # version chain becomes: [v1] -- [v2 draft]
        # v2 = create_deposit({}, version_of=v1_id)
        data = copy_data_from_previous(v1_rec.model.json)
        v2 = create_deposit(data,
                            test_users['deposits_creator'],
                            version_of=v1_id)
        assert filenames(v2) == []
        ObjectVersion.create(v2.files.bucket,
                             'myfile1',
                             stream=BytesIO(b'mycontent'))
        assert filenames(v2) == ['myfile1']

        assert list_published_pids(v1_pid) == [v1_pid]

        # cannot create another draft if one exists
        # not possible: [v1] -- [v2 draft]
        #                    `- [new draft]
        with pytest.raises(DraftExistsVersioningError):
            data = copy_data_from_previous(v1_rec.model.json)
            create_deposit(data,
                           test_users['deposits_creator'],
                           version_of=v1_id)

        # cannot create a version from a draft pid
        # not possible: [v1] -- [v2 draft] -- [new draft]
        with pytest.raises(
                IncorrectRecordVersioningError):  # record pid not created yet
            data = copy_data_from_previous(v1_rec.model.json)
            create_deposit(data,
                           test_users['deposits_creator'],
                           version_of=v2['_deposit']['id'])

        # publish previous draft
        # version chain becomes: [v1] -- [v2]
        v2.submit()
        v2.publish()
        v2_pid, v2_id = pid_of(v2)
        assert list_published_pids(v1_pid) == [v1_pid, v2_pid]

        # cannot create draft based on the first version in a chain
        # not possible: [v1] -- [v2]
        #                    `- [new draft]
        with pytest.raises(IncorrectRecordVersioningError):
            data = copy_data_from_previous(v1_rec.model.json)
            create_deposit(data,
                           test_users['deposits_creator'],
                           version_of=v1_id)

        # create and publish other versions:
        # version chain becomes: [v1] -- [v2] -- [v3]
        data = copy_data_from_previous(v1_rec.model.json)
        v3 = create_deposit(data,
                            test_users['deposits_creator'],
                            version_of=v2_id)
        # assert files are imported from v2
        assert filenames(v3) == ['myfile1']
        ObjectVersion.create(v3.files.bucket,
                             'myfile2',
                             stream=BytesIO(b'mycontent'))
        assert filenames(v3) == ['myfile1', 'myfile2']

        assert list_published_pids(v1_pid) == [v1_pid, v2_pid]

        v3.submit()
        v3.publish()
        v3_pid, v3_id = pid_of(v3)
        v3_rec = Record.get_record(v3_id)
        assert filenames(v3_rec) == ['myfile1', 'myfile2']
        assert list_published_pids(v1_pid) == [v1_pid, v2_pid, v3_pid]

        # cannot create draft based on an intermediate version in a chain
        # not possible: [v1] -- [v2] -- [v3]
        #                            `- [new draft]
        with pytest.raises(IncorrectRecordVersioningError):
            create_deposit({},
                           test_users['deposits_creator'],
                           version_of=v2_id)

        # Create yet another version
        # Version chain becomes: [v1] -- [v2] -- [v3] -- [v4]
        data = copy_data_from_previous(v1_rec.model.json)
        v4 = create_deposit(data,
                            test_users['deposits_creator'],
                            version_of=v3_id)
        v4.submit()
        v4.publish()
        assert filenames(v4) == ['myfile1', 'myfile2']
        v4_pid, v4_id = pid_of(v4)
        assert list_published_pids(v1_pid) == [v1_pid, v2_pid, v3_pid, v4_pid]

        # assert that creating a new version from a deleted pid is not allowed
        resolver = Resolver(pid_type=v4_pid.pid_type,
                            object_type='rec',
                            getter=partial(B2ShareRecord.get_record,
                                           with_deleted=True))
        v4_pid, v4_rec = LazyPIDValue(resolver, v4_pid.pid_value).data
        # delete [v4]
        v4_rec.delete()
        with pytest.raises(RecordNotFoundVersioningError):
            v5 = create_deposit(data,
                                test_users['deposits_creator'],
                                version_of=v4_id)
示例#10
0
    def post(self, **kwargs):
        """Create a record.

        :returns: The created record.
        """
        # import deposit dependencies here in order to avoid recursive imports
        from b2share.modules.deposit.links import deposit_links_factory
        from b2share.modules.records.api import B2ShareRecord
        if request.content_type not in self.loaders:
            abort(415)
        version_of = request.args.get('version_of')
        previous_record = None
        data = None
        if version_of:
            try:
                _, previous_record = Resolver(
                    pid_type='b2rec',
                    object_type='rec',
                    getter=B2ShareRecord.get_record,
                ).resolve(version_of)
            # if the pid doesn't exist
            except PIDDoesNotExistError as e:
                raise RecordNotFoundVersioningError()
            # if it is the parent pid
            except PIDRedirectedError as e:
                raise IncorrectRecordVersioningError(version_of)
            # Copy the metadata from a previous version if this version is
            # specified and no data was provided.
            if request.content_length == 0:
                data = copy_data_from_previous(previous_record.model.json)

        if data is None:
            data = self.loaders[request.content_type]()

        if data is None:
            abort(400)

        # Check permissions
        permission_factory = self.create_permission_factory
        if permission_factory:
            verify_record_permission(permission_factory,
                                     data,
                                     previous_record=previous_record)

        # Create uuid for record
        record_uuid = uuid.uuid4()
        # Create persistent identifier
        pid = self.minter(record_uuid, data=data)

        # Create record
        record = self.record_class.create(data,
                                          id_=record_uuid,
                                          version_of=version_of)
        db.session.commit()

        response = self.make_response(pid,
                                      record,
                                      201,
                                      links_factory=deposit_links_factory)

        # Add location headers
        endpoint = 'b2share_deposit_rest.{0}_item'.format(pid.pid_type)
        location = url_for(endpoint, pid_value=pid.pid_value, _external=True)
        response.headers.extend(dict(location=location))
        return response
示例#11
0
def test_record_delete_version(app, test_records, test_users):
    """Test deletion of a record version."""
    with app.app_context():
        resolver = Resolver(
            pid_type='b2rec',
            object_type='rec',
            getter=B2ShareRecord.get_record,
        )

        v1 = test_records[0].data
        v1_pid, v1_id = pid_of(v1)

        _, v1_rec = resolver.resolve(v1_id)
        data = copy_data_from_previous(v1_rec.model.json)
        v2 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v1_id)
        ObjectVersion.create(v2.files.bucket, 'myfile1',
                             stream=BytesIO(b'mycontent'))
        v2.submit()
        v2.publish()
        v2_pid, v2_id = pid_of(v2)
        data = copy_data_from_previous(v2.model.json)
        v3 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v2_id)
        v3.submit()
        v3.publish()
        v3_pid, v3_id = pid_of(v3)
        v3_pid, v3_rec = resolver.resolve(v3_pid.pid_value)
        # chain is now: [v1] -- [v2] -- [v3]
        version_child = PIDVersioning(child=v2_pid)
        version_master = PIDVersioning(parent=version_child.parent)
        assert len(version_master.children.all()) == 3
        v3_rec.delete()
        assert len(version_master.children.all()) == 2
        # chain is now [v1] -- [v2]
        # assert that we can create again a new version from v2
        data = copy_data_from_previous(v2.model.json)
        v3 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v2_id)
        v3.submit()
        v3.publish()
        v3_pid, v3_id = pid_of(v3)
        v3_pid, v3_rec = resolver.resolve(v3_pid.pid_value)
        assert len(version_master.children.all()) == 3
        v2_pid, v2_rec = resolver.resolve(v2_pid.pid_value)
        # Delete an intermediate version
        v2_rec.delete()
        assert len(version_master.children.all()) == 2
        # chain is now [v1] -- [v3]
        # Add a new version
        data = copy_data_from_previous(v3.model.json)
        v4 = create_deposit(data, test_users['deposits_creator'],
                            version_of=v3_id)
        v4.submit()
        v4.publish()
        assert len(version_master.children.all()) == 3
        # final chain [v1] -- [v3] -- [v4]
        v4_pid, v4_id = pid_of(v4)
        v4_pid, v4_rec = resolver.resolve(v4_pid.pid_value)
        data = copy_data_from_previous(v4)
        draft_child = create_deposit(data, test_users['deposits_creator'],
                                     version_of=v4_id)
        draft_child.submit()

        # delete all children except the draft child
        assert len(version_master.children.all()) == 3
        v4_rec.delete()
        assert len(version_master.children.all()) == 2

        v3_rec.delete()
        assert len(version_master.children.all()) == 1

        v1_rec.delete()
        assert len(version_master.children.all()) == 0

        assert version_master.parent.status != PIDStatus.DELETED

        draft_child.publish()
        draft_child_pid, draft_child_id = pid_of(draft_child)
        draft_child_pid, draft_child_rec = \
            resolver.resolve(draft_child_pid.pid_value)
        # assert that we can create again a new version

        assert len(version_master.children.all()) == 1

        # no child remains and there is no draft_child
        draft_child_rec.delete()
        assert version_master.parent.status == PIDStatus.DELETED