Skip to content

Commit

Permalink
Merge pull request #90 from IMBlues/development
Browse files Browse the repository at this point in the history
feat: #58 add api for exporting login log in saas & update sdk due to #1
  • Loading branch information
IMBlues authored Oct 11, 2021
2 parents 0ef4c7e + f1a1e1e commit 0196ad2
Show file tree
Hide file tree
Showing 45 changed files with 1,276 additions and 284 deletions.
23 changes: 23 additions & 0 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@
# Changelog


## [Version: 2.3.0] - 2021-09-27


### API


- [NEW] 支持传递参数,可以拉取已软删除数据 [#1](https://github.com/TencentBlueKing/bk-user/issues/1)
- [NEW] 支持恢复已删除的数据 [#15](https://github.com/TencentBlueKing/bk-user/issues/15)
- [NEW] 支持记录 LDAP/AD 同步组织架构/人员信息的结构化日志 [#27](https://github.com/TencentBlueKing/bk-user/issues/27)
- [OPTIMIZATION] 优化数据源同步任务为后台执行 [#32](https://github.com/TencentBlueKing/bk-user/issues/32)
- [FIX] 修正 SettingMeta 默认路径参数为 id [#45](https://github.com/TencentBlueKing/bk-user/issues/45)
- [FIX] 修正 API /api/v2/batch/profiles/ 中 swagger 参数 query_ids 缺失问题 [#26](https://github.com/TencentBlueKing/bk-user/issues/26)


### SaaS


- [NEW] 支持数据源同步任务页面查看 [#32](https://github.com/TencentBlueKing/bk-user/issues/32)
- [NEW] 支持登录日志导出 [#32](https://github.com/TencentBlueKing/bk-user/issues/32)
- [OPTIMIZATION] 修改页面拉取上级组件,从全量拉取改为类似【人员选择器】的分页拉取组件 [#55](https://github.com/TencentBlueKing/bk-user/issues/55)



## [Version: 2.2.6] - 2021-05-20


Expand Down
1 change: 1 addition & 0 deletions src/api/bkuser_core/audit/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class LoginLogSerializer(CustomFieldsMixin, serializers.Serializer):
reason = serializers.CharField(help_text=_("失败原因"))
create_time = serializers.DateTimeField(help_text=_("创建时间"))
username = serializers.CharField(help_text=_("登录用户"), source="profile.username")
profile_id = serializers.CharField(help_text=_("登录用户ID"), source="profile.id")
category_id = serializers.CharField(help_text=_("登录用户"), source="profile.category_id")


Expand Down
2 changes: 2 additions & 0 deletions src/api/bkuser_core/common/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,13 @@ class AdvancedListSerializer(serializers.Serializer):
input_formats=["iso-8601", "%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%S"],
help_text=_("筛选某个时间点前的记录"),
)
include_disabled = serializers.BooleanField(required=False, default=False, help_text=_("是否包含已软删除的数据"))


class AdvancedRetrieveSerialzier(serializers.Serializer):
fields = serializers.CharField(required=False, help_text=_("指定对象返回字段,支持多选,以逗号分隔,例如: username,status,id"))
lookup_field = serializers.CharField(required=False, help_text=_("指定查询字段,内容为 lookup_value 所属字段, 例如: username"))
include_disabled = serializers.BooleanField(required=False, default=False, help_text=_("是否包含已软删除的数据"))


class EmptySerializer(serializers.Serializer):
Expand Down
22 changes: 22 additions & 0 deletions src/pages/src/language/lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,26 @@ export default {
日志详细: 'Detail log',
正在发起同步任务: 'A synchronization task is being initiated. Procedure',
请在数据更新记录中查看具体详细: 'Please refer to the data update record for details',
审计导出: 'Audit the export',
创建时间: 'creation time',
最近一次登录时间: 'last login time ',
请输入关键字进行搜索: 'Please enter keywords to search',
用户名: 'user name ',
全名: 'full name',
手机号: 'Tel',
邮箱: 'email',
账户状态: 'account status',
在职状态: 'working state',
最近登录: 'recently the login',
最近未登录: 'not logged in recently',
正常: 'normal',
被禁用: 'disabled',
已删除: 'deleted',
已冻结: 'forzen',
在职: 'onJob',
离职: 'dimission',
一个月: 'one month',
两个月: 'two months',
三个月: 'three months',
'审计日志为空, 无法导出': 'the audit log is empty and cannot be exported',
};
22 changes: 22 additions & 0 deletions src/pages/src/language/lang/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,26 @@ export default {
小时: '小时',
正在发起同步任务: '正在发起同步任务',
请在数据更新记录中查看具体详细: '请在数据更新记录中查看具体详细',
审计导出: '审计导出',
创建时间: '创建时间',
最近一次登录时间: '最近一次登录时间',
请输入关键字进行搜索: '请输入关键字进行搜索',
用户名: '用户名',
全名: '全名',
手机号: '手机号',
邮箱: '邮箱',
账户状态: '账户状态',
在职状态: '在职状态',
最近登录: '最近登录',
最近未登录: '最近未登录',
正常: '正常',
被禁用: '被禁用',
已删除: '已删除',
已冻结: '已冻结',
在职: '在职',
离职: '离职',
一个月: '一个月',
两个月: '两个月',
三个月: '三个月',
'审计日志为空, 无法导出': '审计日志为空, 无法导出',
};
5 changes: 5 additions & 0 deletions src/pages/src/store/modules/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,10 @@ export default {
return http.get(`api/v2/audit/operation_logs/?start_time=${startTime}&end_time=${endTime}&page=${page}&page_size=${pageSize}${keyword && (`&keyword=${keyword}`)}`);
// &keyword=${keyword}&page=${page}&page_size=${page_size}
},
// 审计导出
getAuditderive(context, params, config = {}) {
const { url, startTime, endTime } = params;
return http.get(`${url}/api/v2/audit/login_log/export/?start_time=${startTime}&end_time=${endTime}`);
},
},
};
39 changes: 39 additions & 0 deletions src/pages/src/views/audit/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
v-bind="panel"
:key="index">
</bk-tab-panel>
<div class="derive" v-if="panelActive === 'login'" @click="Auditderive">{{$t('审计导出')}}</div>
<div class="audit-content-wrapper">
<div class="thead-container table-container" data-test-id="list_headTitleData">
<table>
Expand Down Expand Up @@ -126,6 +127,7 @@ export default {
data() {
return {
basicLoading: true,
errorMessage: this.$t('审计日志为空,无法导出'),
paginationConfig: {
current: 1,
count: 1,
Expand Down Expand Up @@ -232,6 +234,30 @@ export default {
this.initUserList(this.panelActive);
},
methods: {
handleWarning(config) {
config.message = this.errorMessage;
config.offsetY = 80;
this.$bkMessage(config);
},
async Auditderive() {
const startTime = this.getMyDate(this.searchCondition.dateRange[0]);
const endTime = this.getMyDate(this.searchCondition.dateRange[1]);
let url = window.AJAX_URL;
if (url.endsWith('/')) {
// 去掉末尾的斜杠
url = url.slice(0, url.length - 1);
}
if (!url.startsWith('http')) {
// tips: 后端提供的 SITE_URL 需以 / 开头
url = window.location.origin + url;
}
if (this.panelActive === 'login' && this.auditList.length === 0) {
this.handleWarning({ theme: 'error' });
} else {
url = `${url}/api/v2/audit/login_log/export/?start_time=${startTime}&end_time=${endTime}`;
window.open(url);
}
},
getMyDate(date) {
// return date.getFullYear() + '-' + (date.getMonth() + 1)
// `${+ '-' + date.getDate()}-${date.toString().match(/\d\d:\d\d:\d\d/)[0]}`;
Expand Down Expand Up @@ -315,6 +341,15 @@ export default {
}
}
}
.derive {
position: absolute;
font-size: 14px;
cursor: pointer;
color: #02a8db;
right: 0px;
top: 65px;
z-index: 9999;
}
// 表格
.audit-content-wrapper {
margin: 0 0 30px 0;
Expand Down Expand Up @@ -441,4 +476,8 @@ export default {
}
}
}
.confirmExport{
text-align: center;
font-weight: normal;
}
</style>
38 changes: 17 additions & 21 deletions src/pages/src/views/organization/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
<div class="table-actions" v-if="noSearchOrSearchDepartment">
<!-- 本地用户目录 -->
<template v-if="currentCategoryType === 'local'">
<div class="table-actions-left-container local-type">
<div class="table-actions-left-container local-type" data-test-id="list_operationUser">
<!-- 添加成员 -->
<bk-dropdown-menu ref="dropdownAdd" class="king-dropdown-menu"
:disabled="basicLoading" @show="isDropdownShowAdd = true"
Expand All @@ -105,12 +105,10 @@
<span class="more-action">{{$t('添加用户')}}</span>
<i :class="['bk-icon icon-angle-down',{ 'icon-flip': isDropdownShowAdd }]"></i>
</bk-button>
<div data-test-id="list_operationUser">
<ul class="bk-dropdown-list" slot="dropdown-content">
<li><a href="javascript:;" @click="addUserFn">{{$t('新增用户')}}</a></li>
<li><a href="javascript:;" @click="pullUserFn">{{$t('从其他组织拉取')}}</a></li>
</ul>
</div>
<ul class="bk-dropdown-list" slot="dropdown-content">
<li><a href="javascript:;" @click="addUserFn">{{$t('新增用户')}}</a></li>
<li><a href="javascript:;" @click="pullUserFn">{{$t('从其他组织拉取')}}</a></li>
</ul>
</bk-dropdown-menu>
<!-- 更多操作 -->
<bk-dropdown-menu ref="dropdownMore" class="king-dropdown-menu"
Expand All @@ -120,20 +118,18 @@
<span class="more-action">{{$t('更多操作')}}</span>
<i :class="['bk-icon icon-angle-down',{ 'icon-flip': isDropdownShowMore }]"></i>
</bk-button>
<div data-test-id="list_deleteUser">
<ul class="bk-dropdown-list" slot="dropdown-content">
<li>
<a href="javascript:;" :class="{ 'disabled': !isClick }"
@click="handleSetDepartment">{{$t('设置所在组织')}}
</a>
</li>
<li>
<a href="javascript:;" :class="{ 'disabled': !isClick }"
@click="deleteProfiles">{{$t('批量删除')}}
</a>
</li>
</ul>
</div>
<ul class="bk-dropdown-list" slot="dropdown-content">
<li>
<a href="javascript:;" :class="{ 'disabled': !isClick }"
@click="handleSetDepartment">{{$t('设置所在组织')}}
</a>
</li>
<li>
<a href="javascript:;" :class="{ 'disabled': !isClick }"
@click="deleteProfiles">{{$t('批量删除')}}
</a>
</li>
</ul>
</bk-dropdown-menu>
<!-- 仅显示本级组织成员 -->
<p class="filter-current">
Expand Down
29 changes: 28 additions & 1 deletion src/saas/RELEASE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -311,4 +311,31 @@ versions:
- "增加'查看'类权限项"
- "增加用户登录审计"
- "审计信息增加客户端来源 IP"
- "支持用户重置密码不能与最近三次密码重复"
- "支持用户重置密码不能与最近三次密码重复"

- version: "2.3.0"
date: "2021-09-27"
changeLogs:
- project: "API"
detail:
- type: "NEW"
content:
- "支持传递参数,可以拉取已软删除数据 [#1](https://github.com/TencentBlueKing/bk-user/issues/1)"
- "支持恢复已删除的数据 [#15](https://github.com/TencentBlueKing/bk-user/issues/15)"
- "支持记录 LDAP/AD 同步组织架构/人员信息的结构化日志 [#27](https://github.com/TencentBlueKing/bk-user/issues/27)"
- type: "OPTIMIZATION"
content:
- "优化数据源同步任务为后台执行 [#32](https://github.com/TencentBlueKing/bk-user/issues/32)"
- type: "FIX"
content:
- "修正 SettingMeta 默认路径参数为 id [#45](https://github.com/TencentBlueKing/bk-user/issues/45)"
- "修正 API /api/v2/batch/profiles/ 中 swagger 参数 query_ids 缺失问题 [#26](https://github.com/TencentBlueKing/bk-user/issues/26)"
- project: "SaaS"
detail:
- type: "NEW"
content:
- "支持数据源同步任务页面查看 [#32](https://github.com/TencentBlueKing/bk-user/issues/32)"
- "支持登录日志导出 [#32](https://github.com/TencentBlueKing/bk-user/issues/32)"
- type: "OPTIMIZATION"
content:
- "修改页面拉取上级组件,从全量拉取改为类似【人员选择器】的分页拉取组件 [#55](https://github.com/TencentBlueKing/bk-user/issues/55)"
7 changes: 4 additions & 3 deletions src/saas/bkuser_shell/audit/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
from django.conf.urls import url
from django.urls import path

from .views import GeneralLogViewSet, LoginLogViewSet

urlpatterns = [
##############
# audit_logs #
##############
url(r"^api/v2/audit/operation_logs/$", GeneralLogViewSet.as_view({"get": "list"}), name="operation_logs"),
url(r"^api/v2/audit/login_log/$", LoginLogViewSet.as_view({"get": "list"}), name="login_log"),
path("api/v2/audit/operation_logs/", GeneralLogViewSet.as_view({"get": "list"}), name="operation_logs"),
path("api/v2/audit/login_log/", LoginLogViewSet.as_view({"get": "list"}), name="login_log"),
path("api/v2/audit/login_log/export/", LoginLogViewSet.as_view({"get": "export"}), name="export_login_log"),
]
53 changes: 50 additions & 3 deletions src/saas/bkuser_shell/audit/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,22 @@
specific language governing permissions and limitations under the License.
"""
import logging
import math

import bkuser_sdk
from bkuser_shell.audit import serializers
from bkuser_shell.audit.constants import OPERATION_OBJ_VALUE_MAP, OPERATION_VALUE_MAP
from bkuser_shell.bkiam.constants import ActionEnum
from bkuser_shell.common.error_codes import error_codes
from bkuser_shell.common.export import ProfileExcelExporter
from bkuser_shell.common.viewset import BkUserApiViewSet
from django.conf import settings
from django.utils.timezone import make_aware
from openpyxl import load_workbook

from bkuser_global.drf_crown import ResponseParams, inject_serializer
from bkuser_global.utils import get_timezone_offset

from . import serializers
from .constants import OPERATION_OBJ_VALUE_MAP, OPERATION_VALUE_MAP

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -92,3 +96,46 @@ def list(self, request, validated_data: dict):

params = self._get_request_params(validated_data)
return ResponseParams(api_instance.v2_audit_login_log_list(**params), {"context": {"categories": categories}})

@inject_serializer(query_in=serializers.LoginLogListReqeustSerializer, tags=["audit"])
def export(self, request, validated_data: dict):
"""导出登录日志"""
api_instance = bkuser_sdk.AuditApi(self.get_api_client_by_request(request))
profile_api_instance = bkuser_sdk.ProfilesApi(self.get_api_client_by_request(request))
fields_api_instance = bkuser_sdk.DynamicFieldsApi(self.get_api_client_by_request(request))

params = self._get_request_params(validated_data)
login_logs = self.get_paging_results(
api_instance.v2_audit_login_log_list, since=params["since"], until=params["until"]
)
if not login_logs:
raise error_codes.CANNOT_EXPORT_EMPTY_LOG

fields = self.get_paging_results(fields_api_instance.v2_dynamic_fields_list)
fields.append(
bkuser_sdk.DynamicFields(name="create_time", display_name="登录时间", type="timer", order=0).to_dict()
)

exporter = ProfileExcelExporter(
load_workbook(settings.EXPORT_LOGIN_TEMPLATE), settings.EXPORT_EXCEL_FILENAME, fields, 1
)

# TODO: remove step when #88 is done
step = 300
profile_ids = list({x["profile_id"] for x in login_logs})
profiles = []
counts = math.ceil(len(profile_ids) / step)
for _c in range(counts):
profiles.extend(
self.get_paging_results(
profile_api_instance.v2_profiles_list,
lookup_field="id",
exact_lookups=profile_ids[_c * step : (_c + 1) * step],
include_disabled=True,
)
)

extra_info = {x["profile_id"]: x for x in login_logs}
exporter.update_profiles(profiles, extra_info)

return exporter.to_response()
Loading

0 comments on commit 0196ad2

Please sign in to comment.