Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cat.udl.eps.softarch.demo.config;
import cat.udl.eps.softarch.demo.domain.Admin;
import cat.udl.eps.softarch.demo.domain.User;
import cat.udl.eps.softarch.demo.repository.AdminRepository;
import cat.udl.eps.softarch.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
Expand All @@ -13,9 +15,11 @@ public class DBInitialization {
@Value("${spring.profiles.active:}")
private String activeProfiles;
private final UserRepository userRepository;
private final AdminRepository adminRepository;

public DBInitialization(UserRepository userRepository) {
public DBInitialization(UserRepository userRepository, AdminRepository adminRepository) {
this.userRepository = userRepository;
this.adminRepository = adminRepository;
}

@PostConstruct
Expand All @@ -39,6 +43,15 @@ public void initializeDatabase() {
user.encodePassword();
userRepository.save(user);
}
// Admin user for testing
if (!adminRepository.existsById("admin")) {
Admin admin = new Admin();
admin.setEmail("admin@sample.app");
admin.setId("admin");
admin.setPassword(defaultPassword);
admin.encodePassword();
adminRepository.save(admin);
}
}
}
}
26 changes: 26 additions & 0 deletions src/main/java/cat/udl/eps/softarch/demo/domain/Admin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cat.udl.eps.softarch.demo.domain;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.Entity;
import jakarta.persistence.Transient;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;

import java.util.Collection;

@Entity
@Data
@EqualsAndHashCode(callSuper = true)
public class Admin extends User {

@Override
@Transient
@JsonValue(value = false)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cat.udl.eps.softarch.demo.handler;

import cat.udl.eps.softarch.demo.domain.Admin;
import cat.udl.eps.softarch.demo.repository.AdminRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.rest.core.annotation.HandleAfterCreate;
import org.springframework.data.rest.core.annotation.HandleAfterDelete;
import org.springframework.data.rest.core.annotation.HandleAfterLinkSave;
import org.springframework.data.rest.core.annotation.HandleAfterSave;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.HandleBeforeDelete;
import org.springframework.data.rest.core.annotation.HandleBeforeLinkSave;
import org.springframework.data.rest.core.annotation.HandleBeforeSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.stereotype.Component;

@Component
@RepositoryEventHandler
public class AdminEventHandler {

final Logger logger = LoggerFactory.getLogger(Admin.class);

final AdminRepository adminRepository;

public AdminEventHandler(AdminRepository adminRepository) {
this.adminRepository = adminRepository;
}

@HandleBeforeCreate
public void handleAdminPreCreate(Admin admin) {
logger.info("Before creating: {}", admin.toString());
}

@HandleBeforeSave
public void handleAdminPreSave(Admin admin) {
logger.info("Before updating: {}", admin.toString());
}

@HandleBeforeDelete
public void handleAdminPreDelete(Admin admin) {
logger.info("Before deleting: {}", admin.toString());
}

@HandleBeforeLinkSave
public void handleAdminPreLinkSave(Admin admin, Object o) {
logger.info("Before linking: {} to {}", admin.toString(), o.toString());
}

@HandleAfterCreate
public void handleAdminPostCreate(Admin admin) {
logger.info("After creating: {}", admin.toString());
admin.encodePassword();
adminRepository.save(admin);
}

@HandleAfterSave
public void handleAdminPostSave(Admin admin) {
logger.info("After updating: {}", admin.toString());
if (admin.isPasswordReset()) {
admin.encodePassword();
}
adminRepository.save(admin);
}

@HandleAfterDelete
public void handleAdminPostDelete(Admin admin) {
logger.info("After deleting: {}", admin.toString());
}

@HandleAfterLinkSave
public void handleAdminPostLinkSave(Admin admin, Object o) {
logger.info("After linking: {} to {}", admin.toString(), o.toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cat.udl.eps.softarch.demo.handler;

import cat.udl.eps.softarch.demo.domain.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Component
@RepositoryEventHandler
public class CategoryEventHandler {

final Logger logger = LoggerFactory.getLogger(Category.class);

@HandleBeforeCreate
public void handleCategoryPreCreate(Category category) throws AccessDeniedException {
logger.info("Before creating category: {}", category.toString());

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication == null || !authentication.isAuthenticated()) {
throw new AccessDeniedException("Authentication required to create categories");
}

boolean isAdmin = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.anyMatch(role -> role.equals("ROLE_ADMIN"));

if (!isAdmin) {
logger.warn("User {} attempted to create category without admin privileges",
authentication.getName());
throw new AccessDeniedException("Only administrators can create categories");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package cat.udl.eps.softarch.demo.repository;

import cat.udl.eps.softarch.demo.domain.Admin;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource
public interface AdminRepository extends CrudRepository<Admin, String>, PagingAndSortingRepository<Admin, String> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import cat.udl.eps.softarch.demo.domain.Admin;
import cat.udl.eps.softarch.demo.domain.User;
import cat.udl.eps.softarch.demo.repository.AdminRepository;
import cat.udl.eps.softarch.demo.repository.UserRepository;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
Expand All @@ -28,6 +30,9 @@ public class RegisterStepDefs {
@Autowired
private UserRepository userRepository;

@Autowired
private AdminRepository adminRepository;

@Given("^There is no registered user with username \"([^\"]*)\"$")
public void thereIsNoRegisteredUserWithUsername(String user) {
assertFalse(userRepository.existsById(user), "User \"" + user + "\"shouldn't exist");
Expand All @@ -45,6 +50,18 @@ public void thereIsARegisteredUserWithUsernameAndPasswordAndEmail(String usernam
}
}

@Given("^There is a registered admin with username \"([^\"]*)\" and password \"([^\"]*)\" and email \"([^\"]*)\"$")
public void thereIsARegisteredAdminWithUsernameAndPasswordAndEmail(String username, String password, String email) {
if (!adminRepository.existsById(username)) {
Admin admin = new Admin();
admin.setEmail(email);
admin.setId(username);
admin.setPassword(password);
admin.encodePassword();
adminRepository.save(admin);
}
}

@And("^I can login with username \"([^\"]*)\" and password \"([^\"]*)\"$")
public void iCanLoginWithUsernameAndPassword(String username, String password) throws Throwable {
AuthenticationStepDefs.currentUsername = username;
Expand Down
26 changes: 13 additions & 13 deletions src/test/resources/features/Category.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ Feature: Register Category
I want to register categories and manage them

Background:
Given There is a registered user with username "demo" and password "password" and email "demo@email.org"
Given There is a registered admin with username "admin" and password "password" and email "admin@sample.app"
And There is a registered user with username "demo" and password "password" and email "demo@email.org"

Scenario: Register category successfully
Given There is no registered category with name "Sweet"
And I login as "demo" with password "password"
And I'm logged in as admin
When I register a new category with name "Sweet" and description "The sweetest products"
Then The response code is 201
And It has been created a category with name "Sweet" and description "The sweetest products"
And I can retrieve the category with name "Sweet"

Scenario: Register existing category name
Given There is a registered category with name "Sweet" and description "The sweetest products"
And I login as "demo" with password "password"
And I'm logged in as admin
When I register a new category with name "Sweet" and description "The sweet paradise for everyone"
Then The response code is 409
And The category description remains "The sweetest products"
Expand All @@ -29,36 +30,35 @@ Feature: Register Category
And It has not been created a category with name "Coffee"

Scenario: Register category with empty name
And I login as "demo" with password "password"
And I'm logged in as admin
When I register a new category with name "" and description "Premium coffee products"
Then The response code is 400
And The error message is "must not be blank"
And It has not been created a category with name ""

Scenario: Register category with empty description
And I login as "demo" with password "password"
And I'm logged in as admin
When I register a new category with name "Pastries" and description ""
Then The response code is 400
And The error message is "must not be blank"
And It has not been created a category with name "Pastries"

Scenario: Register category with name too long
And I login as "demo" with password "password"
And I'm logged in as admin
When I register a new category with name "ThisCategoryNameIsWayTooLongAndExceedsTheMaximumAllowedLengthForCategoryNames" and description "Delicious desserts"
Then The response code is 400
And The error message is "length must be between 1 and 50"
And It has not been created a category with name "ThisCategoryNameIsWayTooLongAndExceedsTheMaximumAllowedLengthForCategoryNames"

Scenario: Register category with description too long
And I login as "demo" with password "password"
And I'm logged in as admin
When I register a new category with name "Beverages" and description "This description is way too long and exceeds the maximum allowed length for category descriptions in our system which should be limited to a reasonable number of characters to maintain data integrity and user experience standards across the platform and ensure that all descriptions are concise and to the point."
Then The response code is 400
And The error message is "length must be between 1 and 255"
And It has not been created a category with name "Beverages"

# TODO: need to implement the Admin user and use it for all previous scenarios, keeping the regular user for this one
# Scenario: Register category without admin privileges
# And I login as "demo" with password "password"
# When I register a new category with name "Cakes" and description "Delicious homemade cakes"
# Then The response code is 403
# And It has not been created a category with name "Cakes"
Scenario: Register category without admin privileges
Given I login as "demo" with password "password"
When I register a new category with name "Cakes" and description "Delicious homemade cakes"
Then The response code is 403
And It has not been created a category with name "Cakes"