Skip to content

Commit ab45e13

Browse files
committed
Merge branch 'Content&ReportFeatures' of https://github.com/UdL-EPS-SoftArch/MyPortfoliosGEIADE-API into Content&ReportFeatures
2 parents 2a113b8 + f91362e commit ab45e13

53 files changed

Lines changed: 2089 additions & 338 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ target/
22
!.mvn/wrapper/maven-wrapper.jar
33
!**/src/main/**/target/
44
!**/src/test/**/target/
5+
/.mvn/
6+
/.tools/
57

68
### STS ###
79
.apt_generated

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# MyPortfolios GEIADE API
22

3+
## Run locally
4+
5+
On Windows PowerShell, use the Maven wrapper included in this repository:
6+
7+
```powershell
8+
.\mvnw.cmd spring-boot:run
9+
```
10+
11+
If you prefer a global Maven installation, `mvn spring-boot:run` also works once `mvn` is available on your `PATH`.
12+
313
Template for a Spring Boot project including Spring REST, HATEOAS, JPA, etc. Additional details: [HELP.md](HELP.md)
414

515
[![Open Issues](https://img.shields.io/github/issues-raw/UdL-EPS-SoftArch/MyPortfoliosGEIADE-API?logo=github)](https://github.com/orgs/UdL-EPS-SoftArch/projects/28)

mvnw.cmd

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import org.springframework.beans.factory.annotation.Value;
77
import org.springframework.context.annotation.Configuration;
88
import jakarta.annotation.PostConstruct;
9-
9+
import cat.udl.eps.softarch.demo.domain.Admin;
10+
import cat.udl.eps.softarch.demo.domain.Creator;
11+
import cat.udl.eps.softarch.demo.domain.Profile;
1012
import java.time.ZonedDateTime;
1113
import java.util.Arrays;
1214

@@ -27,33 +29,62 @@ public DBInitialization(UserRepository userRepository, RecordRepository recordRe
2729
}
2830

2931
@PostConstruct
30-
public void initializeDatabase() {
31-
// Default user
32-
if (!userRepository.existsById("demo")) {
32+
public void initializeDatabase() {
33+
34+
35+
if (!userRepository.existsById("demo")) {
36+
User user = new User();
37+
user.setEmail("demo@sample.app");
38+
user.setId("demo");
39+
user.setPassword(defaultPassword);
40+
user.encodePassword();
41+
userRepository.save(user);
42+
}
43+
44+
if (!userRepository.existsById("admin")) {
45+
Admin admin = new Admin();
46+
admin.setEmail("admin@sample.app");
47+
admin.setId("admin");
48+
admin.setPassword(defaultPassword);
49+
admin.encodePassword();
50+
userRepository.save(admin);
51+
}
52+
53+
if (!userRepository.existsById("creator")) {
54+
Creator creator = new Creator();
55+
creator.setEmail("seed-creator@sample.app");
56+
creator.setId("creator");
57+
creator.setPassword(defaultPassword);
58+
creator.encodePassword();
59+
creator.setEnabled(true);
60+
Profile profile = new Profile();
61+
profile.setDescription("");
62+
profile.setVisibility(Profile.Visibility.PRIVATE);
63+
creator.setProfile(profile);
64+
userRepository.save(creator);
65+
}
66+
67+
// ======================
68+
// 🧪 TEST DATA (tu lógica)
69+
// ======================
70+
if (Arrays.asList(activeProfiles.split(",")).contains("test")) {
71+
72+
if (!userRepository.existsById("test")) {
3373
User user = new User();
34-
user.setEmail("demo@sample.app");
35-
user.setId("demo");
74+
user.setEmail("test@sample.app");
75+
user.setId("test");
3676
user.setPassword(defaultPassword);
3777
user.encodePassword();
38-
userRepository.save(user);
39-
}
40-
if (Arrays.asList(activeProfiles.split(",")).contains("test")) {
41-
// Testing instances
42-
if (!userRepository.existsById("test")) {
43-
User user = new User();
44-
user.setEmail("test@sample.app");
45-
user.setId("test");
46-
user.setPassword(defaultPassword);
47-
user.encodePassword();
48-
user = userRepository.save(user);
49-
cat.udl.eps.softarch.demo.domain.Record record = new Record();
50-
record.setName("My test record");
51-
record.setDescription("A record used for testing purposes, nothing more, nothing less...");
52-
record.setCreated(ZonedDateTime.now());
53-
record.setModified(record.getCreated());
54-
record.setOwnedBy(user);
55-
recordRepository.save(record);
56-
}
78+
user = userRepository.save(user);
79+
80+
Record record = new Record();
81+
record.setName("My test record");
82+
record.setDescription("A record used for testing purposes...");
83+
record.setCreated(ZonedDateTime.now());
84+
record.setModified(record.getCreated());
85+
record.setOwnedBy(user);
86+
recordRepository.save(record);
5787
}
5888
}
5989
}
90+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package cat.udl.eps.softarch.demo.config;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.web.bind.MethodArgumentNotValidException;
8+
import org.springframework.web.bind.annotation.ExceptionHandler;
9+
import org.springframework.web.bind.annotation.RestControllerAdvice;
10+
11+
@RestControllerAdvice
12+
public class RestApiExceptionHandler {
13+
14+
@ExceptionHandler(MethodArgumentNotValidException.class)
15+
public ResponseEntity<Map<String, List<Map<String, String>>>> handleMethodArgumentNotValid(
16+
MethodArgumentNotValidException ex) {
17+
List<Map<String, String>> errors = ex.getBindingResult().getFieldErrors().stream()
18+
.map(fe -> Map.of("message", fe.getDefaultMessage() != null ? fe.getDefaultMessage() : ""))
19+
.toList();
20+
return ResponseEntity.badRequest().body(Map.of("errors", errors));
21+
}
22+
}

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

Lines changed: 51 additions & 14 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;
@@ -26,20 +27,56 @@ public class WebSecurityConfig {
2627

2728
@Bean
2829
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
29-
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, "/*/*").authenticated()
35-
.requestMatchers(HttpMethod.PUT, "/*/*").authenticated()
36-
.requestMatchers(HttpMethod.PATCH, "/*/*").authenticated()
37-
.requestMatchers(HttpMethod.DELETE, "/*/*").authenticated()
38-
.anyRequest().permitAll())
39-
.csrf((csrf) -> csrf.disable())
40-
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
41-
.cors((cors) -> cors.configurationSource(corsConfigurationSource()))
42-
.httpBasic((httpBasic) -> httpBasic.realmName("demo"));
30+
http.authorizeHttpRequests((auth) -> auth
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").hasRole("ADMIN")
45+
.requestMatchers(HttpMethod.POST, "/creators").permitAll()
46+
.requestMatchers(HttpMethod.GET, "/creators/{username}").permitAll()
47+
.requestMatchers(HttpMethod.PUT, "/creators/{username}").hasRole("ADMIN")
48+
.requestMatchers(HttpMethod.PUT, "/creators/*/profile").authenticated()
49+
.requestMatchers(HttpMethod.POST, "/creators/*").hasRole("ADMIN")
50+
51+
// Projects
52+
.requestMatchers(HttpMethod.GET, "/projects/search/findByVisibility").permitAll()
53+
.requestMatchers(HttpMethod.GET, "/projects/search/findByPortfolioAndVisibility").permitAll()
54+
.requestMatchers(HttpMethod.GET, "/projects/**").authenticated()
55+
.requestMatchers(HttpMethod.POST, "/projects").authenticated()
56+
.requestMatchers(HttpMethod.PUT, "/projects/*").authenticated()
57+
.requestMatchers(HttpMethod.PATCH, "/projects/*").authenticated()
58+
.requestMatchers(HttpMethod.DELETE, "/projects/*").authenticated()
59+
// Portfolios
60+
.requestMatchers(HttpMethod.GET, "/portfolios/search/findByVisibility").permitAll()
61+
.requestMatchers(HttpMethod.GET, "/portfolios/*/owner").permitAll()
62+
.requestMatchers(HttpMethod.GET, "/portfolios/**").authenticated()
63+
// Tags
64+
.requestMatchers(HttpMethod.POST, "/tags").hasRole("ADMIN")
65+
.requestMatchers(HttpMethod.DELETE, "/tags/*").hasRole("ADMIN")
66+
// Profile
67+
.requestMatchers(HttpMethod.POST, "/profiles").hasRole("CREATOR")
68+
// Default
69+
70+
.requestMatchers(HttpMethod.POST, "/*/*").authenticated()
71+
.requestMatchers(HttpMethod.PUT, "/*/*").authenticated()
72+
.requestMatchers(HttpMethod.PATCH, "/*/*").authenticated()
73+
.requestMatchers(HttpMethod.DELETE, "/*/*").authenticated()
74+
.anyRequest().permitAll())
75+
.csrf(AbstractHttpConfigurer::disable)
76+
.sessionManagement((session) ->
77+
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
78+
.cors((cors) -> cors.configurationSource(corsConfigurationSource()))
79+
.httpBasic((httpBasic) -> httpBasic.realmName("demo"));
4380
return http.build();
4481
}
4582

0 commit comments

Comments
 (0)