Skip to content

Commit c0ce821

Browse files
authored
Merge pull request #16 from UdL-EPS-SoftArch/userEntity
User entity
2 parents 930f491 + 173ee7c commit c0ce821

34 files changed

Lines changed: 974 additions & 300 deletions

src/main/java/cat/udl/eps/softarch/demo/config/WebSecurityConfig.java

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
1111
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
1212
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
13+
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
1314
import org.springframework.security.config.http.SessionCreationPolicy;
1415
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
1516
import org.springframework.security.web.SecurityFilterChain;
@@ -27,24 +28,44 @@ public class WebSecurityConfig {
2728
@Bean
2829
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
2930
http.authorizeHttpRequests((auth) -> auth
30-
.requestMatchers(HttpMethod.GET, "/identity").authenticated()
31-
.requestMatchers(HttpMethod.GET, "/users").authenticated()
32-
.requestMatchers(HttpMethod.POST, "/users").anonymous()
33-
.requestMatchers(HttpMethod.POST, "/users/*").denyAll()
34-
.requestMatchers(HttpMethod.POST, "/projects").authenticated()
35-
.requestMatchers(HttpMethod.PUT, "/projects/*").authenticated()
36-
.requestMatchers(HttpMethod.DELETE, "/projects/*").authenticated()
37-
.requestMatchers(HttpMethod.POST, "/*/*").authenticated()
38-
.requestMatchers(HttpMethod.PUT, "/*/*").authenticated()
39-
.requestMatchers(HttpMethod.PATCH, "/*/*").authenticated()
40-
.requestMatchers(HttpMethod.DELETE, "/*/*").authenticated()
41-
.requestMatchers(HttpMethod.GET, "/portfolios/search/findByVisibility").permitAll()
42-
.requestMatchers(HttpMethod.GET, "/portfolios/**").authenticated()
43-
.anyRequest().permitAll())
44-
.csrf((csrf) -> csrf.disable())
45-
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
46-
.cors((cors) -> cors.configurationSource(corsConfigurationSource()))
47-
.httpBasic((httpBasic) -> httpBasic.realmName("demo"));
31+
.requestMatchers(HttpMethod.GET, "/identity").authenticated()
32+
// Users
33+
.requestMatchers(HttpMethod.GET, "/users").authenticated()
34+
.requestMatchers(HttpMethod.POST, "/users").anonymous()
35+
.requestMatchers(HttpMethod.GET, "/users/{username}").anonymous()
36+
.requestMatchers(HttpMethod.POST, "/users/*").denyAll()
37+
//Admins
38+
.requestMatchers(HttpMethod.GET, "/admins").hasRole("ADMIN")
39+
.requestMatchers(HttpMethod.POST, "/admins").hasRole("ADMIN")
40+
.requestMatchers(HttpMethod.GET, "/admins/{username}").hasRole("ADMIN")
41+
.requestMatchers(HttpMethod.POST, "/admins/*/suspend").hasRole("ADMIN")
42+
.requestMatchers(HttpMethod.POST, "/admins/*").denyAll()
43+
//Creators
44+
.requestMatchers(HttpMethod.GET, "/creators").permitAll()
45+
.requestMatchers(HttpMethod.POST, "/creators").permitAll()
46+
.requestMatchers(HttpMethod.GET, "/creators/{username}").permitAll()
47+
.requestMatchers(HttpMethod.PUT, "/creators/{username}").hasRole("ADMIN")
48+
.requestMatchers(HttpMethod.POST, "/creators/*").hasRole("ADMIN")
49+
//Projects
50+
.requestMatchers(HttpMethod.POST, "/projects").authenticated()
51+
.requestMatchers(HttpMethod.PUT, "/projects/*").authenticated()
52+
.requestMatchers(HttpMethod.DELETE, "/projects/*").authenticated()
53+
//Portfolios
54+
.requestMatchers(HttpMethod.GET, "/portfolios/search/findByVisibility").permitAll()
55+
.requestMatchers(HttpMethod.GET, "/portfolios/**").authenticated()
56+
//Profile
57+
.requestMatchers(HttpMethod.POST, "/profiles").hasRole("CREATOR")
58+
//Default
59+
.requestMatchers(HttpMethod.POST, "/*/*").authenticated()
60+
.requestMatchers(HttpMethod.PUT, "/*/*").authenticated()
61+
.requestMatchers(HttpMethod.PATCH, "/*/*").authenticated()
62+
.requestMatchers(HttpMethod.DELETE, "/*/*").authenticated()
63+
.anyRequest().permitAll())
64+
.csrf(AbstractHttpConfigurer::disable)
65+
.sessionManagement((session) ->
66+
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
67+
.cors((cors) -> cors.configurationSource(corsConfigurationSource()))
68+
.httpBasic((httpBasic) -> httpBasic.realmName("demo"));
4869
return http.build();
4970
}
5071

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package cat.udl.eps.softarch.demo.controller;
2+
3+
import cat.udl.eps.softarch.demo.domain.Creator;
4+
import cat.udl.eps.softarch.demo.repository.CreatorRepository;
5+
import org.springframework.data.rest.webmvc.RepositoryRestController;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.security.access.prepost.PreAuthorize;
8+
import org.springframework.web.bind.annotation.*;
9+
import org.springframework.web.server.ResponseStatusException;
10+
import org.springframework.http.HttpStatus;
11+
12+
@RepositoryRestController
13+
public class CustomCreatorController {
14+
15+
private CreatorRepository creatorRepository;
16+
public CustomCreatorController(CreatorRepository creatorRepository){
17+
this.creatorRepository = creatorRepository;
18+
}
19+
20+
// PUT creators/username
21+
@PutMapping("/creators/{username}/profile")
22+
@PreAuthorize("@CreatorSecurity.isOwner(principal.username, #username)")
23+
public ResponseEntity<Creator> updateCreator(@PathVariable String username,
24+
@RequestBody Creator updated) {
25+
26+
Creator creator = creatorRepository.findById(username)
27+
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
28+
29+
if (updated.getProfile() != null) {
30+
creator.setProfile(updated.getProfile());
31+
}
32+
if(updated.getEmail() !=null){
33+
creator.setEmail(updated.getEmail());
34+
}
35+
36+
creatorRepository.save(creator);
37+
return ResponseEntity.ok(creator);
38+
}
39+
@PreAuthorize("hasRole('ADMIN')")
40+
@PostMapping("/creators/{username}/suspend")
41+
public ResponseEntity<Creator> suspendCreator (@PathVariable String username) {
42+
43+
Creator creator = creatorRepository.findById(username)
44+
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
45+
creator.suspendCreator();
46+
creatorRepository.save(creator);
47+
48+
return ResponseEntity.ok(creator);
49+
50+
51+
}
52+
53+
54+
55+
56+
57+
58+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package cat.udl.eps.softarch.demo.controller;
2+
import cat.udl.eps.softarch.demo.repository.ProfileRepository;
3+
import cat.udl.eps.softarch.demo.domain.Profile;
4+
import org.springframework.data.rest.webmvc.RepositoryRestController;
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.security.access.prepost.PreAuthorize;
8+
import org.springframework.web.bind.annotation.GetMapping;
9+
import org.springframework.web.bind.annotation.PathVariable;
10+
import org.springframework.web.bind.annotation.PutMapping;
11+
import org.springframework.web.bind.annotation.RequestBody;
12+
import org.springframework.web.bind.annotation.RequestMapping;
13+
import org.springframework.web.bind.annotation.ResponseBody;
14+
import org.springframework.web.server.ResponseStatusException;
15+
16+
import java.util.List;
17+
18+
@RepositoryRestController("customProfileController")
19+
public class CustomProfileController {
20+
21+
private final ProfileRepository profileRepository;
22+
23+
public CustomProfileController(ProfileRepository profileRepository) {
24+
this.profileRepository = profileRepository;
25+
}
26+
27+
// PUT /profiles/id
28+
@PutMapping("/products/{id}")
29+
@PreAuthorize("@profileSecurity.isOwner(principal.username, #id)")
30+
@ResponseBody
31+
public ResponseEntity<Profile> updateProfile(@PathVariable Long id,
32+
@RequestBody Profile updatedProfile) {
33+
Profile profile = profileRepository.findById(id)
34+
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
35+
36+
if (updatedProfile.getDescription() != null) {
37+
profile.setDescription(updatedProfile.getDescription());
38+
}
39+
if (updatedProfile.getVisibility() != null) {
40+
profile.setVisibility(updatedProfile.getVisibility());
41+
}
42+
43+
profileRepository.save(profile);
44+
45+
return ResponseEntity.ok(profile);
46+
}
47+
48+
@GetMapping("/products/{id}")
49+
@PreAuthorize("@profileSecurity.isOwner(principal.username, #id) or @profileSecurity.isPublic(#id)")
50+
@ResponseBody
51+
public ResponseEntity<Profile> getProfile(@PathVariable Long id) {
52+
Profile profile = profileRepository.findById(id)
53+
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
54+
return ResponseEntity.ok(profile);
55+
}
56+
57+
58+
@GetMapping("/products/")
59+
@ResponseBody
60+
public ResponseEntity<List<Profile>> getPublicProfiles() {
61+
List<Profile> publicProfiles = ((List<Profile>) profileRepository.findAll())
62+
.stream()
63+
.filter(profile -> profile.getVisibility()==Profile.Visibility.PUBLIC)
64+
.toList();
65+
return ResponseEntity.ok(publicProfiles);
66+
}
67+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package cat.udl.eps.softarch.demo.domain;
2+
3+
import java.util.Collection;
4+
5+
import org.springframework.security.core.GrantedAuthority;
6+
import org.springframework.security.core.authority.AuthorityUtils;
7+
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
import com.fasterxml.jackson.annotation.JsonValue;
10+
11+
import jakarta.persistence.DiscriminatorValue;
12+
import jakarta.persistence.Entity;
13+
import lombok.Data;
14+
import lombok.EqualsAndHashCode;
15+
16+
@Entity
17+
@Data
18+
@DiscriminatorValue("ADMIN")
19+
@EqualsAndHashCode(callSuper = true)
20+
public class Admin extends User {
21+
22+
@Override
23+
@JsonValue(value = false)
24+
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
25+
public Collection<? extends GrantedAuthority> getAuthorities() {
26+
return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
27+
}
28+
29+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package cat.udl.eps.softarch.demo.domain;
2+
3+
import java.util.Collection;
4+
5+
import org.springframework.security.core.GrantedAuthority;
6+
import org.springframework.security.core.authority.AuthorityUtils;
7+
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
import com.fasterxml.jackson.annotation.JsonValue;
10+
11+
import jakarta.persistence.CascadeType;
12+
import jakarta.persistence.DiscriminatorValue;
13+
import jakarta.persistence.Entity;
14+
import jakarta.persistence.JoinColumn;
15+
import jakarta.persistence.OneToOne;
16+
import lombok.EqualsAndHashCode;
17+
18+
@Entity
19+
@DiscriminatorValue("CREATOR")
20+
@EqualsAndHashCode(callSuper = true)
21+
public class Creator extends User {
22+
23+
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
24+
@JoinColumn(name = "profile_id", unique = true)
25+
private Profile profile;
26+
27+
@Override
28+
@JsonValue(false)
29+
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
30+
public Collection<? extends GrantedAuthority> getAuthorities() {
31+
return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_CREATOR");
32+
}
33+
34+
public void suspendCreator() {
35+
this.enabled = false;
36+
}
37+
38+
public void setProfile(Profile profile) {
39+
this.profile = profile;
40+
if (profile != null) {
41+
profile.setCreator(this);
42+
}
43+
}
44+
45+
public Profile getProfile() {
46+
return profile;
47+
}
48+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package cat.udl.eps.softarch.demo.domain;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Data;
5+
6+
@Entity
7+
@Data
8+
public class Profile {
9+
10+
@Id
11+
@GeneratedValue(strategy = GenerationType.IDENTITY)
12+
private Long id;
13+
14+
public enum Visibility {
15+
PUBLIC,
16+
PRIVATE
17+
}
18+
19+
private String description;
20+
21+
@Enumerated(EnumType.STRING)
22+
private Visibility visibility;
23+
24+
@OneToOne(mappedBy = "profile")
25+
private Creator creator;
26+
27+
public Profile() {}
28+
}

src/main/java/cat/udl/eps/softarch/demo/domain/Tag.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
package cat.udl.eps.softarch.demo.domain;
22

33
import jakarta.persistence.*;
4+
import jakarta.validation.constraints.NotBlank;
45
import lombok.Data;
6+
import lombok.EqualsAndHashCode;
57

68
import java.time.ZonedDateTime;
7-
import java.util.HashSet;
8-
import java.util.Set;
99

1010
@Entity
1111
@Data
12-
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "name"))
13-
public class Tag {
12+
@EqualsAndHashCode(callSuper = true)
13+
public class Tag extends UriEntity<Long> {
1414
@Id
1515
@GeneratedValue(strategy = GenerationType.IDENTITY)
1616
private Long id;
1717

18+
@Column(unique = true)
19+
@NotBlank
1820
private String name;
1921

2022
private String description;

0 commit comments

Comments
 (0)