Skip to content
Open
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
2 changes: 1 addition & 1 deletion .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions LibraryLoop/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
services:

mysql:
image: mysql:8.0
container_name: libraryloop-mysql
Expand All @@ -26,9 +25,10 @@ services:
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/libraryloop?useSSL=false&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/libraryloop?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=America/Sao_Paulo
SPRING_DATASOURCE_USERNAME: libraryuser
SPRING_DATASOURCE_PASSWORD: librarypass
JWT_SECRET: iaowhfdoawfhoqui32gho1ubg24ou1ivb24oi
depends_on:
mysql:
condition: service_healthy
Expand Down
37 changes: 25 additions & 12 deletions LibraryLoop/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,25 @@

<dependencies>

<!-- HTTP Client -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>

<<<<<<< HEAD
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>

<!-- Cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -43,13 +56,6 @@
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
=======
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
>>>>>>> origin/main


<!-- Web / REST API -->
<dependency>
Expand All @@ -63,21 +69,21 @@
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<!-- Lombok (getters, setters, builders etc) -->
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>

<!-- JPA (opcional caso queira salvar livros futuramente) -->
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<optional>true</optional>
</dependency>

<!-- MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
Expand All @@ -91,6 +97,13 @@
<scope>test</scope>
</dependency>

<!-- Spring Security Test -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down Expand Up @@ -122,4 +135,4 @@
</plugins>
</build>

</project>
</project>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aqui eu nao entendi oo motivo dessa interface existir. c todos os atributos são opcionais, prq criar uma lei que os obrigue?

Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@

public interface userRepository extends JpaRepository<User, Long> {

Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
Optional<Object> findByUsername(String username);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.LibraryLoop.controller;

import com.example.LibraryLoop.Repository.userRepository;
import com.example.LibraryLoop.dto.user.LoginRequestDTO;
import com.example.LibraryLoop.dto.user.RegisterRequestDTO;
import com.example.LibraryLoop.dto.user.ResponseDTO;
import com.example.LibraryLoop.entity.User;
import com.example.LibraryLoop.security.config.TokenService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {

private final userRepository repository;
private final PasswordEncoder passwordEncoder;
private final TokenService tokenService;

@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequestDTO body) {
User user = this.repository.findByEmail(body.email())
.orElseThrow(() -> new RuntimeException("User not found"));

if (passwordEncoder.matches(body.password(), user.getPassword())) {
String token = this.tokenService.generateToken(user);
return ResponseEntity.ok(new ResponseDTO(user.getUsername(), token));
}
return ResponseEntity.badRequest().build();
}

@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody RegisterRequestDTO body) {

if (this.repository.findByEmail(body.email()).isPresent()) {
return ResponseEntity.badRequest()
.body(Map.of("error", "Já existe um usuário com esse e-mail cadastrado."));
}

if (this.repository.findByUsername(body.username()).isPresent()) {
return ResponseEntity.badRequest()
.body(Map.of("error", "Já existe um usuário com esse username cadastrado."));
}

User newUser = new User();
newUser.setPassword(passwordEncoder.encode(body.password()));
newUser.setEmail(body.email());
newUser.setUsername(body.username());
this.repository.save(newUser);

String token = this.tokenService.generateToken(newUser);
return ResponseEntity.ok(new ResponseDTO(newUser.getUsername(), token));
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esse arquivo mesmo é refatoração, nao ta ruim, é até bom, mas ai tem que ser um PR exclusivo pra isso, pensa no futuro caso vc queira olhar o historico do repo pra achar onde ta as alterações dessa parte. Vc nao acharia

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vdd vou melhorar isso, acabei colocando tudo no mesmo pacote

Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,17 @@ public BookController(BookService bookService) {
this.bookService = bookService;
}

// 🔎 BUSCAR LIVROS
@GetMapping("/search")
public List<BookSearchDTO> searchBooks(
@RequestParam String title,
@RequestParam(defaultValue = "20") int limit
) {
return bookService.searchBooks(title, limit);
}

// 📖 LER LIVRO COMPLETO
@GetMapping("/{id}/read")
public ResponseEntity<BookReadResponse> readBook(@PathVariable Long id) {

String text = bookService.getFullBook(id);

String text = bookService.readBook(id);
return ResponseEntity.ok(new BookReadResponse(id, text));
}

// 📄 PAGINAÇÃO
@GetMapping("/{id}/pages/{page}")
public ResponseEntity<PageResponse> getBookPage(
public ResponseEntity<PageResponse> getBookPage(
@PathVariable Long id,
@PathVariable int page
) {

List<String> pages = bookService.getBookPages(id);

if (page < 0 || page >= pages.size()) {
Expand All @@ -55,23 +41,17 @@ public ResponseEntity<PageResponse> getBookPage(
return ResponseEntity.ok(
new PageResponse(page, pages.size(), pages.get(page))
);
<<<<<<< HEAD
}
}

// 🔎 buscar livros
@GetMapping(value = "/search")
@GetMapping("/search")
public List<BookSearchDTO> searchBooks(
@RequestParam String title,
@RequestParam(defaultValue = "20") int limit) {

return service.searchBooks(title, limit);
=======
return bookService.searchBooks(title, limit);
}

// 🔗 LINK EXTERNO (OPCIONAL)
@GetMapping("/{id}/link")
public ReadLinkDTO getReadLink(@PathVariable String id) {
return bookService.getReadLink(id);
>>>>>>> origin/main
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mesmo BO de refatoração

Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ public BookSearchDTO(
Integer editionCount,
List<String> language,
Boolean hasFullText,
Integer ratingsAverage,
Boolean readable,
String source
Integer ratingsAverage
) {
this.olid = olid;
this.title = title;
Expand Down
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aqui tem um metodo nao finalizado, esse arquivo é praticamente um arquivo de comentario pra lembrar de fazer o metodo dps, isso nao subiria pra produção. imagine o repositorio aqui como produção

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.LibraryLoop.dto.user;

public record LoginRequestDTO(String email, String password) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aqui tem um metodo nao finalizado, esse arquivo é praticamente um arquivo de comentario pra lembrar de fazer o metodo dps, isso nao subiria pra produção. imagine o repositorio aqui como produção

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.LibraryLoop.dto.user;

public record RegisterRequestDTO(String username, String email, String password) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aqui tem um metodo nao finalizado, esse arquivo é praticamente um arquivo de comentario pra lembrar de fazer o metodo dps, isso nao subiria pra produção. imagine o repositorio aqui como produção

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.LibraryLoop.dto.user;

public record ResponseDTO(String username, String token) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aqui ta uma alteração que gostei bastante, fez uma refatoração no lombok que faz sentido com o pr proposto. percebeu que tava duplicado o bgl, e add as info pra segurança do usuario, isso aqui passaria tranquilo, por mim logico

Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.example.LibraryLoop.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;


import lombok.*;

import java.util.List;

@Entity
@Table(name = "app_user")
@Getter
Expand All @@ -20,6 +18,13 @@ public class User {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(unique = true)
private String username;

@Column(unique = true)
private String email;

@Column(nullable = false)
private String password;

private String savedBook;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aprovado

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.LibraryLoop.config;
package com.example.LibraryLoop.security.config;

import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;

Expand Down
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aprovado

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.LibraryLoop.config;
package com.example.LibraryLoop.security.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.LibraryLoop.security.config;

import com.example.LibraryLoop.Repository.userRepository;
import com.example.LibraryLoop.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private userRepository repository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.repository.findByEmail(username).orElseThrow(() -> new UsernameNotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), new ArrayList<>());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.LibraryLoop.security.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

private final SecurityFilter securityFilter;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

http
// desabilita CSRF (necessário para API REST)
.csrf(csrf -> csrf.disable())

// API stateless (JWT)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

// configuração de rotas
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)

// adiciona filtro JWT antes do filtro padrão
.addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Loading