diff --git a/README.DEV.md b/README.DEV.md
new file mode 100644
index 00000000..2047be19
--- /dev/null
+++ b/README.DEV.md
@@ -0,0 +1,41 @@
+
+## When starting jPrime for first time.
+
+
+### Create new database in MySQL DB
+
+$ mysql -u root -p
+
+mysql> USE mysql;
+
+mysql> CREATE DATABASE IF NOT EXISTS javabg
+ DEFAULT CHARACTER SET = utf8
+ DEFAULT COLLATE = utf8_unicode_ci;
+
+mysql> GRANT ALL ON javabg.* TO 'root'@'localhost' IDENTIFIED BY 'admin';
+
+mysql> exit;
+
+
+### Configure REAL Mail or FAKE Mail server
+
+##### FAKE mail servers used only during development
+
+ - www.mailtrap.io
+
+
+### Copy application-DEV.template.properties to application-DEV.properties
+
+$ cd jprime/src/main/resources/
+
+$ cp application-DEV.template.properties application-DEV.properties
+
+
+### Adjust DEV profile properties file(application-DEV.properties) if needed
+
+$ vim /jprime/src/main/resources/application-DEV.properties
+
+spring.boot.admin.url=http://localhost:9090
+
+server.port=9090
+
diff --git a/jprime - Application.launch b/jprime - Application.launch
new file mode 100644
index 00000000..89b18a41
--- /dev/null
+++ b/jprime - Application.launch
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 22efb4cf..1b6af089 100644
--- a/pom.xml
+++ b/pom.xml
@@ -200,7 +200,7 @@
- site.app.Application
+ site.app.Application
4.1.5.RELEASE
UTF-8
1.5.0.M1
diff --git a/src/main/java/site/app/SecurityConfig.java b/src/main/java/site/app/SecurityConfig.java
index c02a1d1c..40b9fd01 100644
--- a/src/main/java/site/app/SecurityConfig.java
+++ b/src/main/java/site/app/SecurityConfig.java
@@ -22,6 +22,7 @@
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
+import site.model.Role;
import site.model.User;
import site.repository.UserRepository;
@@ -62,8 +63,8 @@ public Authentication authenticate(Authentication authentication) throws Authent
String providedPassword = (String) authentication.getCredentials();
//admin hack
- if(email.equals("admin") && providedPassword.equals(environment.getProperty("admin.password"))){
- return new UsernamePasswordAuthenticationToken(email, providedPassword, Collections.singleton(new SimpleGrantedAuthority("ADMIN")));
+ if(email.equals("admin") && providedPassword.equals(environment.getProperty("admin.password"))) {
+ return new UsernamePasswordAuthenticationToken(email, providedPassword, Collections.singleton(new SimpleGrantedAuthority(Role.ADMIN_NAME)));
}
User user = userRepository.findUserByEmail(email);
@@ -71,8 +72,9 @@ public Authentication authenticate(Authentication authentication) throws Authent
if (user == null || !passwordEncoder().matches(providedPassword, user.getPassword())) {
throw new BadCredentialsException("Username/Password does not match for " + authentication.getPrincipal());
}
-
- return new UsernamePasswordAuthenticationToken(email, providedPassword, Collections.singleton(new SimpleGrantedAuthority("USER")));
+ // @Trifon - Read User roles from DB
+ // return new UsernamePasswordAuthenticationToken(email, providedPassword, Collections.singleton(new SimpleGrantedAuthority("USER")));
+ return new UsernamePasswordAuthenticationToken(email, providedPassword, user.getRoles());
}
@Override
diff --git a/src/main/java/site/controller/AdminArticleController.java b/src/main/java/site/controller/AdminArticleController.java
index b1577f0f..49778efc 100644
--- a/src/main/java/site/controller/AdminArticleController.java
+++ b/src/main/java/site/controller/AdminArticleController.java
@@ -12,6 +12,7 @@
import org.springframework.web.bind.annotation.RequestMethod;
import site.facade.AdminService;
import site.model.Article;
+import site.model.Role;
import site.model.User;
import javax.validation.Valid;
@@ -45,17 +46,18 @@ public String add(@Valid final Article article, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "/admin/article/edit.jsp";
}
- User admin = this.adminFacade.findUserByEmail("admin@jsprime.io");
- if (admin == null) {
- admin = new User();
- admin.setEmail("admin@jsprime.io");
- admin.setFirstName("Admin");
- admin.setLastName("");
- this.adminFacade.saveUser(admin);
+ User adminUser = this.adminFacade.findUserByEmail(User.ADMIN_EMAIL);
+ Role adminRole = this.adminFacade.findRoleByNameOrCreate(Role.ADMIN_NAME); //@Trifon
+ if (adminUser == null) {
+ adminUser = this.adminFacade.createRegularUser(User.ADMIN_EMAIL);
+ adminUser.setFirstName("Admin");
+ adminUser.setLastName("");
+ adminUser.addRole( adminRole ); //@Trifon
+ adminUser = this.adminFacade.saveUser(adminUser);
//refresh
- admin = this.adminFacade.findUserByEmail("admin@jsprime.io");
+ adminUser = this.adminFacade.findUserByEmail(User.ADMIN_EMAIL); // TODO - Maybe this refresh is not needed as admin is already updated by saveUser()?
}
- article.setAuthor(admin);
+ article.setAuthor(adminUser);
this.adminFacade.saveArticle(article);
return "redirect:/admin/article/view";
@@ -83,5 +85,4 @@ public String remove(@PathVariable("itemId") Long itemId, Model model) {
adminFacade.deleteArticle(itemId);
return "redirect:/admin/article/view";
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/site/facade/AdminService.java b/src/main/java/site/facade/AdminService.java
index c9a23ce2..9eeeb324 100644
--- a/src/main/java/site/facade/AdminService.java
+++ b/src/main/java/site/facade/AdminService.java
@@ -40,6 +40,10 @@ public class AdminService {
@Qualifier(UserRepository.NAME)
private UserRepository userRepository;
+ @Autowired
+ @Qualifier(RoleRepository.NAME)
+ private RoleRepository roleRepository;
+
@Autowired
@Qualifier(TagRepository.NAME)
private TagRepository tagRepository;
@@ -149,9 +153,36 @@ public User findOneUser(Long id){
return userRepository.findOne(id);
}
+ //@Trifon
+ public Role findRoleByName(String roleName) {
+ return roleRepository.findByName( roleName );
+ }
+ //@Trifon
+ public Role findRoleByNameOrCreate(String roleName) {
+ Role role = this.findRoleByName( roleName );
+ if (role == null) {
+ role = new Role( roleName );
+ role = this.saveRole( role );
+ }
+ return role;
+ }
+ //@Trifon
+ public Role saveRole(Role role) {
+ return roleRepository.save( role );
+ }
+ //@Trifon
+ public User createRegularUser(String email) {
+ Role userRole = this.findRoleByNameOrCreate(Role.USER_NAME);
+
+ User user = new User();
+ user.setEmail( email );
+ user.addRole( userRole );
+ return user;
+ }
+
//currently used for admin TODO:to be fixed with normal authentication with spring
public User findUserByEmail(String email){
- if(userRepository.findByEmail(email).size()>0) {
+ if (userRepository.findByEmail(email).size()>0) {
return userRepository.findByEmail(email).get(0);
}
return null;
diff --git a/src/main/java/site/model/Role.java b/src/main/java/site/model/Role.java
new file mode 100644
index 00000000..a683ed8a
--- /dev/null
+++ b/src/main/java/site/model/Role.java
@@ -0,0 +1,49 @@
+package site.model;
+
+import javax.persistence.Entity;
+
+import org.springframework.security.core.GrantedAuthority;
+
+/**
+ * @author Trifon Trifonov
+ */
+@Entity
+public class Role
+ extends AbstractEntity
+ implements GrantedAuthority
+{
+
+ private static final long serialVersionUID = 1L;
+
+ public final static String USER_NAME = "USER";
+ public final static String ADMIN_NAME = "ADMIN";
+
+ private String name;
+
+ public Role() {
+
+ }
+ public Role(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getAuthority() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "Role ["+
+ "id=" + getId() +
+ ", name=" + name +
+ "]";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/site/model/User.java b/src/main/java/site/model/User.java
index c93d27c3..babdb05a 100644
--- a/src/main/java/site/model/User.java
+++ b/src/main/java/site/model/User.java
@@ -6,40 +6,51 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
+import javax.persistence.JoinTable;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import org.hibernate.validator.constraints.Email;
-import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
-import org.hibernate.validator.constraints.NotEmpty;
@Entity
public class User extends AbstractEntity {
/**
- * Default serial version uid.
- */
- private static final long serialVersionUID = 1L;
-
+ * Default serial version uid.
+ */
+ private static final long serialVersionUID = 1L;
+
+ public static final String ADMIN_EMAIL = "admin@jsprime.io";
+
private String firstName;
-
+
private String lastName;
-
+
@Column(unique = true)
- @NotBlank
- @Email
+ @NotBlank
+ @Email
private String email;
-
+
private String password;
-
+
@Transient
private String cpassword;
-
+
private String phone;
- @OneToMany(mappedBy = "author", fetch = FetchType.LAZY, targetEntity = Article.class)
- private Collection articles = new HashSet<>();
-
+ @OneToMany(mappedBy = "author", fetch = FetchType.LAZY, targetEntity = Article.class)
+ private Collection articles = new HashSet<>();
+
+ //@Trifon
+ @ManyToMany(fetch = FetchType.EAGER)
+ @JoinTable(name = "user_role"
+ , joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")
+ , inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id") )
+ private Collection roles = new HashSet<>();
+
+
public String getFirstName() {
return firstName;
}
@@ -80,32 +91,32 @@ public void setPhone(String phone) {
this.phone = phone;
}
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (!(o instanceof User))
- return false;
-
- User user = (User) o;
-
- if (email != null && !email.equals(user.email))
- return false;
- if (firstName != null && !firstName.equals(user.firstName))
- return false;
- if (lastName != null && !lastName.equals(user.lastName))
- return false;
-
- return true;
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof User))
+ return false;
+
+ User user = (User) o;
+
+ if (email != null && !email.equals(user.email))
+ return false;
+ if (firstName != null && !firstName.equals(user.firstName))
+ return false;
+ if (lastName != null && !lastName.equals(user.lastName))
+ return false;
+
+ return true;
+ }
- @Override
- public int hashCode() {
- int result = firstName.hashCode();
- result = 31 * result + lastName.hashCode();
- result = 31 * result + email.hashCode();
- return result;
- }
+ @Override
+ public int hashCode() {
+ int result = firstName.hashCode();
+ result = 31 * result + lastName.hashCode();
+ result = 31 * result + email.hashCode();
+ return result;
+ }
public String getPassword() {
return password;
@@ -119,6 +130,21 @@ public String getCpassword() {
return cpassword;
}
+ public Collection getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Collection roles) {
+ this.roles = roles;
+ }
+
+ public void addRole(Role role) {
+ if (role == null) {
+ throw new IllegalArgumentException("Role MUST not be null!");
+ }
+ roles.add(role);
+ }
+
@Override
public String toString() {
return "User [firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]";
@@ -127,4 +153,4 @@ public String toString() {
public void setCpassword(String cpassword) {
this.cpassword = cpassword;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/site/repository/RoleRepository.java b/src/main/java/site/repository/RoleRepository.java
new file mode 100644
index 00000000..293e0a3c
--- /dev/null
+++ b/src/main/java/site/repository/RoleRepository.java
@@ -0,0 +1,18 @@
+package site.repository;
+
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.stereotype.Repository;
+
+import site.model.Role;
+
+
+/**
+ * @author Trifon Trifonov
+ */
+@Repository(value = RoleRepository.NAME)
+public interface RoleRepository extends PagingAndSortingRepository {
+
+ String NAME = "roleRepository";
+
+ public Role findByName(String name);
+}
\ No newline at end of file
diff --git a/src/main/java/site/repository/SessionRepository.java b/src/main/java/site/repository/SessionRepository.java
index 3daec999..d0efadab 100644
--- a/src/main/java/site/repository/SessionRepository.java
+++ b/src/main/java/site/repository/SessionRepository.java
@@ -2,7 +2,6 @@
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import site.model.Session;
diff --git a/src/main/resources/.gitignore b/src/main/resources/.gitignore
new file mode 100644
index 00000000..f982fd56
--- /dev/null
+++ b/src/main/resources/.gitignore
@@ -0,0 +1 @@
+/application-DEV.properties
diff --git a/src/main/resources/application-DEV.template.properties b/src/main/resources/application-DEV.template.properties
new file mode 100644
index 00000000..c272c544
--- /dev/null
+++ b/src/main/resources/application-DEV.template.properties
@@ -0,0 +1,60 @@
+spring.datasource.url=jdbc:mysql://localhost:3306/javabg?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&connectionCollation=utf8_general_ci&characterSetResults=utf8&autoDeserialize=true&useConfigs=maxPerformance
+spring.datasource.username=root
+spring.datasource.password=admin
+spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+
+spring.jpa.open-in-view=true
+spring.jpa.show-sql=false
+spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
+spring.jpa.generate-ddl=true
+spring.jpa.hibernate.ddl-auto=none
+spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.DefaultNamingStrategy
+spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE
+spring.jpa.properties.hibernate.hikari.dataSource.cachePrepStmts=true
+spring.jpa.properties.hibernate.hikari.dataSource.prepStmtCacheSize=250
+spring.jpa.properties.hibernate.hikari.dataSource.prepStmtCacheSqlLimit=2048
+spring.jpa.properties.hibernate.hikari.dataSource.useServerPrepStmts=true
+spring.jpa.properties.hibernate.generate_statistics=false
+spring.jpa.properties.hibernate.cache.use_structured_entries=true
+spring.jpa.properties.hibernate.archive.autodetection=class
+spring.jpa.properties.hibernate.show_sql=false
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.use_sql_comments=true
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
+spring.jpa.properties.hibernate.jdbc.batch_size=50
+spring.jpa.properties.hibernate.order_update=true
+spring.jpa.properties.hibernate.connection.characterEncoding=utf-8
+spring.jpa.properties.hibernate.connection.CharSet=utf-8
+spring.jpa.properties.hibernate.connection.useUnicode=true
+spring.jpa.properties.hibernate.connection.autocommit=true
+spring.jpa.properties.hibernate.cache.use_second_level_cache=true
+spring.jpa.properties.hibernate.cache.region.factory_class=com.hazelcast.hibernate.HazelcastLocalCacheRegionFactory
+spring.jpa.properties.hibernate.cache.region_prefix=
+spring.jpa.properties.hibernate.cache.use_query_cache=true
+spring.jpa.properties.hibernate.cache.use_minimal_puts=true
+# JTA
+spring.jta.enabled=true
+
+spring.mail.host = mail.jprime.io
+spring.mail.username = conference@jprime.io
+#spring.mail.password = pass it on the command line as system property
+
+spring.mail.properties.mail.smtp.auth = true
+spring.mail.properties.mail.smtp.socketFactory.port = 465
+spring.mail.properties.mail.smtp.socketFactory.class = javax.net.ssl.SSLSocketFactory
+spring.mail.properties.mail.smtp.socketFactory.fallback = false
+
+admin.password = password
+spring.boot.admin.url=http://localhost:8080
+
+#mihail.stoynov: different binding address
+#management.port=80
+#management.address=127.0.0.1
+#server.address=127.0.0.1 #don't enable it, many issues with iptables, firewall instead
+
+site.url=jprime.io
+site.url.reset.password=https://jprime.io/createNewPassword?tokenId=
+
+site.reset.password.token.duration.hours=2
+
+