Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 本地目录导入excel支持选择更新 #728 #813

Merged
merged 10 commits into from
Dec 6, 2022
Merged
4 changes: 4 additions & 0 deletions src/api/bkuser_core/api/web/category/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ class CategoryFileImportInputSLZ(serializers.Serializer):
file = serializers.FileField(required=False)


class CategoryFileImportQuerySLZ(serializers.Serializer):
is_overwrite = serializers.BooleanField(required=False, default=False)
Canway-shiisa marked this conversation as resolved.
Show resolved Hide resolved


class CategorySyncResponseOutputSLZ(serializers.Serializer):
task_id = serializers.CharField(help_text="task_id for the sync job.")

Expand Down
9 changes: 8 additions & 1 deletion src/api/bkuser_core/api/web/category/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
CategoryExportInputSLZ,
CategoryExportProfileOutputSLZ,
CategoryFileImportInputSLZ,
CategoryFileImportQuerySLZ,
CategoryMetaOutputSLZ,
CategoryNamespaceSettingUpdateInputSLZ,
CategoryProfileListInputSLZ,
Expand Down Expand Up @@ -454,6 +455,9 @@ def post(self, request, *args, **kwargs):

def _local_category_do_import(self, request, instance):
"""向本地目录导入数据文件"""
query_slz = CategoryFileImportQuerySLZ(data=request.query_params)
query_slz.is_valid(raise_exception=True)

slz = CategoryFileImportInputSLZ(data=request.data)
slz.is_valid(raise_exception=True)

Expand All @@ -465,7 +469,10 @@ def _local_category_do_import(self, request, instance):
raise error_codes.CREATE_SYNC_TASK_FAILED.f(str(e))

instance_id = instance.id
params = {"raw_data_file": slz.validated_data["file"]}
params = {
"raw_data_file": slz.validated_data["file"],
"is_overwrite": query_slz.validated_data["is_overwrite"],
}
try:
# TODO: FileField 可能不能反序列化, 所以可能不能传到 celery 执行
adapter_sync(instance_id, operator=request.operator, task_id=task_id, **params)
Expand Down
25 changes: 18 additions & 7 deletions src/api/bkuser_core/categories/plugins/local/syncer.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,13 @@ def __post_init__(self):
self._default_password_valid_days = int(ConfigProvider(self.category_id).get("password_valid_days"))
self.fetcher: ExcelFetcher = self.get_fetcher()

def sync(self, raw_data_file):
def sync(self, raw_data_file, is_overwrite):
user_rows, departments = self.fetcher.fetch(raw_data_file)
with transaction.atomic():
self._sync_departments(departments)

with transaction.atomic():
self._sync_users(self.fetcher.parser_set, user_rows)
self._sync_users(self.fetcher.parser_set, user_rows, is_overwrite)
self._sync_leaders(self.fetcher.parser_set, user_rows)

self._notify_init_passwords()
Expand Down Expand Up @@ -175,7 +175,7 @@ def _judge_data_all_none(raw_data: list) -> bool:
"""某些状况下会读取 Excel 整个空行"""
return all(x is None for x in raw_data)

def _sync_users(self, parser_set: "ParserSet", users: list):
def _sync_users(self, parser_set: "ParserSet", users: list, is_overwrite: bool = False):
Canway-shiisa marked this conversation as resolved.
Show resolved Hide resolved
"""在内存中操作&判断数据,bulk 插入"""
logger.info("=========== trying to load profiles into memory ===========")
Canway-shiisa marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -235,8 +235,9 @@ def _sync_users(self, parser_set: "ParserSet", users: list):
progress(index, total, f"loading {username}")
try:
updating_profile = Profile.objects.get(username=username, category_id=self.category_id)

# 如果已经存在,则更新该 profile
# 已存在的用户:如果未勾选 <进行覆盖更新>(即is_overwrite为false)=》则忽略,反之则更新该 profile
if not is_overwrite:
wklken marked this conversation as resolved.
Show resolved Hide resolved
continue
for name, value in profile_params.items():
if name == "extras":
extras = updating_profile.extras or {}
Expand All @@ -250,6 +251,7 @@ def _sync_users(self, parser_set: "ParserSet", users: list):

setattr(updating_profile, name, value)
profile_id = updating_profile.id

self.db_sync_manager.magic_add(updating_profile, SyncOperation.UPDATE.value)
logger.debug("(%s/%s) username<%s> already exist, trying to update it", username, index + 1, total)

Expand Down Expand Up @@ -278,13 +280,22 @@ def _sync_users(self, parser_set: "ParserSet", users: list):
# 2 获取关联的部门DB实例,创建关联对象
progress(index, total, "adding profile & department relation")
department_groups = parser_set.get_cell_data("department_name", user_raw_info)

cell_parser = DepartmentCellParser(self.category_id)
# 获取已存在用户 旧的部门-用户关系
old_department_profile_relations = DepartmentThroughModel.objects.filter(profile_id=profile_id)

for department in cell_parser.parse_to_db_obj(department_groups):
relation_params = {"department_id": department.pk, "profile_id": profile_id}
try:
DepartmentThroughModel.objects.get(**relation_params)
new_department_profile_relation = DepartmentThroughModel.objects.get(**relation_params)
# 勾选 <进行覆盖更新>(即is_overwrite为true)、已存用户且用户-部门关系存在 => 将多余的用户-部门关系进行清理即可:
old_department_profile_relations.exclude(id=new_department_profile_relation.id).delete()

except DepartmentThroughModel.DoesNotExist:
# 勾选 <进行覆盖更新>(即is_overwrite为true)、已存用户且用户-部门关系不存在 => 现存的用户-部门关系需要全部清理:
if is_overwrite and old_department_profile_relations:
wklken marked this conversation as resolved.
Show resolved Hide resolved
old_department_profile_relations.delete()
# 用户不存在的情况,不管是否勾选 <进行覆盖更新>,都不需要进行用户-部门关系清理,只需新建用户-部门关联即可:
Canway-shiisa marked this conversation as resolved.
Show resolved Hide resolved
department_attachment = DepartmentThroughModel(**relation_params)
self.db_sync_manager.magic_add(department_attachment)

Expand Down