From 7459544218e6b0a6c11a1b8d3f4f10d98e53019b Mon Sep 17 00:00:00 2001 From: David Date: Thu, 19 Mar 2026 17:50:28 +0100 Subject: [PATCH 1/3] Test to check if the Creator is able to asign TAG to its own contents but not to contents from another creators --- .../udl/eps/softarch/demo/domain/Content.java | 19 ++- .../cat/udl/eps/softarch/demo/domain/Tag.java | 4 +- .../demo/steps/TagOwnershipStepDefs.java | 108 ++++++++++++++++++ src/test/resources/features/TagCreate.feature | 6 - src/test/resources/features/TagDelete.feature | 6 - .../resources/features/TagDuplicate.feature | 6 - .../resources/features/TagEmptyName.feature | 6 - .../resources/features/TagManagement.feature | 39 +++++++ 8 files changed, 155 insertions(+), 39 deletions(-) create mode 100644 src/test/java/cat/udl/eps/softarch/demo/steps/TagOwnershipStepDefs.java delete mode 100644 src/test/resources/features/TagCreate.feature delete mode 100644 src/test/resources/features/TagDelete.feature delete mode 100644 src/test/resources/features/TagDuplicate.feature delete mode 100644 src/test/resources/features/TagEmptyName.feature create mode 100644 src/test/resources/features/TagManagement.feature diff --git a/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java b/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java index 2b5fbbfb..3f815f98 100644 --- a/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java +++ b/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java @@ -4,16 +4,9 @@ import com.fasterxml.jackson.annotation.JsonIdentityReference; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; //import jakarta.persistence.JoinColumn; //import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; import lombok.Data; //import lombok.EqualsAndHashCode; /* @@ -36,10 +29,13 @@ public class Content { @Column(nullable = false) private Project project;*/ - /*@ManyToOne + @ManyToMany + private List tags; + + @ManyToOne + @JoinColumn(nullable = false) @JsonIdentityReference(alwaysAsId = true) - @Column(nullable = false) - private User user;*/ + private User user; @OneToMany(mappedBy = "content") @JsonIdentityReference(alwaysAsId = true) @@ -63,5 +59,4 @@ public class Content { @Enumerated(EnumType.STRING) @Column(nullable = false) private Visibility visibility; - } \ No newline at end of file diff --git a/src/main/java/cat/udl/eps/softarch/demo/domain/Tag.java b/src/main/java/cat/udl/eps/softarch/demo/domain/Tag.java index 7fa8f913..675d3ca3 100644 --- a/src/main/java/cat/udl/eps/softarch/demo/domain/Tag.java +++ b/src/main/java/cat/udl/eps/softarch/demo/domain/Tag.java @@ -1,5 +1,6 @@ package cat.udl.eps.softarch.demo.domain; +import com.fasterxml.jackson.annotation.JsonIdentityReference; import jakarta.persistence.*; import lombok.Data; @@ -22,7 +23,4 @@ public class Tag { private ZonedDateTime created; private ZonedDateTime modified; - - //@ManyToMany(mappedBy = "tags") - //private Set contentSet = new HashSet<>(); } diff --git a/src/test/java/cat/udl/eps/softarch/demo/steps/TagOwnershipStepDefs.java b/src/test/java/cat/udl/eps/softarch/demo/steps/TagOwnershipStepDefs.java new file mode 100644 index 00000000..921df7c4 --- /dev/null +++ b/src/test/java/cat/udl/eps/softarch/demo/steps/TagOwnershipStepDefs.java @@ -0,0 +1,108 @@ +package cat.udl.eps.softarch.demo.steps; + +import cat.udl.eps.softarch.demo.domain.Tag; +import cat.udl.eps.softarch.demo.domain.Content; +import cat.udl.eps.softarch.demo.domain.User; +import cat.udl.eps.softarch.demo.domain.Visibility; +import cat.udl.eps.softarch.demo.repository.TagRepository; +import cat.udl.eps.softarch.demo.repository.ContentRepository; +import cat.udl.eps.softarch.demo.repository.UserRepository; + +import io.cucumber.java.en.*; +import jakarta.transaction.Transactional; + +import java.time.ZonedDateTime; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +public class TagOwnershipStepDefs { + + private final StepDefs stepDefs; + private final TagRepository tagRepository; + private final ContentRepository contentRepository; + private final UserRepository userRepository; + + private Tag tag; + private Content content; + + public TagOwnershipStepDefs(StepDefs stepDefs, + TagRepository tagRepository, + ContentRepository contentRepository, + UserRepository userRepository) { + this.stepDefs = stepDefs; + this.tagRepository = tagRepository; + this.contentRepository = contentRepository; + this.userRepository = userRepository; + } + + @Given("there is a content {string} created by {string}") + public void thereIsAContentCreatedBy(String contentName, String username) { + + User user = userRepository.findById(username) + .orElseThrow(() -> new RuntimeException("User not found")); + + content = new Content(); + content.setName(contentName); + content.setUser(user); + content.setCreatedAt(ZonedDateTime.now()); + content.setModifiedAt(ZonedDateTime.now()); + content.setVisibility(Visibility.PUBLIC); + + content = contentRepository.save(content); + } + + @When("I assign the tag {string} to content {string}") + public void iAssignTagToContent(String tagName, String contentName) throws Exception { + + Tag tagEntity = tagRepository.findByName(tagName) + .orElseThrow(() -> new RuntimeException("Tag not found")); + + Content contentEntity = contentRepository.findById(content.getContentId()) + .orElseThrow(() -> new RuntimeException("Content not found")); + + String authenticatedUsername = "creator1"; + + if (!contentEntity.getUser().getUsername().equals(authenticatedUsername)) { + stepDefs.result = stepDefs.mockMvc.perform( + post("/contents/" + contentEntity.getContentId() + "/tags") + .contentType("text/uri-list") + .content("/tags/" + tagEntity.getId()) + .with(user(authenticatedUsername)) + ).andDo(print()) + .andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.status().isForbidden()); + return; + } + + stepDefs.result = stepDefs.mockMvc.perform( + post("/contents/" + contentEntity.getContentId() + "/tags") + .contentType("text/uri-list") + .content("/tags/" + tagEntity.getId()) + .with(user(authenticatedUsername)) + ).andDo(print()) + .andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.status().isNoContent()); + } + + @Then("The response status is {int}") + public void theResponseStatusIs(int status) throws Exception { + stepDefs.result.andExpect( + org.springframework.test.web.servlet.result.MockMvcResultMatchers.status().is(status) + ); + } + + @Then("content {string} should contain tag {string}") + @Transactional + public void contentShouldContainTag(String contentName, String tagName) { + + Content updatedContent = contentRepository.findById(content.getContentId()) + .orElseThrow(() -> new RuntimeException("Content not found")); + + boolean exists = updatedContent.getTags() + .stream() + .anyMatch(t -> t.getName().equals(tagName)); + + assertTrue(exists, "Tag not assigned correctly to content"); + } +} \ No newline at end of file diff --git a/src/test/resources/features/TagCreate.feature b/src/test/resources/features/TagCreate.feature deleted file mode 100644 index 8180d31a..00000000 --- a/src/test/resources/features/TagCreate.feature +++ /dev/null @@ -1,6 +0,0 @@ -Feature: Tag management - - Scenario: Create a new tag - Given there are no tags in the system - When I create a tag with name "Futurist" and description "Content related to the future" - Then Then the tag is created successfully \ No newline at end of file diff --git a/src/test/resources/features/TagDelete.feature b/src/test/resources/features/TagDelete.feature deleted file mode 100644 index 9737bdc3..00000000 --- a/src/test/resources/features/TagDelete.feature +++ /dev/null @@ -1,6 +0,0 @@ -Feature: Tag management - - Scenario: Delete an existing tag - Given there is a tag with name "Futurist" - When I delete the tag with name "Futurist" - Then the tag should not exist in the system \ No newline at end of file diff --git a/src/test/resources/features/TagDuplicate.feature b/src/test/resources/features/TagDuplicate.feature deleted file mode 100644 index 6e11ede7..00000000 --- a/src/test/resources/features/TagDuplicate.feature +++ /dev/null @@ -1,6 +0,0 @@ -Feature: Tag management - -Scenario: Create a duplicated tag -Given there is already a tag with name "Futurist" - When I create a tag with name "Futurist" and description "Content related to the future" -Then the tag should not be stored in the system \ No newline at end of file diff --git a/src/test/resources/features/TagEmptyName.feature b/src/test/resources/features/TagEmptyName.feature deleted file mode 100644 index 74ad0c46..00000000 --- a/src/test/resources/features/TagEmptyName.feature +++ /dev/null @@ -1,6 +0,0 @@ -Feature: Tag management - -Scenario: Create a tag without name -Given there are no tags in the system -When I try to create a tag without a name -Then the tag should not be stored in the system \ No newline at end of file diff --git a/src/test/resources/features/TagManagement.feature b/src/test/resources/features/TagManagement.feature new file mode 100644 index 00000000..35e4a759 --- /dev/null +++ b/src/test/resources/features/TagManagement.feature @@ -0,0 +1,39 @@ +Feature: Tag management + + Scenario: Create a new tag + Given there are no tags in the system + When I create a tag with name "Futurist" and description "Content related to the future" + Then Then the tag is created successfully + + Scenario: Delete an existing tag + Given there is a tag with name "Futurist" + When I delete the tag with name "Futurist" + Then the tag should not exist in the system + + Scenario: Create a duplicated tag + Given there is already a tag with name "Futurist" + When I create a tag with name "Futurist" and description "Content related to the future" + Then the tag should not be stored in the system + + Scenario: Create a tag without name + Given there are no tags in the system + When I try to create a tag without a name + Then the tag should not be stored in the system + + Scenario: Creator assigns tag to their own content + Given There is a registered user with username "creator1" and password "pass" and email "c1@test.com" + And I can login with username "creator1" and password "pass" + And there is a tag with name "Futurist" + And there is a content "Post1" created by "creator1" + When I assign the tag "Futurist" to content "Post1" + Then The response status is 204 + And content "Post1" should contain tag "Futurist" + + Scenario: Creator cannot assign tag to another user's content + Given There is a registered user with username "creator1" and password "pass" and email "c1@test.com" + And There is a registered user with username "creator2" and password "pass" and email "c2@test.com" + And I can login with username "creator1" and password "pass" + And there is a tag with name "Futurist" + And there is a content "Post1" created by "creator2" + When I assign the tag "Futurist" to content "Post1" + Then The response status is 403 From 8a9efa0f31ff5518e404f57d9e85be4978d68945 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 22 Apr 2026 17:58:37 +0200 Subject: [PATCH 2/3] Fixing some bugs with client side --- .../java/cat/udl/eps/softarch/demo/repository/TagRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/cat/udl/eps/softarch/demo/repository/TagRepository.java b/src/main/java/cat/udl/eps/softarch/demo/repository/TagRepository.java index 38a0a75c..2e72a960 100644 --- a/src/main/java/cat/udl/eps/softarch/demo/repository/TagRepository.java +++ b/src/main/java/cat/udl/eps/softarch/demo/repository/TagRepository.java @@ -12,4 +12,5 @@ public interface TagRepository extends CrudRepository { boolean existsById(Long id); boolean existsByName(String name); Optional findByName(String name); + Optional findById(Long id); } From a67d659753d5114ba394e6b66ab5b6537a9c77f8 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 23 Apr 2026 17:51:05 +0200 Subject: [PATCH 3/3] Fixing some bugs with client side --- .../udl/eps/softarch/demo/domain/Content.java | 24 +++++++------------ .../demo/repository/ContentRepository.java | 1 + 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java b/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java index ffda1ea5..edde7ada 100644 --- a/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java +++ b/src/main/java/cat/udl/eps/softarch/demo/domain/Content.java @@ -4,16 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIdentityReference; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; @@ -38,13 +29,16 @@ public class Content { private Project project;*/ @ManyToMany + @JoinTable( + name = "content_tags", + joinColumns = @JoinColumn(name = "content_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id") + ) private List tags; @ManyToOne - @JoinColumn(nullable = false) - @JsonIdentityReference(alwaysAsId = true) - @Column(nullable = false) - private User user;*/ + @JoinColumn(name = "user_id") + private User user; @NotBlank(message = "Name cannot be empty") @Column(unique = true, nullable = false) @@ -57,10 +51,8 @@ public class Content { @Column(length = 100) private String description; - @Column(nullable = false, updatable = false) private ZonedDateTime createdAt; - @Column(nullable = false, updatable = false) private ZonedDateTime modifiedAt; @Enumerated(EnumType.STRING) diff --git a/src/main/java/cat/udl/eps/softarch/demo/repository/ContentRepository.java b/src/main/java/cat/udl/eps/softarch/demo/repository/ContentRepository.java index da77a057..4e354176 100644 --- a/src/main/java/cat/udl/eps/softarch/demo/repository/ContentRepository.java +++ b/src/main/java/cat/udl/eps/softarch/demo/repository/ContentRepository.java @@ -19,6 +19,7 @@ public interface ContentRepository extends CrudRepository findAll(); + List findByTags_Id(Long tagId); //List findByProjectId(Long projectId);