mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 23:13:10 +00:00
76575: ITs for deleting items and populating virtual metadata
This commit is contained in:
@@ -377,7 +377,7 @@ public class RelationshipServiceImpl implements RelationshipService {
|
|||||||
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
|
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
|
||||||
relationshipDAO.delete(context, relationship);
|
relationshipDAO.delete(context, relationship);
|
||||||
updatePlaceInRelationship(context, relationship);
|
updatePlaceInRelationship(context, relationship);
|
||||||
updateItemsInRelationship(context, relationship);
|
updateItemsInRelationship(context, relationship);
|
||||||
} else {
|
} else {
|
||||||
throw new AuthorizeException(
|
throw new AuthorizeException(
|
||||||
"You do not have write rights on this relationship's items");
|
"You do not have write rights on this relationship's items");
|
||||||
|
@@ -63,9 +63,9 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
|
|||||||
|
|
||||||
private static final Logger log = Logger.getLogger(ItemRestRepository.class);
|
private static final Logger log = Logger.getLogger(ItemRestRepository.class);
|
||||||
|
|
||||||
private static final String[] COPYVIRTUAL_ALL = {"all"};
|
public static final String[] COPYVIRTUAL_ALL = {"all"};
|
||||||
private static final String[] COPYVIRTUAL_CONFIGURED = {"configured"};
|
public static final String[] COPYVIRTUAL_CONFIGURED = {"configured"};
|
||||||
private static final String REQUESTPARAMETER_COPYVIRTUALMETADATA = "copyVirtualMetadata";
|
public static final String REQUESTPARAMETER_COPYVIRTUALMETADATA = "copyVirtualMetadata";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
MetadataConverter metadataConverter;
|
MetadataConverter metadataConverter;
|
||||||
@@ -206,7 +206,14 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
|
|||||||
// of the item's relationships and copy their data depending on the
|
// of the item's relationships and copy their data depending on the
|
||||||
// configuration.
|
// configuration.
|
||||||
for (Relationship relationship : relationshipService.findByItem(context, item)) {
|
for (Relationship relationship : relationshipService.findByItem(context, item)) {
|
||||||
relationshipService.delete(obtainContext(), relationship);
|
boolean copyToLeft = relationship.getRelationshipType().isCopyToLeft();
|
||||||
|
boolean copyToRight = relationship.getRelationshipType().isCopyToRight();
|
||||||
|
if (relationship.getLeftItem().getID().equals(item.getID())) {
|
||||||
|
copyToLeft = false;
|
||||||
|
} else {
|
||||||
|
copyToRight = false;
|
||||||
|
}
|
||||||
|
relationshipService.forceDelete(obtainContext(), relationship, copyToLeft, copyToRight);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Option 3: Copy the virtual metadata of selected types of this item to its related items. The copyVirtual
|
// Option 3: Copy the virtual metadata of selected types of this item to its related items. The copyVirtual
|
||||||
@@ -256,7 +263,7 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
|
|||||||
copyToRight = false;
|
copyToRight = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
relationshipService.delete(obtainContext(), relationshipToDelete, copyToLeft, copyToRight);
|
relationshipService.forceDelete(obtainContext(), relationshipToDelete, copyToLeft, copyToRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -24,6 +24,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -43,6 +44,7 @@ import org.dspace.app.rest.model.MetadataRest;
|
|||||||
import org.dspace.app.rest.model.MetadataValueRest;
|
import org.dspace.app.rest.model.MetadataValueRest;
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
||||||
|
import org.dspace.app.rest.repository.ItemRestRepository;
|
||||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||||
import org.dspace.app.rest.test.MetadataPatchSuite;
|
import org.dspace.app.rest.test.MetadataPatchSuite;
|
||||||
import org.dspace.builder.BitstreamBuilder;
|
import org.dspace.builder.BitstreamBuilder;
|
||||||
@@ -78,6 +80,13 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CollectionService collectionService;
|
private CollectionService collectionService;
|
||||||
|
|
||||||
|
private Item publication1;
|
||||||
|
private Item author1;
|
||||||
|
private Item author2;
|
||||||
|
RelationshipType isAuthorOfPublication;
|
||||||
|
private Relationship relationship1;
|
||||||
|
private Relationship relationship2;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findAllTest() throws Exception {
|
public void findAllTest() throws Exception {
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
@@ -2748,54 +2757,7 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deleteItemWithMinRelationshipsTest() throws Exception {
|
public void deleteItemWithMinRelationshipsTest() throws Exception {
|
||||||
context.turnOffAuthorisationSystem();
|
initPublicationAuthorsRelationships();
|
||||||
|
|
||||||
//** GIVEN **
|
|
||||||
//1. A community with one collection.
|
|
||||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
|
||||||
.withName("Parent Community")
|
|
||||||
.build();
|
|
||||||
Collection col1 = CollectionBuilder
|
|
||||||
.createCollection(context, parentCommunity).withName("Collection 1").build();
|
|
||||||
|
|
||||||
Item author1 = ItemBuilder.createItem(context, col1)
|
|
||||||
.withTitle("Author1")
|
|
||||||
.withIssueDate("2017-10-17")
|
|
||||||
.withAuthor("Smith, Donald")
|
|
||||||
.withPersonIdentifierLastName("Smith")
|
|
||||||
.withPersonIdentifierFirstName("Donald")
|
|
||||||
.withRelationshipType("Person")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Item author2 = ItemBuilder.createItem(context, col1)
|
|
||||||
.withTitle("Author2")
|
|
||||||
.withIssueDate("2016-02-13")
|
|
||||||
.withAuthor("Smith, Maria")
|
|
||||||
.withRelationshipType("Person")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Item publication1 = ItemBuilder.createItem(context, col1)
|
|
||||||
.withTitle("Publication1")
|
|
||||||
.withAuthor("Testy, TEst")
|
|
||||||
.withIssueDate("2015-01-01")
|
|
||||||
.withRelationshipType("Publication")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
EntityType publication = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication").build();
|
|
||||||
EntityType person = EntityTypeBuilder.createEntityTypeBuilder(context, "Person").build();
|
|
||||||
|
|
||||||
|
|
||||||
RelationshipType isAuthorOfPublication = RelationshipTypeBuilder
|
|
||||||
.createRelationshipTypeBuilder(context, publication, person, "isAuthorOfPublication",
|
|
||||||
"isPublicationOfAuthor", 2, null, 0,
|
|
||||||
null).withCopyToLeft(false).withCopyToRight(true).build();
|
|
||||||
|
|
||||||
Relationship relationship1 = RelationshipBuilder
|
|
||||||
.createRelationshipBuilder(context, publication1, author1, isAuthorOfPublication).build();
|
|
||||||
Relationship relationship2 = RelationshipBuilder
|
|
||||||
.createRelationshipBuilder(context, publication1, author2, isAuthorOfPublication).build();
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
@@ -2823,5 +2785,236 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteItemWithMinRelationshipsTest_copyVirtualMetadata_null() throws Exception {
|
||||||
|
initPublicationAuthorsRelationships();
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
//Delete public item with copyVirtualMetadata null
|
||||||
|
getClient(token).perform(delete("/api/core/items/" + publication1.getID()))
|
||||||
|
.andExpect(status().is(204));
|
||||||
|
// The non-deleted item of the relationships the delete item had (other sides) doesn't still have the
|
||||||
|
// relationship Metadata
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author1.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']").doesNotExist());
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author2.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']").doesNotExist());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteItemWithMinRelationshipsTest_copyVirtualMetadata_relationshiptypeid_isAuthorOfPublication()
|
||||||
|
throws Exception {
|
||||||
|
initPublicationAuthorsRelationships();
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
// Delete public item with copyVirtualMetadata isAuthorOfPublication relationship id
|
||||||
|
getClient(token).perform(delete("/api/core/items/" + publication1.getID())
|
||||||
|
.param(ItemRestRepository.REQUESTPARAMETER_COPYVIRTUALMETADATA,
|
||||||
|
String.valueOf(isAuthorOfPublication.getID())))
|
||||||
|
.andExpect(status().is(204));
|
||||||
|
// The non-deleted item of the relationships the delete item had (other sides) still has the
|
||||||
|
// relationship Metadata
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author1.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']" +
|
||||||
|
"[0].value", is(String.valueOf(publication1.getID()))));
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author2.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']" +
|
||||||
|
"[0].value", is(String.valueOf(publication1.getID()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteItemWithMinRelationshipsTest_copyVirtualMetadata_relationshiptypeid_other() throws Exception {
|
||||||
|
initPublicationAuthorsRelationships();
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EntityType journalIssueEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "JournalIssue").build();
|
||||||
|
EntityType journalVolumeEntityType =
|
||||||
|
EntityTypeBuilder.createEntityTypeBuilder(context, "JournalVolume").build();
|
||||||
|
|
||||||
|
RelationshipType isJournalVolumeOfIssueRelationshipType =
|
||||||
|
RelationshipTypeBuilder.createRelationshipTypeBuilder(context, journalIssueEntityType,
|
||||||
|
journalVolumeEntityType, "isIssueOfJournalVolume", "isJournalVolumeOfIssue", 2, null, 0,
|
||||||
|
null).withCopyToLeft(false).withCopyToRight(true).build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// Delete public item with copyVirtualMetadata id of relationship neither item has
|
||||||
|
getClient(token).perform(delete("/api/core/items/" + publication1.getID())
|
||||||
|
.param(ItemRestRepository.REQUESTPARAMETER_COPYVIRTUALMETADATA,
|
||||||
|
String.valueOf(isJournalVolumeOfIssueRelationshipType.getID())))
|
||||||
|
.andExpect(status().is(204));
|
||||||
|
// The non-deleted item of the relationships the delete item had (other sides) doesn't still have the
|
||||||
|
// relationship Metadata
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author1.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']").doesNotExist());
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author2.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']").doesNotExist());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteItemWithMinRelationshipsTest_copyVirtualMetadata_all() throws Exception {
|
||||||
|
initPublicationAuthorsRelationships();
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
//Delete public item with copyVirtualMetadata = all
|
||||||
|
getClient(token).perform(delete("/api/core/items/" + publication1.getID())
|
||||||
|
.param(ItemRestRepository.REQUESTPARAMETER_COPYVIRTUALMETADATA, ItemRestRepository.COPYVIRTUAL_ALL))
|
||||||
|
.andExpect(status().is(204));
|
||||||
|
// The non-deleted item of the relationships the delete item had (other sides) now still has the
|
||||||
|
// relationship Metadata
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author1.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']" +
|
||||||
|
"[0].value", is(String.valueOf(publication1.getID()))));
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author2.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']" +
|
||||||
|
"[0].value", is(String.valueOf(publication1.getID()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteItemWithMinRelationshipsTest_copyVirtualMetadata_configured_withCopyToRightTrueConfigured()
|
||||||
|
throws Exception {
|
||||||
|
initPublicationAuthorsRelationships();
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
//Delete public item with copyVirtualMetadata = configured
|
||||||
|
getClient(token).perform(delete("/api/core/items/" + publication1.getID())
|
||||||
|
.param(ItemRestRepository.REQUESTPARAMETER_COPYVIRTUALMETADATA, ItemRestRepository.COPYVIRTUAL_CONFIGURED))
|
||||||
|
.andExpect(status().is(204));
|
||||||
|
// The non-deleted item of the relationships the delete item had (other sides) now still has the
|
||||||
|
// relationship Metadata
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author1.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']" +
|
||||||
|
"[0].value", is(String.valueOf(publication1.getID()))));
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author2.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']" +
|
||||||
|
"[0].value", is(String.valueOf(publication1.getID()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteItemWithMinRelationshipsTest_copyVirtualMetadata_configured_withCopyToRightFalseConfigured()
|
||||||
|
throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
//** GIVEN **
|
||||||
|
//1. A community with one collection.
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder
|
||||||
|
.createCollection(context, parentCommunity).withName("Collection 1").build();
|
||||||
|
|
||||||
|
author1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Author1")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withPersonIdentifierLastName("Smith")
|
||||||
|
.withPersonIdentifierFirstName("Donald")
|
||||||
|
.withRelationshipType("Person")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
author2 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Author2")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.withAuthor("Smith, Maria")
|
||||||
|
.withRelationshipType("Person")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
publication1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Publication1")
|
||||||
|
.withAuthor("Testy, TEst")
|
||||||
|
.withIssueDate("2015-01-01")
|
||||||
|
.withRelationshipType("Publication")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EntityType publication = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication").build();
|
||||||
|
EntityType person = EntityTypeBuilder.createEntityTypeBuilder(context, "Person").build();
|
||||||
|
|
||||||
|
isAuthorOfPublication = RelationshipTypeBuilder
|
||||||
|
.createRelationshipTypeBuilder(context, publication, person, "isAuthorOfPublication",
|
||||||
|
"isPublicationOfAuthor", 2, null, 0,
|
||||||
|
null).withCopyToLeft(false).withCopyToRight(false).build();
|
||||||
|
|
||||||
|
relationship1 = RelationshipBuilder
|
||||||
|
.createRelationshipBuilder(context, publication1, author1, isAuthorOfPublication).build();
|
||||||
|
relationship2 = RelationshipBuilder
|
||||||
|
.createRelationshipBuilder(context, publication1, author2, isAuthorOfPublication).build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
//Delete public item with copyVirtualMetadata = configured
|
||||||
|
getClient(token).perform(delete("/api/core/items/" + publication1.getID())
|
||||||
|
.param(ItemRestRepository.REQUESTPARAMETER_COPYVIRTUALMETADATA, ItemRestRepository.COPYVIRTUAL_CONFIGURED))
|
||||||
|
.andExpect(status().is(204));
|
||||||
|
// The non-deleted item of the relationships the delete item had (other sides) now still has the
|
||||||
|
// relationship Metadata
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author1.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']").doesNotExist());
|
||||||
|
getClient(token).perform(get("/api/core/items/" + author2.getID()))
|
||||||
|
.andExpect(status().is(200))
|
||||||
|
.andExpect(jsonPath("$.metadata['relation.isPublicationOfAuthor']").doesNotExist());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initPublicationAuthorsRelationships() throws SQLException {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
//** GIVEN **
|
||||||
|
//1. A community with one collection.
|
||||||
|
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||||
|
.withName("Parent Community")
|
||||||
|
.build();
|
||||||
|
Collection col1 = CollectionBuilder
|
||||||
|
.createCollection(context, parentCommunity).withName("Collection 1").build();
|
||||||
|
|
||||||
|
author1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Author1")
|
||||||
|
.withIssueDate("2017-10-17")
|
||||||
|
.withAuthor("Smith, Donald")
|
||||||
|
.withPersonIdentifierLastName("Smith")
|
||||||
|
.withPersonIdentifierFirstName("Donald")
|
||||||
|
.withRelationshipType("Person")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
author2 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Author2")
|
||||||
|
.withIssueDate("2016-02-13")
|
||||||
|
.withAuthor("Smith, Maria")
|
||||||
|
.withRelationshipType("Person")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
publication1 = ItemBuilder.createItem(context, col1)
|
||||||
|
.withTitle("Publication1")
|
||||||
|
.withAuthor("Testy, TEst")
|
||||||
|
.withIssueDate("2015-01-01")
|
||||||
|
.withRelationshipType("Publication")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EntityType publication = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication").build();
|
||||||
|
EntityType person = EntityTypeBuilder.createEntityTypeBuilder(context, "Person").build();
|
||||||
|
|
||||||
|
isAuthorOfPublication = RelationshipTypeBuilder
|
||||||
|
.createRelationshipTypeBuilder(context, publication, person, "isAuthorOfPublication",
|
||||||
|
"isPublicationOfAuthor", 2, null, 0,
|
||||||
|
null).withCopyToLeft(false).withCopyToRight(true).build();
|
||||||
|
|
||||||
|
relationship1 = RelationshipBuilder
|
||||||
|
.createRelationshipBuilder(context, publication1, author1, isAuthorOfPublication).build();
|
||||||
|
relationship2 = RelationshipBuilder
|
||||||
|
.createRelationshipBuilder(context, publication1, author2, isAuthorOfPublication).build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user