提交 b4b0f74a 编写于 作者: MaxKey单点登录官方's avatar MaxKey单点登录官方

Dynamic Groups

动态用户组
上级 e5a830bf
......@@ -188,6 +188,12 @@ public class Groups extends JpaBaseDomain implements Serializable {
builder.append(id);
builder.append(", name=");
builder.append(name);
builder.append(", dynamic=");
builder.append(dynamic);
builder.append(", filters=");
builder.append(filters);
builder.append(", orgIdsList=");
builder.append(orgIdsList);
builder.append(", isdefault=");
builder.append(isdefault);
builder.append(", description=");
......
......@@ -38,6 +38,14 @@ public class Roles extends JpaBaseDomain implements Serializable {
@Column
private String name;
@Column
String dynamic;
@Column
String filters ;
@Column
String orgIdsList;
@Column
String status;
@Column
String description;
......@@ -119,6 +127,30 @@ public class Roles extends JpaBaseDomain implements Serializable {
this.modifiedDate = modifiedDate;
}
public String getDynamic() {
return dynamic;
}
public void setDynamic(String dynamic) {
this.dynamic = dynamic;
}
public String getFilters() {
return filters;
}
public void setFilters(String filters) {
this.filters = filters;
}
public String getOrgIdsList() {
return orgIdsList;
}
public void setOrgIdsList(String orgIdsList) {
this.orgIdsList = orgIdsList;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
......@@ -126,6 +158,12 @@ public class Roles extends JpaBaseDomain implements Serializable {
builder.append(id);
builder.append(", name=");
builder.append(name);
builder.append(", dynamic=");
builder.append(dynamic);
builder.append(", filters=");
builder.append(filters);
builder.append(", orgIdsList=");
builder.append(orgIdsList);
builder.append(", status=");
builder.append(status);
builder.append(", description=");
......
......@@ -62,6 +62,10 @@ public class InitializeContext extends HttpServlet {
_logger.info("SecurityContextHolder StrategyName " + SessionSecurityContextHolderStrategy.class.getCanonicalName());
SecurityContextHolder.setStrategyName(SessionSecurityContextHolderStrategy.class.getCanonicalName());
WebContext.applicationContext = applicationContext;
org.apache.mybatis.jpa.util.WebContext.applicationContext = applicationContext;
// List Environment Variables
listEnvVars();
......
......@@ -57,6 +57,8 @@ public final class WebContext {
public static Properties properties;
public static ApplicationContext applicationContext;
public static ArrayList<String> sessionAttributeNameList = new ArrayList<String>();
static {
......@@ -137,23 +139,24 @@ public final class WebContext {
}
/**
* get ApplicationContext from web ServletContext configuration.
*
* get ApplicationContext from web ServletContext configuration
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return WebApplicationContextUtils.getWebApplicationContext(
getSession().getServletContext());
public static ApplicationContext getApplicationContext(){
return WebApplicationContextUtils.getWebApplicationContext(getSession().getServletContext());
}
/**
* get bean from spring configuration by bean id.
*
* @param id String
* get bean from spring configuration by bean id
* @param id
* @return Object
*/
public static Object getBean(String id) {
return getApplicationContext().getBean(id);
public static Object getBean(String id){
if(applicationContext==null) {
return getApplicationContext().getBean(id);
}else {
return applicationContext.getBean(id);
}
}
// below method is common HttpServlet method
......
......@@ -24,6 +24,7 @@ import java.util.List;
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
import org.maxkey.domain.GroupMember;
import org.maxkey.domain.Groups;
/**
* @author Crystal.sea
......@@ -36,4 +37,13 @@ public interface GroupMemberMapper extends IJpaBaseMapper<GroupMember> {
public List<GroupMember> memberInGroup(GroupMember entity);
public List<GroupMember> memberNotInGroup(GroupMember entity);
public List<GroupMember> groupMemberInGroup(GroupMember entity);
public int addDynamicGroupMember(Groups dynamicGroup);
public int deleteDynamicGroupMember(Groups dynamicGroup);
public int deleteByGroupId(String groupId);
}
......@@ -20,6 +20,8 @@
*/
package org.maxkey.persistence.mapper;
import java.util.List;
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
import org.maxkey.domain.Groups;
......@@ -30,4 +32,5 @@ import org.maxkey.domain.Groups;
public interface GroupsMapper extends IJpaBaseMapper<Groups> {
public List<Groups> queryDynamicGroups(Groups groups);
}
......@@ -24,6 +24,7 @@ import java.util.List;
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
import org.maxkey.domain.RoleMember;
import org.maxkey.domain.Roles;
/**
* @author Crystal.sea
......@@ -36,4 +37,10 @@ public interface RoleMemberMapper extends IJpaBaseMapper<RoleMember> {
public List<RoleMember> memberInRole(RoleMember entity);
public List<RoleMember> memberNotInRole(RoleMember entity);
public List<RoleMember> roleMemberInRole(RoleMember entity);
public int addDynamicRoleMember(Roles dynamicRole);
public int deleteDynamicRoleMember(Roles dynamicRole);
public int deleteByRoleId(String roleId);
}
......@@ -38,4 +38,6 @@ public interface RolesMapper extends IJpaBaseMapper<Roles> {
public int logisticDeleteRolePermissions(List<RolePermissions> rolePermissionsList);
public List<RolePermissions> queryRolePermissions(RolePermissions rolePermissions);
public List<Roles> queryDynamicRoles(Roles role);
}
......@@ -19,6 +19,7 @@ package org.maxkey.persistence.service;
import org.apache.mybatis.jpa.persistence.JpaBaseService;
import org.maxkey.domain.GroupMember;
import org.maxkey.domain.Groups;
import org.maxkey.persistence.mapper.GroupMemberMapper;
import org.springframework.stereotype.Service;
......@@ -37,4 +38,16 @@ public class GroupMemberService extends JpaBaseService<GroupMember>{
// TODO Auto-generated method stub
return (GroupMemberMapper)super.getMapper();
}
public int addDynamicGroupMember(Groups dynamicGroup) {
return getMapper().addDynamicGroupMember(dynamicGroup);
}
public int deleteDynamicGroupMember(Groups dynamicGroup) {
return getMapper().deleteDynamicGroupMember(dynamicGroup);
}
public int deleteByGroupId(String groupId) {
return getMapper().deleteByGroupId(groupId);
}
}
......@@ -17,14 +17,22 @@
package org.maxkey.persistence.service;
import java.util.List;
import org.apache.mybatis.jpa.persistence.JpaBaseService;
import org.maxkey.domain.Groups;
import org.maxkey.persistence.mapper.GroupsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class GroupsService extends JpaBaseService<Groups>{
@Autowired
@Qualifier("groupMemberService")
GroupMemberService groupMemberService;
public GroupsService() {
super(GroupsMapper.class);
}
......@@ -37,4 +45,27 @@ public class GroupsService extends JpaBaseService<Groups>{
// TODO Auto-generated method stub
return (GroupsMapper)super.getMapper();
}
public List<Groups> queryDynamicGroups(Groups groups){
return this.getMapper().queryDynamicGroups(groups);
}
public boolean deleteById(String groupId) {
this.remove(groupId);
groupMemberService.deleteByGroupId(groupId);
return true;
}
public void refreshDynamicGroups(Groups dynamicGroup){
if(dynamicGroup.getDynamic().equals("1")) {
if(dynamicGroup.getOrgIdsList()!=null && !dynamicGroup.getOrgIdsList().equals("")) {
dynamicGroup.setOrgIdsList("'"+dynamicGroup.getOrgIdsList().replace(",", "','")+"'");
}
groupMemberService.deleteDynamicGroupMember(dynamicGroup);
groupMemberService.addDynamicGroupMember(dynamicGroup);
}
}
}
......@@ -19,6 +19,7 @@ package org.maxkey.persistence.service;
import org.apache.mybatis.jpa.persistence.JpaBaseService;
import org.maxkey.domain.RoleMember;
import org.maxkey.domain.Roles;
import org.maxkey.persistence.mapper.RoleMemberMapper;
import org.springframework.stereotype.Service;
......@@ -37,4 +38,17 @@ public class RoleMemberService extends JpaBaseService<RoleMember>{
// TODO Auto-generated method stub
return (RoleMemberMapper)super.getMapper();
}
public int addDynamicRoleMember(Roles dynamicRole) {
return getMapper().addDynamicRoleMember(dynamicRole);
}
public int deleteDynamicRoleMember(Roles dynamicRole) {
return getMapper().deleteDynamicRoleMember(dynamicRole);
}
public int deleteByRoleId(String roleId) {
return getMapper().deleteByRoleId(roleId);
}
}
......@@ -23,11 +23,17 @@ import org.apache.mybatis.jpa.persistence.JpaBaseService;
import org.maxkey.domain.RolePermissions;
import org.maxkey.domain.Roles;
import org.maxkey.persistence.mapper.RolesMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class RolesService extends JpaBaseService<Roles>{
@Autowired
@Qualifier("roleMemberService")
RoleMemberService roleMemberService;
public RolesService() {
super(RolesMapper.class);
}
......@@ -51,4 +57,25 @@ public class RolesService extends JpaBaseService<Roles>{
public List<RolePermissions> queryRolePermissions(RolePermissions rolePermissions){
return getMapper().queryRolePermissions(rolePermissions);
}
public List<Roles> queryDynamicRoles(Roles dynamicRole){
return this.getMapper().queryDynamicRoles(dynamicRole);
}
public boolean deleteById(String roleId) {
this.remove(roleId);
roleMemberService.deleteByRoleId(roleId);
return true;
}
public void refreshDynamicRoles(Roles dynamicRole){
if(dynamicRole.getDynamic().equals("1")) {
if(dynamicRole.getOrgIdsList()!=null && !dynamicRole.getOrgIdsList().equals("")) {
dynamicRole.setOrgIdsList("'"+dynamicRole.getOrgIdsList().replace(",", "','")+"'");
}
roleMemberService.deleteDynamicRoleMember(dynamicRole);
roleMemberService.addDynamicRoleMember(dynamicRole);
}
}
}
......@@ -108,7 +108,7 @@
<if test="groupName != null and groupName != ''">
AND G.NAME = #{groupName}
</if>
AND GM.TYPE = 'USER'
AND GM.TYPE IN( 'USER','USER-DYNAMIC')
AND GM.GROUPID = G.ID
AND GM.MEMBERID = U.ID
</select>
......@@ -167,7 +167,7 @@
<if test="groupName != null and groupName != ''">
AND G.NAME = #{groupName}
</if>
AND GM.TYPE = 'USER'
AND GM.TYPE IN( 'USER','USER-DYNAMIC')
AND GM.GROUPID = G.ID
)
</select>
......@@ -195,5 +195,54 @@
</if>
</select>
<update id="addDynamicGroupMember" parameterType="Groups" >
INSERT INTO MXK_GROUP_MEMBER(
ID,
GROUPID,
MEMBERID,
TYPE
)
SELECT
CONCAT_WS('-','UD','${id}',U.ID) ID,
'${id}' GROUPID,
U.ID MEMBERID,
'USER-DYNAMIC' TYPE
FROM MXK_USERINFO U
WHERE NOT EXISTS(
SELECT 1 FROM MXK_GROUP_MEMBER GM
WHERE GM.GROUPID=#{id}
AND GM.MEMBERID=U.ID
AND GM.TYPE='USER-DYNAMIC'
)
<if test="filters != null and filters != ''">
${filters}
</if>
<if test="orgIdsList != null and orgIdsList != ''">
AND U.DEPARTMENTID IN( ${orgIdsList})
</if>
</update>
<delete id="deleteDynamicGroupMember" parameterType="Groups" >
DELETE FROM MXK_GROUP_MEMBER GM
WHERE TYPE = 'USER-DYNAMIC'
AND GM.GROUPID=#{id}
AND NOT EXISTS(
SELECT 1
FROM MXK_USERINFO U
WHERE 1 = 1
AND U.ID=GM.MEMBERID
<if test="filters != null and filters != ''">
${filters}
</if>
<if test="orgIdsList != null and orgIdsList != ''">
AND U.DEPARTMENTID IN( ${orgIdsList})
</if>
)
</delete>
<delete id="deleteByGroupId" parameterType="string" >
DELETE FROM MXK_GROUP_MEMBER GM
WHERE GM.GROUPID=#{value}
</delete>
</mapper>
\ No newline at end of file
......@@ -23,6 +23,16 @@
<include refid="where_statement"/>
</select>
<select id="queryDynamicGroups" parameterType="Groups" resultType="Groups">
SELECT
*
FROM
`MXK_GROUPS`
WHERE
DYNAMIC = '1'
<include refid="where_statement"/>
</select>
<update id="logisticDelete" parameterType="Groups" >
UPDATE `MXK_GROUPS` SET
......
......@@ -108,7 +108,7 @@
<if test="roleName != null and roleName != ''">
AND R.NAME = #{roleName}
</if>
AND RM.TYPE = 'USER'
AND RM.TYPE IN( 'USER','USER-DYNAMIC')
AND RM.ROLEID = R.ID
AND RM.MEMBERID = U.ID
</select>
......@@ -167,14 +167,14 @@
<if test="roleName != null and roleName != ''">
AND R.NAME = #{roleName}
</if>
AND RM.TYPE = 'USER'
AND RM.TYPE IN( 'USER','USER-DYNAMIC')
AND RM.ROLEID = R.ID
)
</select>
<!-- ROLE_MEMBER Roles Member-->
<select id="groupMemberInRole" parameterType="RoleMember" resultType="Roles">
<select id="roleMemberInRole" parameterType="RoleMember" resultType="Roles">
SELECT DISTINCT
IR.*
FROM
......@@ -185,7 +185,7 @@
1 = 1
AND RM.GROUPID = R.ID
AND RM.MEMBERID = IR.ID
AND RM.TYPE = 'ROLE'
AND RM.TYPE IN( 'USER','USER-DYNAMIC')
<if test="roleId != null and roleId != ''">
AND RM.ROLEID = #{roleId}
AND R.ID = #{roleId}
......@@ -195,5 +195,54 @@
</if>
</select>
<update id="addDynamicRoleMember" parameterType="Roles" >
INSERT INTO MXK_ROLE_MEMBER(
ID,
ROLEID,
MEMBERID,
TYPE
)
SELECT
CONCAT_WS('-','UD','${id}',U.ID) ID,
'${id}' ROLEID,
U.ID MEMBERID,
'USER-DYNAMIC' TYPE
FROM MXK_USERINFO U
WHERE NOT EXISTS(
SELECT 1 FROM MXK_ROLE_MEMBER RM
WHERE RM.ROLEID=#{id}
AND RM.MEMBERID=U.ID
AND RM.TYPE='USER-DYNAMIC'
)
<if test="filters != null and filters != ''">
${filters}
</if>
<if test="orgIdsList != null and orgIdsList != ''">
AND U.DEPARTMENTID IN( ${orgIdsList})
</if>
</update>
<delete id="deleteDynamicRoleMember" parameterType="Roles" >
DELETE FROM MXK_ROLE_MEMBER RM
WHERE TYPE = 'USER-DYNAMIC'
AND RM.ROLEID=#{id}
AND NOT EXISTS(
SELECT 1
FROM MXK_USERINFO U
WHERE 1 = 1
AND U.ID=RM.MEMBERID
<if test="filters != null and filters != ''">
${filters}
</if>
<if test="orgIdsList != null and orgIdsList != ''">
AND U.DEPARTMENTID IN( ${orgIdsList})
</if>
)
</delete>
<delete id="deleteByRoleId" parameterType="string" >
DELETE FROM MXK_ROLE_MEMBER RM
WHERE RM.ROLEID=#{value}
</delete>
</mapper>
\ No newline at end of file
......@@ -11,9 +11,17 @@
</if>
</sql>
<select id="queryDynamicRoles" parameterType="Roles" resultType="Roles">
SELECT
*
FROM
`MXK_GROUPS`
WHERE
DYNAMIC = '1'
<include refid="where_statement"/>
</select>
<select id="queryPageResults" parameterType="Groups" resultType="Groups">
<select id="queryPageResults" parameterType="Roles" resultType="Roles">
SELECT
*
FROM
......@@ -24,7 +32,7 @@
</select>
<update id="logisticDelete" parameterType="Groups" >
<update id="logisticDelete" parameterType="Roles" >
UPDATE MXK_ROLES SET
STATUS = '2'
WHERE 1 = 1
......
......@@ -24,10 +24,20 @@ import org.maxkey.authz.oauth2.provider.token.TokenStore;
import org.maxkey.authz.oauth2.provider.token.store.InMemoryTokenStore;
import org.maxkey.authz.oauth2.provider.token.store.JdbcTokenStore;
import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
import org.maxkey.authz.oidc.idtoken.OIDCIdTokenEnhancer;
import org.maxkey.constants.ConstantsProperties;
import org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn;
import org.maxkey.jobs.DynamicGroupsJob;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.maxkey.persistence.service.GroupsService;
import org.opensaml.xml.ConfigurationException;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.maxkey.authn.realm.jdbc.JdbcAuthenticationRealm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -37,6 +47,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
......@@ -44,9 +55,8 @@ import org.springframework.security.crypto.password.PasswordEncoder;
public class MaxKeyMgtConfig implements InitializingBean {
private static final Logger _logger = LoggerFactory.getLogger(MaxKeyMgtConfig.class);
@Bean(name = "oauth20JdbcClientDetailsService")
@Bean(name = "oauth20JdbcClientDetailsService")
public JdbcClientDetailsService JdbcClientDetailsService(
DataSource dataSource,PasswordEncoder passwordReciprocal) {
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
......@@ -111,9 +121,47 @@ public class MaxKeyMgtConfig implements InitializingBean {
return tfaOptAuthn;
}
/**
* schedulerJobsInit.
* @return schedulerJobsInit
* @throws ConfigurationException
* @throws SchedulerException
*/
@Bean(name = "schedulerJobs")
public Scheduler schedulerJobs(
SchedulerFactoryBean schedulerFactoryBean,
GroupsService groupsService,
@Value("${config.job.cron.dynamicgroups}") String cronScheduleDynamicGroups
) throws SchedulerException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
dynamicGroupsJob(scheduler,cronScheduleDynamicGroups,groupsService);
return scheduler;
}
private void dynamicGroupsJob(Scheduler scheduler ,
String cronSchedule,
GroupsService groupsService) throws SchedulerException {
JobDetail jobDetail =
JobBuilder.newJob(DynamicGroupsJob.class)
.withIdentity("DynamicGroupsJob", "DynamicGroups")
.build();
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("groupsService", groupsService);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronSchedule);
CronTrigger cronTrigger =
TriggerBuilder.newTrigger()
.withIdentity("triggerDynamicGroups", "DynamicGroups")
.usingJobData(jobDataMap)
.withSchedule(scheduleBuilder)
.build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
}
......
package org.maxkey.jobs;
import java.util.List;
import org.maxkey.domain.Groups;
import org.maxkey.persistence.service.GroupsService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DynamicGroupsJob implements Job {
final static Logger _logger = LoggerFactory.getLogger(DynamicGroupsJob.class);
private static GroupsService groupsService = null;
public static class JOBSTATUS{
public static int STOP = 0;
public static int RUNNING = 1;
public static int FINISHED = 2;
}
private static int jobStatus = JOBSTATUS.STOP;
@Override
public void execute(JobExecutionContext context){
if(jobStatus == JOBSTATUS.RUNNING) {
_logger.info("DynamicGroupsJob is in running . " );
return;
}
_logger.debug("DynamicGroupsJob is running ... " );
jobStatus = JOBSTATUS.RUNNING;
try {
if(groupsService == null) {
groupsService = (GroupsService) context.getMergedJobDataMap().get("groupsService");
}
List<Groups> groupsList = groupsService.queryDynamicGroups(null);
for(Groups group : groupsList) {
_logger.debug("group " + group);
groupsService.refreshDynamicGroups(group);
}
Thread.sleep(10 *1000);
_logger.debug("DynamicGroupsJob is success " );
}catch(Exception e) {
_logger.error("Exception " ,e);
jobStatus = JOBSTATUS.STOP;
}
jobStatus = JOBSTATUS.FINISHED;
_logger.debug("DynamicGroupsJob is finished . " );
}
}
package org.maxkey.jobs;
public class DynamicRolesJob {
}
......@@ -85,6 +85,7 @@ public class GroupsController {
_logger.debug("-Add :" + group);
if (groupsService.insert(group)) {
groupsService.refreshDynamicGroups(group);
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
} else {
......@@ -122,6 +123,7 @@ public class GroupsController {
_logger.debug("-update group :" + group);
if (groupsService.update(group)) {
groupsService.refreshDynamicGroups(group);
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
} else {
......@@ -136,7 +138,7 @@ public class GroupsController {
public Message delete(@ModelAttribute("group") Groups group) {
_logger.debug("-delete group :" + group);
if (groupsService.remove(group.getId())) {
if (groupsService.deleteById(group.getId())) {
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
} else {
......
......@@ -85,6 +85,7 @@ public class RolesController {
_logger.debug("-Add :" + role);
if (rolesService.insert(role)) {
rolesService.refreshDynamicRoles(role);
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
} else {
......@@ -122,6 +123,7 @@ public class RolesController {
_logger.debug("-update role :" + role);
if (rolesService.update(role)) {
rolesService.refreshDynamicRoles(role);
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
} else {
......@@ -136,7 +138,7 @@ public class RolesController {
public Message delete(@ModelAttribute("role") Roles role) {
_logger.debug("-delete role :" + role);
if (rolesService.remove(role.getId())) {
if (rolesService.deleteById(role.getId())) {
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
} else {
......
......@@ -66,4 +66,6 @@ config.oidc.metadata.issuer=https://${config.server.domain}/maxkey
config.oidc.metadata.authorizationEndpoint=${config.server.name}/maxkey/oauth/v20/authorize
config.oidc.metadata.tokenEndpoint=${config.server.name}/maxkey/oauth/v20/token
config.oidc.metadata.userinfoEndpoint=${config.server.name}/maxkey/api/connect/userinfo
#############################################################################
\ No newline at end of file
#############################################################################
#one hour for refresh dynamic groups
config.job.cron.dynamicgroups=0 0 0/1 * * ?
\ No newline at end of file
......@@ -420,6 +420,9 @@ group.orgidslist=\u673a\u6784\u5217\u8868
#role
role.id=\u89d2\u8272\u7f16\u7801
role.name=\u89d2\u8272
role.dynamic=\u52a8\u6001\u7ec4
role.filters=\u8fc7\u6ee4\u5668
role.orgidslist=\u673a\u6784\u5217\u8868
resource.id=\u8d44\u6e90\u7f16\u7801
resource.name=\u8d44\u6e90\u540d\u79f0
......
......@@ -419,6 +419,9 @@ group.orgidslist=orgIdsList
#role
role.id=id
role.name=name
role.dynamic=dynamic
role.filters=filters
role.orgidslist=orgIdsList
resource.id=id
resource.name=name
......
......@@ -421,6 +421,9 @@ group.orgidslist=\u673a\u6784\u5217\u8868
#role
role.id=\u89d2\u8272\u7f16\u7801
role.name=\u89d2\u8272
role.dynamic=\u52a8\u6001\u7ec4
role.filters=\u8fc7\u6ee4\u5668
role.orgidslist=\u673a\u6784\u5217\u8868
resource.id=\u8d44\u6e90\u7f16\u7801
resource.name=\u8d44\u6e90\u540d\u79f0
......
......@@ -3,13 +3,13 @@
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<script type="text/javascript">
function dynamicFormatter(value, row, index){
return value=='0'? '<@locale code="common.text.no" />':'<@locale code="common.text.yes" />';
};
</script>
</head>
<script type="text/javascript">
function dynamicFormatter(value, row, index){
return value=='0'? '<@locale code="common.text.no" />':'<@locale code="common.text.yes" />';
};
</script>
<body>
<div class="app header-default side-nav-dark">
<div class="layout">
......
......@@ -9,6 +9,155 @@
vertical-align: middle;
}
</style>
<script type="text/javascript">
function onClick (event, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("orgsTree");
nodes = zTree.getCheckedNodes(true);
var orgsName = "";
var orgsId = "";
for (var i=0, l=nodes.length; i<l; i++) {
orgsName += nodes[i].name + ",";
orgsId += nodes[i].id + ",";
}
$("#orgIdsListName").val(orgsName);
$("#orgIdsList").val(orgsId);
}
$(function () {
var treeSettings={
element : "orgsTree",
rootId : "1",
checkbox : true,
onClick : onClick,
onDblClick : null,
url : "<@base/>/orgs/tree"
};
function singlePath(newNode) {
if (newNode === curExpandNode) return;
if (curExpandNode && curExpandNode.open==true) {
var zTree = $.fn.zTree.getZTreeObj(treeSettings.element);
if (newNode.parentTId === curExpandNode.parentTId) {
zTree.expandNode(curExpandNode, false);
} else {
var newParents = [];
while (newNode) {
newNode = newNode.getParentNode();
if (newNode === curExpandNode) {
newParents = null;
break;
} else if (newNode) {
newParents.push(newNode);
}
}
if (newParents!=null) {
var oldNode = curExpandNode;
var oldParents = [];
while (oldNode) {
oldNode = oldNode.getParentNode();
if (oldNode) {
oldParents.push(oldNode);
}
}
if (newParents.length>0) {
for (var i = Math.min(newParents.length, oldParents.length)-1; i>=0; i--) {
if (newParents[i] !== oldParents[i]) {
zTree.expandNode(oldParents[i], false);
break;
}
}
} else {
zTree.expandNode(oldParents[oldParents.length-1], false);
}
}
}
}
curExpandNode = newNode;
};
function beforeExpand(treeId, treeNode) {
var pNode = curExpandNode ? curExpandNode.getParentNode():null;
var treeNodeP = treeNode.parentTId ? treeNode.getParentNode():null;
var zTree = $.fn.zTree.getZTreeObj(""+treeSettings.element);
for(var i=0, l=!treeNodeP ? 0:treeNodeP.children.length; i<l; i++ ) {
if (treeNode !== treeNodeP.children[i]) {
zTree.expandNode(treeNodeP.children[i], false);
}
}
while (pNode) {
if (pNode === treeNode) {
break;
}
pNode = pNode.getParentNode();
}
if (!pNode) {
singlePath(treeNode);
}
};
$.fn.zTree.init(
$("#"+treeSettings.element), //element
{//json object
check : {
enable : treeSettings.checkbox
},
async : {
enable : true,
url : treeSettings.url,
autoParam : ["id", "name=n", "level=lv"],
otherParam : {"otherParam":"zTreeAsyncTest",id:treeSettings.rootId},
dataFilter : function (treeId, parentNode, childNodes) {
if (!childNodes) return null;
for (var i=0, l=childNodes.length; i<l; i++) {
childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
}
return childNodes;
}
},
data : {
simpleData : {
enable : true
}
},
callback: {
onClick : treeSettings.onClick,
onDblClick : treeSettings.onDblClick,
beforeAsync : function(treeId, treeNode){
$.loading();
},
onAsyncSuccess : function(event, treeId, treeNode, msg){
$.unloading();
},
//beforeExpand : beforeExpand,
onExpand : function onExpand(event, treeId, treeNode) {
curExpandNode = treeNode;
}
}
}
);//end tree
});
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "orgIdsListName" || event.target.id == "orgContent" || $(event.target).parents("#orgContent").length>0)) {
$("#orgContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
}
function showOrgsTree() {
var treeObj = $("#orgIdsListName");
var treeOffset = $("#orgIdsListName").offset();
$("#orgContent").css({left:treeOffset.left + "px", top:treeOffset.top + treeObj.outerHeight() + "px"}).slideDown("fast");
$("body").bind("mousedown", onBodyDown);
}
</script>
</head>
<body>
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/roles/add" class="needs-validation" novalidate>
......@@ -26,10 +175,32 @@
<input type="text" id="name" name="name" class="form-control" title="" value="" required="" />
</td>
</tr>
<tr>
<th><@locale code="role.dynamic" /></th>
<td nowrap>
<select id="dynamic" name="dynamic" class="form-control">
<option value="0" selected ><@locale code="common.text.no" /></option>
<option value="1" ><@locale code="common.text.yes" /></option>
</select>
</td>
</tr>
<tr>
<th><@locale code="role.orgidslist" /></th>
<td nowrap>
<input type="text" id="orgIdsListName" name="orgIdsListName" readonly class="form-control" title="" value="" onclick="showOrgsTree();"/>
<input type="hidden" id="orgIdsList" name="orgIdsList" readonly class="form-control" title="" value="" />
</td>
</tr>
<tr>
<th><@locale code="role.filters" /></th>
<td nowrap>
<textarea id="filters" name="filters" class="form-control" rows="7" cols="20"></textarea>
</td>
</tr>
<tr>
<th><@locale code="common.text.description" /></th>
<td nowrap>
<input type="text" id="description" name="description" class="form-control" title="" value="" />
<textarea id="description" name="description" class="form-control" rows="6" cols="20"></textarea>
</td>
</tr>
......@@ -44,5 +215,8 @@
</tbody>
</table>
</form>
<div id="orgContent" class="menuContent" style="display:none; position: absolute;">
<ul id="orgsTree" class="ztree" style="margin-top:0; width:180px; height: 300px;"></ul>
</div>
</body>
</html>
\ No newline at end of file
......@@ -9,6 +9,169 @@
vertical-align: middle;
}
</style>
<script type="text/javascript">
function onClick (event, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("orgsTree");
nodes = zTree.getCheckedNodes(true);
var orgsName = "";
var orgsId = "";
for (var i=0; i<nodes.length; i++) {
orgsName += nodes[i].name + ",";
orgsId += nodes[i].id + ",";
}
$("#orgIdsListName").val(orgsName);
$("#orgIdsList").val(orgsId);
}
$(function () {
var treeSettings={
element : "orgsTree",
rootId : "1",
checkbox : true,
onClick : onClick,
onDblClick : null,
url : "<@base/>/orgs/tree"
};
function singlePath(newNode) {
if (newNode === curExpandNode) return;
if (curExpandNode && curExpandNode.open==true) {
var zTree = $.fn.zTree.getZTreeObj(treeSettings.element);
if (newNode.parentTId === curExpandNode.parentTId) {
zTree.expandNode(curExpandNode, false);
} else {
var newParents = [];
while (newNode) {
newNode = newNode.getParentNode();
if (newNode === curExpandNode) {
newParents = null;
break;
} else if (newNode) {
newParents.push(newNode);
}
}
if (newParents!=null) {
var oldNode = curExpandNode;
var oldParents = [];
while (oldNode) {
oldNode = oldNode.getParentNode();
if (oldNode) {
oldParents.push(oldNode);
}
}
if (newParents.length>0) {
for (var i = Math.min(newParents.length, oldParents.length)-1; i>=0; i--) {
if (newParents[i] !== oldParents[i]) {
zTree.expandNode(oldParents[i], false);
break;
}
}
} else {
zTree.expandNode(oldParents[oldParents.length-1], false);
}
}
}
}
curExpandNode = newNode;
};
function beforeExpand(treeId, treeNode) {
var pNode = curExpandNode ? curExpandNode.getParentNode():null;
var treeNodeP = treeNode.parentTId ? treeNode.getParentNode():null;
var zTree = $.fn.zTree.getZTreeObj(""+treeSettings.element);
for(var i=0, l=!treeNodeP ? 0:treeNodeP.children.length; i<l; i++ ) {
if (treeNode !== treeNodeP.children[i]) {
zTree.expandNode(treeNodeP.children[i], false);
}
}
while (pNode) {
if (pNode === treeNode) {
break;
}
pNode = pNode.getParentNode();
}
if (!pNode) {
singlePath(treeNode);
}
};
function onLoadSuccessed(){
var zTree = $.fn.zTree.getZTreeObj("orgsTree");
var orgsIdValues = $("#orgIdsList").val().split(",") ;
var orgsName="";
for (var i=0; i<orgsIdValues.length; i++) {
var node = zTree.getNodeByParam("id",orgsIdValues[i] );
if(node != null){
zTree.checkNode(node, true, false);//将指定ID的节点选中
orgsName += node.name;
}
}
$("#orgIdsListName").val(orgsName);
}
$.fn.zTree.init(
$("#"+treeSettings.element), //element
{//json object
check : {
enable : treeSettings.checkbox
},
async : {
enable : true,
url : treeSettings.url,
autoParam : ["id", "name=n", "level=lv"],
otherParam : {"otherParam":"zTreeAsyncTest",id:treeSettings.rootId},
dataFilter : function (treeId, parentNode, childNodes) {
if (!childNodes) return null;
for (var i=0, l=childNodes.length; i<l; i++) {
childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
}
return childNodes;
}
},
data : {
simpleData : {
enable : true
}
},
callback: {
onClick : treeSettings.onClick,
onDblClick : treeSettings.onDblClick,
beforeAsync : function(treeId, treeNode){
$.loading();
},
onAsyncSuccess : function(event, treeId, treeNode, msg){
$.unloading();
onLoadSuccessed();
},
//beforeExpand : beforeExpand,
onExpand : function onExpand(event, treeId, treeNode) {
curExpandNode = treeNode;
}
}
}
);//end tree
});
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "orgIdsListName" || event.target.id == "orgContent" || $(event.target).parents("#orgContent").length>0)) {
$("#orgContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
}
function showOrgsTree() {
var treeObj = $("#orgIdsListName");
var treeOffset = $("#orgIdsListName").offset();
$("#orgContent").css({left:treeOffset.left + "px", top:treeOffset.top + treeObj.outerHeight() + "px"}).slideDown("fast");
$("body").bind("mousedown", onBodyDown);
}
</script>
</head>
<body>
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/roles/update" class="needs-validation" novalidate>
......@@ -26,10 +189,32 @@
<input type="text" id="name" name="name" class="form-control" title="" value="${model.name!}" required="" />
</td>
</tr>
<tr>
<th><@locale code="role.dynamic" /></th>
<td nowrap>
<select id="dynamic" name="dynamic" class="form-control">
<option value="0" <#if '0'==model.dynamic>selected</#if> ><@locale code="common.text.no" /></option>
<option value="1" <#if '1'==model.dynamic>selected</#if> ><@locale code="common.text.yes" /></option>
</select>
</td>
</tr>
<tr>
<th><@locale code="role.orgidslist" /></th>
<td nowrap>
<input type="text" id="orgIdsListName" name="orgIdsListName" readonly class="form-control" title="" value="" onclick="showOrgsTree();"/>
<input type="hidden" id="orgIdsList" name="orgIdsList" readonly class="form-control" title="" value="${model.orgIdsList!}" />
</td>
</tr>
<tr>
<th><@locale code="role.filters" /></th>
<td nowrap>
<textarea id="filters" name="filters" class="form-control" rows="7" cols="20">${model.filters!}</textarea>
</td>
</tr>
<tr>
<th><@locale code="common.text.description" /></th>
<td nowrap>
<input type="text" id="description" name="description" class="form-control" title="" value="${model.description!}" />
<textarea id="description" name="description" class="form-control" rows="6" cols="20">${model.description!}</textarea>
</td>
</tr>
<tr>
......@@ -43,5 +228,8 @@
</tbody>
</table>
</form>
<div id="orgContent" class="menuContent" style="display:none; position: absolute;">
<ul id="orgsTree" class="ztree" style="margin-top:0; width:180px; height: 300px;"></ul>
</div>
</body>
</html>
\ No newline at end of file
......@@ -3,7 +3,11 @@
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<script type="text/javascript">
function dynamicFormatter(value, row, index){
return value=='0'? '<@locale code="common.text.no" />':'<@locale code="common.text.yes" />';
};
</script>
</head>
<body>
<div class="app header-default side-nav-dark">
......@@ -52,13 +56,13 @@
<input class="button btn btn-success mr-3" id="addBtn" type="button" value="<@locale code="button.text.add"/>"
wurl="<@base/>/roles/forwardAdd"
wwidth="500"
wheight="200"
wheight="600"
target="window">
<input class="button btn btn-info mr-3 " id="modifyBtn" type="button" value="<@locale code="button.text.edit"/>"
wurl="<@base/>/roles/forwardUpdate"
wwidth="500"
wheight="200"
wheight="600"
target="window">
<input class="button btn btn-danger mr-3 " id="deleteBtn" type="button" value="<@locale code="button.text.delete"/>"
......@@ -94,11 +98,12 @@
<th data-checkbox="true"></th>
<th data-sortable="true" data-field="id" data-visible="false">Id</th>
<th data-field="name"><@locale code="role.name"/></th>
<th data-field="dynamic" data-formatter="dynamicFormatter"><@locale code="group.dynamic"/></th>
<th data-field="description"><@locale code="common.text.description"/></th>
<th data-field="createdBy"><@locale code="common.text.createdby"/></th>
<th data-field="createdDate"><@locale code="common.text.createddate"/></th>
<th data-field="modifiedBy"><@locale code="common.text.modifiedby"/></th>
<th data-field="modifiedDate"><@locale code="common.text.modifieddate"/></th>
<th data-field="createdBy" data-visible="false"><@locale code="common.text.createdby"/></th>
<th data-field="createdDate" data-visible="false"><@locale code="common.text.createddate"/></th>
<th data-field="modifiedBy" data-visible="false"><@locale code="common.text.modifiedby"/></th>
<th data-field="modifiedDate" data-visible="false"><@locale code="common.text.modifieddate"/></th>
</tr>
</thead>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册