diff --git a/demo/.gitignore b/demo/.gitignore index bd6fd30..94c6ff0 100644 --- a/demo/.gitignore +++ b/demo/.gitignore @@ -1,2 +1,5 @@ .idea/ .gradle/ +gradle/ +.DS_STORE +target/ \ No newline at end of file diff --git a/demo/.idea/workspace.xml b/demo/.idea/workspace.xml index 57e2b60..4b8a910 100644 --- a/demo/.idea/workspace.xml +++ b/demo/.idea/workspace.xml @@ -49,17 +49,6 @@ - - - - - - - - - - - @@ -351,10 +488,10 @@ - + - + @@ -362,6 +499,11 @@ + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -396,18 +633,55 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -418,17 +692,18 @@ - + - - + + - + + @@ -436,7 +711,7 @@ - + @@ -448,6 +723,36 @@ + + + + + file://$PROJECT_DIR$/src/main/java/com/example/easynotes/service/NoteService.java + 67 + + + + file://$PROJECT_DIR$/src/main/java/com/example/easynotes/service/NoteService.java + 81 + + + + file://$PROJECT_DIR$/src/main/java/com/example/easynotes/service/NoteService.java + 83 + + + + file://$PROJECT_DIR$/src/main/java/com/example/easynotes/service/NoteService.java + 87 + + + + + @@ -463,232 +768,379 @@ - + - - + + + + + - + - - + + - + + + + - - - - - - - + + - + + + + + + + + - - + + - - - + - - + + - + + + + + + + + + + + + + - - + + - + - - + + - + + + + + + + + + + + + + + + + + + - + - + - - + + - - + + + + + + - + + + + + + + + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - + + + + + + + + + + + + + - + - - + + - + - - + + + + + + + + + + - - + + + + - + - - + + + + + + + + + + + + + + - + - - + + - + - - + + - + - - + + - + - - + + + + - + - - + + - + - - + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/pom.xml b/demo/pom.xml index b390cfe..f193dc9 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -72,6 +72,12 @@ modelmapper 2.3.0 + + org.springframework.security + spring-security-test + 4.0.0.RELEASE + test + diff --git a/demo/src/main/java/com/example/easynotes/controller/NoteController.java b/demo/src/main/java/com/example/easynotes/controller/NoteController.java index 864d04d..91b089f 100644 --- a/demo/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/demo/src/main/java/com/example/easynotes/controller/NoteController.java @@ -24,13 +24,13 @@ public List getAllNotesByUserId(@PathVariable (value = "userId") Long //Create a new Note @PostMapping("/{userId}/notes") public NotesDto createNote(@PathVariable (value = "userId") Long userId, @Valid @RequestBody NotesDto notesDto) throws ParseException { - return noteService.createNote1(userId, notesDto); + return noteService.createNote(userId, notesDto); } //Get a Single Note @GetMapping("/{userId}/notes/{noteId}") public NotesDto getNoteByUserIdAndNoteId(@PathVariable(value = "userId") Long userId, @PathVariable(value = "noteId") Long noteId) throws ParseException { - return noteService.getNoteByUserAndNoteId(userId, noteId); + return noteService.getNoteByUserIdAndNoteId(userId, noteId); } //Update a Note diff --git a/demo/src/main/java/com/example/easynotes/dto/ApplicationUserDto.java b/demo/src/main/java/com/example/easynotes/dto/ApplicationUserDto.java index 904e965..6c5409c 100644 --- a/demo/src/main/java/com/example/easynotes/dto/ApplicationUserDto.java +++ b/demo/src/main/java/com/example/easynotes/dto/ApplicationUserDto.java @@ -4,9 +4,9 @@ public class ApplicationUserDto { private Long id; - private Date createdAt; private String username; private Date updatedAt; + private Date createdAt; public void setId(Long id) { this.id = id; diff --git a/demo/src/main/java/com/example/easynotes/dto/DtoManager.java b/demo/src/main/java/com/example/easynotes/dto/DtoManager.java index d2faebe..3d17787 100644 --- a/demo/src/main/java/com/example/easynotes/dto/DtoManager.java +++ b/demo/src/main/java/com/example/easynotes/dto/DtoManager.java @@ -3,22 +3,36 @@ import com.example.easynotes.model.ApplicationUser; import com.example.easynotes.model.Note; import org.modelmapper.ModelMapper; +import org.modelmapper.TypeMap; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import java.text.ParseException; +@Service public class DtoManager { + + private final ModelMapper modelMapper; + @Autowired - private final ModelMapper modelMapper = new ModelMapper(); + public DtoManager(ModelMapper modelMapper) { + this.modelMapper = modelMapper; + } public Note convertToEntity(NotesDto notesDto) throws ParseException { Note note = modelMapper.map(notesDto, Note.class); return note; } - public NotesDto convertToDto(Note note){ - NotesDto noteDto = modelMapper.map(note, NotesDto.class); - return noteDto; + public NotesDto convertFromNoteToNotesDto(Note note){ + TypeMap typeMap = modelMapper.getTypeMap(Note.class, NotesDto.class); + if (typeMap == null) { + TypeMap typeMap1 = modelMapper.createTypeMap(Note.class, NotesDto.class); + typeMap1.includeBase(Note.class, NotesDto.class); + typeMap = typeMap1; + } + + return typeMap.map(note); } public ApplicationUser convertToEntity(ApplicationUserDto userDto) throws ParseException { diff --git a/demo/src/main/java/com/example/easynotes/dto/NotesDto.java b/demo/src/main/java/com/example/easynotes/dto/NotesDto.java index 483f99a..de87de1 100644 --- a/demo/src/main/java/com/example/easynotes/dto/NotesDto.java +++ b/demo/src/main/java/com/example/easynotes/dto/NotesDto.java @@ -1,11 +1,8 @@ package com.example.easynotes.dto; -import org.modelmapper.ModelMapper; -import org.springframework.beans.factory.annotation.Autowired; +import java.util.Date; public class NotesDto { - @Autowired - private ModelMapper modelMapper; private Long noteId; @@ -15,6 +12,26 @@ public class NotesDto { private ApplicationUserDto user; + private Date updatedAt; + + private Date createdAt; + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public Long getNoteId() { return noteId; } diff --git a/demo/src/main/java/com/example/easynotes/model/ApplicationUser.java b/demo/src/main/java/com/example/easynotes/model/ApplicationUser.java index e71e609..be701d5 100644 --- a/demo/src/main/java/com/example/easynotes/model/ApplicationUser.java +++ b/demo/src/main/java/com/example/easynotes/model/ApplicationUser.java @@ -1,22 +1,54 @@ package com.example.easynotes.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import javax.persistence.*; -import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; @Entity @Table(name = "users") -public class ApplicationUser extends AuditModel { +@EntityListeners(AuditingEntityListener.class) +@JsonIgnoreProperties(value = {"createdAt", "updatedAt"}, allowGetters = true) +public class ApplicationUser implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @NotNull @Column(unique = true) private String username; - @NotNull private String password; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_at", nullable = false, updatable = false) + @CreatedDate + private Date createdAt; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "updated_at", nullable = false) + @LastModifiedDate + private Date updatedAt; + + public Date getCreatedAt() { + return this.createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public ApplicationUser() { } public Long getId() { diff --git a/demo/src/main/java/com/example/easynotes/model/AuditModel.java b/demo/src/main/java/com/example/easynotes/model/AuditModel.java deleted file mode 100644 index a48dde9..0000000 --- a/demo/src/main/java/com/example/easynotes/model/AuditModel.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.example.easynotes.model; - - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.*; -import java.io.Serializable; -import java.util.Date; - -@MappedSuperclass -@EntityListeners(AuditingEntityListener.class) -@JsonIgnoreProperties(value = {"createdAt", "updatedAt"}, allowGetters = true) -public class AuditModel implements Serializable { - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "created_at", nullable = false, updatable = false) - @CreatedDate - private Date createdAt; - - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "updated_at", nullable = false) - @LastModifiedDate - private Date updatedAt; - - public Date getCreatedAt() { - return createdAt; - } - - public Date getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; - } - - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } -} diff --git a/demo/src/main/java/com/example/easynotes/model/Note.java b/demo/src/main/java/com/example/easynotes/model/Note.java index 58d035e..fb24e77 100644 --- a/demo/src/main/java/com/example/easynotes/model/Note.java +++ b/demo/src/main/java/com/example/easynotes/model/Note.java @@ -1,21 +1,28 @@ package com.example.easynotes.model; +import com.example.easynotes.dto.ApplicationUserDto; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import javax.persistence.*; -import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; @Entity @Table(name = "notes") -public class Note extends AuditModel { +@EntityListeners(AuditingEntityListener.class) +@JsonIgnoreProperties(value = {"createdAt", "updatedAt"}, allowGetters = true) +public class Note implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long noteId; - @NotNull @Lob private String title; - @NotNull @Lob private String content; @@ -23,6 +30,31 @@ public class Note extends AuditModel { @JoinColumn(name = "user_id", nullable = false) private ApplicationUser user; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_at", nullable = false, updatable = false) + @CreatedDate + private Date createdAt; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "updated_at", nullable = false) + @LastModifiedDate + private Date updatedAt; + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } public Long getNoteId() { return noteId; @@ -40,7 +72,7 @@ public void setUser(ApplicationUser user) { this.user = user; } - protected Note() { } + public Note() { } public String getTitle() { return title; diff --git a/demo/src/main/java/com/example/easynotes/security/WebSecurity.java b/demo/src/main/java/com/example/easynotes/security/WebSecurity.java index 4e68982..a5a8e7f 100644 --- a/demo/src/main/java/com/example/easynotes/security/WebSecurity.java +++ b/demo/src/main/java/com/example/easynotes/security/WebSecurity.java @@ -26,17 +26,35 @@ public WebSecurity(UserDetailsServiceImpl userDetailsService, BCryptPasswordEnco } protected void configure(HttpSecurity httpSecurity) throws Exception{ - httpSecurity.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll().anyRequest().authenticated().and().addFilter(new JWTAuthenticationFilter(authenticationManager())).addFilter(new JWTAuthorizationFilter(authenticationManager())).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + httpSecurity + .cors() + .and() + .csrf() + .disable() + .authorizeRequests() + .antMatchers(HttpMethod.POST, SIGN_UP_URL) + .permitAll() + .anyRequest() + .authenticated() + .and() + .addFilter(new JWTAuthenticationFilter(authenticationManager())) + .addFilter(new JWTAuthorizationFilter(authenticationManager())) + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{ - authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder); + authenticationManagerBuilder + .userDetailsService(userDetailsService) + .passwordEncoder(bCryptPasswordEncoder); } @Bean CorsConfigurationSource corsConfigurationSource(){ final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues()); + source + .registerCorsConfiguration("/**", new CorsConfiguration() + .applyPermitDefaultValues()); return source; } } diff --git a/demo/src/main/java/com/example/easynotes/service/NoteService.java b/demo/src/main/java/com/example/easynotes/service/NoteService.java index 3c8d160..dc47a52 100644 --- a/demo/src/main/java/com/example/easynotes/service/NoteService.java +++ b/demo/src/main/java/com/example/easynotes/service/NoteService.java @@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.validation.Valid; import java.text.ParseException; @@ -25,15 +26,16 @@ public class NoteService { private final UserService userService; - private final DtoManager dtoManager = new DtoManager(); + private final DtoManager dtoManager; private final int MAX = 10; @Autowired - public NoteService(NoteRepository noteRepository, UserService userService){ + public NoteService(NoteRepository noteRepository, UserService userService, DtoManager dtoManager){ this.noteRepository = noteRepository; this.userService = userService; + this.dtoManager = dtoManager; } public List getAllNotesByUser(ApplicationUser user) { @@ -52,25 +54,26 @@ public List getAllNotesByUserId(Long userId) throws ParseException { notes.set(i, notes.get(notes.size() - 1 - i)); notes.set(notes.size() - 1 - i, aux); } - return notes.stream().map(dtoManager::convertToDto).collect(Collectors.toList()); + return notes.stream().map(dtoManager::convertFromNoteToNotesDto).collect(Collectors.toList()); } - public NotesDto createNote1(Long userId, NotesDto notesDto) throws ParseException { + @Transactional + public NotesDto createNote(Long userId, NotesDto notesDto) throws ParseException { ApplicationUser user = dtoManager.convertToEntity(userService.getById(userId)); int numberOfNotes = getAllNotesByUser(user).size(); if(user != null && numberOfNotes < MAX){ Note note = dtoManager.convertToEntity(notesDto); note.setUser(user); noteRepository.save(note); - return dtoManager.convertToDto(note); + return dtoManager.convertFromNoteToNotesDto(note); } throw new NotesLimitReachedException("Can not add a new Note"); } - public NotesDto getNoteByUserAndNoteId(Long userId, Long noteId) throws ParseException { + public NotesDto getNoteByUserIdAndNoteId(Long userId, Long noteId) throws ParseException { ApplicationUserDto user = userService.getById(userId); if (user != null) { Note saved = noteRepository.findByUserAndNoteId(dtoManager.convertToEntity(user), noteId); - if (saved != null) return dtoManager.convertToDto(saved); + if (saved != null) return dtoManager.convertFromNoteToNotesDto(saved); } throw new ResourceNotFoundException("UserId " + userId + " not found"); } @@ -80,9 +83,10 @@ public NotesDto updateNote(Long noteId, @Valid NotesDto noteRequest) throws Pars if(!note.isPresent()) { throw new ResourceNotFoundException(); } - Note newNote = dtoManager.convertToEntity(noteRequest); - newNote.setNoteId(noteId); - return dtoManager.convertToDto(noteRepository.save(newNote)); + note.get().setContent(noteRequest.getContent()); + note.get().setTitle(noteRequest.getTitle()); + noteRepository.save(note.get()); + return dtoManager.convertFromNoteToNotesDto(note.get()); } public ResponseEntity deleteNote(Long noteId) { diff --git a/demo/src/main/java/com/example/easynotes/service/UserService.java b/demo/src/main/java/com/example/easynotes/service/UserService.java index 68cc3e9..0981a74 100644 --- a/demo/src/main/java/com/example/easynotes/service/UserService.java +++ b/demo/src/main/java/com/example/easynotes/service/UserService.java @@ -19,12 +19,13 @@ public class UserService { private BCryptPasswordEncoder bCryptPasswordEncoder; - private DtoManager dtoManager = new DtoManager(); + private DtoManager dtoManager; @Autowired - public UserService(UserRepository userRepository, BCryptPasswordEncoder bCryptPasswordEncoder){ + public UserService(UserRepository userRepository, BCryptPasswordEncoder bCryptPasswordEncoder, DtoManager dtoManager){ this.userRepository = userRepository; this.bCryptPasswordEncoder = bCryptPasswordEncoder; + this.dtoManager = dtoManager; } public ApplicationUserDto getById(Long userId){ @@ -45,16 +46,12 @@ public ApplicationUser findByUsername(String username){ return userRepository.findByUsername(username); } - public void delete(ApplicationUser user){ - userRepository.delete(user); - } - public ApplicationUserDto updateUser(Long userId, ApplicationUser userRequest) throws ParseException { ApplicationUserDto savedUser = getById(userId); if(savedUser != null){ ApplicationUser user = dtoManager.convertToEntity(savedUser); user.setUsername(userRequest.getUsername()); - savedUser = createUser(user); + savedUser = dtoManager.convertToDto(user); return savedUser; } throw new ResourceNotFoundException("UserId "+userId+" not found"); @@ -64,7 +61,7 @@ public ResponseEntity deleteUser(Long userId) throws ParseException { ApplicationUserDto user = getById(userId); if(user == null) throw new ResourceNotFoundException("UserId "+userId+ " not found"); - delete(dtoManager.convertToEntity(user)); + userRepository.delete(dtoManager.convertToEntity(user)); return ResponseEntity.ok().build(); } } diff --git a/demo/src/main/resources/application.properties b/demo/src/main/resources/application.properties index c236fd8..98bed57 100644 --- a/demo/src/main/resources/application.properties +++ b/demo/src/main/resources/application.properties @@ -1,5 +1,5 @@ ## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) -spring.datasource.url = jdbc:mysql://localhost:3306/user_with_notess?useSSL=false +spring.datasource.url = jdbc:mysql://localhost:3306/user_with_notess?useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username = root spring.datasource.password = mysql debug=true @@ -8,10 +8,10 @@ debug=true ##Hibernate Properties # The SQL dialect makes Hibernate generate better SQL for the chosen database -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect #Hibernate ddl auto (creat, creat-drop, validate, update) -spring.jpa.hibernate.ddl-auto = create-drop +spring.jpa.hibernate.ddl-auto = update spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy spring.jpa.show-sql=true \ No newline at end of file diff --git a/demo/src/test/java/com/example/easynotes/EasyNotesApplicationTests.java b/demo/src/test/java/com/example/easynotes/EasyNotesApplicationTests.java deleted file mode 100644 index 4bf539c..0000000 --- a/demo/src/test/java/com/example/easynotes/EasyNotesApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.example.easynotes; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class EasyNotesApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/demo/src/test/java/com/example/easynotes/tests/controller/NoteControllerTest.java b/demo/src/test/java/com/example/easynotes/tests/controller/NoteControllerTest.java new file mode 100644 index 0000000..57aa787 --- /dev/null +++ b/demo/src/test/java/com/example/easynotes/tests/controller/NoteControllerTest.java @@ -0,0 +1,186 @@ +package com.example.easynotes.tests.controller; + +import com.example.easynotes.EasyNotesApplication; +import com.example.easynotes.controller.NoteController; +import com.example.easynotes.dto.DtoManager; +import com.example.easynotes.dto.NotesDto; +import com.example.easynotes.model.ApplicationUser; +import com.example.easynotes.model.Note; +import com.example.easynotes.service.UserDetailsServiceImpl; +import com.example.easynotes.service.UserService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import java.text.ParseException; +import java.util.List; +import static java.util.Collections.singletonList; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.hamcrest.core.Is.is; +import static org.mockito.BDDMockito.given; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = EasyNotesApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@ContextConfiguration +@AutoConfigureMockMvc +public class NoteControllerTest { + + @Autowired + private MockMvc mvc; + + @MockBean + private NoteController noteController; + + @MockBean + private UserService userService; + + @Autowired + private DtoManager dtoManager; + + @InjectMocks + private UserDetailsServiceImpl userDetailsService = new UserDetailsServiceImpl(userService); + + @Test + public void getNotesByUserId() throws ParseException, Exception { + ApplicationUser user = createUser(); + + UserDetails userDetails = userDetailsService.loadUserByUsername("caio"); + + Authentication authToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); + + SecurityContextHolder.getContext().setAuthentication(authToken); + + Note note = createNote(user); + + NotesDto notesDto = dtoManager.convertFromNoteToNotesDto(note); + List allNotes = singletonList(notesDto); + + given(noteController.getAllNotesByUserId(user.getId())) + .willReturn(allNotes); + + mvc.perform(get("/1/notes") + .with(user("root").password("mysql")) + .contentType(APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].title", is(note.getTitle()))); + } + + @Test + public void getNoteByUserAndNoteId() throws Exception, ParseException { + ApplicationUser user = createUser(); + + UserDetails userDetails = userDetailsService.loadUserByUsername("caio"); + + Authentication authToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); + + SecurityContextHolder.getContext().setAuthentication(authToken); + + Note note = createNote(user); + + NotesDto notesDto = dtoManager.convertFromNoteToNotesDto(note); + + given(noteController.getNoteByUserIdAndNoteId(user.getId(), note.getNoteId())) + .willReturn(notesDto); + + mvc.perform(get("/1/notes/1") + .with(user("blaze") + .password("Q1w2e3r4")) + .contentType(APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("title", is(note.getTitle()))); + } + + + //Put + @Test + public void updateNote() throws ParseException, Exception { + ApplicationUser user = createUser(); + + UserDetails userDetails = userDetailsService.loadUserByUsername("caio"); + + Authentication authToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); + + SecurityContextHolder.getContext().setAuthentication(authToken); + + Note note = createNote(user); + + Note noteToUpdate = new Note(); + note.setTitle("test 2"); + note.setContent("testingg"); + note.setUser(user); + + NotesDto notesDto = dtoManager.convertFromNoteToNotesDto(note); + + NotesDto noteUpdatedDto = dtoManager.convertFromNoteToNotesDto(noteToUpdate); + + given(noteController.updateNote(note.getNoteId(), noteUpdatedDto)) + .willReturn(notesDto); + + mvc.perform(put("/notes/1") + .with(user("blaze") + .password("Q1w2e3r4")) + .contentType(APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("title", is(noteUpdatedDto.getTitle()))); + } + + + //Delete + @Test + public void removeNoteByNoteId() throws ParseException, Exception { + ApplicationUser user = createUser(); + + UserDetails userDetails = userDetailsService.loadUserByUsername("caio"); + + Authentication authToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); + + SecurityContextHolder.getContext().setAuthentication(authToken); + + Note note = createNote(user); + + NotesDto notesDto = dtoManager.convertFromNoteToNotesDto(note); + + mvc.perform(delete("/notes/1") + .with(user("blaze") + .password("Q1w2e3r4")) + .contentType(APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + public ApplicationUser createUser(){ + ApplicationUser user = new ApplicationUser(); + user.setUsername("caio"); + user.setPassword("test"); + return user; + } + + public Note createNote(ApplicationUser user) throws ParseException { + Note note = new Note(); + note.setTitle("test 1"); + note.setContent("testing"); + note.setUser(user); + return note; + } + +} diff --git a/demo/src/test/java/com/example/easynotes/tests/controller/UserControllerTest.java b/demo/src/test/java/com/example/easynotes/tests/controller/UserControllerTest.java new file mode 100644 index 0000000..c1dce2f --- /dev/null +++ b/demo/src/test/java/com/example/easynotes/tests/controller/UserControllerTest.java @@ -0,0 +1,107 @@ +package com.example.easynotes.tests.controller; + +import com.example.easynotes.EasyNotesApplication; +import com.example.easynotes.controller.UserController; +import com.example.easynotes.dto.ApplicationUserDto; +import com.example.easynotes.dto.DtoManager; +import com.example.easynotes.model.ApplicationUser; + +import com.example.easynotes.service.UserDetailsServiceImpl; +import com.example.easynotes.service.UserService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import java.text.ParseException; +import static org.hamcrest.core.Is.is; +import static org.mockito.BDDMockito.given; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = EasyNotesApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@ContextConfiguration +@AutoConfigureMockMvc +public class UserControllerTest { + + @Autowired + private MockMvc mvc; + + @MockBean + private UserController userController; + + @Autowired + private DtoManager dtoManager; + + + @MockBean + private UserService userService; + + @InjectMocks + private UserDetailsServiceImpl userDetailsService = new UserDetailsServiceImpl(userService); + + //delete + @Test + public void deleteUser() throws Exception { + ApplicationUser user = createUser(); + + UserDetails userDetails = userDetailsService.loadUserByUsername("caio"); + + Authentication authToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); + + SecurityContextHolder.getContext().setAuthentication(authToken); + + mvc.perform(delete("/users/"+user.getId()) + .contentType(APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + + //put + @Test + public void updateUser() throws ParseException, Exception { + ApplicationUser user = createUser(); + + ApplicationUser userRequest = new ApplicationUser(); + userRequest.setPassword("caioo"); + userRequest.setUsername("testt"); + + ApplicationUserDto userRequestDto = dtoManager.convertToDto(userRequest); + + given(userController.updateUser(user.getId(), userRequest)) + .willReturn(userRequestDto); + + mvc.perform(put("/users/"+ user.getId()) + .with(user("blaze").password("Q1w2e3r4")) + .contentType(APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("username", is(userRequestDto.getUsername()))); + } + + + public ApplicationUser createUser(){ + ApplicationUser user = new ApplicationUser(); + user.setUsername("caio"); + user.setPassword("test"); + return user; + } + +} diff --git a/demo/src/test/java/com/example/easynotes/tests/service/NoteServiceTest.java b/demo/src/test/java/com/example/easynotes/tests/service/NoteServiceTest.java new file mode 100644 index 0000000..36730df --- /dev/null +++ b/demo/src/test/java/com/example/easynotes/tests/service/NoteServiceTest.java @@ -0,0 +1,132 @@ +package com.example.easynotes.tests.service; + + +import com.example.easynotes.EasyNotesApplication; +import com.example.easynotes.dto.DtoManager; +import com.example.easynotes.dto.NotesDto; +import com.example.easynotes.exception.NotesLimitReachedException; +import com.example.easynotes.model.ApplicationUser; +import com.example.easynotes.model.Note; +import com.example.easynotes.repository.UserRepository; +import com.example.easynotes.service.NoteService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.Assert.assertEquals; + +import java.text.ParseException; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = EasyNotesApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +public class NoteServiceTest { + + @Autowired + private NoteService noteService; + + @Autowired + private UserRepository userRepository; + + @Autowired + private DtoManager dtoManager; + + //getAllNotesByUserId + @Test + public void whenValidUserId_thenReturnListOfNotesDto() throws ParseException { + ApplicationUser user = createUser("ca", "passwo"); + + NotesDto note = createNote(user); + + List foundDto = noteService.getAllNotesByUserId(user.getId()); + + assertEquals((note.getTitle()), foundDto.get(0).getTitle()); + } + + //getNoteByUserAndNoteId + @Test + public void whenValidUserIdAndNoteId_thenReturnNoteDto() throws ParseException { + ApplicationUser user = createUser("cai", "passwor"); + + NotesDto note = createNote(user); + + NotesDto notesDto = noteService.getNoteByUserIdAndNoteId(user.getId(), note.getNoteId()); + + Note found = dtoManager.convertToEntity(notesDto); + + assertEquals((note.getTitle()), found.getTitle()); + } + + //updateNote + @Test + public void whenValidNoteId_thenUpdateNoteAndReturnNoteDto() throws ParseException{ + ApplicationUser user = createUser("caiooo", "passworddd"); + + NotesDto note = createNote(user); + + Note noteRequest = new Note(); + noteRequest.setContent("testingg"); + noteRequest.setTitle("test 12"); + + NotesDto notesRequestDto = dtoManager.convertFromNoteToNotesDto(noteRequest); + + NotesDto foundDto = noteService.updateNote(note.getNoteId(), notesRequestDto); + + assertEquals((noteRequest.getTitle()), foundDto.getTitle()); + } + + //deleteNote + @Test + public void whenValidNoteId_thenDeleteNote() throws ParseException{ + ApplicationUser user = createUser("caioo", "passwordd"); + + NotesDto note = createNote(user); + + ResponseEntity deleted = noteService.deleteNote(note.getNoteId()); + } + + + //create more than 10 notes + @Test + public void whenCreatingMoreThan10Notes_thenReturnNotesLimitReachedException() throws NotesLimitReachedException, ParseException { + ApplicationUser user = createUser("Caio", "password"); + + for(int i = 0; i<11; i++) { + NotesDto notesDto = new NotesDto(); + notesDto.setTitle("test " + i); + notesDto.setContent("testing " + i); + noteService.createNote(user.getId(), notesDto); + } + + NotesDto writeNote = new NotesDto(); + writeNote.setTitle("test 11"); + writeNote.setContent("testing 11"); + noteService.createNote(user.getId(), writeNote); + + assertEquals(noteService.getNoteByUserIdAndNoteId(user.getId(), writeNote.getNoteId()), writeNote); + } + + //createNote + @Transactional + public NotesDto createNote(ApplicationUser user) throws ParseException { + NotesDto note = new NotesDto(); + note.setTitle("test 1"); + note.setContent("testing"); + return noteService.createNote(user.getId(), note); + } + + @Transactional + public ApplicationUser createUser(String username, String password){ + ApplicationUser user = new ApplicationUser(); + user.setPassword(password); + user.setUsername(username); + userRepository.save(user); + return user; + } +} diff --git a/demo/src/test/java/com/example/easynotes/tests/service/UserServiceTest.java b/demo/src/test/java/com/example/easynotes/tests/service/UserServiceTest.java new file mode 100644 index 0000000..519430f --- /dev/null +++ b/demo/src/test/java/com/example/easynotes/tests/service/UserServiceTest.java @@ -0,0 +1,87 @@ +package com.example.easynotes.tests.service; + +import com.example.easynotes.EasyNotesApplication; +import com.example.easynotes.dto.ApplicationUserDto; +import com.example.easynotes.dto.DtoManager; +import com.example.easynotes.model.ApplicationUser; +import com.example.easynotes.service.UserService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.text.ParseException; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = EasyNotesApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@ContextConfiguration +public class UserServiceTest { + + @Autowired + private UserService userService; + + @Autowired + private DtoManager dtoManager; + + + //getById + @Test + public void whenValidUserId_thenReturnUserDto(){ + ApplicationUserDto user = createUser("caio", "password"); + + assertEquals(user.getId(), userService.getById(user.getId()).getId()); + } + + //findByUsername + @Test + public void whenValidUsername_thenReturnUser_ifUserExists(){ + ApplicationUserDto user = createUser("caio1", "password1"); + + assertEquals(user.getId(), userService.findByUsername("caio1").getId()); + } + + + //deleteUser + @Test + public void whenValidUserId_thenDeleteUser() throws ParseException { + ApplicationUserDto user = createUser("caio2", "password2"); + + ResponseEntity deleted = userService.deleteUser(user.getId()); + + ResponseEntity expected = ResponseEntity.ok().build(); + + assertEquals(deleted.getStatusCode(), expected.getStatusCode()); + } + + + + //updateUser + @Test + public void whenValidUserId_thenUpdateUser() throws ParseException { + ApplicationUserDto user = createUser("caio3", "password3"); + + ApplicationUserDto userRequest = createUser("caio4", "password4"); + + user = userService.updateUser(user.getId(), dtoManager.convertToEntity(userRequest)); + + assertEquals(userRequest.getUsername(), user.getUsername()); + } + + + //createUser + private ApplicationUserDto createUser(String username, String password){ + ApplicationUser user = new ApplicationUser(); + user.setUsername(username); + user.setPassword(password); + return userService.createUser(user); + } + + +} diff --git a/demo/target/classes/application.properties b/demo/target/classes/application.properties index c236fd8..98bed57 100644 --- a/demo/target/classes/application.properties +++ b/demo/target/classes/application.properties @@ -1,5 +1,5 @@ ## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) -spring.datasource.url = jdbc:mysql://localhost:3306/user_with_notess?useSSL=false +spring.datasource.url = jdbc:mysql://localhost:3306/user_with_notess?useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username = root spring.datasource.password = mysql debug=true @@ -8,10 +8,10 @@ debug=true ##Hibernate Properties # The SQL dialect makes Hibernate generate better SQL for the chosen database -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect #Hibernate ddl auto (creat, creat-drop, validate, update) -spring.jpa.hibernate.ddl-auto = create-drop +spring.jpa.hibernate.ddl-auto = update spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy spring.jpa.show-sql=true \ No newline at end of file