<?php
namespace AppBundle\Controller;
use AppBundle\Common\ArrayToolkit;
use AppBundle\Common\Exception\ResourceNotFoundException;
use AppBundle\Common\LoginToolkit;
use Biz\ResourceManage\Service\ResourceManageService;
use Biz\ResourceManage\Type\BaseType;
use Biz\User\CurrentUser;
use Bodoudou\SDK\BodoudouApi;
use Common\PrepareOrgTrait;
use Common\Validator;
use CorporateTrainingBundle\Biz\ManagePermission\Service\ManagePermissionOrgService;
use CorporateTrainingBundle\Biz\ResourceScope\Service\ResourceAccessScopeService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Topxia\Service\Common\ServiceKernel;
class BaseController extends AbstractController
{
use PrepareOrgTrait;
/**
* @return CurrentUser
*/
protected function getCurrentUser()
{
return $this->getUser();
}
protected function getBiz()
{
return $this->container->get('biz');
}
/**
* @return CurrentUser
*/
public function getUser()
{
$biz = $this->getBiz();
return $biz['user'];
}
/**
* switch current user.
*
* @return CurrentUser
*/
protected function switchUser(Request $request, CurrentUser $user)
{
$user['currentIp'] = $request->getClientIp();
$token = new UsernamePasswordToken($user, null, 'main', $user['roles']);
$this->container->get('security.token_storage')->setToken($token);
$biz = $this->getBiz();
$biz['user'] = $user;
$this->container->get('event_dispatcher')->dispatch(
new InteractiveLoginEvent($request, $token),
SecurityEvents::INTERACTIVE_LOGIN
);
return $user;
}
protected function authenticateUser(array $user)
{
if (!$user['pwdInit'] && !LoginToolkit::isEnforcementInitPwd()) {
$this->getUserService()->changePwdInit($user['id']);
$user['pwdInit'] = 1;
}
$user['currentIp'] = $this->container->get('request_stack')->getCurrentRequest()->getClientIp();
$currentUser = new CurrentUser();
$currentUser->fromArray($user);
return $this->switchUser($this->get('request_stack')->getCurrentRequest(), $currentUser);
}
protected function fillOrgCode($conditions)
{
if (isset($conditions['orgCode']) && !$this->getCurrentUser()->hasManagePermissionWithOrgCode($conditions['orgCode'])) {
$conditions['likeOrgCode'] = '-1';
return $conditions;
}
if ($this->setting('magic.enable_org')) {
if (!isset($conditions['orgCode'])) {
$orgCodes = $this->getCurrentUser()->getManageOrgCodes();
$conditions['likeOrgCode'] = empty($orgCodes) ? '-1' : $orgCodes[0];
} else {
$conditions['likeOrgCode'] = $conditions['orgCode'];
unset($conditions['orgCode']);
}
} else {
if (isset($conditions['orgCode'])) {
unset($conditions['orgCode']);
}
}
return $conditions;
}
protected function buildAccessScope($fields)
{
return $this->getResourceAccessService()->processAccessScope($fields);
}
protected function createViolationJsonResponse($message = '', $code = 0)
{
return $this->createJsonResponse([
'status' => false,
'code' => $code,
'message' => $this->getMessage($message),
], Response::HTTP_BAD_REQUEST);
}
protected function getMessage($message, $arguments = [], $domain = null, $locale = null)
{
return ServiceKernel::instance()->trans($message, $arguments, $domain, $locale);
}
/**
* 判断是否微信内置浏览器访问.
*
* @return bool
*/
protected function isWxClient()
{
return $this->isMobileClient() && false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger');
}
protected function qrcode($routerName, $params)
{
$token = $this->getTokenService()->makeToken('qrcode', [
'data' => [
'url' => $this->generateUrl($routerName, $params, UrlGeneratorInterface::ABSOLUTE_URL),
],
'duration' => 3600 * 24 * 365,
]);
$url = $this->generateUrl('common_parse_qrcode', ['token' => $token['token']], UrlGeneratorInterface::ABSOLUTE_URL);
return $this->generateUrl('common_qrcode', ['text' => $url], UrlGeneratorInterface::ABSOLUTE_URL);
}
/**
* 是否移动端访问访问.
*
* @return bool
*/
protected function isMobileClient()
{
// 如果有HTTP_X_WAP_PROFILE则一定是移动设备
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
return true;
}
// 判断手机发送的客户端标志,兼容性有待提高
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$clientkeywords = [
'nokia',
'sony',
'ericsson',
'mot',
'samsung',
'htc',
'sgh',
'lg',
'sharp',
'sie-',
'philips',
'panasonic',
'alcatel',
'lenovo',
'iphone',
'ipod',
'blackberry',
'meizu',
'android',
'netfront',
'symbian',
'ucweb',
'windowsce',
'palm',
'operamini',
'operamobi',
'openwave',
'nexusone',
'cldc',
'midp',
'wap',
'mobile',
'ipad',
];
// 从HTTP_USER_AGENT中查找手机浏览器的关键字
if (preg_match('/('.implode('|', $clientkeywords).')/i', strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
}
// 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
if (isset($_SERVER['HTTP_VIA'])) {
// 找不到为flase,否则为true
return (bool) stristr($_SERVER['HTTP_VIA'], 'wap');
}
// 协议法,因为有可能不准确,放到最后判断
if (isset($_SERVER['HTTP_ACCEPT'])) {
// 如果只支持wml并且不支持html那一定是移动设备
// 如果支持wml和html但是wml在html之前则是移动设备
if ((false !== strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml'))
&& (false === strpos($_SERVER['HTTP_ACCEPT'], 'text/html')
|| (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html'))
)) {
return true;
}
}
return false;
}
protected function purifyHtml($html, $trusted = false)
{
$biz = $this->getBiz();
$htmlHelper = $biz['html_helper'];
return $htmlHelper->purify($html, $trusted);
}
protected function trans($id, array $parameters = [], $domain = null, $locale = null)
{
return $this->container->get('translator')->trans($id, $parameters, $domain, $locale);
}
protected function isPluginInstalled($pluginName)
{
return $this->get('kernel')->getPluginConfigurationManager()->isPluginInstalled($pluginName);
}
protected function getTargetPath(Request $request)
{
if ($request->query->get('goto')) {
$targetPath = $request->query->get('goto');
} elseif ($request->getSession()->has('_target_path')) {
$targetPath = $request->getSession()->get('_target_path');
} else {
$targetPath = $request->headers->get('Referer');
}
if (false !== strpos($targetPath, '/register')) {
return $this->generateUrl('homepage');
}
if ($targetPath == $this->generateUrl('login', [], UrlGeneratorInterface::ABSOLUTE_URL)) {
return $this->generateUrl('homepage');
}
$url = explode('?', $targetPath);
if ($url[0] == $this->generateUrl('partner_logout', [], UrlGeneratorInterface::ABSOLUTE_URL)) {
return $this->generateUrl('homepage');
}
if ($url[0] == $this->generateUrl('password_reset_update', [], UrlGeneratorInterface::ABSOLUTE_URL)) {
$targetPath = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
}
if (strpos($url[0], $request->getPathInfo()) > -1) {
$targetPath = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
}
if (false !== strpos($url[0], 'callback')
|| false !== strpos($url[0], '/login/bind')
|| false !== strpos($url[0], 'crontab')
) {
$targetPath = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
}
if (empty($targetPath)) {
$targetPath = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
}
return $this->filterRedirectUrl($targetPath);
}
protected function setFlashMessage($level, $message)
{
$this->get('session')->getFlashBag()->add($level, $message);
}
protected function agentInWhiteList($userAgent)
{
$whiteList = ['iPhone', 'iPad', 'Android', 'HTC'];
return ArrayToolkit::some(
$whiteList,
function ($agent) use ($userAgent) {
return strpos($userAgent, $agent) > -1;
}
);
}
protected function createNamedFormBuilder($name, $data = null, array $options = [])
{
return $this->container->get('form.factory')->createNamedBuilder($name, FormType::class, $data, $options);
}
protected function createJsonResponse($data = null, $status = 200, $headers = [])
{
return new JsonResponse($data, $status, $headers);
}
protected function createJsonpResponse($data = null, $callback = 'callback', $status = 200, $headers = [])
{
$response = $this->createJsonResponse($data, $status, $headers);
return $response->setCallback($callback);
}
// @todo 此方法是为了和旧的调用兼容,考虑清理掉
protected function createErrorResponse($request, $name, $message)
{
$error = ['error' => ['name' => $name, 'message' => $message]];
return new JsonResponse($error, '200');
}
/**
* JSONM
* https://github.com/lifesinger/lifesinger.github.com/issues/118.
*/
protected function createJsonmResponse($data)
{
$response = new JsonResponse($data);
$response->setCallback('define');
return $response;
}
/**
* 创建消息提示响应.
*
* @param string $type 消息类型:info, warning, error
* @param string $message 消息内容
* @param string $title 消息抬头
* @param int $duration 消息显示持续的时间
* @param string $goto 消息跳转的页面
*
* @return Response
*/
protected function createMessageResponse($type, $message, $title = '', $duration = 0, $goto = null)
{
if (!in_array($type, ['info', 'warning', 'error'])) {
throw new \RuntimeException('type error');
}
return $this->render(
'default/message.html.twig',
[
'type' => $type,
'message' => $message,
'title' => $title,
'duration' => $duration,
'goto' => $this->filterRedirectUrl($goto),
]
);
}
protected function createResourceNotFoundException($resourceType, $resourceId, $message = '')
{
return new ResourceNotFoundException($resourceType, $resourceId, $message);
}
protected function createAccessDeniedException(string $message = 'Access Denied.', ?\Throwable $previous = null): AccessDeniedException
{
return new AccessDeniedException($message, $previous);
}
/**
* 安全的重定向.
*
* 如果url不属于非本站域名下的,则重定向到本周首页。
*
* @param $url string 重定向url
* @param $status int 重定向时的HTTP状态码
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function redirectSafely($url, $status = 302)
{
$url = $this->filterRedirectUrl($url);
return $this->redirect($url, $status);
}
/**
* 过滤URL.
*
* 如果url不属于非本站域名下的,则返回本站首页地址。
*
* @param $url string 待过滤的$url
*
* @return string
*/
public function filterRedirectUrl($url)
{
$host = $this->get('request_stack')->getCurrentRequest()->getHost();
$safeHosts = [$host];
$parsedUrl = parse_url($url);
$isUnsafeHost = isset($parsedUrl['host']) && !in_array($parsedUrl['host'], $safeHosts);
if (empty($url) || $isUnsafeHost) {
$url = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
}
return $url;
}
/**
* @param $conditions
*
* @return array
* // 带有仅自己管理 组建查询的orgIds过滤
*/
protected function prepareManageTypeOrgIds($conditions)
{
if (!isset($conditions['orgIds'])) {
$orgIds = $this->getCurrentUser()->getManageOrgIdsRecursively();
} else {
$orgIds = explode(',', $conditions['orgIds']);
}
if (!isset($conditions['orgIds']) || (in_array(0, explode(',', $conditions['orgIds'])) && '' != $conditions['orgIds'])) {
$orgIds = array_merge([0], $orgIds);
}
return $orgIds;
}
/**
* @param $resourceType
* @param $orgIds
*
* @return array
* //带仅定管理员查询组件查询参数构造
*/
protected function prepareManageResourceIds($resourceType, $orgIds): array
{
$userIds = [];
if (in_array(0, $orgIds)) {
if ($this->getUser()->isSuperAdmin()) {
$userIds = $this->getResourceManageClass($resourceType)->searchManageUserIds();
}
$userIds[] = $this->getUser()->getId();
}
$targetList = [
'org' => array_values(array_unique($orgIds)),
'user' => array_values(array_unique($userIds)),
];
if (empty($targetList['org']) && empty($targetList['user'])) {
return [];
}
return $this->getResourceManageClass($resourceType)->searchManageResourceIds($targetList);
}
/**
* @param $fields
*
* @return mixed
* // 处理资源带有指定管理员权限组件的创建数据
*/
protected function processResourceManagePermission($fields)
{
$resourceManage = [
'manageType' => 'user',
'manageTargetIds' => [$this->getCurrentUser()->getId()],
];
if (empty($fields['manageType']) || empty($fields['manageUserIds'])) {
$fields['resourceManage'] = $resourceManage;
return $fields;
}
if ('org' == $fields['manageType']) {
$manageOrg = !empty($fields['orgCode']) ? $this->getOrgService()->getOrgByOrgCode($fields['orgCode']) : ($this->getCurrentUser()->getManageOrgIds() ? ['id' => $this->getCurrentUser()->getManageOrgIds()[0]] : []);
$orgId = empty($manageOrg['id']) ? $this->getCurrentUser()->getCurrentOrgId() : $manageOrg['id'];
$org = $this->getOrgService()->getOrg($orgId);
if ('org' == $fields['manageType'] && !$this->getCurrentUser()->hasManagePermissionWithOrgCode($org['orgCode'])) {
throw $this->createAccessDeniedException($this->trans('所属部门不在你的管理范围内'));
}
$resourceManage['manageType'] = 'org';
$resourceManage['manageTargetIds'] = [$orgId];
} else {
$resourceManage['manageTargetIds'] = explode(',', $fields['manageUserIds']);
}
$fields['resourceManage'] = $resourceManage;
unset($fields['orgId']);
unset($fields['orgCode']);
unset($fields['manageUserIds']);
return $fields;
}
protected function prepareListKeyWordTypeConditions($conditions, $resourceType)
{
if (!empty($conditions['keyword']) && 'nameLike' == $conditions['keywordType']) {
$conditions[$conditions['keywordType']] = $conditions['keyword'];
}
if (!empty($conditions['keyword']) && 'createdUserId' == $conditions['keywordType']) {
$users = $this->getUserService()->searchUsers(['truename' => $conditions['keyword']], [], 0, 2000, ['id']);
$conditions['createdUserIds'] = empty($users) ? [-1] : array_column($users, 'id');
}
if (!empty($conditions['keyword']) && 'manageUser' == $conditions['keywordType']) {
$users = $this->getUserService()->searchUsers(['truename' => $conditions['keyword']], [], 0, 2000, ['id', 'truename']);
$resourceRecords = $this->getResourceManageService()->searchRecords(['manageType' => 'user', 'resourceType' => $resourceType, 'targetIds' => empty($users) ? [-1] : array_column($users, 'id')], [], 0, PHP_INT_MAX, ['resourceId']);
$resourceIds = isset($conditions['ids']) ? array_intersect($conditions['ids'], array_column($resourceRecords, 'resourceId')) : array_column($resourceRecords, 'resourceId');
$conditions['ids'] = empty($resourceIds) ? [-1] : $resourceIds;
}
unset($conditions['keywordType']);
unset($conditions['keyword']);
return $conditions;
}
protected function filterLockedAndDeletedUsers($conditions)
{
$conditions['userIds'] = isset($conditions['userIds']) ? $conditions['userIds'] : [];
$users = $this->getUserService()->findDeletedAndLockedUsers();
$excludeUserIds = ArrayToolkit::column($users, 'id');
if (empty($excludeUserIds)) {
return $conditions;
}
if (!empty($conditions['userIds'])) {
$conditions['userIds'] = array_diff($conditions['userIds'], $excludeUserIds);
}
return $conditions;
}
protected function getResourceManageClass($type): BaseType
{
return $this->getBiz()->offsetGet('resource_manage.'.$type);
}
/**
* @return ResourceManageService
*/
protected function getResourceManageService()
{
return $this->createService('ResourceManage:ResourceManageService');
}
protected function createSuccessJsonResponse($data = [])
{
$data = array_merge(['success' => 1], $data);
return $this->createJsonResponse($data);
}
protected function createFailJsonResponse($data = [])
{
$data = array_merge(['success' => 0], $data);
return $this->createJsonResponse($data);
}
protected function getWebExtension()
{
return $this->get('web.twig.extension');
}
protected function createService($alias)
{
$biz = $this->getBiz();
return $biz->service($alias);
}
protected function setting($name, $default = null)
{
return $this->get('web.twig.extension')->getSetting($name, $default);
}
/**
* @return ManagePermissionOrgService
*/
protected function getManagePermissionService()
{
return $this->getBiz()->service('CorporateTrainingBundle:ManagePermission:ManagePermissionOrgService');
}
/**
* @return \Biz\User\Service\UserService
*/
protected function getUserService()
{
return $this->getBiz()->service('User:UserService');
}
protected function getTokenService()
{
return $this->getBiz()->service('User:TokenService');
}
/**
* @return \Biz\System\Service\LogService
*/
protected function getLogService()
{
return $this->getBiz()->service('System:LogService');
}
/**
* @return \Biz\Org\Service\OrgService
*/
protected function getOrgService()
{
return $this->getBiz()->service('Org:OrgService');
}
/**
* @return ResourceAccessScopeService
*/
protected function getResourceAccessService()
{
return $this->createService('CorporateTrainingBundle:ResourceScope:ResourceAccessScopeService');
}
/**
* @return BodoudouApi
*/
protected function getBodoudouApiService()
{
return $this->getBiz()['bodoudou.api'];
}
/**
* @return Validator
*/
protected function getCommonValidator()
{
return $this->getBiz()['common.validator'];
}
}