diff --git a/.gitignore b/.gitignore index 549e00a..41f1049 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ target/ !**/src/main/**/target/ !**/src/test/**/target/ +uploaded/ + ### STS ### .apt_generated .classpath diff --git a/pom.xml b/pom.xml index c273b81..d80d00a 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,10 @@ org.springframework.boot spring-boot-starter-validation + + org.hibernate.validator + hibernate-validator + org.springframework.boot spring-boot-starter-web @@ -58,11 +62,27 @@ true + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-mail + + org.springframework.boot spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + + diff --git a/src/main/java/com/sahabuddin/contactmanager/ContactManagerApplication.java b/src/main/java/com/sahabuddin/contactmanager/ContactManagerApplication.java index be8f2d8..9454a7d 100644 --- a/src/main/java/com/sahabuddin/contactmanager/ContactManagerApplication.java +++ b/src/main/java/com/sahabuddin/contactmanager/ContactManagerApplication.java @@ -2,6 +2,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; @SpringBootApplication public class ContactManagerApplication { diff --git a/src/main/java/com/sahabuddin/contactmanager/configs/AppProperties.java b/src/main/java/com/sahabuddin/contactmanager/configs/AppProperties.java new file mode 100644 index 0000000..3b72a11 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/configs/AppProperties.java @@ -0,0 +1,18 @@ +package com.sahabuddin.contactmanager.configs; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Component +@Configuration +@ConfigurationProperties(prefix = "app") +@Getter +@Setter +public class AppProperties { + + private String filePath; + +} diff --git a/src/main/java/com/sahabuddin/contactmanager/constants/AppConstant.java b/src/main/java/com/sahabuddin/contactmanager/constants/AppConstant.java new file mode 100644 index 0000000..a9a2319 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/constants/AppConstant.java @@ -0,0 +1,22 @@ +package com.sahabuddin.contactmanager.constants; + +public final class AppConstant { + + private AppConstant() { + } + + public static final String SIGN_IN_URL = "/sign-in"; + + public static final String SIGN_UP_PAGE = "signup"; + + public static final String TITLE = "title"; + public static final String MESSAGE = "message"; + public static final String CONTACT = "contact"; + public static final String SIGN_UP_TITLE = "Sign up | Contact Manager"; + + public static final String PAGE_NO = "pageNo"; + public static final String PAGE_SIZE = "pageSize"; + + public static final String PAGE = "0"; + public static final String SIZE = "10"; +} diff --git a/src/main/java/com/sahabuddin/contactmanager/controllers/ForgetPasswordController.java b/src/main/java/com/sahabuddin/contactmanager/controllers/ForgetPasswordController.java new file mode 100644 index 0000000..aafbd23 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/controllers/ForgetPasswordController.java @@ -0,0 +1,47 @@ +package com.sahabuddin.contactmanager.controllers; + +import ch.qos.logback.core.model.Model; +import com.sahabuddin.contactmanager.services.EmailService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Random; + +@Slf4j +@Controller +@RequestMapping +@RequiredArgsConstructor +public class ForgetPasswordController { + + private final EmailService emailService; + + @GetMapping(value = "/forget-password") + public String openEmailForm(Model model) { + return "forget_password"; + } + + @PostMapping(value = "/send-otp") + public String sendOTP(@RequestParam("email") String email, Model model) { + log.info("Sending OTP for {}", email); + Random random = new Random(); + int otp = random.nextInt(999999); + log.info("OTP generated {}", otp); + String message = String.format("OTP generated for %s and OTP is: %s", email, otp); + log.info(message); + emailService.sendSimpleMessage(email, "Forget password OTP", message); + return "verify_otp"; + } + + @PostMapping(value = "/verify-otp") + public String verifyOTP(@RequestParam("otp") String otp, Model model) { + log.info("OTP is {}", otp); + + return "change_password"; + } + +} diff --git a/src/main/java/com/sahabuddin/contactmanager/controllers/HomeController.java b/src/main/java/com/sahabuddin/contactmanager/controllers/HomeController.java new file mode 100644 index 0000000..d517467 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/controllers/HomeController.java @@ -0,0 +1,89 @@ +package com.sahabuddin.contactmanager.controllers; + +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.models.response.Message; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import jakarta.servlet.http.HttpSession; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import static com.sahabuddin.contactmanager.constants.AppConstant.*; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class HomeController { + + private final UserRepository userRepository; + + private final PasswordEncoder passwordEncoder; + + @GetMapping(value = {"/","/home"}) + public String home(Model model) { + model.addAttribute(TITLE, "Home | Contact Manager"); + return "home"; + } + + @GetMapping(value = "/about") + public String about(Model model) { + model.addAttribute(TITLE, "About | Contact Manager"); + return "about"; + } + + @GetMapping(value = "/signup") + public String signup(Model model) { + model.addAttribute(TITLE, SIGN_UP_TITLE); + model.addAttribute("user", new User()); + return SIGN_UP_PAGE; + } + + @PostMapping(value = "/signup") + public String userSignup(@Valid @ModelAttribute("user") User user,BindingResult result, @RequestParam(value = "agreement", defaultValue = "false") boolean agreement, Model model, HttpSession session) { + try{ + if (!agreement) { + log.error("You have not agreed the terms and conditions"); + throw new IllegalArgumentException("You have not agreed the terms and conditions"); + } + + if (result.hasErrors()) { + log.error("Error: {}", result); + model.addAttribute(TITLE, SIGN_UP_TITLE); + model.addAttribute("user", user); + return SIGN_UP_PAGE; + } + + model.addAttribute(TITLE, SIGN_UP_TITLE); + user.setRole("ROLE_USER"); + user.setEnabled(true); + user.setImageUrl("default.png"); + user.setPassword(passwordEncoder.encode(user.getPassword())); + log.info("User: {}", user); + User saved = userRepository.save(user); + log.info("User registered successfully {}", saved); + log.info("user info: {}", user); + + model.addAttribute("user", new User()); + session.setAttribute("message", new Message("Registration successfully! ", "alert-success")); + + + } catch (Exception e){ + model.addAttribute("title", "Sign up | Contact Manager"); + model.addAttribute("user", new User()); + log.error("error: {}", e.getMessage()); + session.setAttribute("message", new Message("Something went wrong! "+e.getMessage(), "alert-danger")); + } + return SIGN_UP_PAGE; + } + + @GetMapping(value = "/sign-in") + public String singIn(Model model){ + model.addAttribute(TITLE, "Login | Contact Manager"); + return "login"; + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/controllers/UserController.java b/src/main/java/com/sahabuddin/contactmanager/controllers/UserController.java index e5d10f6..7f11527 100644 --- a/src/main/java/com/sahabuddin/contactmanager/controllers/UserController.java +++ b/src/main/java/com/sahabuddin/contactmanager/controllers/UserController.java @@ -1,7 +1,167 @@ package com.sahabuddin.contactmanager.controllers; +import com.sahabuddin.contactmanager.configs.AppProperties; +import com.sahabuddin.contactmanager.entities.Contact; +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.models.requests.ContactRequest; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import com.sahabuddin.contactmanager.services.ContactService; +import com.sahabuddin.contactmanager.models.response.Message; +import com.sahabuddin.contactmanager.services.UserService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.security.Principal; + +import static com.sahabuddin.contactmanager.constants.AppConstant.*; + +@Slf4j @Controller +@RequiredArgsConstructor +@RequestMapping(value = "/user") public class UserController { + + private final UserRepository userRepository; + + private final ContactService contactService; + + private final AppProperties appProperties; + + private final PasswordEncoder passwordEncoder; + + private final UserService userService; + + @ModelAttribute + public void commonAttributes(Model model, Principal principal) { + log.info("user is {}", principal.getName()); + model.addAttribute("user", getUser(principal)); + } + + + @GetMapping(value = "/index") + public String userDashboard(Model model) { + model.addAttribute(TITLE, "User Dashboard | Contact Manager"); + return "user/user_dashboard"; + } + + @GetMapping(value = "/add-contact") + public String addContactView(Model model) { + model.addAttribute(TITLE, "Add Contact | Contact Manager"); + model.addAttribute(CONTACT, new ContactRequest()); + return "user/add_contact"; + } + + @PostMapping(value = "/add-contact") + public String addContactSave(@Valid @ModelAttribute("contact") ContactRequest request, BindingResult result, @RequestParam("imageFile")MultipartFile file, Model model, Principal principal) { + model.addAttribute(TITLE, "Add Contact | Contact Manager"); + log.info("add contact request is {}", request); + try{ + contactService.createContact(request, getUser(principal), file); + model.addAttribute(MESSAGE, new Message("Contact added successfully! ", "alert-success")); + } catch (Exception e) { + model.addAttribute(MESSAGE, new Message("Something went wrong "+e.getMessage(), "alert-danger")); + } + model.addAttribute(MESSAGE, new ContactRequest()); + + return "user/add_contact"; + } + + @GetMapping(value = "/view-contacts") + public String viewContacts( + @RequestParam(value = PAGE_NO, required = false, defaultValue = PAGE) int pageNo, + @RequestParam(value = PAGE_SIZE, required = false, defaultValue = SIZE) int pageSize, + Model model, Principal principal) { + Pageable pageable = PageRequest.of(pageNo, pageSize); + Page pages = contactService.getAllContactByUser(getUser(principal), pageable); + model.addAttribute(TITLE, "View Contact | Contact Manager"); + model.addAttribute("dataList",pages ); + model.addAttribute("currentPage", pageNo); + model.addAttribute("pageSize", pageSize); + model.addAttribute("totalPage", pages.getTotalPages()); + model.addAttribute("imageBasePath", appProperties.getFilePath()); + return "user/view_contacts"; + } + + @GetMapping(value = "/{id}/contact") + public String detailsContact(@PathVariable Long id, Model model, Principal principal) { + + model.addAttribute(TITLE, "View Contact | Contact Manager"); + model.addAttribute(CONTACT,contactService.getContactByIdAndUser(id,getUser(principal))); + return "user/details_contact"; + } + + @GetMapping(value = "delete/{id}/contact") + public String deleteContact(@PathVariable Long id, Model model, Principal principal) { + + contactService.deleteContactByIdAndUser(id,getUser(principal)); + model.addAttribute(TITLE, "View Contact | Contact Manager"); + model.addAttribute(MESSAGE, new Message("Contact deleted successfully! ", "alert-success")); + return "redirect:/user/view-contacts"; + } + + @GetMapping(value = "update/{id}/contact") + public String updateGetContact(@PathVariable Long id, Model model, Principal principal) { + model.addAttribute(TITLE, "Update Contact | Contact Manager"); + model.addAttribute(CONTACT, contactService.getContactByIdAndUser(id,getUser(principal))); + model.addAttribute("updateRequest", new ContactRequest()); + return "user/update_contact"; + } + + @PostMapping(value = "update/contact") + public String updatePostContact(@ModelAttribute("updateRequest") ContactRequest request,@RequestParam("imageFile")MultipartFile file, Model model, Principal principal) { + model.addAttribute(MESSAGE, new Message("Contact updated successfully! ", "alert-success")); + log.info("update contact request is {}", request); + try{ + contactService.updateContact(request, getUser(principal), file); + } catch (Exception e) { + log.error(e.getMessage()); + } + return "redirect:/user/view-contacts"; + } + + @GetMapping(value = "me") + public String getMe(Model model, Principal principal) { + model.addAttribute(TITLE, "Me | Contact Manager"); + model.addAttribute("me", getUser(principal)); + return "user/me"; + } + + @GetMapping(value = "change-password") + public String getChangePassword(Model model) { + model.addAttribute(TITLE, "Change Password | Contact Manager"); + return "user/settings"; + + } + + @PostMapping(value = "change-password") + public String postChangePassword(@RequestParam("oldPassword") String oldPassword,@RequestParam("newPassword") String newPassword, Model model, Principal principal) { + model.addAttribute(TITLE, "Change Password | Contact Manager"); + User user = getUser(principal); + + if (passwordEncoder.matches(oldPassword, user.getPassword())) { + userService.passwordChange(oldPassword, newPassword, user); + return "redirect:/user/view-contacts"; + + } else { + model.addAttribute("message", new Message("old password dose not match!", "alert-danger")); + return "user/settings"; + } + + + + } + + private User getUser( Principal principal) { + return userRepository.findByEmail(principal.getName()); + } } diff --git a/src/main/java/com/sahabuddin/contactmanager/controllers/rest/SearchController.java b/src/main/java/com/sahabuddin/contactmanager/controllers/rest/SearchController.java new file mode 100644 index 0000000..39667d5 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/controllers/rest/SearchController.java @@ -0,0 +1,31 @@ +package com.sahabuddin.contactmanager.controllers.rest; + +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import com.sahabuddin.contactmanager.services.ContactService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/user") +public class SearchController { + + private final ContactService contactService; + + private final UserRepository userRepository; + + @GetMapping(value = "/search/{query}") + public ResponseEntity search( @PathVariable("query") String query, Principal principal) { + return ResponseEntity.ok(contactService.searchByName(query, getUser(principal))); + } + private User getUser(Principal principal) { + return userRepository.findByEmail(principal.getName()); + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/controllers/rest/UserRestController.java b/src/main/java/com/sahabuddin/contactmanager/controllers/rest/UserRestController.java new file mode 100644 index 0000000..e805891 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/controllers/rest/UserRestController.java @@ -0,0 +1,34 @@ +package com.sahabuddin.contactmanager.controllers.rest; + + +import com.sahabuddin.contactmanager.entities.Contact; +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.respositories.ContactRepository; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping(value = "/rest") +@RequiredArgsConstructor +public class UserRestController { + + private final UserRepository userRepository; + + private final ContactRepository contactRepository; + + + @GetMapping(value = "/user") + List getAllUser(){ + return userRepository.findAll(); + } + + @GetMapping(value = "/contact") + List getAllContact(){ + return contactRepository.findAll(); + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/entities/Contact.java b/src/main/java/com/sahabuddin/contactmanager/entities/Contact.java index 84505cc..9ad1855 100644 --- a/src/main/java/com/sahabuddin/contactmanager/entities/Contact.java +++ b/src/main/java/com/sahabuddin/contactmanager/entities/Contact.java @@ -1,5 +1,6 @@ package com.sahabuddin.contactmanager.entities; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.Data; @@ -28,6 +29,7 @@ public class Contact { private String imageUrl; @ManyToOne + @JsonIgnore private User user; } diff --git a/src/main/java/com/sahabuddin/contactmanager/entities/User.java b/src/main/java/com/sahabuddin/contactmanager/entities/User.java index 83f09c5..54fed34 100644 --- a/src/main/java/com/sahabuddin/contactmanager/entities/User.java +++ b/src/main/java/com/sahabuddin/contactmanager/entities/User.java @@ -1,6 +1,8 @@ package com.sahabuddin.contactmanager.entities; import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.Data; import java.util.ArrayList; @@ -15,11 +17,15 @@ public class User { @GeneratedValue(strategy = GenerationType.AUTO) private Long id; + @NotBlank(message = "Name is required") + @Size(min = 3, max = 50, message = "Name must be between 3 and 50 characters") private String name; + @NotBlank(message = "Email is required") @Column(unique = true) private String email; + @NotBlank(message = "Password is required") private String password; @Column(length = 500) diff --git a/src/main/java/com/sahabuddin/contactmanager/models/requests/ContactRequest.java b/src/main/java/com/sahabuddin/contactmanager/models/requests/ContactRequest.java new file mode 100644 index 0000000..da719f7 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/models/requests/ContactRequest.java @@ -0,0 +1,27 @@ +package com.sahabuddin.contactmanager.models.requests; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class ContactRequest { + + private Long id; + + private String name; + + private String nickName; + + private String email; + + private String phone; + + private String work; + + private String description; + + private String imageUrl; +} diff --git a/src/main/java/com/sahabuddin/contactmanager/models/requests/SignInRequest.java b/src/main/java/com/sahabuddin/contactmanager/models/requests/SignInRequest.java new file mode 100644 index 0000000..151a32b --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/models/requests/SignInRequest.java @@ -0,0 +1,18 @@ +package com.sahabuddin.contactmanager.models.requests; + +import jakarta.validation.constraints.NotBlank; +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class SignInRequest { + + @NotBlank(message = "Email is required") + private String email; + + @NotBlank(message = "Password is required") + private String password; +} diff --git a/src/main/java/com/sahabuddin/contactmanager/models/response/Message.java b/src/main/java/com/sahabuddin/contactmanager/models/response/Message.java new file mode 100644 index 0000000..a8d41dd --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/models/response/Message.java @@ -0,0 +1,16 @@ +package com.sahabuddin.contactmanager.models.response; + +import lombok.*; + +import java.io.Serializable; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class Message implements Serializable { + + private String content; + private String type; +} diff --git a/src/main/java/com/sahabuddin/contactmanager/respositories/ContactRepository.java b/src/main/java/com/sahabuddin/contactmanager/respositories/ContactRepository.java index 7040307..af36292 100644 --- a/src/main/java/com/sahabuddin/contactmanager/respositories/ContactRepository.java +++ b/src/main/java/com/sahabuddin/contactmanager/respositories/ContactRepository.java @@ -1,9 +1,20 @@ package com.sahabuddin.contactmanager.respositories; import com.sahabuddin.contactmanager.entities.Contact; +import com.sahabuddin.contactmanager.entities.User; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ContactRepository extends JpaRepository { + + Page findAllByUser(User user, Pageable pageable); + + Contact findByIdAndUser(Long id, User user); + + List findByNameContainingIgnoreCaseAndUser(String keywords, User user); } diff --git a/src/main/java/com/sahabuddin/contactmanager/respositories/UserRepository.java b/src/main/java/com/sahabuddin/contactmanager/respositories/UserRepository.java index 7d9e1ab..d2002df 100644 --- a/src/main/java/com/sahabuddin/contactmanager/respositories/UserRepository.java +++ b/src/main/java/com/sahabuddin/contactmanager/respositories/UserRepository.java @@ -1,9 +1,12 @@ package com.sahabuddin.contactmanager.respositories; import com.sahabuddin.contactmanager.entities.User; +import jakarta.validation.constraints.NotBlank; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends JpaRepository { + + User findByEmail(@NotBlank(message = "Email is required") String email); } diff --git a/src/main/java/com/sahabuddin/contactmanager/security/CustomUserDetails.java b/src/main/java/com/sahabuddin/contactmanager/security/CustomUserDetails.java new file mode 100644 index 0000000..0d0becc --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/security/CustomUserDetails.java @@ -0,0 +1,53 @@ +package com.sahabuddin.contactmanager.security; + +import com.sahabuddin.contactmanager.entities.User; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.List; + +public class CustomUserDetails implements UserDetails { + + private User user; + + public CustomUserDetails(User user) { + this.user = user; + } + + @Override + public Collection getAuthorities() { + return List.of(new SimpleGrantedAuthority(user.getRole())); + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public String getUsername() { + return user.getEmail(); + } + + @Override + public boolean isAccountNonExpired() { + return UserDetails.super.isAccountNonExpired(); + } + + @Override + public boolean isAccountNonLocked() { + return UserDetails.super.isAccountNonLocked(); + } + + @Override + public boolean isCredentialsNonExpired() { + return UserDetails.super.isCredentialsNonExpired(); + } + + @Override + public boolean isEnabled() { + return UserDetails.super.isEnabled(); + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/security/SecurityConfig.java b/src/main/java/com/sahabuddin/contactmanager/security/SecurityConfig.java new file mode 100644 index 0000000..451aeac --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/security/SecurityConfig.java @@ -0,0 +1,62 @@ +package com.sahabuddin.contactmanager.security; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +import static com.sahabuddin.contactmanager.constants.AppConstant.SIGN_IN_URL; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final UserDetailsServiceImpl userDetailsService; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(Customizer.withDefaults()) + .authorizeHttpRequests(auth -> + auth + .requestMatchers("/admin/**").hasRole("ADMIN") + .requestMatchers("/user/**").hasRole("USER") + .requestMatchers("/**").permitAll() + ) + .formLogin(form -> form + .loginPage(SIGN_IN_URL) + .loginProcessingUrl(SIGN_IN_URL) + .defaultSuccessUrl("/user/index") + .failureUrl("/sign-in?error=true") + .permitAll()) + .logout(logout -> logout + .logoutUrl("/logout") // Only responds to POST requests + .logoutSuccessUrl(SIGN_IN_URL) // Redirect after successful logout + .invalidateHttpSession(true) // Invalidate session + .deleteCookies("JSESSIONID")); + + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationProvider authenticationProvider() { + DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); + daoAuthenticationProvider.setUserDetailsService(userDetailsService); + daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); + return daoAuthenticationProvider; + } + +} diff --git a/src/main/java/com/sahabuddin/contactmanager/security/UserDetailsServiceImpl.java b/src/main/java/com/sahabuddin/contactmanager/security/UserDetailsServiceImpl.java new file mode 100644 index 0000000..ac08bae --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/security/UserDetailsServiceImpl.java @@ -0,0 +1,27 @@ +package com.sahabuddin.contactmanager.security; + +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import lombok.RequiredArgsConstructor; +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.Service; + +@Service +@RequiredArgsConstructor +public class UserDetailsServiceImpl implements UserDetailsService { + + private final UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + + User user = userRepository.findByEmail(username); + if (user == null) { + throw new UsernameNotFoundException("User not found with this: "+username); + } + + return new CustomUserDetails(user); + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/services/ContactService.java b/src/main/java/com/sahabuddin/contactmanager/services/ContactService.java index 8a47b35..19ca92a 100644 --- a/src/main/java/com/sahabuddin/contactmanager/services/ContactService.java +++ b/src/main/java/com/sahabuddin/contactmanager/services/ContactService.java @@ -1,4 +1,29 @@ package com.sahabuddin.contactmanager.services; +import com.sahabuddin.contactmanager.entities.Contact; +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.models.requests.ContactRequest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.security.Principal; +import java.util.List; + public interface ContactService { + + Contact createContact(ContactRequest request, User user, MultipartFile file) throws IOException; + + Page getAllContactByUser(User user, Pageable pageable); + + Contact getContactById(Long id); + + Contact getContactByIdAndUser(Long id, User user); + + void deleteContactByIdAndUser(Long id, User user); + + void updateContact(ContactRequest request, User user, MultipartFile file); + + List searchByName(String query, User user); } diff --git a/src/main/java/com/sahabuddin/contactmanager/services/EmailService.java b/src/main/java/com/sahabuddin/contactmanager/services/EmailService.java new file mode 100644 index 0000000..6b29a8e --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/services/EmailService.java @@ -0,0 +1,6 @@ +package com.sahabuddin.contactmanager.services; + +public interface EmailService { + + void sendSimpleMessage(String to, String subject, String text); +} diff --git a/src/main/java/com/sahabuddin/contactmanager/services/UserService.java b/src/main/java/com/sahabuddin/contactmanager/services/UserService.java index 16b1e07..7a67daf 100644 --- a/src/main/java/com/sahabuddin/contactmanager/services/UserService.java +++ b/src/main/java/com/sahabuddin/contactmanager/services/UserService.java @@ -1,5 +1,9 @@ package com.sahabuddin.contactmanager.services; +import com.sahabuddin.contactmanager.entities.User; + public interface UserService { + void passwordChange(String oldPassword, String newPassword, User user); + } diff --git a/src/main/java/com/sahabuddin/contactmanager/services/impl/ContactServiceImpl.java b/src/main/java/com/sahabuddin/contactmanager/services/impl/ContactServiceImpl.java new file mode 100644 index 0000000..23cec0b --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/services/impl/ContactServiceImpl.java @@ -0,0 +1,151 @@ +package com.sahabuddin.contactmanager.services.impl; + +import com.sahabuddin.contactmanager.entities.Contact; +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.models.requests.ContactRequest; +import com.sahabuddin.contactmanager.respositories.ContactRepository; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import com.sahabuddin.contactmanager.services.ContactService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ContactServiceImpl implements ContactService { + + private final ContactRepository contactRepository; + + private final UserRepository userRepository; + + @Override + public Contact createContact(ContactRequest request, User user, MultipartFile file) { + Contact contact = new Contact(); + if (!file.isEmpty()){ + uploadFile(file); + contact.setImageUrl(file.getOriginalFilename()); + }else{ + contact.setImageUrl("contact.png"); + } + + contact.setEmail(request.getEmail()); + contact.setName(request.getName()); + contact.setNickName(request.getNickName()); + contact.setPhone(request.getPhone()); + contact.setDescription(request.getDescription()); + contact.setWork(request.getWork()); + contact.setUser(user); + Contact savedContact = contactRepository.save(contact); + user.getContacts().add(savedContact); + userRepository.save(user); + return savedContact; + + } + + @Override + public Page getAllContactByUser(User user, Pageable pageable) { + return contactRepository.findAllByUser(user, pageable); + } + + @Override + public Contact getContactById(Long id) { + return contactRepository.findById(id).orElse(null); + } + + @Override + public Contact getContactByIdAndUser(Long id, User user) { + return contactRepository.findByIdAndUser(id, user); + } + + @Override + public void deleteContactByIdAndUser(Long id, User user) { + Contact contact = contactRepository.findByIdAndUser(id, user); + user.getContacts().remove(contact); + userRepository.save(user); + contact.setUser(null); + deleteFileByFileName(contact.getImageUrl()); + contactRepository.delete(contact); + } + + @Override + public void updateContact(ContactRequest request, User user, MultipartFile file) { + + Contact contact = contactRepository.findByIdAndUser(request.getId(), user); + try{ + if (!file.isEmpty()){ + deleteFileByFileName(contact.getImageUrl()); + uploadFile(file); + contact.setImageUrl(file.getOriginalFilename()); + } + } catch (Exception e){ + log.error(e.getMessage()); + } + + contact.setEmail(request.getEmail()); + contact.setName(request.getName()); + contact.setNickName(request.getNickName()); + contact.setPhone(request.getPhone()); + contact.setDescription(request.getDescription()); + contact.setWork(request.getWork()); + contactRepository.save(contact); + + + } + + @Override + public List searchByName(String query, User user) { + return contactRepository.findByNameContainingIgnoreCaseAndUser(query, user); + } + + private void deleteFileByFileName(String fileName) { + try { + if (!fileName.equals("contact.png")) { + File file = new ClassPathResource("static/uploaded").getFile(); + Path path = Paths.get(file + File.separator + fileName); + if (Files.exists(path)) { + Files.delete(path); // Delete the file + log.info("File deleted successfully."); + } else { + log.warn("File not found: {}", path); + } + } + } catch (Exception e){ + log.error(e.getMessage()); + } + } + + private void uploadFile(MultipartFile file){ + try { + File savedFile = new ClassPathResource("static/uploaded").getFile(); + log.info("path: {}", savedFile); + Path path = Paths.get(savedFile + File.separator + file.getOriginalFilename()); + File fileNew = new File(String.valueOf(path)); + File directory = fileNew.getParentFile(); + + if (directory != null && !directory.exists()) { + if (directory.mkdirs()) { + log.info("Directory created successfully."); + } else { + log.info("Failed to create directory."); + } + } + Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + log.error(e.getMessage()); + } + + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/services/impl/EmailServiceImpl.java b/src/main/java/com/sahabuddin/contactmanager/services/impl/EmailServiceImpl.java new file mode 100644 index 0000000..f33085d --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/services/impl/EmailServiceImpl.java @@ -0,0 +1,23 @@ +package com.sahabuddin.contactmanager.services.impl; + +import com.sahabuddin.contactmanager.services.EmailService; +import lombok.RequiredArgsConstructor; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EmailServiceImpl implements EmailService { + + private final JavaMailSender emailSender; + + public void sendSimpleMessage(String to, String subject, String text) { + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom("kazi.sahabuddin16@gmail.com"); + message.setTo(to); + message.setSubject(subject); + message.setText(text); + emailSender.send(message); + } +} \ No newline at end of file diff --git a/src/main/java/com/sahabuddin/contactmanager/services/impl/UserServiceImpl.java b/src/main/java/com/sahabuddin/contactmanager/services/impl/UserServiceImpl.java new file mode 100644 index 0000000..f15ff58 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/services/impl/UserServiceImpl.java @@ -0,0 +1,22 @@ +package com.sahabuddin.contactmanager.services.impl; + +import com.sahabuddin.contactmanager.entities.User; +import com.sahabuddin.contactmanager.respositories.UserRepository; +import com.sahabuddin.contactmanager.services.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + + private final PasswordEncoder passwordEncoder; + @Override + public void passwordChange(String oldPassword, String newPassword, User user) { + user.setPassword(passwordEncoder.encode(newPassword)); + userRepository.save(user); + } +} diff --git a/src/main/java/com/sahabuddin/contactmanager/utilities/SessionUtils.java b/src/main/java/com/sahabuddin/contactmanager/utilities/SessionUtils.java new file mode 100644 index 0000000..08759d2 --- /dev/null +++ b/src/main/java/com/sahabuddin/contactmanager/utilities/SessionUtils.java @@ -0,0 +1,30 @@ +package com.sahabuddin.contactmanager.utilities; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +@Slf4j +@Component +public class SessionUtils { + + public void removeAttributeFromSession(String attributeName) { + try{ + log.debug("Removing attribute {} from session", attributeName); + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + HttpSession session = request.getSession(); + session.removeAttribute(attributeName); + } + + } catch (Exception e){ + log.error(e.getMessage()); + + } + + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7580e82..2760179 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,5 +7,16 @@ spring.datasource.password=1234 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.servlet.multipart.max-file-size=10MB +spring.servlet.multipart.max-request-size=10MB + +app.filePath=/home/sahabuddin/durgesh/project_files + +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=kazi.sahabuddin16@gmail.com +spring.mail.password=qcou pemv yegt gjog +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true +spring.mail.properties.mail.smtp.from=kazi.sahabuddin16@gmail.com diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css new file mode 100644 index 0000000..2420563 --- /dev/null +++ b/src/main/resources/static/css/style.css @@ -0,0 +1,94 @@ +body{ + background-color: #e2e2e2 !important; +} + +.banner{ + width: 100%; + height: 93vh; + background:linear-gradient(rgba(0,0,0,.8), rgba(0,0,0,.8)),url(../images/banner.jpg); + background-size: cover; + color: white; +} + +.my-card{ + padding: 20px; + background:#ffffff; + +} + +/*Sidebar Style*/ + +@media only screen and (max-width: 600px) { + .sidebar{ + display: none; + width: 80% !important; + background: white; + height: 100vh; + position: fixed; + padding-top: 20px; + } + + .content{ + margin-left: 0 !important; + } +} + +.sidebar{ + width: 18%; + background: white; + height: 100vh; + position: fixed; + padding-top: 45px; + z-index: 999; +} + +.sidebar a{ + display: block; + width: 100%; + padding: 10px 25px; + text-decoration: none; + color: gray; +} + +.sidebar a:hover{ + background: #e2e2e2; +} + +.sidebar .divider{ + height: 0.5px; + width: 100%; + background: #e2e2e2; + margin-top: 10px; +} + +.sidebar .crossBtn{ + position: absolute; + top: 0; + right: 35px; + font-size: 36px; + cursor: pointer; +} + +.content{ + margin-left: 20%; +} + +.search-container{ + position: relative; +} +.search-result { + position: absolute; + width: 100%; + background: white; + padding: 10px; + border: 1px solid #e2e2e2; + display: none; +} + +.active-menu{ + background: #0d6efd; + color: white !important; +} +.active-menu:hover{ + color: gray !important; +} \ No newline at end of file diff --git a/src/main/resources/static/images/banner.jpg b/src/main/resources/static/images/banner.jpg new file mode 100644 index 0000000..7daff55 Binary files /dev/null and b/src/main/resources/static/images/banner.jpg differ diff --git a/src/main/resources/static/images/confidental.png b/src/main/resources/static/images/confidental.png new file mode 100644 index 0000000..a8c6d15 Binary files /dev/null and b/src/main/resources/static/images/confidental.png differ diff --git a/src/main/resources/static/images/key.png b/src/main/resources/static/images/key.png new file mode 100644 index 0000000..e92afa1 Binary files /dev/null and b/src/main/resources/static/images/key.png differ diff --git a/src/main/resources/static/images/membership.png b/src/main/resources/static/images/membership.png new file mode 100644 index 0000000..6d678f1 Binary files /dev/null and b/src/main/resources/static/images/membership.png differ diff --git a/src/main/resources/static/images/profile.png b/src/main/resources/static/images/profile.png new file mode 100644 index 0000000..1c927a4 Binary files /dev/null and b/src/main/resources/static/images/profile.png differ diff --git a/src/main/resources/static/images/reset-password.png b/src/main/resources/static/images/reset-password.png new file mode 100644 index 0000000..ac2ae52 Binary files /dev/null and b/src/main/resources/static/images/reset-password.png differ diff --git a/src/main/resources/static/js/script.js b/src/main/resources/static/js/script.js new file mode 100644 index 0000000..146e739 --- /dev/null +++ b/src/main/resources/static/js/script.js @@ -0,0 +1,57 @@ +const toggleSidebar = () => { + if ($(".sidebar").is(":visible")){ + $(".sidebar").css("display", "none"); + $(".content").css("margin-left", "0") + } else { + $(".sidebar").css("display", "block"); + $(".content").css("margin-left", "20%") + } +}; + +function deleteContact(id){ + Swal.fire({ + title: "Are you sure?", + text: "You won't be able to revert this!", + icon: "warning", + showCancelButton: true, + confirmButtonColor: "#3085d6", + cancelButtonColor: "#d33", + confirmButtonText: "Yes, delete it!" + }).then((result) => { + if (result.isConfirmed) { + Swal.fire({ + title: "Deleted!", + text: "Your file has been deleted.", + icon: "success" + }); + window.location = '/user/delete/'+id+'/contact' + } else { + Swal.fire({ + //title: "Deleted!", + text: "Your Contact is safe!", + icon: "info" + }); + } + }); +} + +const search = () => { + const query = document.getElementById("search-input").value; + if (query.length > 0){ + let url = window.location.origin+'/user/search/'+query; + fetch(url).then(response => { + return response.json(); + }).then(data => { + let text = `
`; + data.forEach((contact) => { + text += `${contact.name} `; + }); + text+= `
`; + $('.search-result').html(text); + $('.search-result').show(); + }) + }else { + $('.search-result').hide() + } + +} \ No newline at end of file diff --git a/src/main/resources/templates/about.html b/src/main/resources/templates/about.html new file mode 100644 index 0000000..f996ffa --- /dev/null +++ b/src/main/resources/templates/about.html @@ -0,0 +1,14 @@ + + + + + About page + + + +
+

This is about page

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/base.html b/src/main/resources/templates/base.html new file mode 100644 index 0000000..841a0b6 --- /dev/null +++ b/src/main/resources/templates/base.html @@ -0,0 +1,43 @@ + + + + + + Base page + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/change_password.html b/src/main/resources/templates/change_password.html new file mode 100644 index 0000000..b002303 --- /dev/null +++ b/src/main/resources/templates/change_password.html @@ -0,0 +1,44 @@ + + + + + This is login Page + + +
+
+
+
+
+ +
+ +
+ +

Enter New Password

+
+ +
+ + +
+
+ + +
+
+ +
+ +
+
+
+
+ +
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/forget_password.html b/src/main/resources/templates/forget_password.html new file mode 100644 index 0000000..4f05c4f --- /dev/null +++ b/src/main/resources/templates/forget_password.html @@ -0,0 +1,39 @@ + + + + + Forget password + + +
+
+
+
+
+
+ +
+ +

Recover your password

+
+ +
+ + +
+
+ +
+ +
+
+
+
+ +
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html new file mode 100644 index 0000000..bd386bf --- /dev/null +++ b/src/main/resources/templates/home.html @@ -0,0 +1,20 @@ + + + + + This is Home Page + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..aa51bc4 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,52 @@ + + + + + This is login Page + + +
+
+
+
+
+ +
+ Invalid Username or password +
+
+ You have been logged out +
+
+ +
+ +

Login Here !!

+
+ +
+ + +
+
+ + +
+ +
+ +
+ +
+ Forget Password? +
+
+
+ +
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..21f81e6 --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,63 @@ + + + + + This is sign up Page + + +
+
+
+
+
+ +
+ +
+ +

Register Here !!

+
+
+ + + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+ +
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/add_contact.html b/src/main/resources/templates/user/add_contact.html new file mode 100644 index 0000000..169c19b --- /dev/null +++ b/src/main/resources/templates/user/add_contact.html @@ -0,0 +1,86 @@ + + + + + Add contact + + +
+
+
+

Add Contact

+ +
+
+
+
+
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ +
+
+ + + + +
+ +
+ +
+ +
+
+
+
+
+
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/details_contact.html b/src/main/resources/templates/user/details_contact.html new file mode 100644 index 0000000..5916a07 --- /dev/null +++ b/src/main/resources/templates/user/details_contact.html @@ -0,0 +1,30 @@ + + + + + details contacts + + +
+
+
+
User Details
+
+
+ User Avatar +
()
+

Email:

+

Phone:

+

Work:

+

Description:

+
+ +
+ +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/me.html b/src/main/resources/templates/user/me.html new file mode 100644 index 0000000..8668250 --- /dev/null +++ b/src/main/resources/templates/user/me.html @@ -0,0 +1,36 @@ + + + + + details contacts + + +
+
+
+
Details
+
+
+ User Avatar +
+

Email:

+

About:

+

Role:

+
+ + + + +
+ + + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/settings.html b/src/main/resources/templates/user/settings.html new file mode 100644 index 0000000..0a36a46 --- /dev/null +++ b/src/main/resources/templates/user/settings.html @@ -0,0 +1,54 @@ + + + + + Add contact + + +
+
+
+

Change your password

+ +
+
+
+
+
+ + + + +
+ +
+ + + + +
+ +
+ +
+ +
+
+
+
+
+
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/update_contact.html b/src/main/resources/templates/user/update_contact.html new file mode 100644 index 0000000..3e5975b --- /dev/null +++ b/src/main/resources/templates/user/update_contact.html @@ -0,0 +1,83 @@ + + + + + Update contact + + +
+
+
+

Update Contact

+ +
+
+
+
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ +
+
+ + + + +
+ +
+ +
+ +
+
+
+
+
+
+ + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/user-base.html b/src/main/resources/templates/user/user-base.html new file mode 100644 index 0000000..06c113a --- /dev/null +++ b/src/main/resources/templates/user/user-base.html @@ -0,0 +1,82 @@ + + + + + + Base page + + + + + + + + + + + + + +
+
+
+
+ + +
+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/user/user_dashboard.html b/src/main/resources/templates/user/user_dashboard.html new file mode 100644 index 0000000..2fed893 --- /dev/null +++ b/src/main/resources/templates/user/user_dashboard.html @@ -0,0 +1,27 @@ + + + + + This is user dashboard + + +
+ +
+
+ user picture +
+

User dashboard

+
+ + + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user/view_contacts.html b/src/main/resources/templates/user/view_contacts.html new file mode 100644 index 0000000..3a8b1b5 --- /dev/null +++ b/src/main/resources/templates/user/view_contacts.html @@ -0,0 +1,75 @@ + + + + + view all contacts + + +
+
+
+

Your Contacts

+ +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + +
#ImageNameEmailPhoneAction
1 +
Profile image
+
()Otto@mdo + + + +
+ + + +
+
+ + + +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/verify_otp.html b/src/main/resources/templates/verify_otp.html new file mode 100644 index 0000000..58dba53 --- /dev/null +++ b/src/main/resources/templates/verify_otp.html @@ -0,0 +1,40 @@ + + + + + This is login Page + + +
+
+
+
+
+ +
+ +
+ +

OTP Verify

+
+ +
+ + +
+
+ +
+ +
+
+
+
+ +
+ + +
+ + + \ No newline at end of file