diff --git a/chatto/.attach_pid30353 b/chatto/.attach_pid30353 new file mode 100644 index 0000000..e69de29 diff --git a/chatto/config/application.properties b/chatto/config/application.properties index e418935..ed7ad66 100644 --- a/chatto/config/application.properties +++ b/chatto/config/application.properties @@ -5,3 +5,4 @@ spring.datasource.username = chatto_user spring.datasource.password = password database-name = chatto_db2 website-url = 192.168.1.13 +test.bindAddress=192.168.1.106 diff --git a/chatto/config/messages.properties b/chatto/config/messages.properties new file mode 100644 index 0000000..45b2e30 --- /dev/null +++ b/chatto/config/messages.properties @@ -0,0 +1 @@ +test.bindAddress=192.168.1.106 diff --git a/chatto/message.properties b/chatto/message.properties new file mode 100644 index 0000000..822a5e2 --- /dev/null +++ b/chatto/message.properties @@ -0,0 +1,2 @@ +#Sat Oct 12 01:13:02 IST 2019 +test.bindAddress=192.168.1.106 diff --git a/chatto/messages.properties b/chatto/messages.properties new file mode 100644 index 0000000..ca1c7f3 --- /dev/null +++ b/chatto/messages.properties @@ -0,0 +1,2 @@ +#Sat Oct 12 01:15:41 IST 2019 +test.bindAddress=192.168.1.106 diff --git a/chatto/pom.xml b/chatto/pom.xml index ec9dfd3..45e7c6d 100644 --- a/chatto/pom.xml +++ b/chatto/pom.xml @@ -84,6 +84,46 @@ 2.3.5 + + org.springframework.boot + spring-boot-starter-cache + + + + + org.ehcache + ehcache + + + + javax.cache + cache-api + + + + com.sun.xml.bind + jaxb-impl + 2.2.11 + + + + com.sun.xml.bind + jaxb-core + 2.2.11 + + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + + + + + diff --git a/chatto/src/main/java/org/ros/chatto/BeanConfigurations.java b/chatto/src/main/java/org/ros/chatto/BeanConfigurations.java index ea54bfb..fab183d 100644 --- a/chatto/src/main/java/org/ros/chatto/BeanConfigurations.java +++ b/chatto/src/main/java/org/ros/chatto/BeanConfigurations.java @@ -1,15 +1,13 @@ package org.ros.chatto; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - import org.modelmapper.ModelMapper; import org.ros.chatto.security.AuthenticationSuccessHandlerImpl; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; @PropertySource(value = "classpath:queries.properties") @@ -36,6 +34,16 @@ public class BeanConfigurations { return modelMapper; } + @Bean + public MessageSource messageSource() { + final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + messageSource.setBasenames("classpath:/messages,file:./config/messages"); + messageSource.setUseCodeAsDefaultMessage(true); + messageSource.setDefaultEncoding("UTF-8"); + messageSource.setCacheSeconds(5); + return messageSource; + } + // @Bean // public Connection connection() throws SQLException // { diff --git a/chatto/src/main/java/org/ros/chatto/ChattoApplication.java b/chatto/src/main/java/org/ros/chatto/ChattoApplication.java index 310bbd8..e25052c 100644 --- a/chatto/src/main/java/org/ros/chatto/ChattoApplication.java +++ b/chatto/src/main/java/org/ros/chatto/ChattoApplication.java @@ -1,31 +1,38 @@ package org.ros.chatto; +import java.sql.SQLException; + +import org.ros.chatto.service.DBInitializerService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cache.annotation.EnableCaching; -@EnableAutoConfiguration @SpringBootApplication +//@EnableCaching public class ChattoApplication extends SpringBootServletInitializer { // @Value("${spring.datasource.url}") // private static String url; - public static void main(String[] args) { + + public static void main(String[] args) throws SQLException { SpringApplication application = new SpringApplication(ChattoApplication.class); addInitHooks(application); // SpringApplication.run(ChattoApplication.class, args); application.run(args); + + } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(ChattoApplication.class); } - static void addInitHooks(SpringApplication application) { + static void addInitHooks(SpringApplication application) throws SQLException { // TBD … // System.out.println("Hello world very loooooooooooooooooooooooooooooooooooooong string"); // String url = environment.getProperty("spring.datasource.url"); diff --git a/chatto/src/main/java/org/ros/chatto/RestAuthenticationEntryPoint.java b/chatto/src/main/java/org/ros/chatto/RESTAuthenticationEntryPoint.java similarity index 96% rename from chatto/src/main/java/org/ros/chatto/RestAuthenticationEntryPoint.java rename to chatto/src/main/java/org/ros/chatto/RESTAuthenticationEntryPoint.java index 83550e9..e0c67f3 100644 --- a/chatto/src/main/java/org/ros/chatto/RestAuthenticationEntryPoint.java +++ b/chatto/src/main/java/org/ros/chatto/RESTAuthenticationEntryPoint.java @@ -12,7 +12,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationEn import org.springframework.stereotype.Component; @Component -public final class RestAuthenticationEntryPoint +public final class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint { // @Override diff --git a/chatto/src/main/java/org/ros/chatto/WebSecurityConfiguration.java b/chatto/src/main/java/org/ros/chatto/WebSecurityConfiguration.java index e5a1437..8c4b774 100644 --- a/chatto/src/main/java/org/ros/chatto/WebSecurityConfiguration.java +++ b/chatto/src/main/java/org/ros/chatto/WebSecurityConfiguration.java @@ -5,14 +5,19 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserCache; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration @@ -25,13 +30,15 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { private MyUserDetailsService myUserDetailsService; @Autowired private PasswordEncoder passwordEncoder; - + @Autowired + private UserCache userCache; // @SuppressWarnings("deprecation") @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(myUserDetailsService); + provider.setUserCache(userCache); provider.setPasswordEncoder(passwordEncoder); return provider; } @@ -40,30 +47,24 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { public static PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } - - @Configuration @Order(1) public static class ApiWebSecurity extends WebSecurityConfigurerAdapter { @Autowired - private RestAuthenticationEntryPoint restAuthenticationEntryPoint; + private RESTAuthenticationEntryPoint authenticationEntryPoint; + @Override protected void configure(HttpSecurity http) throws Exception { - http - .csrf().disable() - .exceptionHandling() - - .and() + http.csrf().disable().exceptionHandling() + + .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // .cors().and() - .antMatcher("/api/**") - .authorizeRequests() + .antMatcher("/api/**").authorizeRequests() // .antMatchers("/perform-login").permitAll() .anyRequest() // .hasAnyRole("USER", "ADMIN", "SUPER_USER") - .authenticated() - .and().httpBasic() - .authenticationEntryPoint(restAuthenticationEntryPoint) + .authenticated().and().httpBasic().authenticationEntryPoint(authenticationEntryPoint) // .and() // .logout().invalidateHttpSession(true).clearAuthentication(true) // .logoutRequestMatcher(new AntPathRequestMatcher("/api/perform_logout")) @@ -79,8 +80,19 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { } +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// auth.eraseCredentials(false); +// } +// +// public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { +// +// } + } + + @Configuration @Order(2) public static class FormWebSecurity extends WebSecurityConfigurerAdapter { @@ -89,12 +101,12 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.authorizeRequests() // .antMatchers(HttpMethod.POST, "/api/**").permitAll() - .antMatchers("/", "perform_login","/login*", "/registration", "/perform_registration", "/css/**", "/js/**", - "/images/**") + .antMatchers("/", "perform_login","/logout**" ,"/favicon.ico","/login*", "/registration", "/perform_registration", "/css/**", + "/js/**", "/img/**") .permitAll() // .antMatchers("/","/api**","/api/**","/login*","/registration","/perform_registration","/css/**", "/js/**", "/images/**").permitAll() - .antMatchers("/user/**").hasAnyRole("USER", "ADMIN", "SUPER_USER") - .antMatchers("/admin/**").hasAnyRole("ADMIN", "SUPER_USER") + .antMatchers("/user/**").hasAnyRole("USER", "ADMIN", "SUPER_USER").antMatchers("/admin/**") + .hasAnyRole("ADMIN", "SUPER_USER") // .and() // .antMatcher("/api/**") // .authorizeRequests() @@ -102,19 +114,18 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { .and() - .formLogin() - .loginPage("/login").permitAll() - .loginProcessingUrl("/login") + .formLogin().loginPage("/login").permitAll().loginProcessingUrl("/perform_login") // .successHandler(authenticationSuccessHandler) // .failureUrl("/?login_error") - .and() - .logout().invalidateHttpSession(true).clearAuthentication(true) - .logoutRequestMatcher(new AntPathRequestMatcher("/perform_logout")) +// .and() +// .logout().invalidateHttpSession(true) +// .clearAuthentication(true) +// .logoutRequestMatcher(new AntPathRequestMatcher("/perform_logout")) // .logoutSuccessUrl("/").permitAll() // .and().httpBasic(); // .and().cors() -// .and().csrf().disable(); - ; + .and().csrf().disable(); + ; // httpSecurity // .csrf().disable() // .authorizeRequests().antMatchers("login").permitAll() @@ -129,7 +140,17 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { // .logoutSuccessUrl("/").permitAll(); } +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// auth.eraseCredentials(false); +// } + } + +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// auth.eraseCredentials(false); +// } // @Override // protected void configure(AuthenticationManagerBuilder auth) throws Exception { diff --git a/chatto/src/main/java/org/ros/chatto/config/CacheConfig.java b/chatto/src/main/java/org/ros/chatto/config/CacheConfig.java new file mode 100644 index 0000000..33f8809 --- /dev/null +++ b/chatto/src/main/java/org/ros/chatto/config/CacheConfig.java @@ -0,0 +1,47 @@ +package org.ros.chatto.config; + + +import org.ros.chatto.security.MyUserDetailsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.userdetails.UserCache; +import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache; + +@EnableCaching +@Configuration +public class CacheConfig { + + @Autowired + private CacheManager cacheManager; + + + @Bean + public UserCache userCache() throws Exception { +// return new EhCacheBasedUserCache(); +// Cache cache = (Cache) cacheManager().getCache("userCache"); + Cache cache = cacheManager.getCache("chatUser"); + return new SpringCacheBasedUserCache(cache); + } + +// private net.sf.ehcache.CacheManager cacheManager; + +// @PreDestroy +// public void destroy() { +// cacheManager.shutdown(); +// } +// +// @Bean +// public CacheManager cacheManager() { +//// log.debug("Starting Ehcache"); +// cacheManager = net.sf.ehcache.CacheManager.create(); +// cacheManager.getConfiguration().setMaxBytesLocalHeap("16M"); +// EhCacheCacheManager ehCacheManager = new EhCacheCacheManager(); +// ehCacheManager.setCacheManager(cacheManager); +// return ehCacheManager; +// } +} \ No newline at end of file diff --git a/chatto/src/main/java/org/ros/chatto/config/CustomCacheEventLogger.java b/chatto/src/main/java/org/ros/chatto/config/CustomCacheEventLogger.java new file mode 100644 index 0000000..2324078 --- /dev/null +++ b/chatto/src/main/java/org/ros/chatto/config/CustomCacheEventLogger.java @@ -0,0 +1,19 @@ +package org.ros.chatto.config; + +import org.ehcache.event.CacheEvent; +import org.ehcache.event.CacheEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +//@Component +public class CustomCacheEventLogger implements CacheEventListener { + + private static final Logger LOG = LoggerFactory.getLogger(CustomCacheEventLogger.class); + + @Override + public void onEvent(CacheEvent cacheEvent) { + LOG.info("custom Caching event {} key = {} old {} new {} ", cacheEvent.getType(), cacheEvent.getKey(), + cacheEvent.getOldValue(), cacheEvent.getNewValue()); + } +} diff --git a/chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java b/chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java index 11e8aa8..baf4c4d 100644 --- a/chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java +++ b/chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java @@ -10,6 +10,7 @@ import java.util.List; import org.ros.chatto.dto.ChatMessageDTO; import org.ros.chatto.model.MessageCipher; import org.ros.chatto.service.ChatService; +import org.ros.chatto.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -26,6 +27,9 @@ import org.springframework.web.bind.annotation.RestController; public class ChatMessageController { @Autowired private ChatService chatService; + + @Autowired + private UserService userService; @PostMapping(value = "/post/message", consumes = { "application/json" }) @ResponseBody @@ -64,6 +68,11 @@ public class ChatMessageController { List chatMessageDTOs = chatService.getNewMessages(principal.getName(), userName, date); return chatMessageDTOs; } + @GetMapping("/get/users") + public List getAllOtherUsers(Principal principal) + { + return userService.findAllOtherUsers(principal.getName()); + } } //public ResponseEntity> getMessages(@PathVariable String userName, Principal principal) { diff --git a/chatto/src/main/java/org/ros/chatto/controller/Home.java b/chatto/src/main/java/org/ros/chatto/controller/Home.java index d892387..0a0a789 100644 --- a/chatto/src/main/java/org/ros/chatto/controller/Home.java +++ b/chatto/src/main/java/org/ros/chatto/controller/Home.java @@ -34,23 +34,27 @@ public class Home { @Autowired private UserService userService; - @Autowired - private DBInitializerService dbInitializerService; +// @Autowired +// private DBInitializerService dbInitializerService; - private boolean installationChecked = false; +// private boolean installationChecked = false; @RequestMapping("/") public ModelAndView showPage(Principal principal) throws SQLException { ModelAndView mv = new ModelAndView("home"); - mv.addObject("message", "Welcome!"); + String welcomeMesage = String.format("Welcome to chatto"); + if (principal != null) { + welcomeMesage = String.format("Welcome back %s!", principal.getName()); + } + mv.addObject("message", welcomeMesage); // mv.addObject("userNames", userService.findAllOtherUsers(principal.getName())); - if (!installationChecked) { - dbInitializerService.connectDB(); - if(dbInitializerService.getNumTables() == 0) - dbInitializerService.populateDB(); - dbInitializerService.closeConnection(); - installationChecked = true; - } +// if (!installationChecked) { +// dbInitializerService.connectDB(); +// if(dbInitializerService.getNumTables() == 0) +// dbInitializerService.populateDB(); +// dbInitializerService.closeConnection(); +// installationChecked = true; +// } return mv; } diff --git a/chatto/src/main/java/org/ros/chatto/model/ChatUser.java b/chatto/src/main/java/org/ros/chatto/model/ChatUser.java index 7328bc7..30afad8 100644 --- a/chatto/src/main/java/org/ros/chatto/model/ChatUser.java +++ b/chatto/src/main/java/org/ros/chatto/model/ChatUser.java @@ -45,8 +45,9 @@ public class ChatUser { // @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) @JsonBackReference - private Set userRoles = new HashSet(); - +// private Set userRoles = new HashSet(); + private Set userRoles; + public int getUserID() { return userID; } diff --git a/chatto/src/main/java/org/ros/chatto/repository/UserRoleRepository.java b/chatto/src/main/java/org/ros/chatto/repository/UserRoleRepository.java index 943a946..a17785e 100644 --- a/chatto/src/main/java/org/ros/chatto/repository/UserRoleRepository.java +++ b/chatto/src/main/java/org/ros/chatto/repository/UserRoleRepository.java @@ -11,4 +11,7 @@ import org.springframework.stereotype.Repository; public interface UserRoleRepository extends JpaRepository{ @Query("select ur from UserRole ur where ur.user.userID = ?1") public List findByUser(int userID); + + @Query("select ur from UserRole ur where ur.user.userName = ?1") + public List findByUser(String username); } diff --git a/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java b/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java index e86fd8f..9b5a0fc 100644 --- a/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java +++ b/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java @@ -1,8 +1,11 @@ package org.ros.chatto.security; import java.util.List; +import java.util.stream.Collector; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; +import javax.validation.constraints.Size; import org.ros.chatto.model.ChatUser; import org.ros.chatto.model.UserRole; @@ -10,7 +13,11 @@ import org.ros.chatto.repository.RoleRepository; import org.ros.chatto.repository.UserRepository; import org.ros.chatto.repository.UserRoleRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.CacheManager; +import org.springframework.cache.Cache.ValueWrapper; +import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserCache; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -19,57 +26,102 @@ import org.springframework.web.context.WebApplicationContext; @Service public class MyUserDetailsService implements UserDetailsService { - + // @Autowired // private WebApplicationContext applicationContext; - @Autowired - private UserRepository userRepository; - + @Autowired + private UserRepository userRepository; + // @Autowired // private RoleRepository roleRepository; - - @Autowired - private UserRoleRepository userRoleRepository; + + @Autowired + private UserRoleRepository userRoleRepository; + +// @Autowired +// private UserCache userCache; + + @Autowired + private CacheManager cacheManager; + +// @Autowired +// private UserCache userCache; // @PostConstruct // public void completeSetup() { // userRepository = applicationContext.getBean(UserRepository.class); // } - - public MyUserDetailsService() { - super(); - } - @Override - public UserDetails loadUserByUsername(String username) { - ChatUser user = userRepository.findByUserName(username); - - - - if (user == null) { - throw new UsernameNotFoundException(username); - } - System.out.println("Found useeeeeeeeeeeeeeeeeeeeeeeeeeeeeeer " + user.getUserName() + user.getPassword()); - List userRoles = userRoleRepository.findByUser(user.getUserID()); - System.out.println("User role iddddddddddddddddd = " + userRoles.get(0).getRole().getName()); + + public MyUserDetailsService() { + super(); + } + + @Override +// @Cacheable(value="chatUser") + public UserDetails loadUserByUsername(String username) { +// ChatUser user = userRepository.findByUserName(username); + + List userRoles = userRoleRepository.findByUser(username); +// @SuppressWarnings("unchecked") +// List userRoles = (List)cacheManager.getCache(username); +// if((userRoles == null)) { +// userRoles = userRoleRepository.findByUser(username); +// } +// UserDetails userDetails = (UserDetails) cacheManager.getCache(username); +// if((userDetails == null)) { +// user = userRoleRepository.findByUser(username); +// } + System.out.println("Test from userdetails"); + + ValueWrapper valueWrapper = cacheManager.getCache("chatUser").get("hmm"); + if (valueWrapper != null) { + UserDetails userDetails = (UserDetails) valueWrapper.get(); + if (userDetails != null) { + System.out.println("cache username = " + userDetails.getUsername()); + System.out.println("cache password = " + userDetails.getPassword()); + } + } + if (userRoles.size() == 0) { + throw new UsernameNotFoundException(username); + } +// System.out.println("Found useeeeeeeeeeeeeeeeeeeeeeeeeeeeeeer " + user.getUserName() + user.getPassword()); + +// ChatUser user2 = userRoles.get(0).getUser(); +// System.out.println("User role iddddddddddddddddd = " + userRoles.get(0).getRole().getName()); // System.out.println(userRoles.); // return new MyUserPrincipal(user); - return toUserDetails(new UserObject(user.getUserName(), user.getPassword(), userRoles.get(0).getRole().getName())); - } - - private UserDetails toUserDetails(UserObject userObject) { - return User.withUsername(userObject.name) - .password(userObject.password) - .roles(userObject.role).build(); - } - - private static class UserObject { - private String name; - private String password; - private String role; - - public UserObject(String name, String password, String role) { - this.name = name; - this.password = password; - this.role = role; - } - } +// return toUserDetails(new UserObject(user.getUserName(), user.getPassword(), userRoles.get(0).getRole().getName())); +// return User.withUsername(user.getUserName()).password(user.getPassword()) +// .roles( +// user.getUserRoles() +// .stream() +// .map(userRole -> { +// System.out.println("role = " + userRole.getRole().getName()); +// return userRole.getRole().getName(); +// }) +// .toArray(size -> new String[size]) +// ) +// .build(); + ChatUser user = userRoles.get(0).getUser(); + return User.withUsername(user.getUserName()).password(user.getPassword()) + .roles(userRoles.stream().map(userRole -> { + System.out.println("role = " + userRole.getRole().getName()); + return userRole.getRole().getName(); + }).toArray(size -> new String[size])).build(); + } + + private UserDetails toUserDetails(UserObject userObject) { + return User.withUsername(userObject.name).password(userObject.password).roles(userObject.role).build(); + } + + private static class UserObject { + private String name; + private String password; + private String role; + + public UserObject(String name, String password, String role) { + this.name = name; + this.password = password; + this.role = role; + } + } } \ No newline at end of file diff --git a/chatto/src/main/java/org/ros/chatto/service/DBInitializerService.java b/chatto/src/main/java/org/ros/chatto/service/DBInitializerService.java index 93c48d7..89d756d 100644 --- a/chatto/src/main/java/org/ros/chatto/service/DBInitializerService.java +++ b/chatto/src/main/java/org/ros/chatto/service/DBInitializerService.java @@ -1,14 +1,22 @@ package org.ros.chatto.service; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Properties; +import org.ros.chatto.ChattoApplication; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.PropertySource; +import org.springframework.context.event.EventListener; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.EncodedResource; import org.springframework.jdbc.datasource.init.ScriptUtils; @@ -38,6 +46,9 @@ public class DBInitializerService { @Value("${num-tables}") private String numTablesQuery; + @Value("${test.bindAddress}") + private String bindAddress; + private Connection connection; // public DBInitializerService(Connection connection) { @@ -111,7 +122,18 @@ public class DBInitializerService { return numTables; } - public void populateDB() throws SQLException { + @EventListener(ApplicationReadyEvent.class) + public void doSomethingAfterStartup() throws SQLException, IOException { +// setProperties(); + System.out.println("Hello world, I have just started up"); + System.out.println("Initializing database"); + connectDB(); + if (getNumTables() == 0) + populateDB(); + closeConnection(); + } + + public void populateDB() throws SQLException, IOException { // System.out.println("Database name = " + dbName); // String sql = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '" + dbName + "' and TABLE_TYPE='BASE TABLE' "; // String sql = numTablesQuery; @@ -139,6 +161,36 @@ public class DBInitializerService { // connection.close(); } + public void setProperties() throws IOException { +// InputStream input = ChattoApplication.class.getClassLoader().getResourceAsStream("messages.properties"); + OutputStream outputStream = new FileOutputStream("messages.properties"); +// FileInputStream in = new FileInputStream("First.properties"); +// Properties props = new Properties(); +// props.load(in); +// in.close(); +// +// FileOutputStream out = new FileOutputStream("First.properties"); +// props.setProperty("country", "america"); +// props.store(out, null); +// out.close(); + Properties prop = new Properties(); + System.out.println("Hello from setProperties"); + + prop.setProperty("test.bindAddress", bindAddress); + prop.store(outputStream, null); +// if (input == null) { +// System.out.println("Sorry, unable to find messages.properties"); +// return; +// } + + // load a properties file from class path, inside static method +// prop.load(input); +// Object object = prop.setProperty("test.bindAddress", bindAddress); +// input.close(); + outputStream.close(); +// prop.store(object, comments); + } + public void closeConnection() throws SQLException { connection.close(); } diff --git a/chatto/src/main/resources/application.properties b/chatto/src/main/resources/application.properties index dd5ee56..24bf0ae 100644 --- a/chatto/src/main/resources/application.properties +++ b/chatto/src/main/resources/application.properties @@ -20,4 +20,8 @@ logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE spring.http.log-request-details=true #spring.jackson.date-format=yyyy-MM-d spring.jackson.serialization.write-dates-as-timestamps=false -#spring.mvc.static-path-pattern=/static/** \ No newline at end of file +#spring.mvc.static-path-pattern=/static/** +#spring.cache.type=ehcache3 +spring.cache.jcache.config=classpath:ehcache.xml +logging.level.org.springframework.cache = DEBUG +#test.bindAddress=192.168.1.106 \ No newline at end of file diff --git a/chatto/src/main/resources/ehcache.xml b/chatto/src/main/resources/ehcache.xml new file mode 100644 index 0000000..8cbdabe --- /dev/null +++ b/chatto/src/main/resources/ehcache.xml @@ -0,0 +1,44 @@ + + + + + + + + java.lang.String + org.springframework.security.core.userdetails.UserDetails + + 600 + + + + org.ros.chatto.config.CustomCacheEventLogger + ASYNCHRONOUS + UNORDERED + CREATED + UPDATED + EXPIRED + REMOVED + EVICTED + + + + 2000 + 100 + + + + + + \ No newline at end of file diff --git a/chatto/src/main/resources/messages.properties b/chatto/src/main/resources/messages.properties new file mode 100644 index 0000000..a39da72 --- /dev/null +++ b/chatto/src/main/resources/messages.properties @@ -0,0 +1 @@ +#test.bindAddress=192.168.1.106 \ No newline at end of file diff --git a/chatto/src/main/resources/static/css/colors.css b/chatto/src/main/resources/static/css/colors.css new file mode 100644 index 0000000..a4437e2 --- /dev/null +++ b/chatto/src/main/resources/static/css/colors.css @@ -0,0 +1,322 @@ +/*------------------------------------ +- COLOR primary +------------------------------------*/ + + +/* +.alert-primary { + color: #191d21; + background-color: #b8c1c9; + border-color: #adb6c0; +} + +.alert-primary hr { + border-top-color: #9eaab5; +} + +.alert-primary .alert-link { + color: #030404; +} + +.badge-primary { + color: #fff; + background-color: #4f5b67; +} + +.badge-primary[href]:hover, +.badge-primary[href]:focus { + color: #fff; + background-color: #38414a; +} + +.bg-primary { + background-color: #4f5b67 !important; +} + +a.bg-primary:hover, +a.bg-primary:focus, +button.bg-primary:hover, +button.bg-primary:focus { + background-color: #38414a !important; +} + +.border-primary { + border-color: #4f5b67 !important; +} + +.btn-primary { + color: #fff; + background-color: #4f5b67; + border-color: #4f5b67; +} + +.btn-primary:hover { + color: #fff; + background-color: #3f4952; + border-color: #38414a; +} + +.btn-primary:focus, +.btn-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(79, 91, 103, 0.5); +} + +.btn-primary.disabled, +.btn-primary:disabled { + color: #fff; + background-color: #4f5b67; + border-color: #4f5b67; +} + +.btn-primary:not(:disabled):not(.disabled):active, +.btn-primary:not(:disabled):not(.disabled).active, +.show>.btn-primary.dropdown-toggle { + color: #fff; + background-color: #38414a; + border-color: #323941; +} + +.btn-primary:not(:disabled):not(.disabled):active:focus, +.btn-primary:not(:disabled):not(.disabled).active:focus, +.show>.btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(79, 91, 103, 0.5); +} + +.btn-outline-primary { + color: #4f5b67; + background-color: transparent; + border-color: #4f5b67; +} + +.btn-outline-primary:hover { + color: #fff; + background-color: #4f5b67; + border-color: #4f5b67; +} + +.btn-outline-primary:focus, +.btn-outline-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(79, 91, 103, 0.5); +} + +.btn-outline-primary.disabled, +.btn-outline-primary:disabled { + color: #4f5b67; + background-color: transparent; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active, +.btn-outline-primary:not(:disabled):not(.disabled).active, +.show>.btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #4f5b67; + border-color: #4f5b67; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, +.btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(79, 91, 103, 0.5); +} + +.list-group-item-primary { + color: #191d21; + background-color: #adb6c0; +} + +.list-group-item-primary.list-group-item-action:hover, +.list-group-item-primary.list-group-item-action:focus { + color: #191d21; + background-color: #9eaab5; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #191d21; + border-color: #191d21; +} + +.table-primary, +.table-primary>th, +.table-primary>td { + background-color: #adb6c0; +} + +.table-hover .table-primary:hover { + background-color: #9eaab5; +} + +.table-hover .table-primary:hover>td, +.table-hover .table-primary:hover>th { + background-color: #9eaab5; +} + +.text-primary { + color: #4f5b67 !important; +} + +a.text-primary:hover, +a.text-primary:focus { + color: #38414a !important; +} */ + + +/*------------------------------------ +- COLOR primary +------------------------------------*/ + +.alert-primary { + color: #14171b; + background-color: #b1bbc4; + border-color: #a5b0bb; +} + +.alert-primary hr { + border-top-color: #97a4b0; +} + +.alert-primary .alert-link { + color: #000000; +} + +.badge-primary { + color: #fff; + background-color: #495561; +} + +.badge-primary[href]:hover, +.badge-primary[href]:focus { + color: #fff; + background-color: #333b43; +} + +.bg-primary { + background-color: #495561 !important; +} + +a.bg-primary:hover, +a.bg-primary:focus, +button.bg-primary:hover, +button.bg-primary:focus { + background-color: #333b43 !important; +} + +.border-primary { + border-color: #495561 !important; +} + +.btn-primary { + color: #fff; + background-color: #495561; + border-color: #495561; +} + +.btn-primary:hover { + color: #fff; + background-color: #39434c; + border-color: #333b43; +} + +.btn-primary:focus, +.btn-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(73, 85, 97, 0.5); +} + +.btn-primary.disabled, +.btn-primary:disabled { + color: #fff; + background-color: #495561; + border-color: #495561; +} + +.btn-primary:not(:disabled):not(.disabled):active, +.btn-primary:not(:disabled):not(.disabled).active, +.show>.btn-primary.dropdown-toggle { + color: #fff; + background-color: #333b43; + border-color: #2c333b; +} + +.btn-primary:not(:disabled):not(.disabled):active:focus, +.btn-primary:not(:disabled):not(.disabled).active:focus, +.show>.btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(73, 85, 97, 0.5); +} + +.btn-outline-primary { + color: #495561; + background-color: transparent; + border-color: #495561; +} + +.btn-outline-primary:hover { + color: #fff; + background-color: #495561; + border-color: #495561; +} + +.btn-outline-primary:focus, +.btn-outline-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(73, 85, 97, 0.5); +} + +.btn-outline-primary.disabled, +.btn-outline-primary:disabled { + color: #495561; + background-color: transparent; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active, +.btn-outline-primary:not(:disabled):not(.disabled).active, +.show>.btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #495561; + border-color: #495561; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, +.btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(73, 85, 97, 0.5); +} + +.list-group-item-primary { + color: #14171b; + background-color: #a5b0bb; +} + +.list-group-item-primary.list-group-item-action:hover, +.list-group-item-primary.list-group-item-action:focus { + color: #14171b; + background-color: #97a4b0; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #14171b; + border-color: #14171b; +} + +.table-primary, +.table-primary>th, +.table-primary>td { + background-color: #a5b0bb; +} + +.table-hover .table-primary:hover { + background-color: #97a4b0; +} + +.table-hover .table-primary:hover>td, +.table-hover .table-primary:hover>th { + background-color: #97a4b0; +} + +.text-primary { + color: #495561 !important; +} + +a.text-primary:hover, +a.text-primary:focus { + color: #333b43 !important; +} \ No newline at end of file diff --git a/chatto/src/main/resources/static/css/master.css b/chatto/src/main/resources/static/css/master.css index 0895505..569b3d5 100644 --- a/chatto/src/main/resources/static/css/master.css +++ b/chatto/src/main/resources/static/css/master.css @@ -1,24 +1,126 @@ -.myClass { +/* .myClass { color: red; +} */ + + +/* https://arcusiridis.com/images/background.jpg */ + +body { + background: #333; + color: #ffffff; + /* background-image: url('https://bluestnight.com/images/background_lg.jpg'); */ } -#body-container { + + +/* #body-container { margin: 0 auto 0 auto; max-width: 80%; - /* vertical-align: auto; */ -} -.shadow-sm { - width: 50%; -} -input[type="radio"]{ - /*position:fixed;*/ - opacity:0; + vertical-align: auto; +} +*/ + +input[type="radio"] { + /*position:fixed;*/ + opacity: 0; } + input[type=radio]+label { - font-weight: normal; + font-weight: normal; } + input[type=radio]:checked+label { - font-weight: bold; + font-weight: bold; + background-color: #566069; } + input[type=radio]:focus+label { - border: 1px dotted #000; + border: 1px dotted #000; +} + +#home-section { + background-image: url('../img/home.jpg'); + background-repeat: no-repeat; + background-size: cover; + background-attachment: fixed; + min-height: 900px; + height: auto; +} + +#home-section .home-inner { + padding-top: 75px; + /* padding-bottom: 10px; */ + /* background: #333; */ +} + + +/* #home-section .card-form { + opacity: 0.8; +} */ + +#home-section .dark-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + min-height: 900px; + background: rgba(0, 0, 0, 0.7); +} + +#chat-section { + /* background-image: url('../img/home.jpg'); */ + background: #495561; + /* background-repeat: no-repeat; + background-size: cover; + background-attachment: fixed; */ + min-height: 500px; +} + +#chat-section .chat-inner { + padding-top: 75px; + /* background: #333; */ +} + +#chat-section .dark-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + min-height: 600px; + /* background: rgba(0, 0, 0, 0.7); */ +} + +textarea { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100%; +} + +#chatTextArea { + min-height: 300px; +} + + +/* .container { + width: 50%; +} */ + +.my-form-inputs { + width: 80%; +} + +#login-card { + width: 40%; + /* margin: 0 auto; */ + /* Added */ + /* float: none; */ + /* Added */ + /* margin-bottom: 10px; */ + /* Added */ +} + +@media only screen and (max-width: 600px) { + #login-card { + width: 90%; + } } \ No newline at end of file diff --git a/chatto/src/main/resources/static/img/home.jpg b/chatto/src/main/resources/static/img/home.jpg new file mode 100644 index 0000000..68474cb Binary files /dev/null and b/chatto/src/main/resources/static/img/home.jpg differ diff --git a/chatto/src/main/resources/static/js/chat.js b/chatto/src/main/resources/static/js/chat.js index 40b7987..e4b8697 100644 --- a/chatto/src/main/resources/static/js/chat.js +++ b/chatto/src/main/resources/static/js/chat.js @@ -14,14 +14,19 @@ if(!ischecked_method) { //payment method button is not checked var toUserRadios = document.getElementsByName('toUser'); var isCheckedUser = false; var chatTextArea = document.getElementById('chatTextArea'); + var passphraseInput = document.getElementById('passphrase'); -var postNewMessageUrl = "http://localhost:8080/api/chat/post/message"; -var getAllMessagesUrl = "http://localhost:8080/api/chat/get/messages/"; -var getNewMessagesUrl = "http://localhost:8080/api/chat/get/messages/"; +var postNewMessageUrl = `http://${hostAddress}/api/chat/post/message`; //hostAddress variable is set in the thymeleaf head fragment +var getAllMessagesUrl = `http://${hostAddress}/api/chat/get/messages/`; +var getNewMessagesUrl = `http://${hostAddress}/api/chat/get/messages/`; +// var postNewMessageUrl = "http://localhost:8080/api/chat/post/message"; +// var getAllMessagesUrl = "http://localhost:8080/api/chat/get/messages/"; +// var getNewMessagesUrl = "http://localhost:8080/api/chat/get/messages/"; // var messageLog = []; var username = sessionStorage.getItem('username'); var password = sessionStorage.getItem('password'); var authToken = 'Basic ' + btoa(username + ":" + password); +var iterations = 100000; // var lastMessageTimeStamp; // console.log(authToken); @@ -60,8 +65,9 @@ function handleChatForm() { let localDate = new Date(); let messageLine = sprintf('%s %s %s: %s', localDate.toLocaleDateString(), localDate.toLocaleTimeString(), username, messageContent); chatTextArea.append(messageLine + "\n"); + chatTextArea.scrollTop = chatTextArea.scrollHeight; // let messageCipher = sjcl.encrypt("password", messageContent); - let messageCipher = sjcl.encrypt(passphraseInput.value, messageContent); + let messageCipher = sjcl.encrypt(passphraseInput.value, messageContent,{mode: "gcm",ts: 128, adata: "",iter: iterations}); let messageCipherJson = JSON.parse(messageCipher); // let messageCipherSpring = JSON.stringify(messageCipherJson); // console.log('message cipher json ' + messageCipherJson); @@ -75,6 +81,7 @@ function handleChatForm() { messageSend(JSON.stringify(chatMessageDTO)); // sessionStorage.setItem('passphrase', passphraseInput.value); // console.log(sessionStorage.getItem('passphrase')); + }) } @@ -215,6 +222,7 @@ parent.addDelegatedListener("click", "input[type='radio']", function (event) { // chatTextArea.append(obj.fromUser + ": " + message + "\n"); chatTextArea.append(messageLine + '\n'); messageLog[i++] = messageLine; + chatTextArea.scrollTop = chatTextArea.scrollHeight; // console.log('Message log = ' + messageLog); @@ -255,7 +263,7 @@ parent.addDelegatedListener("click", "input[type='radio']", function (event) { console.log(messageLine); // chatTextArea.append(obj.fromUser + ": " + message + "\n"); chatTextArea.append(messageLine + '\n'); - + chatTextArea.scrollTop = chatTextArea.scrollHeight; storedMessages.push(messageLine); }) @@ -264,12 +272,15 @@ parent.addDelegatedListener("click", "input[type='radio']", function (event) { console.log("this value stored" + sessionStorage.getItem(this.value)) console.log("last message time stamp = " + lastMessageTimeStamp); console.log(sessionStorage.getItem(this.value + '-time')); - chatTextArea.textContent = ''; + + } + chatTextArea.textContent = ''; console.log("Stored messages 2 = " + storedMessages); storedMessages.forEach(function (messageLine) { chatTextArea.append(messageLine + '\n'); + chatTextArea.scrollTop = chatTextArea.scrollHeight; }) - } + }); diff --git a/chatto/src/main/resources/static/js/chatStatic.js b/chatto/src/main/resources/static/js/chatStatic.js new file mode 100644 index 0000000..1dbaae6 --- /dev/null +++ b/chatto/src/main/resources/static/js/chatStatic.js @@ -0,0 +1,22 @@ +var chatTextArea = document.getElementById('chatTextArea'); +function handleChatForm() { + let chatInput = document.getElementById('chatInput'); + let myForm = document.getElementById('chatMessageForm').addEventListener( + 'submit', function (e) { + e.preventDefault(); + + // let user = getSelectedUser(); + // if (!isCheckedUser) { + // window.alert('please select a user'); + // return; + // } + // console.log('second user = ' + user); + let messageContent = chatInput.value; + let localDate = new Date(); + let messageLine = localDate.toLocaleDateString() + localDate.toLocaleTimeString() + 'fromUser' + ': ' + messageContent; + chatTextArea.append(messageLine + "\n"); + chatTextArea.scrollTop = chatTextArea.scrollHeight; + }) +} + +handleChatForm(); \ No newline at end of file diff --git a/chatto/src/main/resources/templates/NewFile.html b/chatto/src/main/resources/templates/NewFile.html new file mode 100644 index 0000000..c38c981 --- /dev/null +++ b/chatto/src/main/resources/templates/NewFile.html @@ -0,0 +1,17 @@ + + + +
+ + Home +
+ + + + + + + + + \ No newline at end of file diff --git a/chatto/src/main/resources/templates/chat.html b/chatto/src/main/resources/templates/chat.html index 89c3e4e..c8385f2 100644 --- a/chatto/src/main/resources/templates/chat.html +++ b/chatto/src/main/resources/templates/chat.html @@ -2,37 +2,104 @@ -
- - Chat -
- - - + + + +
+ + Chat +
+ + + - - - -
- - - - -
- -
- - - -
+
+
+
+
+
+
+

Chat with your friends

+
+
+ +
+
+ + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Laboriosam dolorem nostrum consequatur eos voluptates. Ipsam ullam quos illo qui. Quaerat corrupti nisi numquam rerum quasi nesciunt deserunt fugit commodi consequatur! + +
+
+
+
+ +
+
+
+
+
+
+
+

Chat

+
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+ + + + + +
+
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + + - + + + - - - - Layout Generic Title - + + + + + + + + + + + + + + + + Layout Generic Title + diff --git a/chatto/src/main/resources/templates/fragments/navbar.html b/chatto/src/main/resources/templates/fragments/navbar.html new file mode 100644 index 0000000..995b9d0 --- /dev/null +++ b/chatto/src/main/resources/templates/fragments/navbar.html @@ -0,0 +1,60 @@ + + + + +
+ + Navbar Fragment +
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/chatto/src/main/resources/templates/home.html b/chatto/src/main/resources/templates/home.html index 85a5d36..216bbef 100644 --- a/chatto/src/main/resources/templates/home.html +++ b/chatto/src/main/resources/templates/home.html @@ -1,19 +1,107 @@ + -Title +
+ + Home +
+ + + + + + + + + + + -
- Web Application. Passed parameter : -
- -

Welcome to home page. Please login to access any features.

- login - - +
+
+
+
+
+
+ + +
+ +
+

Chatto - Self Hosted, Minimal E2E Chat

+ + Welcome +

Chatto is a minimal, end to end encrypted chat application.

+ + Get Started +
+ +
+
+
+
+

Features

+
+ +

+

    +
  • +

    + + Self Hosted

    +
  • +
  • +

    + + End To End Encrypted Messaging

    +
  • +
  • +

    + + Free Software (AGPLv3 Licensed)

    +
  • +
  • +

    + + Built With Java And Spring

    +
  • +
+

+ +
+
+
+
+
+
+
+
+
+
+
+

+

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquid illum ea accusamus animi voluptate. Quam temporibus aperiam, similique in labore sint quasi harum. Praesentium enim iste dicta quaerat perspiciatis eos.

+

+ Find out more +
+
+
+
+ + + \ No newline at end of file diff --git a/chatto/src/main/resources/templates/login.html b/chatto/src/main/resources/templates/login.html index ccc2936..7ca5c70 100644 --- a/chatto/src/main/resources/templates/login.html +++ b/chatto/src/main/resources/templates/login.html @@ -2,50 +2,103 @@ -
- Login -
- +
+ Login +
+ + + -
- -
-
- +
+
+
+
+ +
+ +
+ + + + +
+ + +

Please Sign In

+
+ Invalid username or password. +
+
+ You have been logged out. +
+
+ + +
+ +
+ + +
+ +
+ +
+ + +
+
+
+
+
+
+
+ + + + + + + + - - Please Login -
- Invalid username or password. -
-
- You have been logged out. -
- - - -

- - -

- - -
- -
- - - - \ No newline at end of file + --> \ No newline at end of file diff --git a/chatto/src/main/resources/templates/user/home.html b/chatto/src/main/resources/templates/user/home.html index 1ca6a34..1624d70 100644 --- a/chatto/src/main/resources/templates/user/home.html +++ b/chatto/src/main/resources/templates/user/home.html @@ -1,13 +1,58 @@ + - -Insert title here +
+ User Home +
+ + + + + - user page -
- -
+
+ +
+
+
+
+ + +
+

User Page

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