<?php
namespace CorporateTrainingBundle\Biz\User\Service\Impl;
use AppBundle\Common\ArrayToolkit;
use Biz\System\Service\SessionService;
use Biz\User\Service\Impl\UserServiceImpl as BaseServiceImpl;
use Biz\User\Service\NotificationService;
use Biz\User\Service\TokenService;
use Codeages\Biz\Framework\Event\Event;
use CorporateTrainingBundle\Biz\Post\Service\PostService;
use CorporateTrainingBundle\Biz\User\Service\UserService;
use CorporateTrainingBundle\Common\Constant\CTConst;
use PostMapPlugin\Biz\Rank\Service\RankService;
use Topxia\Service\Common\ServiceKernel;
class UserServiceImpl extends BaseServiceImpl implements UserService
{
public function getUserWithOrgScopes($id)
{
$user = $this->getUserDao()->get($id);
if (!($user)) {
return null;
}
$user = UserSerialize::unserialize($user);
$user['lineOrgIds'] = $this->getUserlineOrgIds($user);
$user['manageOrgIds'] = $this->getUserManageOrgIds($user);
$user['manageOrgCodes'] = $this->getUserManageOrgCodes($user);
return $user;
}
public function searchUsers(array $conditions, array $orderBy, $start, $limit, $columns = [])
{
if (isset($conditions['nickname'])) {
$conditions['nickname'] = strtoupper($conditions['nickname']);
}
if (empty($conditions['locked']) && empty($conditions['noNeedLocked'])) {
$conditions['locked'] = 0;
}
if (empty($conditions['type'])) {
$conditions['excludeTypes'] = ['deleted', 'system'];
}
if (isset($conditions['type']) && $conditions['type'] === 'all') {
unset($conditions['type']);
}
unset($conditions['noNeedLocked']);
$users = $this->getUserDao()->searchUsers($conditions, $orderBy, $start, $limit, $columns);
return UserSerialize::unserializes($users);
}
public function findDeletedUsers()
{
return $this->getUserDao()->findDeleteUsers();
}
public function findDeletedAndLockedUsers()
{
return $this->getUserDao()->findDeletedAndLockedUsers();
}
public function findDeletedAndLockedUsersByIds($userIds)
{
return $this->getUserDao()->findDeletedAndLockedUsersByIds($userIds);
}
public function findUsersByNicknames($nicknames)
{
return $this->getUserDao()->findByNicknames($nicknames);
}
public function findByVerifiedMobiles(array $verifiedMobiles)
{
return $this->getUserDao()->findByVerifiedMobiles($verifiedMobiles);
}
public function findByEmails(array $emails)
{
return $this->getUserDao()->findByEmails($emails);
}
public function findByIds(array $ids)
{
return $this->getUserDao()->findByIds($ids);
}
public function findUserIdsByConditions($conditions)
{
if (empty($conditions['locked'])) {
$conditions['locked'] = 0;
}
if (empty($conditions['type'])) {
$conditions['noType'] = 'deleted';
}
if (isset($conditions['userIds']) && count($conditions['userIds']) > 15000) {
$existIds = $conditions['userIds'];
unset($conditions['userIds']);
$userIds = $this->getUserDao()->search($conditions, [], 0, PHP_INT_MAX, ['id']);
$userIds = array_intersect($existIds, array_column($userIds, 'id'));
return empty($userIds) ? [-1] : $userIds;
}
$userIds = $this->getUserDao()->search($conditions, [], 0, PHP_INT_MAX, ['id']);
return empty($userIds) ? [-1] : array_column($userIds, 'id');
}
public function initPassword($id, $newPassword)
{
$connection = $this->getKernel()->getConnection();
$connection->beginTransaction();
$user = $this->getUserDao()->get($id);
try {
$init = [
'pwdInit' => '1',
'type' => 'init' == $user['type'] ? 'default' : $user['type'],
];
$this->getAuthService()->changePassword($id, null, $newPassword);
$this->getUserDao()->update($id, $init);
$connection->commit();
} catch (\Exception $e) {
$connection->rollback();
throw $e;
}
return $this->getUserDao()->update($id, $init);
}
public function changePwdInit($id)
{
$init = [
'pwdInit' => '1',
];
return $this->getUserDao()->update($id, $init);
}
public function readGuide($id)
{
$user = $this->getUser($id);
if (empty($user)) {
throw $this->createNotFoundException('User', $id, '用户不存在');
}
return $this->getUserDao()->update($id, ['readGuide' => 1]);
}
public function changeUserPost($id, $postId)
{
$user = $this->getUser($id);
if (empty($user)) {
throw $this->createNotFoundException('User', $id, '用户不存在');
}
$post = $this->getPostService()->getPost($postId);
if (empty($post)) {
throw $this->createNotFoundException('Post', $id, '岗位不存在');
}
$updatedUser = $this->getUserDao()->update($id, ['postId' => $postId]);
$this->getPostMemberService()->becomePostMember($user['id'], $post['id']);
$this->dispatchEvent('user.change_post', new Event($updatedUser, ['oldUser' => $user]));
$this->getLogService()->info('user', 'post_change', "修改用户{$user['nickname']}岗位为{$post['name']}成功");
return $updatedUser;
}
public function findUserProfilesByTrueName($truename)
{
if (empty($truename)) {
return null;
}
return $this->getProfileDao()->findByTrueName($truename);
}
public function statisticsOrgUserNumGroupByOrgId()
{
return $this->getUserDao()->statisticsOrgUserNumGroupByOrgId();
}
public function statisticsPostUserNumGroupByPostId()
{
return $this->getUserDao()->statisticsPostUserNumGroupByPostId();
}
public function batchUpdatePost($ids, $postId)
{
$ids = explode(',', $ids);
$connection = $this->getKernel()->getConnection();
$connection->beginTransaction();
try {
foreach ($ids as $id) {
$this->changeUserPost($id, $postId);
}
$connection->commit();
} catch (\Exception $e) {
$connection->rollback();
throw $e;
}
}
public function countUsersByLockedStatus()
{
return [
'enable' => $this->countUsers(['locked' => 0, 'noType' => 'system']),
'disable' => $this->countUsers(['locked' => 1]),
];
}
public function isOverMaxUsersNumber()
{
return true;
}
public function getMaxUsersNumber()
{
return $this->getSettingService()->get('max_users_number', 0);
}
public function changeUserOrgs($userId, $orgCodes)
{
$user = $this->getUser($userId);
if (empty($user) || ($user['orgCodes'] == $orgCodes)) {
return [];
}
$orgCodes = $this->filterOrgCodes($orgCodes);
$orgs = $this->getOrgService()->findOrgsByOrgCodes($orgCodes);
$existOrgCodes = ArrayToolkit::column($orgs, 'orgCode');
if (array_diff($orgCodes, $existOrgCodes)) {
throw $this->createNotFoundException('Org Not Found');
}
$this->getKernel()->getConnection()->beginTransaction();
try {
$fields = [
'orgCodes' => empty($orgCodes) ? [1.] : ArrayToolkit::column($orgs, 'orgCode'),
'orgIds' => empty($orgCodes) ? [1] : ArrayToolkit::column($orgs, 'id'),
];
$this->getUserDao()->update($userId, $fields);
$this->getUserOrgService()->setUserOrgs($userId, $orgs);
$this->getKernel()->getConnection()->commit();
} catch (\Exception $e) {
$this->getKernel()->getConnection()->rollBack();
throw $e;
}
return $user;
}
public function getUserBindByTypeAndFromId($type, $fromId)
{
return $this->getUserBindDao()->getByTypeAndFromId($this->getUserBindType($type), $fromId);
}
public function getUserBindByTypeAndUserId($type, $toId)
{
$user = $this->getUserDao()->get($toId);
if (empty($user)) {
throw $this->createNotFoundException("User#{$toId} Not Found");
}
if (!$this->typeInOAuthClient($type)) {
throw $this->createInvalidArgumentException('Invalid Type');
}
return $this->getUserBindDao()->getByToIdAndType($this->getUserBindType($type), $toId);
}
public function bindUser($type, $fromId, $toId, $token)
{
$user = $this->getUserDao()->get($toId);
if (empty($user)) {
throw $this->createNotFoundException("User#{$toId} Not Found");
}
if (!$this->typeInOAuthClient($type)) {
throw $this->createInvalidArgumentException('Invalid Type');
}
if ('weixinweb' == $type || 'weixinmob' == $type) {
$type = 'weixin';
}
if ('dingtalkweb' == $type || 'dingtalkmob' == $type) {
$type = 'dingtalk';
}
if ('feishuweb' == $type || 'feishumob' == $type) {
$type = 'feishu';
}
if ($this->isUserBound($toId, $type)) {
throw $this->createAccessDeniedException('account already bound');
}
$bind = $this->getUserBindDao()->create([
'type' => $type,
'fromId' => $fromId,
'toId' => $toId,
'token' => empty($token['token']) ? '' : $token['token'],
'createdTime' => time(),
'expiredTime' => empty($token['expiredTime']) ? 0 : $token['expiredTime'],
]);
$this->dispatchEvent('user.bind', new Event($bind));
}
public function isUserBound($userId, $type)
{
$bind = $this->getUserBindDao()->getByToIdAndType($this->getUserBindType($type), $userId);
return !empty($bind) ? true : false;
}
public function batchUpdateOrgs($userIds, $orgCodes)
{
$currentUser = $this->getCurrentUser();
$userIds = $this->filterUserIds($userIds);
foreach ($userIds as $userId) {
if ($currentUser['id'] == $userId) {
continue;
}
$this->changeUserOrgs($userId, $orgCodes);
}
}
public function batchLockUser(array $userIds)
{
if (!$this->getCurrentUser()->hasPermission('admin_user_lock')) {
throw $this->createAccessDeniedException($this->trans('admin.role.no_permission'));
}
$currentUser = $this->getCurrentUser();
$userIds = array_diff($userIds, [$currentUser['id']]);
if (empty($userIds)) {
return;
}
$users = $this->searchUsers(
['userIds' => $userIds, 'locked' => 0],
[],
0,
count($userIds),
['id']
);
foreach ($users as $user) {
$this->lockUser($user['id']);
$this->kickUserLogout($user['id']);
}
}
public function batchDeleteUser($userIds)
{
$currentUser = $this->getCurrentUser();
foreach ($userIds as $userId) {
if ($currentUser['id'] == $userId) {
continue;
}
$this->deleteUser($userId);
}
}
public function batchWaveUserNotificationNum(array $userIds)
{
if (empty($userIds)) {
return;
}
$this->getUserDao()->wave($userIds, ['newNotificationNum' => 1]);
}
public function findUserIdsByNickNameOrTrueName($name)
{
$userIdsByNickname = $this->getUserDao()->findUserIds(['nickname' => $name]);
$userIdsByNickname = ArrayToolkit::column($userIdsByNickname, 'id');
$userIdsByTruename = $this->getProfileDao()->findUserIds(['truename' => $name]);
$userIdsByTruename = ArrayToolkit::column($userIdsByTruename, 'id');
return array_merge($userIdsByNickname, $userIdsByTruename);
}
/**
* 批量设置讲师
*
* @param $userIds
*/
public function batchSetTeachers($userIds)
{
if (empty($userIds)) {
return;
}
$users = $this->searchUsers(['userIds' => $userIds], [], 0, count($userIds), ['id', 'roles']);
$updateUsers = [];
foreach ($users as $user) {
if (in_array('ROLE_TEACHER', $user['roles'])) {
continue;
}
$updateUsers[$user['id']] = ['roles' => array_merge($user['roles'], ['ROLE_TEACHER'])];
}
if (empty($updateUsers)) {
return;
}
$this->getUserDao()->batchUpdate(array_keys($updateUsers), $updateUsers, 'id');
$this->getLogService()->info('user', 'user_batch_set_teacher', '批量设置讲师'.json_encode($userIds));
}
/**
* 批量设置管理范围
*
* @param $userIds
* @param $orgIds
*/
public function batchSetUserManagePermissions($userIds, $orgIds)
{
if (empty($userIds)) {
return;
}
foreach ($userIds as $userId) {
$manageOrgIds = $this->getManagePermissionService()->findUserManageOrgIdsByUserId($userId);
if (!$this->getManagePermissionService()->checkOrgManagePermission($orgIds, $manageOrgIds)) {
continue;
}
$this->getManagePermissionOrgService()->setUserManagePermissionOrgs($userId, $orgIds);
}
$this->getLogService()->info('user', 'user_batch_set_permissions', '批量设置管理范围'.json_encode($userIds));
}
public function getTotalUserCount(array $conditions)
{
$conditions['locked'] = 0;
$conditions['noType'] = 'system';
$userCount = $this->countUsers(ArrayToolkit::parts($conditions, ['locked', 'noType']));
$userIncreaseCount = $this->countUsers(ArrayToolkit::parts($conditions, ['startTime', 'noType']));
$conditions['locked'] = 1;
$userIncreaseLockedCount = $this->countUsers(ArrayToolkit::parts($conditions, ['locked', 'updatedTime_GE', 'noType']));
return $userCount - $userIncreaseCount + $userIncreaseLockedCount;
}
protected function kickUserLogout($userId)
{
$this->getSessionService()->clearByUserId($userId);
$tokens = $this->getTokenService()->findTokensByUserIdAndType($userId, 'mobile_login');
if (!empty($tokens)) {
foreach ($tokens as $token) {
$this->getTokenService()->destoryToken($token['token']);
}
}
}
protected function filterOrgCodes($orgCodes)
{
if (is_array($orgCodes)) {
return $orgCodes;
} else {
return explode('|', $orgCodes);
}
}
protected function filterUserIds($userIds)
{
if (is_array($userIds)) {
return $userIds;
} else {
return explode(',', $userIds);
}
}
public function initOrgsRelation()
{
$org = $this->getOrgService()->getOrgByOrgCode(CTConst::ROOT_ORG_CODE);
$users = $this->searchUsers([], [], 0, PHP_INT_MAX);
if (!empty($users)) {
foreach ($users as $user) {
$this->getUserOrgService()->setUserOrgs($user['id'], [$org]);
}
}
return $this->getUserDao()->initOrgsRelation();
}
public function initSystemUsers()
{
$users = [
[
'type' => 'system',
'roles' => ['ROLE_USER', 'ROLE_SUPER_ADMIN'],
],
];
foreach ($users as $user) {
$existsUser = $this->getUserDao()->getUserByType($user['type']);
if (!empty($existsUser)) {
continue;
}
$user['nickname'] = $this->generateNickname($user).'(系统用户)';
$user['emailVerified'] = 1;
$user['password'] = $this->getRandomChar();
$user['email'] = $this->generateEmail($user);
$user['salt'] = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
$user['password'] = $this->getPasswordEncoder()->encodePassword($user['password'], $user['salt']);
$user = UserSerialize::unserialize(
$this->getUserDao()->create(UserSerialize::serialize($user))
);
$profile = [];
$profile['id'] = $user['id'];
$this->getProfileDao()->create($profile);
}
}
public function updateUserHireDate($userId, $hireDate)
{
return $this->getUserDao()->update($userId, ['hireDate' => $hireDate]);
}
public function findFollowersByFromId($fromId)
{
return $this->getFriendDao()->findFollowingsByFromId($fromId);
}
public function sortPromoteUser($ids)
{
if (!empty($ids)) {
foreach ($ids as $index => $id) {
$this->promoteUser($id, $index + 1);
}
}
}
public function getUserCustomColumns($id)
{
$profile = $this->getUserProfile($id);
$customColumns = $profile['custom_column'];
$defaultColumns = [
'onlineCourse',
'offlineCourse',
'classroom',
'postCourse',
'projectPlan',
'offlineActivity',
];
return !empty($customColumns) ? $customColumns : $defaultColumns;
}
public function updateUserCustomColumns($id, $columns)
{
$this->updateUserProfile($id, ['custom_column' => $columns]);
return $this->getUserCustomColumns($id);
}
public function updateUserBind($id, $fields)
{
return $this->getUserBindDao()->update($id, $fields);
}
public function getDingTalkUsers($userIds)
{
return $this->getUserBindDao()->search(['type' => 'dingtalk', 'toIds' => $userIds], [], 0, PHP_INT_MAX);
}
public function searchUserBinds($conditions, $orderBys, $start, $limit, $columns = [])
{
return $this->getUserBindDao()->search($conditions, $orderBys, $start, $limit, $columns);
}
public function countUserBinds($conditions)
{
return $this->getUserBindDao()->count($conditions);
}
public function batchDeleteUserBinds($conditions)
{
try {
$this->beginTransaction();
$this->getUserBindDao()->batchDelete($conditions);
$this->commit();
} catch (\Exception $e) {
$this->rollback();
throw $e;
}
return true;
}
public function batchSetPostAndManagePermissionsAndRolesAndOrgCodes($userIds, $fields)
{
if (empty($userIds)) {
return;
}
$currentUser = $this->getCurrentUser();
try {
$this->beginTransaction();
foreach ($userIds as $userId) {
if (in_array('post', $fields['types'], true) && !empty($fields['postId'])) {
$this->changeUserPost($userId, $fields['postId']);
}
if (in_array('roles', $fields['types'], true) && !empty($fields['roles']) && $userId != $currentUser->getId()) {
$this->changeUserRolesBatchDedicated($userId, $fields['roles']);
}
if (in_array('org', $fields['types'], true) && $userId != $currentUser->getId()) {
$this->changeUserOrgBatchDedicated($userId, $fields['orgIds']);
}
if (in_array('orgCode', $fields['types'], true) && $userId != $currentUser->getId()) {
$this->changeUserOrgCodeBatchDedicated($userId, $fields['orgCodes']);
}
}
$this->commit();
} catch (\Exception $e) {
$this->rollback();
throw $e;
}
}
public function findUserFromIdsByType($type, $userIds)
{
if (empty($userIds) || $userIds === [-1]) {
return [];
}
$users = $this->getUserBindDao()->search(['type' => $type, 'toIds' => $userIds], [], 0, count($userIds), ['fromId']);
return ArrayToolkit::column($users, 'fromId');
}
public function statisticsDistinctOrgUserNumGroupByOrgId()
{
return $this->getUserDao()->statisticsDistinctOrgUserNumGroupByOrgId();
}
public function findUserIdsByManageOrgIds($orgIds)
{
return $this->getUserOrgService()->findUserIdsByOrgIds($orgIds);
}
public function pickIdsByTruenameOrNicknameOrMobile($keyword)
{
return ArrayToolkit::uniqueValue(array_merge(
$this->getUserDao()->pickIdsByLikeNickname($keyword),
$this->getProfileDao()->pickIdsByLikeTruename($keyword),
$this->getUserDao()->pickIdsByLikeVerifiedMobile($keyword)
));
}
public function pickIdsByPostId($postId)
{
return $this->getUserDao()->pickIdsByPostId($postId);
}
private function changeUserOrgCodeBatchDedicated($userId, $orgCodes)
{
if ($this->getCurrentUser()->getId() == $userId) {
return;
}
$orgCodes = explode(',', $orgCodes);
$this->changeUserOrgs($userId, $orgCodes);
}
private function changeUserOrgBatchDedicated($userId, $orgIds)
{
$orgIds = explode(',', $orgIds);
$user = $this->getUser($userId);
$user['manageOrgIds'] = $this->getManagePermissionService()->findUserManageOrgIdsByUserId($userId);
if (!$this->getManagePermissionService()->checkOrgManagePermission($orgIds, $user['manageOrgIds'])) {
throw $this->createAccessDeniedException($this->trans('admin.manage.org_permission_beyond_error'));
}
$this->getManagePermissionOrgService()->setUserManagePermissionOrgs($userId, $orgIds);
}
private function changeUserRolesBatchDedicated($userId, $roles)
{
$currentUser = $this->getCurrentUser();
$currentUserProfile = $this->getUserProfile($currentUser['id']);
if (in_array('ROLE_TRAINING_ADMIN', $roles) && !in_array('ROLE_TEACHER', $roles)) {
$roles[] = 'ROLE_TEACHER';
}
$this->changeUserRoles($userId, $roles);
if (!empty($roles)) {
$roleSet = $this->getRoleService()->searchRoles([], 'created', 0, 9999);
$rolesByIndexCode = \AppBundle\Common\ArrayToolkit::index($roleSet, 'code');
$roleNames = $this->getRoleNames($roles, $rolesByIndexCode);
$message = [
'userId' => $currentUser['id'],
'userName' => !empty($currentUserProfile['truename']) ? $currentUserProfile['truename'] : $currentUser['nickname'],
'role' => implode(',', $roleNames),
];
$this->getNotifiactionService()->notify($userId, 'role', $message);
}
}
protected function getRoleNames($roles, $roleSet)
{
$roleNames = [];
$roles = array_unique($roles);
global $kernel;
$userRoleDict = $kernel->getContainer()->get('codeages_plugin.dict_twig_extension')->getDict('userRole');
$roleDictCodes = array_keys($userRoleDict);
foreach ($roles as $role) {
if (in_array($role, $roleDictCodes)) {
$roleNames[] = $userRoleDict[$role];
} elseif ('ROLE_BACKEND' === $role) {
continue;
} else {
$role = $roleSet[$role];
$roleNames[] = $role['name'];
}
}
return $roleNames;
}
private function getUserBindType($type)
{
if ('workwechatweb' == $type || 'workwechatmob' == $type || 'work_wechat' == $type) {
$type = 'work_wechat';
}
if ('weixinweb' == $type || 'weixinmob' == $type || 'weixin' == $type) {
$type = 'weixin';
}
if ('dingtalkweb' == $type || 'dingtalkmob' == $type || 'dingtalk' == $type) {
$type = 'dingtalk';
}
if ('feishuweb' == $type || 'feishumob' == $type || 'feishu' == $type) {
$type = 'feishu';
}
return $type;
}
protected function convertOAuthType($type)
{
if ('weixinweb' == $type || 'weixinmob' == $type) {
$type = 'weixin';
}
if ('dingtalkweb' == $type || 'dingtalkmob' == $type) {
$type = 'dingtalk';
}
return $type;
}
/*
* 返回用户直属部门及直线向上所有父级部门id
*/
protected function getUserLineOrgIds($user)
{
$orgIds = [];
foreach ($user['orgCodes'] as $orgCode) {
$orgIds = array_merge($orgIds, explode('.', substr($orgCode, 0, -1)));
}
return array_unique($orgIds);
}
/*
* 返回用户管理范围部门id
*/
protected function getUserManageOrgIds($user)
{
return $this->getManagePermissionService()->findUserManageOrgIdsByUserId($user['id']);
}
/*
* 返回用户管理范围部门code
*/
protected function getUserManageOrgCodes($user)
{
return $this->getManagePermissionService()->findUserManageOrgCodesByUserId($user['id']);
}
protected function getManagePermissionService()
{
return $this->createService('ManagePermission:ManagePermissionOrgService');
}
protected function getAuthService()
{
return $this->createService('User:AuthService');
}
/**
* @return PostService
*/
protected function getPostService()
{
return $this->createService('CorporateTrainingBundle:Post:PostService');
}
/**
* @return RankService
*/
protected function getRankService()
{
return $this->createService('PostMapPlugin:Rank:RankService');
}
/**
* @return \CorporateTrainingBundle\Biz\User\Service\UserOrgService
*/
protected function getUserOrgService()
{
return $this->createService('User:UserOrgService');
}
protected function getPostMemberService()
{
return $this->createService('CorporateTrainingBundle:Post:PostMemberService');
}
/**
* @return SessionService
*/
protected function getSessionService()
{
return $this->createService('System:SessionService');
}
/**
* @return TokenService
*/
protected function getTokenService()
{
return $this->createService('User:TokenService');
}
/**
* @return NotificationService
*/
protected function getNotifiactionService()
{
return $this->createService('User:NotificationService');
}
}
class UserSerialize
{
public static function serialize(array $user)
{
return $user;
}
public static function unserialize(array $user = null)
{
if (empty($user)) {
return;
}
$user = self::_userRolesSort($user);
return $user;
}
public static function unserializes(array $users)
{
return array_map(
function ($user) {
return UserSerialize::unserialize($user);
},
$users
);
}
private static function _userRolesSort($user)
{
if (!empty($user['roles'][1]) && 'ROLE_USER' == $user['roles'][1]) {
$temp = $user['roles'][1];
$user['roles'][1] = $user['roles'][0];
$user['roles'][0] = $temp;
}
//交换学员角色跟roles数组第0个的位置;
return $user;
}
}