1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-07-23 00:16:39 +08:00

1.优化ShareUrl

2.第三方登录增加账号可用性判断
3.优化公众号关注相关
This commit is contained in:
xiaochong0302 2024-05-12 19:02:07 +08:00
parent 0c30cda0c3
commit a31c991b1c
30 changed files with 598 additions and 615 deletions

View File

@ -1,3 +1,5 @@
### [v1.7.1](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.1)(2024-06-15)
### [v1.7.0](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.0)(2024-05-15)
- 升级layui-2.9.8

View File

@ -29,7 +29,7 @@ class ConnectController extends Controller
$service->setWechatRedirectCache($redirect);
}
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_WECHAT);
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_WECHAT_OA);
return $this->response->redirect($url, true);
}
@ -41,7 +41,7 @@ class ConnectController extends Controller
{
$service = new ConnectService();
$data = $service->handleCallback(ConnectModel::PROVIDER_WECHAT);
$data = $service->handleCallback(ConnectModel::PROVIDER_WECHAT_OA);
$redirect = $service->getWechatRedirectCache();

View File

@ -8,12 +8,12 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Account as AccountService;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Services\Logic\Account\EmailUpdate as EmailUpdateService;
use App\Services\Logic\Account\OAuthProvider as OAuthProviderService;
use App\Services\Logic\Account\PasswordReset as PasswordResetService;
use App\Services\Logic\Account\PasswordUpdate as PasswordUpdateService;
use App\Services\Logic\Account\PhoneUpdate as PhoneUpdateService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
/**
* @RoutePrefix("/account")

View File

@ -8,7 +8,6 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Answer as AnswerService;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Http\Home\Services\Question as QuestionService;
use App\Models\Answer as AnswerModel;
use App\Services\Logic\Answer\AnswerAccept as AnswerAcceptService;
@ -17,6 +16,7 @@ use App\Services\Logic\Answer\AnswerDelete as AnswerDeleteService;
use App\Services\Logic\Answer\AnswerInfo as AnswerInfoService;
use App\Services\Logic\Answer\AnswerLike as AnswerLikeService;
use App\Services\Logic\Answer\AnswerUpdate as AnswerUpdateService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use Phalcon\Mvc\View;
/**

View File

@ -9,7 +9,6 @@ namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Article as ArticleService;
use App\Http\Home\Services\ArticleQuery as ArticleQueryService;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Models\Article as ArticleModel;
use App\Services\Logic\Article\ArticleClose as ArticleCloseService;
use App\Services\Logic\Article\ArticleCreate as ArticleCreateService;
@ -20,6 +19,7 @@ use App\Services\Logic\Article\ArticleLike as ArticleLikeService;
use App\Services\Logic\Article\ArticleList as ArticleListService;
use App\Services\Logic\Article\ArticleUpdate as ArticleUpdateService;
use App\Services\Logic\Article\RelatedArticleList as RelatedArticleListService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use Phalcon\Mvc\View;
/**

View File

@ -7,7 +7,6 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Models\ChapterLive as LiveModel;
use App\Models\Course as CourseModel;
use App\Services\Logic\Chapter\ChapterInfo as ChapterInfoService;
@ -15,6 +14,7 @@ use App\Services\Logic\Chapter\ChapterLike as ChapterLikeService;
use App\Services\Logic\Chapter\Learning as ChapterLearningService;
use App\Services\Logic\Course\BasicInfo as CourseInfoService;
use App\Services\Logic\Course\ChapterList as CourseChapterListService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
/**
* @RoutePrefix("/chapter")

View File

@ -8,7 +8,6 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\CourseQuery as CourseQueryService;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Services\Logic\Course\ChapterList as CourseChapterListService;
use App\Services\Logic\Course\ConsultList as CourseConsultListService;
use App\Services\Logic\Course\CourseFavorite as CourseFavoriteService;
@ -20,6 +19,7 @@ use App\Services\Logic\Course\ResourceList as CourseResourceListService;
use App\Services\Logic\Course\ReviewList as CourseReviewListService;
use App\Services\Logic\Course\TopicList as CourseTopicListService;
use App\Services\Logic\Reward\OptionList as RewardOptionList;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use Phalcon\Mvc\View;
/**

View File

@ -7,9 +7,9 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Services\Logic\Help\HelpInfo as HelpInfoService;
use App\Services\Logic\Help\HelpList as HelpListService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
/**
* @RoutePrefix("/help")

View File

@ -7,8 +7,8 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Http\Home\Services\Index as IndexService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
class IndexController extends Controller
{

View File

@ -7,9 +7,9 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Http\Home\Services\Index as IndexService;
use App\Services\Logic\Page\PageInfo as PageInfoService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
/**
* @RoutePrefix("/page")

View File

@ -11,6 +11,7 @@ use App\Services\Logic\Point\GiftInfo as GiftInfoService;
use App\Services\Logic\Point\GiftList as GiftListService;
use App\Services\Logic\Point\GiftRedeem as GiftRedeemService;
use App\Services\Logic\Point\HotGiftList as HotGiftListService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use App\Services\Logic\User\Console\BalanceInfo as BalanceInfoService;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\View;
@ -38,6 +39,13 @@ class PointGiftController extends Controller
*/
public function listAction()
{
$service = new FullH5UrlService();
if ($service->isMobileBrowser() && $service->h5Enabled()) {
$location = $service->getPointGiftListUrl();
return $this->response->redirect($location);
}
$this->seo->prependTitle('积分商城');
$this->view->pick('point/gift/list');

View File

@ -7,10 +7,11 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\ShareUrl as ShareUrlService;
use App\Library\CsrfToken as CsrfTokenService;
use App\Repos\Upload as UploadRepo;
use App\Services\LiveNotify as LiveNotifyService;
use App\Services\Logic\Url\ShareUrl as ShareUrlService;
use App\Services\Logic\WeChat\OfficialAccount as WeChatOAService;
use App\Services\Pay\Alipay as AlipayService;
use App\Services\Pay\Wxpay as WxpayService;
use App\Services\Storage as StorageService;
@ -150,6 +151,42 @@ class PublicController extends \Phalcon\Mvc\Controller
exit;
}
/**
* @Get("/wechat/oa/notify", name="home.wechat_oa.verify")
*/
public function wechatOaVerifyAction()
{
$service = new WeChatOAService();
$app = $service->getOfficialAccount();
$response = $app->server->serve();
$response->send();
exit;
}
/**
* @Post("/wechat/oa/notify", name="home.wechat_oa.notify")
*/
public function wechatOaNotifyAction()
{
$service = new WeChatOAService();
$app = $service->getOfficialAccount();
$app->server->push(function ($message) use ($service) {
return $service->handleNotify($message);
});
$response = $app->server->serve();
$response->send();
exit;
}
/**
* @Post("/live/notify", name="home.live_notify")
*/

View File

@ -7,7 +7,6 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Http\Home\Services\Question as QuestionService;
use App\Http\Home\Services\QuestionQuery as QuestionQueryService;
use App\Models\Question as QuestionModel;
@ -20,6 +19,7 @@ use App\Services\Logic\Question\QuestionLike as QuestionLikeService;
use App\Services\Logic\Question\QuestionList as QuestionListService;
use App\Services\Logic\Question\QuestionUpdate as QuestionUpdateService;
use App\Services\Logic\Question\RelatedQuestionList as RelatedQuestionListService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use Phalcon\Mvc\View;
/**

View File

@ -7,9 +7,9 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Services\Logic\Teacher\CourseList as TeacherCourseListService;
use App\Services\Logic\Teacher\TeacherList as TeacherListService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use App\Services\Logic\User\UserInfo as UserInfoService;
use Phalcon\Mvc\View;

View File

@ -7,7 +7,7 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use App\Services\Logic\User\AnswerList as UserAnswerListService;
use App\Services\Logic\User\ArticleList as UserArticleListService;
use App\Services\Logic\User\CourseList as UserCourseListService;

View File

@ -7,7 +7,7 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\FullH5Url as FullH5UrlService;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use App\Services\Logic\Vip\CourseList as VipCourseListService;
use App\Services\Logic\Vip\OptionList as VipOptionListService;
use App\Services\Logic\Vip\UserList as VipUserListService;

View File

@ -7,31 +7,59 @@
namespace App\Http\Home\Controllers;
use App\Http\Home\Services\WeChatOfficialAccount as WeChatOAService;
use App\Http\Home\Services\WeChatOfficialAccount as HomeWeChatOAService;
use App\Services\Logic\WeChat\OfficialAccount as WeChatOAService;
use App\Traits\Response as ResponseTrait;
/**
* @RoutePrefix("/wechat/oa")
*/
class WeChatOfficialAccountController extends \Phalcon\Mvc\Controller
class WeChatOfficialAccountController extends Controller
{
use ResponseTrait;
/**
* @Get("/subscribe/status", name="home.wechat_oa.sub_status")
* @Get("/bind", name="home.wechat_oa.bind")
*/
public function subscribeStatusAction()
public function bindAction()
{
$service = new WeChatOAService();
$captcha = $this->getSettings('captcha');
$status = $service->getSubscribeStatus();
$this->seo->prependTitle('绑定帐号');
return $this->jsonSuccess(['status' => $status]);
$this->view->pick('wechat/oa/bind');
$this->view->setVar('captcha', $captcha);
}
/**
* @Get("/subscribe/qrcode", name="home.wechat_oa.sub_qrcode")
* @Get("/login/qrcode", name="home.wechat_oa.login_qrcode")
*/
public function loginQrCodeAction()
{
$service = new WeChatOAService();
$qrcode = $service->createLoginQrCode();
return $this->jsonSuccess(['qrcode' => $qrcode]);
}
/**
* @Get("/login/status", name="home.wechat_oa.lgoin_status")
*/
public function loginStatusAction()
{
$ticket = $this->request->getQuery('ticket');
$service = new WeChatOAService();
$data = $service->getLoginStatus($ticket);
return $this->jsonSuccess(['data' => $data]);
}
/**
* @Get("/subscribe/qrcode", name="home.wechat_oa.subscribe_qrcode")
*/
public function subscribeQrCodeAction()
{
@ -43,39 +71,63 @@ class WeChatOfficialAccountController extends \Phalcon\Mvc\Controller
}
/**
* @Get("/notify", name="home.wechat_oa.verify")
* @Get("/subscribe/status", name="home.wechat_oa.subscribe_status")
*/
public function verifyAction()
public function subscribeStatusAction()
{
$service = new WeChatOAService();
$app = $service->getOfficialAccount();
$status = $service->getSubscribeStatus();
$response = $app->server->serve();
$response->send();
exit;
return $this->jsonSuccess(['status' => $status]);
}
/**
* @Post("/notify", name="home.wechat_oa.notify")
* @Post("/auth/login", name="home.wechat_oa.auth_login")
*/
public function notifyAction()
public function authLoginAction()
{
$service = new WeChatOAService();
$service = new HomeWeChatOAService();
$app = $service->getOfficialAccount();
$service->authLogin();
$app->server->push(function ($message) use ($service) {
return $service->handleNotify($message);
});
$returnUrl = $this->request->getPost('return_url', 'string');
$response = $app->server->serve();
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
$response->send();
return $this->jsonSuccess(['location' => $location]);
}
exit;
/**
* @Post("/bind/login", name="home.wechat_oa.bind_login")
*/
public function bindLoginAction()
{
$service = new HomeWeChatOAService();
$service->bindLogin();
$returnUrl = $this->request->getPost('return_url', 'string');
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
return $this->jsonSuccess(['location' => $location]);
}
/**
* @Post("/bind/register", name="home.wechat_oa.bind_register")
*/
public function bindRegisterAction()
{
$service = new HomeWeChatOAService();
$service->bindRegister();
$returnUrl = $this->request->getPost('return_url', 'string');
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
return $this->jsonSuccess(['location' => $location]);
}
}

View File

@ -101,6 +101,10 @@ class Connect extends Service
$user = $userRepo->findById($connect->user_id);
$validator = new AccountValidator();
$validator->checkIfAllowLogin($user);
$this->handleLoginNotice($user);
$auth = $this->getAppAuth();

View File

@ -1,153 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Home\Services;
use App\Models\Course as CourseModel;
use App\Repos\Chapter as ChapterRepo;
use App\Traits\Client as ClientTrait;
class FullH5Url extends Service
{
protected $baseUrl;
use ClientTrait;
public function __construct()
{
$this->baseUrl = $this->getBaseUrl();
}
public function getHomeUrl()
{
return sprintf('%s/index/index', $this->baseUrl);
}
public function getAccountRegisterUrl()
{
return sprintf('%s/account/register', $this->baseUrl);
}
public function getAccountLoginUrl()
{
return sprintf('%s/account/login', $this->baseUrl);
}
public function getAccountForgetUrl()
{
return sprintf('%s/account/forget', $this->baseUrl);
}
public function getVipIndexUrl()
{
return sprintf('%s/vip/index', $this->baseUrl);
}
public function getHelpIndexUrl()
{
return sprintf('%s/help/index', $this->baseUrl);
}
public function getCourseListUrl()
{
return sprintf('%s/course/list', $this->baseUrl);
}
public function getArticleListUrl()
{
return sprintf('%s/article/list', $this->baseUrl);
}
public function getQuestionListUrl()
{
return sprintf('%s/question/list', $this->baseUrl);
}
public function getLiveListUrl()
{
return sprintf('%s/discovery/index', $this->baseUrl);
}
public function getTeacherListUrl()
{
return sprintf('%s/discovery/index', $this->baseUrl);
}
public function getPointGiftListUrl()
{
return sprintf('%s/point/gift/list', $this->baseUrl);
}
public function getPageInfoUrl($id)
{
return sprintf('%s/page/info?id=%s', $this->baseUrl, $id);
}
public function getHelpInfoUrl($id)
{
return sprintf('%s/help/info?id=%s', $this->baseUrl, $id);
}
public function getArticleInfoUrl($id)
{
return sprintf('%s/article/info?id=%s', $this->baseUrl, $id);
}
public function getQuestionInfoUrl($id)
{
return sprintf('%s/question/info?id=%s', $this->baseUrl, $id);
}
public function getAnswerInfoUrl($id)
{
return sprintf('%s/answer/info?id=%s', $this->baseUrl, $id);
}
public function getCourseInfoUrl($id)
{
return sprintf('%s/course/info?id=%s', $this->baseUrl, $id);
}
public function getChapterInfoUrl($id)
{
$chapterRepo = new ChapterRepo();
$chapter = $chapterRepo->findById($id);
if ($chapter->model == CourseModel::MODEL_VOD) {
return sprintf('%s/chapter/vod?id=%s', $this->baseUrl, $id);
} elseif ($chapter->model == CourseModel::MODEL_LIVE) {
return sprintf('%s/chapter/live?id=%s', $this->baseUrl, $id);
} elseif ($chapter->model == CourseModel::MODEL_READ) {
return sprintf('%s/chapter/read?id=%s', $this->baseUrl, $id);
} else {
return $this->getHomeUrl();
}
}
public function getUserIndexUrl($id)
{
return sprintf('%s/user/index?id=%s', $this->baseUrl, $id);
}
public function getTeacherIndexUrl($id)
{
return sprintf('%s/teacher/index?id=%s', $this->baseUrl, $id);
}
public function getPointGiftInfoUrl($id)
{
return sprintf('%s/point/gift/info?id=%s', $this->baseUrl, $id);
}
protected function getBaseUrl()
{
return sprintf('%s/h5/#/pages', kg_site_url());
}
}

View File

@ -1,79 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Home\Services;
class FullWebUrl extends Service
{
protected $baseUrl;
public function __construct()
{
$this->baseUrl = $this->getBaseUrl();
}
public function getHomeUrl()
{
return $this->baseUrl;
}
public function getArticleShowUrl($id)
{
$route = $this->url->get(['for' => 'home.article.show', 'id' => $id]);
return $this->baseUrl . $route;
}
public function getQuestionShowUrl($id)
{
$route = $this->url->get(['for' => 'home.question.show', 'id' => $id]);
return $this->baseUrl . $route;
}
public function getCourseShowUrl($id)
{
$route = $this->url->get(['for' => 'home.course.show', 'id' => $id]);
return $this->baseUrl . $route;
}
public function getChapterShowUrl($id)
{
$route = $this->url->get(['for' => 'home.chapter.show', 'id' => $id]);
return $this->baseUrl . $route;
}
public function getUserShowUrl($id)
{
$route = $this->url->get(['for' => 'home.user.show', 'id' => $id]);
return $this->baseUrl . $route;
}
public function getTeacherShowUrl($id)
{
$route = $this->url->get(['for' => 'home.teacher.show', 'id' => $id]);
return $this->baseUrl . $route;
}
public function getPointGiftShowUrl($id)
{
$route = $this->url->get(['for' => 'home.point_gift.show', 'id' => $id]);
return $this->baseUrl . $route;
}
protected function getBaseUrl()
{
return kg_site_url();
}
}

View File

@ -1,123 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Home\Services;
use App\Traits\Client as ClientTrait;
class ShareUrl extends Service
{
/**
* WEB站点URL
*
* @var string
*/
protected $fullWebUrl;
/**
* H5站点URL
*
* @var string
*/
protected $fullH5Url;
use ClientTrait;
public function __construct()
{
$this->fullWebUrl = new FullWebUrl();
$this->fullH5Url = new FullH5Url();
}
public function handle($id, $type)
{
if ($type == 'article') {
$result = $this->getArticleUrl($id);
} elseif ($type == 'question') {
$result = $this->getQuestionUrl($id);
} elseif ($type == 'course') {
$result = $this->getCourseUrl($id);
} elseif ($type == 'chapter') {
$result = $this->getChapterUrl($id);
} elseif ($type == 'user') {
$result = $this->getUserUrl($id);
} elseif ($type == 'teacher') {
$result = $this->getTeacherUrl($id);
} else {
$result = $this->getHomeUrl();
}
$gotoH5 = $this->h5Enabled() && $this->isMobileBrowser();
return $gotoH5 ? $result['h5'] : $result['web'];
}
public function getHomeUrl()
{
$webUrl = $this->fullWebUrl->getHomeUrl();
$h5Url = $this->fullH5Url->getHomeUrl();
return ['web' => $webUrl, 'h5' => $h5Url];
}
public function getArticleUrl($id = 0)
{
$webUrl = $this->fullWebUrl->getArticleShowUrl($id);
$h5Url = $this->fullH5Url->getArticleInfoUrl($id);
return ['web' => $webUrl, 'h5' => $h5Url];
}
public function getQuestionUrl($id = 0)
{
$webUrl = $this->fullWebUrl->getQuestionShowUrl($id);
$h5Url = $this->fullH5Url->getQuestionInfoUrl($id);
return ['web' => $webUrl, 'h5' => $h5Url];
}
public function getCourseUrl($id = 0)
{
$webUrl = $this->fullWebUrl->getCourseShowUrl($id);
$h5Url = $this->fullH5Url->getCourseInfoUrl($id);
return ['web' => $webUrl, 'h5' => $h5Url];
}
public function getChapterUrl($id = 0)
{
$webUrl = $this->fullWebUrl->getChapterShowUrl($id);
$h5Url = $this->fullH5Url->getChapterInfoUrl($id);
return ['web' => $webUrl, 'h5' => $h5Url];
}
public function getUserUrl($id = 0)
{
$webUrl = $this->fullWebUrl->getUserShowUrl($id);
$h5Url = $this->fullH5Url->getUserIndexUrl($id);
return ['web' => $webUrl, 'h5' => $h5Url];
}
public function getTeacherUrl($id = 0)
{
$webUrl = $this->fullWebUrl->getTeacherShowUrl($id);
$h5Url = $this->fullH5Url->getTeacherIndexUrl($id);
return ['web' => $webUrl, 'h5' => $h5Url];
}
}

View File

@ -7,242 +7,119 @@
namespace App\Http\Home\Services;
use App\Models\WeChatSubscribe as WeChatSubscribeModel;
use App\Models\Connect as ConnectModel;
use App\Models\User as UserModel;
use App\Repos\Connect as ConnectRepo;
use App\Repos\User as UserRepo;
use App\Repos\WeChatSubscribe as WeChatSubscribeRepo;
use App\Services\WeChat as WeChatService;
use EasyWeChat\Kernel\Messages\Text as TextMessage;
use App\Services\Auth\Home as AuthService;
use App\Services\Logic\Account\Register as RegisterService;
use App\Services\Logic\Notice\External\AccountLogin as AccountLoginNotice;
use App\Validators\Account as AccountValidator;
use App\Validators\WeChatOfficialAccount as WeChatOAValidator;
class WeChatOfficialAccount extends Service
{
public function getOfficialAccount()
public function authLogin()
{
$service = new WeChatService();
$ticket = $this->request->getPost('ticket');
return $service->getOfficialAccount();
}
$validator = new WeChatOAValidator();
public function createSubscribeQrCode()
{
$user = $this->getLoginUser();
$openId = $validator->checkLoginOpenId($ticket);
$app = $this->getOfficialAccount();
$connectRepo = new ConnectRepo();
$result = $app->qrcode->temporary($user->id);
return $app->qrcode->url($result['ticket']);
}
public function getSubscribeStatus()
{
$user = $this->getLoginUser();
$subscribeRepo = new WeChatSubscribeRepo();
$subscribe = $subscribeRepo->findByUserId($user->id);
return $subscribe ? 1 : 0;
}
public function handleNotify($message)
{
$service = new WeChatService();
$service->logger->debug('Received Message ' . json_encode($message));
switch ($message['MsgType']) {
case 'event':
switch ($message['Event']) {
case 'subscribe':
return $this->handleSubscribeEvent($message);
case 'unsubscribe':
return $this->handleUnsubscribeEvent($message);
case 'SCAN':
return $this->handleScanEvent($message);
case 'CLICK':
return $this->handleClickEvent($message);
case 'VIEW':
return $this->handleViewEvent($message);
case 'LOCATION':
return $this->handleLocationEvent($message);
default:
return $this->noMatchReply();
}
case 'text':
return $this->handleTextReply($message);
case 'image':
return $this->handleImageReply($message);
case 'voice':
return $this->handleVoiceReply($message);
case 'video':
return $this->handleVideoReply($message);
case 'shortvideo':
return $this->handleShortVideoReply($message);
case 'location':
return $this->handleLocationReply($message);
case 'link':
return $this->handleLinkReply($message);
default:
return $this->noMatchReply();
}
}
protected function handleSubscribeEvent($message)
{
$openId = $message['FromUserName'] ?? '';
$eventKey = $message['EventKey'] ?? '';
/**
* 带场景值的关注事件
*/
$userId = str_replace('qrscene_', '', $eventKey);
if ($userId && $openId) {
$this->saveWechatSubscribe($userId, $openId);
}
return new TextMessage('开心呀,我们又多了一个小伙伴!');
}
protected function handleUnsubscribeEvent($message)
{
$openId = $message['FromUserName'] ?? '';
$subscribeRepo = new WeChatSubscribeRepo();
$subscribe = $subscribeRepo->findByOpenId($openId);
if ($subscribe) {
$subscribe->deleted = 1;
$subscribe->update();
}
return new TextMessage('伤心呀,我们又少了一个小伙伴!');
}
protected function handleScanEvent($message)
{
$openId = $message['FromUserName'] ?? '';
$eventKey = $message['EventKey'] ?? '';
$userId = str_replace('qrscene_', '', $eventKey);
if ($userId && $openId) {
$userInfo = $this->getUserInfo($openId);
$unionId = $userInfo['unionid'] ?: '';
$this->saveWechatSubscribe($userId, $openId, $unionId);
}
return $this->emptyReply();
}
protected function handleClickEvent($message)
{
return $this->emptyReply();
}
protected function handleViewEvent($message)
{
return $this->emptyReply();
}
protected function handleLocationEvent($message)
{
return $this->emptyReply();
}
protected function handleTextReply($message)
{
return $this->emptyReply();
}
protected function handleImageReply($message)
{
return $this->emptyReply();
}
protected function handleVoiceReply($message)
{
return $this->emptyReply();
}
protected function handleVideoReply($message)
{
return $this->emptyReply();
}
protected function handleShortVideoReply($message)
{
return $this->emptyReply();
}
protected function handleLocationReply($message)
{
return $this->emptyReply();
}
protected function handleLinkReply($message)
{
return $this->emptyReply();
}
protected function emptyReply()
{
return null;
}
protected function noMatchReply()
{
return new TextMessage('没有匹配的服务哦!');
}
protected function saveWechatSubscribe($userId, $openId, $unionId = '')
{
if (!$userId || !$openId) return;
$connect = $connectRepo->findByOpenId($openId, ConnectModel::PROVIDER_WECHAT_OA);
$userRepo = new UserRepo();
$user = $userRepo->findById($userId);
$user = $userRepo->findById($connect->user_id);
if (!$user) return;
$validator = new AccountValidator();
$subscribeRepo = new WeChatSubscribeRepo();
$validator->checkIfAllowLogin($user);
$subscribe = $subscribeRepo->findByOpenId($openId);
$this->handleLoginNotice($user);
if ($subscribe) {
if ($subscribe->user_id != $userId) {
$subscribe->user_id = $userId;
}
if (empty($subscribe->union_id) && !empty($unionId)) {
$subscribe->union_id = $unionId;
}
if ($subscribe->deleted == 1) {
$subscribe->deleted = 0;
}
$subscribe->update();
} else {
$subscribe = new WeChatSubscribeModel();
$subscribe->user_id = $userId;
$subscribe->open_id = $openId;
$subscribe->union_id = $unionId;
$subscribe->create();
}
$auth = $this->getAppAuth();
$auth->saveAuthInfo($user);
}
protected function getUserInfo($openId)
public function bindLogin()
{
$app = $this->getOfficialAccount();
$post = $this->request->getPost();
return $app->user->get($openId);
$validator = new AccountValidator();
$user = $validator->checkUserLogin($post['account'], $post['password']);
$validator = new WeChatOAValidator();
$openId = $validator->checkLoginOpenId($post['ticket']);
$connect = new ConnectModel();
$connect->user_id = $user->id;
$connect->open_id = $openId;
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
$connect->create();
$this->handleLoginNotice($user);
$auth = $this->getAppAuth();
$auth->saveAuthInfo($user);
}
protected function getWechatLogger()
public function bindRegister()
{
$service = new WeChatService();
$post = $this->request->getPost();
return $service->logger;
$validator = new WeChatOAValidator();
$openId = $validator->checkLoginOpenId($post['ticket']);
$registerService = new RegisterService();
$account = $registerService->handle();
$userRepo = new UserRepo();
$user = $userRepo->findById($account->id);
$connect = new ConnectModel();
$connect->user_id = $user->id;
$connect->open_id = $openId;
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
$connect->create();
$this->handleLoginNotice($user);
$auth = $this->getAppAuth();
$auth->saveAuthInfo($user);
}
protected function getAppAuth()
{
/**
* @var $auth AuthService
*/
$auth = $this->getDI()->get('auth');
return $auth;
}
protected function handleLoginNotice(UserModel $user)
{
$notice = new AccountLoginNotice();
$notice->createTask($user);
}
}

View File

@ -16,7 +16,7 @@ class AppInfo
protected $link = 'https://www.koogua.com';
protected $version = '1.7.0';
protected $version = '1.7.1';
public function __get($name)
{

View File

@ -15,7 +15,9 @@ class Connect extends Model
const PROVIDER_QQ = 1; // QQ
const PROVIDER_WEIXIN = 2; // 微信扫码
const PROVIDER_WEIBO = 3; // 新浪微博
const PROVIDER_WECHAT = 4; // 公众号网页
const PROVIDER_WECHAT_OA = 4; // 微信公众号
const PROVIDER_WECHAT_MINI = 5; // 微信小程序
/**
* 主键编号

View File

@ -67,4 +67,17 @@ class Connect extends Repository
]);
}
/**
* @param int $userId
* @param int $provider
* @return ConnectModel|Model|bool
*/
public function findByUserId($userId, $provider)
{
return ConnectModel::findFirst([
'conditions' => 'user_id = ?1 AND provider = ?2 AND deleted = 0',
'bind' => [1 => $userId, 2 => $provider],
]);
}
}

View File

@ -116,11 +116,6 @@ class FullH5Url extends AppService
return $this->getFullUrl('/question/info', ['id' => $id]);
}
public function getAnswerInfoUrl($id)
{
return $this->getFullUrl('/answer/info', ['id' => $id]);
}
public function getTopicInfoUrl($id)
{
return $this->getFullUrl('/topic/info', ['id' => $id]);

View File

@ -48,6 +48,8 @@ class ShareUrl extends AppService
$result = $this->getArticleUrl($id);
} elseif ($type == 'page') {
$result = $this->getPageUrl($id);
} elseif ($type == 'help') {
$result = $this->getHelpUrl($id);
} elseif ($type == 'question') {
$result = $this->getQuestionUrl($id);
} elseif ($type == 'course') {

View File

@ -0,0 +1,317 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Logic\WeChat;
use App\Models\Connect as ConnectModel;
use App\Repos\Connect as ConnectRepo;
use App\Services\Service as AppService;
use App\Services\WeChat as WeChatService;
use EasyWeChat\Kernel\Messages\Text as TextMessage;
use Phalcon\Text;
class OfficialAccount extends AppService
{
/**
* 二维码场景类型
*/
const QR_SCENE_LOGIN = 'login';
const QR_SCENE_SUBSCRIBE = 'subscribe';
public function getOfficialAccount()
{
$service = new WeChatService();
return $service->getOfficialAccount();
}
public function createSubscribeQrCode()
{
$user = $this->getLoginUser();
$app = $this->getOfficialAccount();
$sceneValue = sprintf('%s%s', self::QR_SCENE_SUBSCRIBE, $user->id);
$result = $app->qrcode->temporary($sceneValue);
$url = $app->qrcode->url($result['ticket']);
return ['url' => $url];
}
public function createLoginQrCode()
{
$app = $this->getOfficialAccount();
$ticket = Text::random(0, 16);
$sceneValue = sprintf('%s%s', self::QR_SCENE_LOGIN, $ticket);
$result = $app->qrcode->temporary($sceneValue);
$keyName = $this->getLoginCacheKey($ticket);
$content = [
'action' => '',
'open_id' => '',
];
$this->getCache()->save($keyName, $content, 30 * 60);
$url = $app->qrcode->url($result['ticket']);
return [
'ticket' => $ticket,
'url' => $url,
];
}
public function getLoginStatus($ticket)
{
$keyName = $this->getLoginCacheKey($ticket);
return $this->getCache()->get($keyName);
}
public function getSubscribeStatus()
{
$user = $this->getLoginUser();
$connectRepo = new ConnectRepo();
$connect = $connectRepo->findByUserId($user->id, ConnectModel::PROVIDER_WECHAT_OA);
return $connect ? 1 : 0;
}
public function getLoginOpenId($ticket)
{
$keyName = $this->getLoginCacheKey($ticket);
$content = $this->getCache()->get($keyName);
return $content['open_id'] ?? null;
}
public function getLoginCacheKey($key)
{
return "wechat_oa_login:{$key}";
}
public function handleNotify($message)
{
$logger = $this->getWeChatLogger();
$logger->debug('Received Message: ' . json_encode($message));
switch ($message['MsgType']) {
case 'event':
switch ($message['Event']) {
case 'subscribe':
return $this->handleSubscribeEvent($message);
case 'unsubscribe':
return $this->handleUnsubscribeEvent($message);
case 'SCAN':
return $this->handleScanEvent($message);
case 'CLICK':
return $this->handleClickEvent($message);
case 'VIEW':
return $this->handleViewEvent($message);
case 'LOCATION':
return $this->handleLocationEvent($message);
default:
return $this->noMatchReply();
}
case 'text':
return $this->handleTextReply($message);
case 'image':
return $this->handleImageReply($message);
case 'voice':
return $this->handleVoiceReply($message);
case 'video':
return $this->handleVideoReply($message);
case 'shortvideo':
return $this->handleShortVideoReply($message);
case 'location':
return $this->handleLocationReply($message);
case 'link':
return $this->handleLinkReply($message);
default:
return $this->noMatchReply();
}
}
protected function handleSubscribeEvent($message)
{
$openId = $message['FromUserName'] ?? '';
if (empty($openId)) return null;
return new TextMessage('开心呀,我们又多了一个小伙伴!');
}
protected function handleUnsubscribeEvent($message)
{
$openId = $message['FromUserName'] ?? '';
if (empty($openId)) return null;
$connectRepo = new ConnectRepo();
$connect = $connectRepo->findByOpenId($openId, ConnectModel::PROVIDER_WECHAT_OA);
if ($connect) {
$connect->deleted = 1;
$connect->update();
}
return new TextMessage('伤心呀,我们又少了一个小伙伴!');
}
protected function handleScanEvent($message)
{
$openId = $message['FromUserName'] ?? '';
$eventKey = $message['EventKey'] ?? '';
if (Text::startsWith($eventKey, self::QR_SCENE_LOGIN)) {
return $this->handleLoginScanEvent($eventKey, $openId);
} elseif (Text::startsWith($eventKey, self::QR_SCENE_SUBSCRIBE)) {
return $this->handleSubscribeScanEvent($eventKey, $openId);
}
return $this->emptyReply();
}
protected function handleLoginScanEvent($eventKey, $openId)
{
$ticket = str_replace(self::QR_SCENE_LOGIN, '', $eventKey);
if (empty($ticket) || empty($openId)) return null;
$connectRepo = new ConnectRepo();
$connect = $connectRepo->findByOpenId($openId, ConnectModel::PROVIDER_WECHAT_OA);
$keyName = $this->getLoginCacheKey($ticket);
$cache = $this->getCache();
$content = [
'action' => $connect ? 'login' : 'bind',
'open_id' => $openId,
];
$cache->save($keyName, $content, 30 * 60);
return $this->emptyReply();
}
protected function handleSubscribeScanEvent($eventKey, $openId)
{
$userId = str_replace(self::QR_SCENE_SUBSCRIBE, '', $eventKey);
if (empty($userId) || empty($openId)) return null;
$userInfo = $this->getUserInfo($openId);
$unionId = $userInfo['unionid'] ?: '';
$connectRepo = new ConnectRepo();
$connect = $connectRepo->findByOpenId($openId, ConnectModel::PROVIDER_WECHAT_OA);
if ($connect) return null;
$connect = new ConnectModel();
$connect->user_id = $userId;
$connect->open_id = $openId;
$connect->union_id = $unionId;
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
$connect->create();
return $this->emptyReply();
}
protected function handleClickEvent($message)
{
return $this->emptyReply();
}
protected function handleViewEvent($message)
{
return $this->emptyReply();
}
protected function handleLocationEvent($message)
{
return $this->emptyReply();
}
protected function handleTextReply($message)
{
return $this->emptyReply();
}
protected function handleImageReply($message)
{
return $this->emptyReply();
}
protected function handleVoiceReply($message)
{
return $this->emptyReply();
}
protected function handleVideoReply($message)
{
return $this->emptyReply();
}
protected function handleShortVideoReply($message)
{
return $this->emptyReply();
}
protected function handleLocationReply($message)
{
return $this->emptyReply();
}
protected function handleLinkReply($message)
{
return $this->emptyReply();
}
protected function emptyReply()
{
return null;
}
protected function noMatchReply()
{
return new TextMessage('没有匹配的服务哦!');
}
protected function getUserInfo($openId)
{
$app = $this->getOfficialAccount();
return $app->user->get($openId);
}
protected function getWeChatLogger()
{
$service = new WeChatService();
return $service->logger;
}
}

View File

@ -91,7 +91,7 @@ class WeChat extends OAuth
$userInfo['name'] = $data['nickname'];
$userInfo['avatar'] = $data['headimgurl'];
$userInfo['unionid'] = $data['unionid'] ?? '';
$userInfo['provider'] = ConnectModel::PROVIDER_WECHAT;
$userInfo['provider'] = ConnectModel::PROVIDER_WECHAT_OA;
return $userInfo;
}

View File

@ -0,0 +1,29 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Validators;
use App\Exceptions\BadRequest as BadRequestException;
use App\Services\Logic\WeChat\OfficialAccount as WeChatOfficeAccount;
class WeChatOfficialAccount extends Validator
{
public function checkLoginOpenId($ticket)
{
$service = new WeChatOfficeAccount();
$openId = $service->getLoginOpenId($ticket);
if (!$openId) {
throw new BadRequestException('wechat_oa.invalid_login_ticket');
}
return $openId;
}
}