mirror of https://gitee.com/topiam/eiam
统计调整
parent
f35ab5abbb
commit
08dca580c3
|
@ -73,6 +73,7 @@ public class AuditEventListener implements ApplicationListener<AuditEvent> {
|
|||
entity.setUserAgent(userAgent);
|
||||
entity.setActorId(actor.getId());
|
||||
entity.setActorType(actor.getType());
|
||||
entity.setActorAuthType(actor.getAuthType());
|
||||
auditRepository.save(entity);
|
||||
} catch (Exception e) {
|
||||
logger.error("Audit record saving failed: {}", JSONObject.toJSONString(entity), e);
|
||||
|
|
|
@ -78,6 +78,13 @@ public class AccountEventType {
|
|||
public static Type MOVE_ORGANIZATION = new Type(
|
||||
"eiam:event:account:move_organization", "移动组织", ORG_ACCOUNT_RESOURCE, List.of(ADMIN));
|
||||
|
||||
/**
|
||||
* 添加组织用户
|
||||
*/
|
||||
public static Type CREATE_ORGANIZATION_MEMBER = new Type(
|
||||
"eiam:event:account:create_organization_member", "添加组织用户", ORG_ACCOUNT_RESOURCE,
|
||||
List.of(ADMIN));
|
||||
|
||||
/**
|
||||
* 用户离职
|
||||
*/
|
||||
|
|
|
@ -72,6 +72,11 @@ public enum EventType {
|
|||
*/
|
||||
MOVE_ORGANIZATION(AccountEventType.MOVE_ORGANIZATION),
|
||||
|
||||
/**
|
||||
* 添加组织用户
|
||||
*/
|
||||
CREATE_ORGANIZATION_MEMBER(AccountEventType.CREATE_ORGANIZATION_MEMBER),
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.audit.repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import cn.topiam.employee.audit.event.type.EventType;
|
||||
import cn.topiam.employee.audit.repository.result.AuditStatisticsResult;
|
||||
import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
|
||||
|
||||
/**
|
||||
* 组织成员
|
||||
*
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2022/10/2 02:53
|
||||
*/
|
||||
public interface AuditCustomizedRepository {
|
||||
|
||||
List<AuditStatisticsResult> authnHotProvider(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime);
|
||||
|
||||
List<AuthnQuantityResult> authnQuantity(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime, String dateFormat);
|
||||
|
||||
List<AuditStatisticsResult> appVisitRank(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime);
|
||||
|
||||
List<AuditStatisticsResult> authnZone(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime);
|
||||
}
|
|
@ -36,7 +36,7 @@ import cn.topiam.employee.support.repository.LogicDeleteRepository;
|
|||
*/
|
||||
@Repository
|
||||
public interface AuditRepository extends LogicDeleteRepository<AuditEntity, Long>,
|
||||
QuerydslPredicateExecutor<AuditEntity> {
|
||||
QuerydslPredicateExecutor<AuditEntity>, AuditCustomizedRepository {
|
||||
|
||||
/**
|
||||
* 统计指定时间范围内用户登录失败次数
|
||||
|
@ -58,4 +58,8 @@ public interface AuditRepository extends LogicDeleteRepository<AuditEntity, Long
|
|||
* @return {@link AuditEntity}
|
||||
*/
|
||||
Optional<AuditEntity> findByRequestId(String requestId);
|
||||
|
||||
@Query(value = "SELECT COUNT(*) FROM audit WHERE event_type = :type AND event_time BETWEEN :startTime AND :endTime", nativeQuery = true)
|
||||
Long countByTypeAndTime(@Param("type") String type, @Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.audit.repository.impl;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import cn.topiam.employee.audit.event.type.EventType;
|
||||
import cn.topiam.employee.audit.repository.AuditCustomizedRepository;
|
||||
import cn.topiam.employee.audit.repository.impl.mapper.AuditStatisticsResultMapper;
|
||||
import cn.topiam.employee.audit.repository.impl.mapper.AuthnQuantityResultMapper;
|
||||
import cn.topiam.employee.audit.repository.result.AuditStatisticsResult;
|
||||
import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2022/10/2 02:54
|
||||
*/
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class AuditCustomizedRepositoryImpl implements AuditCustomizedRepository {
|
||||
|
||||
/**
|
||||
* JdbcTemplate
|
||||
*/
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Override
|
||||
public List<AuditStatisticsResult> authnHotProvider(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime) {
|
||||
String sql = """
|
||||
SELECT
|
||||
actor_auth_type AS key_,
|
||||
COUNT(*) AS count_
|
||||
FROM
|
||||
audit
|
||||
WHERE
|
||||
event_type = ?
|
||||
AND event_time BETWEEN ?
|
||||
AND ?
|
||||
GROUP BY
|
||||
actor_auth_type
|
||||
""";
|
||||
return jdbcTemplate.query(sql, new AuditStatisticsResultMapper(), type.getCode(), startTime,
|
||||
endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuthnQuantityResult> authnQuantity(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime, String dateFormat) {
|
||||
String sql = """
|
||||
SELECT
|
||||
DATE_FORMAT( event_time, ? ) AS name_,
|
||||
COUNT(*) AS count_,
|
||||
event_status AS status_
|
||||
FROM
|
||||
audit
|
||||
WHERE
|
||||
event_type = ?
|
||||
AND event_time BETWEEN ?
|
||||
AND ?
|
||||
GROUP BY
|
||||
DATE_FORMAT( event_time, ? ),
|
||||
event_status
|
||||
""";
|
||||
|
||||
return jdbcTemplate.query(sql, new AuthnQuantityResultMapper(), dateFormat, type.getCode(),
|
||||
startTime, endTime, dateFormat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditStatisticsResult> appVisitRank(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime) {
|
||||
String sql = """
|
||||
SELECT
|
||||
JSON_EXTRACT( target_, '$[0].id' ) AS key_,
|
||||
COUNT(*) AS count_
|
||||
FROM
|
||||
audit
|
||||
WHERE
|
||||
event_type = ?
|
||||
AND event_time BETWEEN ?
|
||||
AND ?
|
||||
GROUP BY
|
||||
JSON_EXTRACT(
|
||||
target_,
|
||||
'$[0].id'
|
||||
)
|
||||
""";
|
||||
return jdbcTemplate.query(sql, new AuditStatisticsResultMapper(), type.getCode(), startTime,
|
||||
endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditStatisticsResult> authnZone(EventType type, LocalDateTime startTime,
|
||||
LocalDateTime endTime) {
|
||||
String sql = """
|
||||
SELECT
|
||||
JSON_EXTRACT( target_, '$.provinceCode' ) AS key_,
|
||||
COUNT(*) AS count_
|
||||
FROM
|
||||
audit
|
||||
WHERE
|
||||
event_type = ?
|
||||
AND event_time BETWEEN ?
|
||||
AND ?
|
||||
GROUP BY
|
||||
JSON_EXTRACT(
|
||||
target_,
|
||||
'$.provinceCode'
|
||||
)
|
||||
""";
|
||||
return jdbcTemplate.query(sql, new AuditStatisticsResultMapper(), type.getCode(), startTime,
|
||||
endTime);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.audit.repository.impl.mapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import cn.topiam.employee.audit.repository.result.AuditStatisticsResult;
|
||||
|
||||
/**
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2023/10/04 22:25
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class AuditStatisticsResultMapper implements RowMapper<AuditStatisticsResult> {
|
||||
/**
|
||||
* Implementations must implement this method to map each row of data
|
||||
* in the ResultSet. This method should not call {@code next()} on
|
||||
* the ResultSet; it is only supposed to map values of the current row.
|
||||
*
|
||||
* @param rs the ResultSet to map (pre-initialized for the current row)
|
||||
* @param rowNum the number of the current row
|
||||
* @return the result object for the current row (may be {@code null})
|
||||
* @throws SQLException if an SQLException is encountered getting
|
||||
* column values (that is, there's no need to catch SQLException)
|
||||
*/
|
||||
@Override
|
||||
public AuditStatisticsResult mapRow(@NonNull ResultSet rs, int rowNum) throws SQLException {
|
||||
//@formatter:off
|
||||
AuditStatisticsResult user = new AuditStatisticsResult();
|
||||
if (StringUtils.isNoneBlank(rs.getString("key_"))) {
|
||||
user.setKey(rs.getString("key_").replace("\"", ""));
|
||||
}
|
||||
user.setCount(rs.getLong("count_"));
|
||||
//@formatter:on
|
||||
return user;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.audit.repository.impl.mapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
|
||||
|
||||
/**
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2023/10/04 22:25
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class AuthnQuantityResultMapper implements RowMapper<AuthnQuantityResult> {
|
||||
/**
|
||||
* Implementations must implement this method to map each row of data
|
||||
* in the ResultSet. This method should not call {@code next()} on
|
||||
* the ResultSet; it is only supposed to map values of the current row.
|
||||
*
|
||||
* @param rs the ResultSet to map (pre-initialized for the current row)
|
||||
* @param rowNum the number of the current row
|
||||
* @return the result object for the current row (may be {@code null})
|
||||
* @throws SQLException if an SQLException is encountered getting
|
||||
* column values (that is, there's no need to catch SQLException)
|
||||
*/
|
||||
@Override
|
||||
public AuthnQuantityResult mapRow(@NonNull ResultSet rs, int rowNum) throws SQLException {
|
||||
//@formatter:off
|
||||
AuthnQuantityResult user = new AuthnQuantityResult();
|
||||
user.setName(rs.getString("name_"));
|
||||
user.setCount(rs.getLong("count_"));
|
||||
user.setStatus(rs.getString("status_"));
|
||||
//@formatter:on
|
||||
return user;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.audit.repository.impl;
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.audit.repository.result;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 审计统计
|
||||
*
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2023/10/04 23:16
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "审计统计")
|
||||
public class AuditStatisticsResult implements Serializable {
|
||||
|
||||
/**
|
||||
* key
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* count
|
||||
*/
|
||||
private Long count;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* eiam-console - Employee Identity and Access Management
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -15,12 +15,13 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.console.pojo.result.analysis;
|
||||
package cn.topiam.employee.audit.repository.result;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
|
@ -31,6 +32,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
* Created by support@topiam.cn on 2020/11/22 23:16
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "认证量统计响应")
|
||||
public class AuthnQuantityResult implements Serializable {
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* eiam-console - Employee Identity and Access Management
|
||||
* eiam-audit - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -15,7 +15,9 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.console.pojo.result.analysis;
|
||||
package cn.topiam.employee.audit.repository.result;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
@ -33,7 +35,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "登录区域响应")
|
||||
public class AuthnZoneResult {
|
||||
public class AuthnZoneResult implements Serializable {
|
||||
|
||||
/**
|
||||
* 省份code
|
|
@ -55,13 +55,19 @@ public class OrganizationMemberEntity extends LogicDeleteEntity<Long> {
|
|||
* 组织机构ID
|
||||
*/
|
||||
@Column(name = "org_id")
|
||||
private String orgId;
|
||||
private String orgId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Column(name = "user_id")
|
||||
private Long userId;
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 主组织
|
||||
*/
|
||||
@Column(name = "primary_")
|
||||
private Boolean primary;
|
||||
|
||||
public OrganizationMemberEntity() {
|
||||
}
|
||||
|
|
|
@ -41,4 +41,9 @@ public class UserPO extends UserEntity {
|
|||
* 组织机构显示目录
|
||||
*/
|
||||
private String orgDisplayPath;
|
||||
|
||||
/**
|
||||
* 主组织机构显示目录
|
||||
*/
|
||||
private String primaryOrgDisplayPath;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ public class UserGroupMemberRepositoryCustomizedImpl implements
|
|||
`u`.update_by,
|
||||
`u`.update_time,
|
||||
`u`.remark_,
|
||||
group_concat( organization_.display_path ) AS org_display_path
|
||||
group_concat( IF(organization_member.primary_ = 1, null, organization_.display_path ) ) AS org_display_path,
|
||||
group_concat( IF(organization_member.primary_ IS NULL, null, organization_.display_path ) ) AS primary_org_display_path
|
||||
FROM
|
||||
user_group_member ugm
|
||||
INNER JOIN user u ON ugm.user_id = u.id_ AND u.is_deleted = '0'
|
||||
|
|
|
@ -70,6 +70,7 @@ public class UserPoMapper implements RowMapper<UserPO> {
|
|||
user.setExpireDate(ObjectUtils.isNotEmpty(rs.getTimestamp("expire_date")) ? rs.getDate("expire_date").toLocalDate() : null);
|
||||
user.setLastAuthTime(ObjectUtils.isNotEmpty(rs.getTimestamp("last_auth_time")) ? rs.getTimestamp("last_auth_time").toLocalDateTime() : null);
|
||||
user.setOrgDisplayPath(rs.getString("org_display_path"));
|
||||
user.setPrimaryOrgDisplayPath(rs.getString("primary_org_display_path"));
|
||||
//额外数据
|
||||
user.setCreateBy(rs.getString("create_by"));
|
||||
user.setCreateTime(ObjectUtils.isNotEmpty(rs.getTimestamp("create_time")) ? rs.getTimestamp("create_time").toLocalDateTime() : null);
|
||||
|
|
|
@ -82,11 +82,22 @@
|
|||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<!-- 添加字段 -->
|
||||
<addColumn tableName="organization_member">
|
||||
<column name="primary_" remarks="主组织" type="TINYINT(1)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<!--创建索引-->
|
||||
<createIndex tableName="app_group_association" indexName="uk_app_group_association" unique="true">
|
||||
<column name="group_id"/>
|
||||
<column name="app_id"/>
|
||||
<column name="is_deleted"/>
|
||||
</createIndex>
|
||||
<createIndex tableName="organization_member" indexName="uk_organization_member_primary" unique="true">
|
||||
<column name="user_id"/>
|
||||
<column name="primary_"/>
|
||||
<column name="is_deleted"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
|
@ -39,6 +39,8 @@ import {
|
|||
Table,
|
||||
Tooltip,
|
||||
Typography,
|
||||
Tag,
|
||||
Popover
|
||||
} from 'antd';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import CreateUser from '../CreateUser';
|
||||
|
@ -182,6 +184,45 @@ export default (props: UserListProps) => {
|
|||
dataIndex: 'orgDisplayPath',
|
||||
search: false,
|
||||
ellipsis: true,
|
||||
render: (_, record) => [
|
||||
<Popover
|
||||
key="pop"
|
||||
title={
|
||||
<Tag color={'geekblue'} key={record.primaryOrgDisplayPath}>
|
||||
{record.primaryOrgDisplayPath}
|
||||
</Tag>
|
||||
}
|
||||
content={
|
||||
<Space direction="vertical" size="small" style={{ display: 'flex' }}>
|
||||
{record.orgDisplayPath.split(",")?.map((p: string) => {
|
||||
return (
|
||||
<Tag color={'green'} key={p}>
|
||||
{p}
|
||||
</Tag>
|
||||
)
|
||||
})}
|
||||
</Space>
|
||||
}>
|
||||
<Space key="primary_path">
|
||||
{
|
||||
<Tag color={'geekblue'} key={record.primaryOrgDisplayPath}>
|
||||
{record.primaryOrgDisplayPath}
|
||||
</Tag>
|
||||
}
|
||||
</Space>
|
||||
<Space key="path" direction="vertical" size="small" style={{ display: 'flex' }}>
|
||||
{
|
||||
record.orgDisplayPath.split(",")?.map((p: string) => {
|
||||
return (
|
||||
<Tag color={'green'} key={p}>
|
||||
{p}
|
||||
</Tag>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Space>
|
||||
</Popover>
|
||||
],
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'pages.account.user_list.user.columns.status' }),
|
||||
|
|
|
@ -25,6 +25,8 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
|
||||
import cn.topiam.employee.audit.repository.result.AuthnZoneResult;
|
||||
import cn.topiam.employee.console.pojo.query.analysis.AnalysisQuery;
|
||||
import cn.topiam.employee.console.pojo.result.analysis.*;
|
||||
import cn.topiam.employee.console.service.analysis.AnalysisService;
|
||||
|
|
|
@ -69,15 +69,15 @@ public class AnalysisQuery implements Serializable {
|
|||
/**
|
||||
* HOUR
|
||||
*/
|
||||
HOUR(CalendarInterval.Hour, "HH时"),
|
||||
HOUR(CalendarInterval.Hour, "%h时"),
|
||||
/**
|
||||
* DAY
|
||||
*/
|
||||
DAY(CalendarInterval.Day, "dd日"),
|
||||
DAY(CalendarInterval.Day, "%d日"),
|
||||
/**
|
||||
* MONTH
|
||||
*/
|
||||
MONTH(CalendarInterval.Month, "MM月");
|
||||
MONTH(CalendarInterval.Month, "%m月");
|
||||
|
||||
private final CalendarInterval type;
|
||||
private final String format;
|
||||
|
|
|
@ -19,6 +19,8 @@ package cn.topiam.employee.console.service.analysis;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
|
||||
import cn.topiam.employee.audit.repository.result.AuthnZoneResult;
|
||||
import cn.topiam.employee.console.pojo.query.analysis.AnalysisQuery;
|
||||
import cn.topiam.employee.console.pojo.result.analysis.*;
|
||||
|
||||
|
@ -65,7 +67,7 @@ public interface AnalysisService {
|
|||
* 登录区域统计
|
||||
*
|
||||
* @param params {@link AnalysisQuery}
|
||||
* @return {@link List<AuthnZoneResult>}
|
||||
* @return {@link List< AuthnZoneResult >}
|
||||
*/
|
||||
List<AuthnZoneResult> authnZone(AnalysisQuery params);
|
||||
}
|
||||
|
|
|
@ -24,14 +24,15 @@ import java.util.*;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.data.elasticsearch.client.elc.*;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.topiam.employee.audit.entity.AuditElasticSearchEntity;
|
||||
import cn.topiam.employee.audit.enums.EventStatus;
|
||||
import cn.topiam.employee.audit.event.type.EventType;
|
||||
import cn.topiam.employee.authentication.common.IdentityProviderType;
|
||||
import cn.topiam.employee.audit.repository.AuditRepository;
|
||||
import cn.topiam.employee.audit.repository.result.AuditStatisticsResult;
|
||||
import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
|
||||
import cn.topiam.employee.audit.repository.result.AuthnZoneResult;
|
||||
import cn.topiam.employee.common.entity.app.AppEntity;
|
||||
import cn.topiam.employee.common.repository.account.UserRepository;
|
||||
import cn.topiam.employee.common.repository.app.AppRepository;
|
||||
|
@ -44,17 +45,12 @@ import cn.topiam.employee.support.autoconfiguration.SupportProperties;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import co.elastic.clients.elasticsearch._types.aggregations.*;
|
||||
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
|
||||
import co.elastic.clients.json.JsonData;
|
||||
import static cn.topiam.employee.audit.entity.Actor.ACTOR_AUTH_TYPE;
|
||||
import static cn.topiam.employee.audit.entity.Event.*;
|
||||
import static cn.topiam.employee.audit.entity.GeoLocation.GEO_LOCATION_PROVINCE_CODE;
|
||||
import static cn.topiam.employee.audit.entity.Target.TARGET_ID_KEYWORD;
|
||||
import static cn.topiam.employee.common.constant.AuditConstants.getAuditIndexPrefix;
|
||||
import static cn.topiam.employee.console.converter.authn.IdentityProviderConverter.getIdentityProviderType;
|
||||
import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_DATE_TIME_FORMATTER_PATTERN;
|
||||
|
||||
|
@ -76,27 +72,13 @@ public class AnalysisServiceImpl implements AnalysisService {
|
|||
*/
|
||||
@Override
|
||||
public OverviewResult overview() {
|
||||
IndexCoordinates indexCoordinates = IndexCoordinates
|
||||
.of(getAuditIndexPrefix(supportProperties.getAudit().getIndexPrefix()) + "*");
|
||||
// 不存在索引
|
||||
if (!elasticsearchTemplate.indexOps(indexCoordinates).exists()) {
|
||||
return new OverviewResult();
|
||||
}
|
||||
OverviewResult result = new OverviewResult();
|
||||
result.setAppCount(appRepository.count());
|
||||
result.setUserCount(userRepository.count());
|
||||
result.setIdpCount(identityProviderRepository.count());
|
||||
// 查询今日认证量条件
|
||||
Query rangeQuery = QueryBuilders.range(range -> range.field(EVENT_TIME)
|
||||
.gte(JsonData.of(LocalDateTime.of(LocalDate.now(), LocalTime.MIN)
|
||||
.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMATTER_PATTERN))))
|
||||
.lt(JsonData.of(LocalDateTime.of(LocalDate.now(), LocalTime.MAX)
|
||||
.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMATTER_PATTERN))))
|
||||
.timeZone(ZONE_ID).format(DEFAULT_DATE_TIME_FORMATTER_PATTERN));
|
||||
Query query = getQuery(rangeQuery, EventType.LOGIN_PORTAL);
|
||||
result.setTodayAuthnCount(
|
||||
elasticsearchTemplate.count(new NativeQueryBuilder().withQuery(query).build(),
|
||||
AuditElasticSearchEntity.class, indexCoordinates));
|
||||
result.setTodayAuthnCount(auditRepository.countByTypeAndTime(
|
||||
EventType.LOGIN_PORTAL.getCode(), LocalDateTime.MIN, LocalDateTime.MAX));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -108,71 +90,11 @@ public class AnalysisServiceImpl implements AnalysisService {
|
|||
*/
|
||||
@Override
|
||||
public List<AuthnQuantityResult> authnQuantity(AnalysisQuery params) {
|
||||
IndexCoordinates indexCoordinates = IndexCoordinates
|
||||
.of(getAuditIndexPrefix(supportProperties.getAudit().getIndexPrefix()) + "*");
|
||||
// 不存在索引
|
||||
if (!elasticsearchTemplate.indexOps(indexCoordinates).exists()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
LocalDateTime min = params.getStartTime();
|
||||
LocalDateTime max = params.getEndTime();
|
||||
AnalysisQuery.Interval timeInterval = params.getTimeInterval();
|
||||
// 根据事件月份分组统计认证数量 count
|
||||
Aggregation dateGroup = AggregationBuilders
|
||||
.dateHistogram(count -> count.calendarInterval(timeInterval.getType()).extendedBounds(
|
||||
fieldDateMathBuilder -> fieldDateMathBuilder.min(FieldDateMath.of(math -> {
|
||||
math.value(
|
||||
(double) min.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
||||
return math;
|
||||
})).max(FieldDateMath.of(math -> {
|
||||
math.value(
|
||||
(double) max.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
||||
return math;
|
||||
}))).field(EVENT_TIME).timeZone(ZONE_ID).format(timeInterval.getFormat()));
|
||||
// 事件状态group
|
||||
TermsAggregation statusGroup = AggregationBuilders.terms(t -> t.field(EVENT_STATUS))
|
||||
.terms();
|
||||
Aggregation group = new Aggregation.Builder().aggregations("dateGroup", dateGroup)
|
||||
.terms(statusGroup).build();
|
||||
|
||||
return getAuthnQuantityResults(indexCoordinates, min, max, group);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<AuthnQuantityResult> getAuthnQuantityResults(IndexCoordinates indexCoordinates,
|
||||
LocalDateTime min, LocalDateTime max,
|
||||
Aggregation aggregation) {
|
||||
// 查询条件
|
||||
Query rangeBuilder = QueryBuilders.range(range -> range.field(EVENT_TIME).timeZone(ZONE_ID)
|
||||
.format(DEFAULT_DATE_TIME_FORMATTER_PATTERN)
|
||||
.gt(JsonData
|
||||
.of(min.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMATTER_PATTERN))))
|
||||
.lt(JsonData
|
||||
.of(max.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMATTER_PATTERN)))));
|
||||
Query query = getQuery(rangeBuilder, EventType.LOGIN_PORTAL);
|
||||
NativeQuery authCountBuild = new NativeQueryBuilder().withQuery(query)
|
||||
.withAggregation(COUNT, aggregation).withMaxResults(0).build();
|
||||
// 统计认证量
|
||||
SearchHits<AuditElasticSearchEntity> authCountResult = elasticsearchTemplate
|
||||
.search(authCountBuild, AuditElasticSearchEntity.class, indexCoordinates);
|
||||
ElasticsearchAggregation countGroupAggregation = getCountAggregation(authCountResult);
|
||||
List<AuthnQuantityResult> authCountList = new ArrayList<>();
|
||||
if (countGroupAggregation != null) {
|
||||
List<StringTermsBucket> buckets = countGroupAggregation.aggregation().getAggregate()
|
||||
.sterms().buckets().array();
|
||||
for (StringTermsBucket bucket : buckets) {
|
||||
// success/fail
|
||||
String statusGroupKey = bucket.key().stringValue();
|
||||
List<DateHistogramBucket> dateGroupList = bucket.aggregations().get("dateGroup")
|
||||
.dateHistogram().buckets().array();
|
||||
for (DateHistogramBucket dateGroup : dateGroupList) {
|
||||
String dateGroupKey = dateGroup.keyAsString();
|
||||
authCountList.add(new AuthnQuantityResult(dateGroupKey, dateGroup.docCount(),
|
||||
Objects.requireNonNull(EventStatus.getType(statusGroupKey)).getDesc()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return authCountList;
|
||||
return auditRepository.authnQuantity(EventType.LOGIN_PORTAL, min, max,
|
||||
timeInterval.getFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,32 +105,13 @@ public class AnalysisServiceImpl implements AnalysisService {
|
|||
*/
|
||||
@Override
|
||||
public List<AppVisitRankResult> appVisitRank(AnalysisQuery params) {
|
||||
IndexCoordinates indexCoordinates = IndexCoordinates
|
||||
.of(getAuditIndexPrefix(supportProperties.getAudit().getIndexPrefix()) + "*");
|
||||
// 不存在索引
|
||||
if (!elasticsearchTemplate.indexOps(indexCoordinates).exists()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Query rangeQuery = getRangeQueryBuilder(params);
|
||||
Query query = getQuery(rangeQuery, EventType.APP_SSO);
|
||||
// 应用访问频次前10条
|
||||
Aggregation groupAppVisit = AggregationBuilders
|
||||
.terms(terms -> terms.field(TARGET_ID_KEYWORD).size(10));
|
||||
NativeQuery appVisitBuild = new NativeQueryBuilder().withQuery(query)
|
||||
.withAggregation(COUNT, groupAppVisit).build();
|
||||
SearchHits<AuditElasticSearchEntity> appVisitResult = elasticsearchTemplate
|
||||
.search(appVisitBuild, AuditElasticSearchEntity.class, indexCoordinates);
|
||||
ElasticsearchAggregation countAggregation = getCountAggregation(appVisitResult);
|
||||
List<AppVisitRankResult> applicationVisitList = new ArrayList<>();
|
||||
if (countAggregation != null) {
|
||||
List<StringTermsBucket> array = countAggregation.aggregation().getAggregate().sterms()
|
||||
.buckets().array();
|
||||
for (StringTermsBucket bucket : array) {
|
||||
String key = bucket.key().stringValue();
|
||||
// 单点登录
|
||||
String name = getAppName(key);
|
||||
applicationVisitList.add(new AppVisitRankResult(name, bucket.docCount()));
|
||||
}
|
||||
List<AuditStatisticsResult> auditRankResults = auditRepository
|
||||
.appVisitRank(EventType.APP_SSO, params.getStartTime(), params.getEndTime());
|
||||
for (AuditStatisticsResult auditRankResult : auditRankResults) {
|
||||
// 单点登录
|
||||
String name = getAppName(auditRankResult.getKey());
|
||||
applicationVisitList.add(new AppVisitRankResult(name, auditRankResult.getCount()));
|
||||
}
|
||||
return applicationVisitList;
|
||||
}
|
||||
|
@ -236,33 +139,14 @@ public class AnalysisServiceImpl implements AnalysisService {
|
|||
*/
|
||||
@Override
|
||||
public List<AuthnHotProviderResult> authnHotProvider(AnalysisQuery params) {
|
||||
IndexCoordinates indexCoordinates = IndexCoordinates
|
||||
.of(getAuditIndexPrefix(supportProperties.getAudit().getIndexPrefix()) + "*");
|
||||
// 不存在索引
|
||||
if (!elasticsearchTemplate.indexOps(indexCoordinates).exists()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Query builder = getRangeQueryBuilder(params);
|
||||
BoolQuery.Builder queryBuilder = getQueryBuilder(builder, EventType.LOGIN_PORTAL);
|
||||
queryBuilder.must(QueryBuilders.exists(e -> e.field(ACTOR_AUTH_TYPE)));
|
||||
// 授权类型频次
|
||||
Aggregation groupAuthType = AggregationBuilders
|
||||
.terms(terms -> terms.field(ACTOR_AUTH_TYPE).size(IdentityProviderType.size()));
|
||||
NativeQuery appVisitBuild = new NativeQueryBuilder()
|
||||
.withQuery(queryBuilder.build()._toQuery()).withAggregation(COUNT, groupAuthType)
|
||||
.build();
|
||||
SearchHits<AuditElasticSearchEntity> authTypeResult = elasticsearchTemplate
|
||||
.search(appVisitBuild, AuditElasticSearchEntity.class, indexCoordinates);
|
||||
ElasticsearchAggregation authTypeStringTerms = getCountAggregation(authTypeResult);
|
||||
List<AuthnHotProviderResult> authTypeList = new ArrayList<>();
|
||||
if (authTypeStringTerms != null) {
|
||||
List<StringTermsBucket> array = authTypeStringTerms.aggregation().getAggregate()
|
||||
.sterms().buckets().array();
|
||||
for (StringTermsBucket bucket : array) {
|
||||
String key = bucket.key().stringValue();
|
||||
// 授权类型
|
||||
String name = getIdentityProviderType(key).name();
|
||||
authTypeList.add(new AuthnHotProviderResult(name, bucket.docCount()));
|
||||
List<AuditStatisticsResult> auditRankResults = auditRepository
|
||||
.authnHotProvider(EventType.LOGIN_PORTAL, params.getStartTime(), params.getEndTime());
|
||||
for (AuditStatisticsResult auditRankResult : auditRankResults) {
|
||||
// 授权类型
|
||||
if (Objects.nonNull(auditRankResult.getKey())) {
|
||||
String name = getIdentityProviderType(auditRankResult.getKey()).name();
|
||||
authTypeList.add(new AuthnHotProviderResult(name, auditRankResult.getCount()));
|
||||
}
|
||||
}
|
||||
return authTypeList;
|
||||
|
@ -272,38 +156,16 @@ public class AnalysisServiceImpl implements AnalysisService {
|
|||
* 登录区域统计
|
||||
*
|
||||
* @param params {@link AnalysisQuery}
|
||||
* @return {@link List<AuthnZoneResult>}
|
||||
* @return {@link List< AuthnZoneResult >}
|
||||
*/
|
||||
@Override
|
||||
public List<AuthnZoneResult> authnZone(AnalysisQuery params) {
|
||||
IndexCoordinates indexCoordinates = IndexCoordinates
|
||||
.of(getAuditIndexPrefix(supportProperties.getAudit().getIndexPrefix()) + "*");
|
||||
// 不存在索引
|
||||
if (!elasticsearchTemplate.indexOps(indexCoordinates).exists()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Query builder = getRangeQueryBuilder(params);
|
||||
BoolQuery.Builder queryBuilder = getQueryBuilder(builder, EventType.LOGIN_PORTAL);
|
||||
queryBuilder.must(QueryBuilders.exists(exists -> exists.field(GEO_LOCATION_PROVINCE_CODE)));
|
||||
// 登录城市分组统计
|
||||
Aggregation groupAuthZone = AggregationBuilders
|
||||
.terms(terms -> terms.field(GEO_LOCATION_PROVINCE_CODE).size(36));
|
||||
NativeQuery appVisitBuild = new NativeQueryBuilder()
|
||||
.withQuery(queryBuilder.build()._toQuery()).withAggregation(COUNT, groupAuthZone)
|
||||
.build();
|
||||
SearchHits<AuditElasticSearchEntity> authZoneResult = elasticsearchTemplate
|
||||
.search(appVisitBuild, AuditElasticSearchEntity.class, indexCoordinates);
|
||||
ElasticsearchAggregation authZoneStringTerms = getCountAggregation(authZoneResult);
|
||||
List<AuthnZoneResult> authnZoneResults = new ArrayList<>();
|
||||
if (authZoneStringTerms != null) {
|
||||
List<StringTermsBucket> array = authZoneStringTerms.aggregation().getAggregate()
|
||||
.sterms().buckets().array();
|
||||
for (StringTermsBucket bucket : array) {
|
||||
String key = bucket.key().stringValue();
|
||||
authnZoneResults.add(new AuthnZoneResult(key, bucket.docCount()));
|
||||
}
|
||||
}
|
||||
return authnZoneResults;
|
||||
List<AuditStatisticsResult> auditStatisticsResults = auditRepository
|
||||
.authnZone(EventType.LOGIN_PORTAL, params.getStartTime(), params.getEndTime());
|
||||
return auditStatisticsResults.stream()
|
||||
.map(auditStatisticsResult -> new AuthnZoneResult(auditStatisticsResult.getKey(),
|
||||
auditStatisticsResult.getCount()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -372,7 +234,9 @@ public class AnalysisServiceImpl implements AnalysisService {
|
|||
|
||||
private final SupportProperties supportProperties;
|
||||
|
||||
private final ElasticsearchTemplate elasticsearchTemplate;
|
||||
// private final ElasticsearchTemplate elasticsearchTemplate;
|
||||
|
||||
private final AuditRepository auditRepository;
|
||||
|
||||
private final AppRepository appRepository;
|
||||
|
||||
|
|
|
@ -132,10 +132,6 @@ spring:
|
|||
overwrite-existing-jobs: true
|
||||
jdbc:
|
||||
initialize-schema: never
|
||||
#rabbitmq
|
||||
rabbitmq:
|
||||
template:
|
||||
reply-timeout: 60000
|
||||
#日志配置
|
||||
logging:
|
||||
config: classpath:config/logback-spring.xml
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package cn.topiam.employee.openapi.converter.account;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -25,10 +26,15 @@ import org.mapstruct.Mapping;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import cn.topiam.employee.common.entity.account.OrganizationEntity;
|
||||
import cn.topiam.employee.common.entity.account.OrganizationMemberEntity;
|
||||
import cn.topiam.employee.openapi.pojo.result.account.OrganizationChildResult;
|
||||
import cn.topiam.employee.openapi.pojo.result.account.OrganizationMember;
|
||||
import cn.topiam.employee.openapi.pojo.result.account.OrganizationResult;
|
||||
import cn.topiam.employee.openapi.pojo.save.account.OrganizationCreateParam;
|
||||
import cn.topiam.employee.openapi.pojo.save.account.OrganizationMemberCreateParam;
|
||||
import cn.topiam.employee.openapi.pojo.update.account.OrganizationUpdateParam;
|
||||
import cn.topiam.employee.support.exception.BadParamsException;
|
||||
import cn.topiam.employee.support.security.util.SecurityUtils;
|
||||
|
||||
/**
|
||||
* 组织架构数据映射
|
||||
|
@ -119,4 +125,42 @@ public interface OrganizationConverter {
|
|||
* @return {@link OrganizationResult}
|
||||
*/
|
||||
OrganizationResult entityConvertToOrgDetailResult(OrganizationEntity organization);
|
||||
|
||||
/**
|
||||
* 组织用户关系入参转entity
|
||||
*
|
||||
* @param createParam {@link OrganizationMemberCreateParam}
|
||||
* @return {@link List}
|
||||
*/
|
||||
default List<OrganizationMemberEntity> orgMemberConvertToEntity(OrganizationMemberCreateParam createParam) {
|
||||
List<OrganizationMemberCreateParam.Organization> list = createParam.getOrganizationList();
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
if (!(list.stream().filter(OrganizationMemberCreateParam.Organization::getPrimary)
|
||||
.count() == 1)) {
|
||||
throw new BadParamsException("主组织有且只能存在一个");
|
||||
}
|
||||
List<OrganizationMemberEntity> entities = new ArrayList<>(list.size());
|
||||
for (OrganizationMemberCreateParam.Organization organization : list) {
|
||||
OrganizationMemberEntity organizationMemberEntity = new OrganizationMemberEntity();
|
||||
organizationMemberEntity.setOrgId(organization.getOrgId());
|
||||
organizationMemberEntity.setUserId(createParam.getUserId());
|
||||
organizationMemberEntity.setPrimary(organization.getPrimary());
|
||||
organizationMemberEntity.setCreateBy(SecurityUtils.getCurrentUserId());
|
||||
organizationMemberEntity.setCreateTime(LocalDateTime.now());
|
||||
organizationMemberEntity.setUpdateBy(SecurityUtils.getCurrentUserId());
|
||||
organizationMemberEntity.setUpdateTime(LocalDateTime.now());
|
||||
entities.add(organizationMemberEntity);
|
||||
}
|
||||
return entities;
|
||||
};
|
||||
|
||||
/**
|
||||
* entity转组织用户关系
|
||||
*
|
||||
* @param list {@link List}
|
||||
* @return {@link List}
|
||||
*/
|
||||
List<OrganizationMember> entityConvertToOrgMember(List<OrganizationMemberEntity> list);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* eiam-openapi - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.openapi.pojo.result.account;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 组织用户关系
|
||||
*
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2020/8/11 21:27
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "组织用户关系")
|
||||
public class OrganizationMember implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 5599721546299698344L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@Schema(description = "ID")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Schema(description = "用户ID")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
@Schema(description = "组织ID")
|
||||
private String orgId;
|
||||
|
||||
/**
|
||||
* 是否主组织
|
||||
*/
|
||||
@Schema(description = "是否主组织")
|
||||
private Boolean primary;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* eiam-openapi - Employee Identity and Access Management
|
||||
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package cn.topiam.employee.openapi.pojo.save.account;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 保存组织用户关系
|
||||
*
|
||||
* @author TopIAM
|
||||
* Created by support@topiam.cn on 2023/9/23 21:27
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "保存组织用户关系")
|
||||
public class OrganizationMemberCreateParam implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 5599713546299698344L;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Schema(description = "用户ID")
|
||||
@NotNull(message = "用户ID不能为空")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 组织信息
|
||||
*/
|
||||
@Schema(description = "组织信息")
|
||||
@Valid
|
||||
@Size(min = 1, message = "至少选择一个组织")
|
||||
private List<Organization> organizationList;
|
||||
|
||||
@Data
|
||||
@Schema(description = "组织信息")
|
||||
public static class Organization {
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
@Schema(description = "组织ID")
|
||||
@NotNull(message = "组织ID不能为空")
|
||||
private String orgId;
|
||||
|
||||
/**
|
||||
* 是否主组织
|
||||
*/
|
||||
@Schema(description = "是否主组织")
|
||||
private Boolean primary;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue