Skip to content

Commit dafd9ae

Browse files
committed
Merge branch 'dev'
2 parents f6ee887 + f871292 commit dafd9ae

30 files changed

+968
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package br.com.catalog.models;
2+
3+
import br.com.catalog.models.abstract_entity.AuditableEntity;
4+
import br.com.catalog.models.enums.Status;
5+
import jakarta.persistence.*;
6+
import jakarta.validation.constraints.NotBlank;
7+
import lombok.*;
8+
9+
import java.util.List;
10+
11+
@Getter
12+
@Setter
13+
@ToString
14+
@RequiredArgsConstructor
15+
@AllArgsConstructor
16+
@Builder
17+
@Entity
18+
@Table(name = "tb_brand")
19+
public class Brand extends AuditableEntity {
20+
@Id
21+
@GeneratedValue(strategy = GenerationType.IDENTITY)
22+
private Long id;
23+
24+
@Column(nullable = false, unique = true, length = 50)
25+
@NotBlank(message = "O nome é obrigatório")
26+
private String name;
27+
28+
@OneToMany(mappedBy = "brand", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
29+
@ToString.Exclude
30+
private List<Product> products;
31+
32+
@Override
33+
protected void onStatusChange(Status newStatus) {
34+
this.products.forEach(product -> product.setStatus(newStatus));
35+
}
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package br.com.catalog.models;
2+
3+
import br.com.catalog.models.abstract_entity.AuditableEntity;
4+
import jakarta.persistence.*;
5+
import jakarta.validation.constraints.DecimalMin;
6+
import jakarta.validation.constraints.Digits;
7+
import jakarta.validation.constraints.Min;
8+
import jakarta.validation.constraints.NotBlank;
9+
import lombok.*;
10+
11+
import java.math.BigDecimal;
12+
13+
@Getter
14+
@Setter
15+
@ToString
16+
@RequiredArgsConstructor
17+
@AllArgsConstructor
18+
@Builder
19+
@Entity
20+
@Table(name = "tb_product")
21+
public class Product extends AuditableEntity {
22+
@Id
23+
@GeneratedValue(strategy = GenerationType.IDENTITY)
24+
private Long id;
25+
26+
@Column(nullable = false, unique = true, length = 50)
27+
@NotBlank(message = "O nome é obrigatório")
28+
private String name;
29+
30+
@ManyToOne
31+
@JoinColumn(name = "brand_id", nullable = false)
32+
private Brand brand;
33+
34+
@Column(nullable = false, columnDefinition = "TEXT")
35+
@NotBlank(message = "A descrição do produto é obrigatória")
36+
private String description;
37+
38+
@Column(nullable = false, precision = 5, scale = 2)
39+
@DecimalMin(value = "0.0", inclusive = false, message = "O preço do produto deve ser maior que zero")
40+
@Digits(integer = 10, fraction = 2, message = "O preço do produto deve ter no máximo 10 dígitos inteiros e 2 dígitos decimais")
41+
private BigDecimal price;
42+
43+
@Column(nullable = false)
44+
@Min(value = 0, message = "A quantidade em estoque do produto não pode ser negativa")
45+
private int stockQuantity;
46+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package br.com.catalog.models;
2+
3+
import br.com.catalog.models.abstract_entity.AuditableEntity;
4+
import br.com.catalog.models.enums.Status;
5+
import br.com.catalog.models.enums.UserRole;
6+
import jakarta.persistence.*;
7+
import lombok.*;
8+
import org.springframework.security.core.GrantedAuthority;
9+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
10+
import org.springframework.security.core.userdetails.UserDetails;
11+
12+
import java.util.Collection;
13+
import java.util.List;
14+
15+
@Getter
16+
@Setter
17+
@NoArgsConstructor
18+
@AllArgsConstructor
19+
@Builder
20+
@Entity
21+
@Table(name = "tb_user")
22+
public class User extends AuditableEntity implements UserDetails{
23+
@Id
24+
@GeneratedValue(strategy = GenerationType.UUID)
25+
private String id;
26+
@Column(nullable = false, unique = true, length = 50)
27+
private String login;
28+
@Column(nullable = false, length = 50)
29+
private String password;
30+
@Enumerated(EnumType.STRING)
31+
@Column(nullable = false)
32+
private UserRole role;
33+
34+
@Override
35+
public Collection<? extends GrantedAuthority> getAuthorities() {
36+
if (this.role == UserRole.ADMIN)
37+
return List.of(new SimpleGrantedAuthority("ROLE_ADMIN"),
38+
new SimpleGrantedAuthority("ROLE_USER"));
39+
else return List.of(new SimpleGrantedAuthority("ROLE_USER"));
40+
}
41+
42+
@Override
43+
public String getUsername() {
44+
return this.login;
45+
}
46+
47+
@Override
48+
public boolean isAccountNonExpired() {
49+
return this.status != Status.INACTIVE;
50+
}
51+
52+
@Override
53+
public boolean isAccountNonLocked() {
54+
return this.status != Status.DELETED;
55+
}
56+
57+
@Override
58+
public boolean isEnabled() {
59+
return this.status == Status.ACTIVE;
60+
}
61+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package br.com.catalog.models.abstract_entity;
2+
3+
import br.com.catalog.models.enums.Status;
4+
import jakarta.persistence.*;
5+
import lombok.Getter;
6+
import lombok.Setter;
7+
8+
import java.time.LocalDateTime;
9+
10+
@Getter
11+
@Setter
12+
@MappedSuperclass
13+
public abstract class AuditableEntity {
14+
@Enumerated(EnumType.STRING)
15+
@Column(nullable = false)
16+
protected Status status;
17+
18+
@Column(nullable = false, updatable = false)
19+
protected LocalDateTime createdAt;
20+
21+
@Column(nullable = false)
22+
protected LocalDateTime updatedAt;
23+
24+
@PrePersist
25+
protected void onCreate() {
26+
this.createdAt = LocalDateTime.now();
27+
this.updatedAt = LocalDateTime.now();
28+
this.status = Status.ACTIVE;
29+
}
30+
31+
@PreUpdate
32+
protected void onUpdate() {
33+
this.updatedAt = LocalDateTime.now();
34+
}
35+
36+
public void activate() {
37+
this.status = Status.ACTIVE;
38+
this.updatedAt = LocalDateTime.now();
39+
onStatusChange(Status.ACTIVE);
40+
}
41+
42+
public void disable() {
43+
this.status = Status.INACTIVE;
44+
this.updatedAt = LocalDateTime.now();
45+
onStatusChange(Status.INACTIVE);
46+
}
47+
48+
public void delete() {
49+
this.status = Status.DELETED;
50+
this.updatedAt = LocalDateTime.now();
51+
onStatusChange(Status.DELETED);
52+
}
53+
54+
protected void onStatusChange(Status newStatus) {
55+
// TODO Implementar as mudanças necessárias quando o status mudar
56+
};
57+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package br.com.catalog.models.enums;
2+
3+
public enum Status {
4+
ACTIVE,
5+
INACTIVE,
6+
DELETED
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package br.com.catalog.models.enums;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public enum UserRole {
7+
ADMIN("admin"),
8+
USER("user");
9+
10+
private final String role;
11+
12+
UserRole(String role) {
13+
this.role = role;
14+
}
15+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package br.com.catalog.repositories;
2+
3+
import br.com.catalog.models.Brand;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.Pageable;
6+
import org.springframework.data.jpa.repository.JpaRepository;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.stereotype.Repository;
9+
10+
import java.util.Optional;
11+
12+
@Repository
13+
public interface IBrandRepository extends JpaRepository<Brand, Long> {
14+
boolean existsByNameIgnoreCase(String name);
15+
16+
@Query("SELECT b FROM Brand b WHERE LOWER(b.name) = LOWER(:name) AND b.status = 'ACTIVE'")
17+
Optional<Brand> findActiveByNameIgnoreCase(String name);
18+
19+
@Query("SELECT b FROM Brand b WHERE b.id = :id AND b.status = 'ACTIVE'")
20+
Optional<Brand> findActiveById(Long id);
21+
22+
@Query("SELECT b FROM Brand b WHERE b.status = 'ACTIVE'")
23+
Page<Brand> findAllActive(Pageable pageable);
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package br.com.catalog.repositories;
2+
3+
import br.com.catalog.models.Product;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.Pageable;
6+
import org.springframework.data.jpa.repository.JpaRepository;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.stereotype.Repository;
9+
10+
import java.util.Optional;
11+
12+
@Repository
13+
public interface IProductRepository extends JpaRepository<Product, Long>{
14+
boolean existsByNameIgnoreCase(String name);
15+
16+
@Query("SELECT p FROM Product p WHERE LOWER(p.name) = LOWER(:name) AND p.status = 'ACTIVE'")
17+
Optional<Product> findActiveByNameIgnoreCase(String name);
18+
19+
@Query("SELECT p FROM Product p WHERE p.id = :id AND p.status = 'ACTIVE'")
20+
Optional<Product> findActiveById(Long id);
21+
22+
@Query("SELECT p FROM Product p WHERE p.status = 'ACTIVE'")
23+
Page<Product> findAllActive(Pageable pageable);
24+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package br.com.catalog.repositories;
2+
3+
import br.com.catalog.models.User;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.security.core.userdetails.UserDetails;
6+
import org.springframework.stereotype.Repository;
7+
8+
@Repository
9+
public interface IUserRepository extends JpaRepository<User, String> {
10+
UserDetails findByLogin(String login);
11+
boolean existsByLogin(String login);
12+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package br.com.catalog.security;
2+
3+
import br.com.catalog.repositories.IUserRepository;
4+
import org.springframework.security.core.userdetails.UserDetails;
5+
import org.springframework.security.core.userdetails.UserDetailsService;
6+
import org.springframework.security.core.userdetails.UsernameNotFoundException;
7+
import org.springframework.stereotype.Service;
8+
9+
@Service
10+
public class AuthorizationService implements UserDetailsService {
11+
private final IUserRepository userRepository;
12+
13+
public AuthorizationService(IUserRepository userRepository) {
14+
this.userRepository = userRepository;
15+
}
16+
17+
@Override
18+
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
19+
return userRepository.findByLogin(username);
20+
}
21+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package br.com.catalog.security;
2+
3+
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
4+
5+
import org.springframework.http.HttpMethod;
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
import org.springframework.security.authentication.AuthenticationManager;
9+
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
10+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
11+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
12+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
13+
import org.springframework.security.crypto.password.PasswordEncoder;
14+
import org.springframework.security.web.SecurityFilterChain;
15+
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
16+
17+
@Configuration
18+
@EnableWebSecurity
19+
public class SecurityConfig {
20+
private final SecurityFilter securityFilter;
21+
22+
public SecurityConfig(SecurityFilter securityFilter) {
23+
this.securityFilter = securityFilter;
24+
}
25+
26+
@Bean
27+
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
28+
return httpSecurity
29+
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
30+
.authorizeHttpRequests(authorize -> authorize
31+
.requestMatchers(HttpMethod.POST, "/auth/*").permitAll()
32+
.requestMatchers(HttpMethod.GET, "/api/v1/**").permitAll()
33+
.requestMatchers("/api/admin/**").hasAuthority("ADMIN")
34+
.anyRequest().authenticated()
35+
)
36+
.csrf(csrf -> csrf.disable())
37+
.addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
38+
.build();
39+
}
40+
41+
@Bean
42+
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
43+
return authenticationConfiguration.getAuthenticationManager();
44+
}
45+
46+
@Bean
47+
public PasswordEncoder passwordEncoder(){
48+
return new BCryptPasswordEncoder();
49+
}
50+
}

0 commit comments

Comments
 (0)