Agenda na správu uživatelů

multitenant
Josef Rokos 11 years ago
parent 202825322a
commit 6462fb3806

@ -1,10 +1,29 @@
package info.bukova.isspst; package info.bukova.isspst;
import info.bukova.isspst.data.Role;
public class Constants { public class Constants {
public final static String DEF_ADMIN = "admin"; public final static String DEF_ADMIN = "admin";
public final static String DEF_ADMIN_PASSWD = "admin"; public final static String DEF_ADMIN_PASSWD = "admin";
public final static String ROLE_USER = "ROLE_USER"; public final static String ROLE_USER = "ROLE_USER";
public final static String ROLE_ADMIN = "ROLE_ADMIN"; public final static String ROLE_ADMIN = "ROLE_ADMIN";
public final static String ROLES[] = {ROLE_USER, ROLE_ADMIN}; public final static String ROLE_DIRECTOR = "ROLE_DIRECTOR";
public final static String ROLE_MANAGER = "ROLE_MANAGER";
public final static String ROLE_PRINCIPAL = "ROLE_PRINCIPAL";
public final static String ROLE_ACCOUNTANT = "ROLE_ACCOUNTANT";
public final static String ROLE_SUPPLIER = "ROLE_SUPPLIER";
public final static String ROLE_TECHNICIAN = "ROLE_TECHNICIAN";
public final static String ROLE_LEADER = "ROLE_LEADER";
public final static Role ROLES[] = {
new Role(ROLE_ADMIN, "Administrátor"),
new Role(ROLE_DIRECTOR, "Ředitel"),
new Role(ROLE_MANAGER, "Správce"),
new Role(ROLE_PRINCIPAL, "Příkazce"),
new Role(ROLE_ACCOUNTANT, "Účetní"),
new Role(ROLE_SUPPLIER, "Zásobovač"),
new Role(ROLE_TECHNICIAN, "Technik"),
new Role(ROLE_LEADER, "Vedoucí"),
new Role(ROLE_USER, "Uživatel")
};
} }

@ -2,14 +2,15 @@ package info.bukova.isspst;
import info.bukova.isspst.data.Role; import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.User; import info.bukova.isspst.data.User;
import info.bukova.isspst.services.RoleService; import info.bukova.isspst.services.users.RoleService;
import info.bukova.isspst.services.UserService; import info.bukova.isspst.services.users.UserService;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import javax.servlet.ServletContextListener;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.context.support.WebApplicationContextUtils;
@ -37,16 +38,10 @@ public class DbInitListener implements ServletContextListener {
} }
private void checkRoles() { private void checkRoles() {
Role r = null; for (Role role : Constants.ROLES)
for (String auth : Constants.ROLES)
{ {
r = roleService.getRoleByAuthority(auth); if (roleService.getRoleByAuthority(role.getAuthority()) == null) {
if (r == null) { roleService.add(role);
r = new Role();
r.setAuthority(auth);
r.setDescription("---");
roleService.add(r);
} }
} }
} }
@ -62,13 +57,21 @@ public class DbInitListener implements ServletContextListener {
} }
if (!adminExists) { if (!adminExists) {
User u = new User(); User u = null;
u.setUsername(Constants.DEF_ADMIN); try {
u = (User) userService.loadUserByUsername(Constants.DEF_ADMIN);
u.addAuthority(roleService.getRoleByAuthority(Constants.ROLE_ADMIN)); u.addAuthority(roleService.getRoleByAuthority(Constants.ROLE_ADMIN));
u.setEnabled(true); u.setEnabled(true);
userService.update(u);
} catch(UsernameNotFoundException e) {
u = new User();
u.setUsername(Constants.DEF_ADMIN);
userService.setPassword(u, Constants.DEF_ADMIN_PASSWD); userService.setPassword(u, Constants.DEF_ADMIN_PASSWD);
u.addAuthority(roleService.getRoleByAuthority(Constants.ROLE_ADMIN));
u.setEnabled(true);
userService.add(u); userService.add(u);
} }
} }
}
} }

@ -1,7 +1,7 @@
package info.bukova.isspst; package info.bukova.isspst;
import info.bukova.isspst.data.User; import info.bukova.isspst.data.User;
import info.bukova.isspst.services.UserService; import info.bukova.isspst.services.users.UserService;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.Date;

@ -0,0 +1,13 @@
package info.bukova.isspst;
public class StringUtils {
public static String nullStr(String str) {
return str == null ? "" : str;
}
public static String not0ToStr(long i) {
return i == 0 ? "" : String.valueOf(i);
}
}

@ -35,6 +35,15 @@ public class Role implements GrantedAuthority, DataModel {
@Transient @Transient
private boolean valid; private boolean valid;
public Role(String authority, String description) {
this.authority = authority;
this.description = description;
}
public Role() {
}
@Override @Override
public String getAuthority() { public String getAuthority() {
return authority; return authority;
@ -84,4 +93,13 @@ public class Role implements GrantedAuthority, DataModel {
this.valid = valid; this.valid = valid;
} }
@Override
public boolean equals(Object o) {
if ((o instanceof Role) && ((Role)o).getId() == this.id) {
return true;
} else {
return false;
}
}
} }

@ -9,9 +9,9 @@ import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.MapKeyColumn; import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient; import javax.persistence.Transient;
@ -36,9 +36,18 @@ public class User implements UserDetails, DataModel {
private String password; private String password;
@Column(name="ENABLED") @Column(name="ENABLED")
private boolean enabled; private boolean enabled;
private String fullName; @Column(name="FIRST_NAME")
@OneToMany(fetch=FetchType.EAGER) @JoinTable(name="USER_ROLE") private String firstName;
@MapKeyColumn(name="ROLE_ID") @Column(name="LAST_NAME")
private String lastName;
@Column(name="PERSONAL_NUMBER")
private String personalNumber;
@Column(name="EMAIL")
private String email;
@Column(name="NOTIFY")
private boolean notify;
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="USER_ROLE", joinColumns={@JoinColumn(name="USER_ID")}, inverseJoinColumns={@JoinColumn(name="ROLE_ID")})
private List<Role> authorities; private List<Role> authorities;
@Column(name="CREATED") @Column(name="CREATED")
private Date created; private Date created;
@ -139,11 +148,51 @@ public class User implements UserDetails, DataModel {
} }
public String getFullName() { public String getFullName() {
return fullName; String ret = "";
if (firstName != null && !firstName.isEmpty()) {
ret = firstName + " ";
}
return ret + lastName == null ? "" : lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPersonalNumber() {
return personalNumber;
}
public void setPersonalNumber(String personalNumber) {
this.personalNumber = personalNumber;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isNotify() {
return notify;
} }
public void setFullName(String fullName) { public void setNotify(boolean notify) {
this.fullName = fullName; this.notify = notify;
} }
} }

@ -0,0 +1,57 @@
package info.bukova.isspst.filters;
import info.bukova.isspst.data.User;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeMatcher;
import static info.bukova.isspst.StringUtils.nullStr;
public class UserFilter implements Filter<User> {
private User condUser;
public UserFilter(User condition) {
this.condUser = condition;
}
private static class UserMatcher extends TypeSafeMatcher<User> {
private User condUser;
public UserMatcher(User condition) {
this.condUser = condition;
}
@Override
public void describeTo(Description description) {
description.appendText("user matcher");
}
@Override
public boolean matchesSafely(User item) {
return nullStr(item.getUsername()).toLowerCase().contains(nullStr(condUser.getUsername()).toLowerCase())
&& nullStr(item.getFirstName()).toLowerCase().contains(nullStr(condUser.getFirstName()).toLowerCase())
&& nullStr(item.getLastName()).toLowerCase().contains(nullStr(condUser.getLastName()).toLowerCase())
&& nullStr(item.getPersonalNumber()).toLowerCase().contains(nullStr(condUser.getPersonalNumber()).toLowerCase());
}
@Factory
public UserMatcher matchUser(User cond) {
return new UserMatcher(cond);
}
}
@Override
public TypeSafeMatcher<User> matcher() {
return new UserMatcher(condUser);
}
@Override
public String queryString() {
return null;
}
}

@ -1,11 +0,0 @@
package info.bukova.isspst.services;
import info.bukova.isspst.data.User;
public interface UserService extends Service<User> {
public void setPassword(User user, String password);
public boolean hasRole(User user, String authority);
public void test();
}

@ -1,6 +1,7 @@
package info.bukova.isspst.services; package info.bukova.isspst.services.users;
import info.bukova.isspst.data.Role; import info.bukova.isspst.data.Role;
import info.bukova.isspst.services.Service;
public interface RoleService extends Service<Role> { public interface RoleService extends Service<Role> {

@ -1,8 +1,9 @@
package info.bukova.isspst.services; package info.bukova.isspst.services.users;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import info.bukova.isspst.data.Role; import info.bukova.isspst.data.Role;
import info.bukova.isspst.services.AbstractService;
public class RoleServiceImpl extends AbstractService<Role> implements RoleService { public class RoleServiceImpl extends AbstractService<Role> implements RoleService {

@ -0,0 +1,14 @@
package info.bukova.isspst.services.users;
import org.springframework.security.core.userdetails.UserDetailsService;
import info.bukova.isspst.data.User;
import info.bukova.isspst.services.Service;
public interface UserService extends UserDetailsService, Service<User> {
public void setPassword(User user, String password);
public boolean hasRole(User user, String authority);
public void saveWithPwd(User user, String password);
}

@ -1,18 +1,16 @@
package info.bukova.isspst.services; package info.bukova.isspst.services.users;
import org.hibernate.Query; import org.hibernate.Query;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.encoding.PasswordEncoder; import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import info.bukova.isspst.Constants;
import info.bukova.isspst.data.Role; import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.User; import info.bukova.isspst.data.User;
import info.bukova.isspst.services.AbstractService;
public class UserServiceImpl extends AbstractService<User> implements UserService, UserDetailsService { public class UserServiceImpl extends AbstractService<User> implements UserService {
private PasswordEncoder encoder; private PasswordEncoder encoder;
@ -51,9 +49,10 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
} }
@Override @Override
@Secured(Constants.ROLE_ADMIN) @Transactional
public void test() { public void saveWithPwd(User user, String password) {
System.out.println("pokus secured"); this.setPassword(user, password);
this.update(user);
} }

@ -27,8 +27,7 @@ public class ListViewModel<T extends DataModel> {
private boolean filter = false; private boolean filter = false;
private Window editWin; private Window editWin;
private T dataBean; private T dataBean;
//private T filterTemplate; private T filterTemplate;
private Filter<T> dataFilter;
private T editBean; private T editBean;
private List<T> dataList; private List<T> dataList;
private List<T> fullList; private List<T> fullList;
@ -42,6 +41,7 @@ public class ListViewModel<T extends DataModel> {
protected Service<T> service; protected Service<T> service;
protected Class<T> dataClass; protected Class<T> dataClass;
protected String formZul; protected String formZul;
protected Filter<T> dataFilter;
public List<T> getDataList() { public List<T> getDataList() {
if (dataList == null) { if (dataList == null) {
@ -60,6 +60,20 @@ public class ListViewModel<T extends DataModel> {
this.dataFilter = dataFilter; this.dataFilter = dataFilter;
} }
public T getFilterTemplate() {
if (filterTemplate == null) {
try {
filterTemplate = dataClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return filterTemplate;
}
public T getDataBean() { public T getDataBean() {
return dataBean; return dataBean;
} }

@ -1,14 +0,0 @@
package info.bukova.isspst.ui;
import org.zkoss.bind.annotation.Init;
import info.bukova.isspst.data.User;
public class UserForm extends FormViewModel<User> {
@Init(superclass = true)
public void init() {
}
}

@ -0,0 +1,43 @@
package info.bukova.isspst.ui.users;
import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.User;
public class RoleCheck {
private Role role;
private User user;
private boolean checked;
public RoleCheck(User user, Role role) {
this.user = user;
this.role = role;
if (user.getAuthorities().contains(role)) {
checked = true;
} else {
checked = false;
}
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
if (checked && !user.getAuthorities().contains(role)) {
user.addAuthority(role);
} else {
user.getAuthorities().remove(role);
}
}
}

@ -0,0 +1,90 @@
package info.bukova.isspst.ui.users;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import info.bukova.isspst.data.User;
import info.bukova.isspst.services.users.RoleService;
import info.bukova.isspst.services.users.UserService;
import info.bukova.isspst.ui.FormViewModel;
public class UserForm extends FormViewModel<User> {
@WireVariable
private RoleService roleService;
@WireVariable
private UserService userService;
private String retPasswd = "";
private String password = "";
private UserRoles userRoles;
private boolean loginFree;
@Init(superclass = true)
public void init() {
userRoles = new UserRoles(getDataBean(), roleService.getAll());
loginFree = true;
}
public UserRoles getUserRoles() {
return userRoles;
}
public String getRetPasswd() {
return retPasswd;
}
@NotifyChange({"canSave", "pwMatches"})
public void setRetPasswd(String retPasswd) {
this.retPasswd = retPasswd;
}
public String getPassword() {
return password;
}
@NotifyChange({"canSave", "pwMatches"})
public void setPassword(String password) {
this.password = password;
}
@Command
@NotifyChange({"loginFree", "canSave"})
public void checkLogin() {
try {
userService.loadUserByUsername(getDataBean().getUsername());
loginFree = false;
} catch(UsernameNotFoundException e) {
loginFree = true;
}
}
public boolean isPwMatches() {
return password.equals(retPasswd);
}
public boolean isLoginFree() {
return loginFree || isEdit();
}
public boolean isEdit() {
return getDataBean().getCreated() != null;
}
@Override
protected void doSave() {
if (!password.isEmpty()) {
userService.saveWithPwd(getDataBean(), this.password);
} else {
super.doSave();
}
}
@Override
public boolean isCanSave() {
return password.equals(retPasswd) && isLoginFree() && getDataBean().getUsername() != null && !getDataBean().getUsername().isEmpty();
}
}

@ -0,0 +1,24 @@
package info.bukova.isspst.ui.users;
import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.User;
import java.util.ArrayList;
import java.util.List;
public class UserRoles {
private List<RoleCheck> roleChecks;
public UserRoles(User user, List<Role> roles) {
roleChecks = new ArrayList<RoleCheck>();
for (Role r : roles) {
roleChecks.add(new RoleCheck(user, r));
}
}
public List<RoleCheck> getRoleChecks() {
return roleChecks;
}
}

@ -1,10 +1,12 @@
package info.bukova.isspst.ui; package info.bukova.isspst.ui.users;
import org.zkoss.bind.annotation.Init; import org.zkoss.bind.annotation.Init;
import org.zkoss.zk.ui.select.annotation.WireVariable; import org.zkoss.zk.ui.select.annotation.WireVariable;
import info.bukova.isspst.data.User; import info.bukova.isspst.data.User;
import info.bukova.isspst.services.UserService; import info.bukova.isspst.filters.UserFilter;
import info.bukova.isspst.services.users.UserService;
import info.bukova.isspst.ui.ListViewModel;
public class UsersList extends ListViewModel<User> { public class UsersList extends ListViewModel<User> {
@ -16,6 +18,7 @@ public class UsersList extends ListViewModel<User> {
service = userService; service = userService;
dataClass = User.class; dataClass = User.class;
formZul = "userForm.zul"; formZul = "userForm.zul";
dataFilter = new UserFilter(getFilterTemplate());
} }
} }

@ -89,12 +89,12 @@
</bean> </bean>
<!-- Business logic --> <!-- Business logic -->
<bean id="userService" class="info.bukova.isspst.services.UserServiceImpl"> <bean id="userService" class="info.bukova.isspst.services.users.UserServiceImpl">
<property name="dao" ref="userDao"/> <property name="dao" ref="userDao"/>
<property name="encoder" ref="passwordEncoder"/> <property name="encoder" ref="passwordEncoder"/>
</bean> </bean>
<bean id="roleService" class="info.bukova.isspst.services.RoleServiceImpl"> <bean id="roleService" class="info.bukova.isspst.services.users.RoleServiceImpl">
<property name="dao" ref="roleDao"/> <property name="dao" ref="roleDao"/>
</bean> </bean>

@ -1,6 +1,34 @@
<?page title="Uživatel" contentType="text/html;charset=UTF-8"?> <?page title="Uživatel" contentType="text/html;charset=UTF-8"?>
<zk> <zk>
<window title="Uživatel" border="normal"> <window id="editWin" title="Uživatel" border="normal" closable="true" width="450px" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('info.bukova.isspst.ui.users.UserForm')">
<style src="/app/form.css"/>
<grid width="440px">
<columns>
<column hflex="min"></column>
<column></column>
<column></column>
</columns>
<rows>
<row><label value="Login"/><textbox value="@bind(vm.dataBean.username)" instant="true" disabled="@load(vm.edit)" onChange="@command('checkLogin')"/><label value="Login je obsazený" sclass="error" visible="@load(not vm.loginFree)"/></row>
<row><label value="Jméno"/><textbox value="@bind(vm.dataBean.firstName)"/></row>
<row><label value="Příjmení"/><textbox value="@bind(vm.dataBean.lastName)"/></row>
<row><label value="Osobní číslo"/><textbox value="@bind(vm.dataBean.personalNumber)" width="90px"/></row>
<row><label value="E-mail"/><textbox value="@bind(vm.dataBean.email)"/></row>
<row><label value=""/><checkbox label="Zasílat upozornění" checked="@bind(vm.dataBean.notify)"/></row>
<row><label value="Heslo"/><textbox value="@bind(vm.password)" type="password" instant="true"/></row>
<row><label value="Znova heslo"/><textbox value="@bind(vm.retPasswd)" type="password" instant="true"/><label value="Hesla nesouhlasí" sclass="error" visible="@load(not vm.pwMatches)"/></row>
<row><label value=""/><checkbox label="Aktivní" checked="@bind(vm.dataBean.enabled)"/></row>
</rows>
</grid>
<groupbox mold="3d">
<caption label="Role"/>
<vbox children="@load(vm.userRoles.roleChecks)">
<template name="children">
<checkbox label="@load(each.role.description)" checked="@bind(each.checked)"/>
</template>
</vbox>
</groupbox>
<button image="/img/save.png" label="Uložit" onClick="@command('save', window=editWin) @global-command('refresh')" disabled="@load(not vm.canSave)" sclass="nicebutton" /><button image="~./zul/img/misc/drag-disallow.png" label="Zavřít" onClick="editWin.detach()" sclass="nicebutton"/>
</window> </window>
</zk> </zk>

@ -2,19 +2,41 @@
<zk> <zk>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?> <?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="Uživatelé" border="normal" apply="org.zkoss.bind.BindComposer" <window title="Uživatelé" border="normal" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('info.bukova.isspst.ui.UsersList')" height="570px"> viewModel="@id('vm') @init('info.bukova.isspst.ui.users.UsersList')" height="570px">
<include src="/app/toolbar.zul"/> <include src="/app/toolbar.zul"/>
<listbox model="@load(vm.dataList)" selectedItem="@bind(vm.dataBean)"> <listbox model="@load(vm.dataList)" selectedItem="@bind(vm.dataBean)">
<auxhead sclass="category-center" visible="@load(vm.filter)">
<auxheader>
<image src="/img/funnel.png" />
<textbox value="@bind(vm.filterTemplate.username)" instant="true" onChange="@command('doFilter')"/>
</auxheader>
<auxheader>
<image src="/img/funnel.png" />
<textbox value="@bind(vm.filterTemplate.personalNumber)" instant="true" onChange="@command('doFilter')"/>
</auxheader>
<auxheader>
<image src="/img/funnel.png" />
<textbox value="@bind(vm.filterTemplate.firstName)" instant="true" onChange="@command('doFilter')"/>
</auxheader>
<auxheader>
<image src="/img/funnel.png" />
<textbox value="@bind(vm.filterTemplate.lastName)" instant="true" onChange="@command('doFilter')"/>
</auxheader>
</auxhead>
<listhead> <listhead>
<listheader label="Login"/> <listheader label="Login"/>
<listheader label="Celé jméno"/> <listheader label="Osobní číslo"/>
<listheader label="Jméno"/>
<listheader label="Příjmení"/>
</listhead> </listhead>
<template name="model"> <template name="model">
<listitem> <listitem>
<listcell label="@load(each.username)"/> <listcell label="@load(each.username)"/>
<listcell label="@load(each.fullName)"/> <listcell label="@load(each.personalNumber)"/>
<listcell label="@load(each.firstName)"/>
<listcell label="@load(each.lastName)"/>
</listitem> </listitem>
</template> </template>
</listbox> </listbox>

Loading…
Cancel
Save