1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-26 20:52:44 +08:00

Merge branch 'koogua/v1.4.5' into demo

This commit is contained in:
koogua 2021-09-20 17:51:25 +08:00
commit 7b6edab272
14 changed files with 523 additions and 7 deletions

View File

@ -0,0 +1,52 @@
<?php
namespace App\Http\Api\Controllers;
use App\Http\Api\Services\Connect as ConnectService;
use App\Models\Connect as ConnectModel;
/**
* @RoutePrefix("/api/oauth")
*/
class ConnectController extends Controller
{
/**
* @Get("/wechat", name="api.oauth.wechat")
*/
public function wechatAction()
{
$service = new ConnectService();
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_WECHAT);
return $this->response->redirect($url, true);
}
/**
* @Get("/wechat/callback", name="api.oauth.wechat_callback")
*/
public function wechatCallbackAction()
{
$service = new ConnectService();
$data = $service->handleCallback(ConnectModel::PROVIDER_WECHAT);
$location = kg_h5_index_url() . '?' . http_build_query($data);
return $this->response->redirect($location, true);
}
/**
* @Get("/wechat/info", name="api.oauth.wechat_info")
*/
public function wechatInfoAction()
{
$service = new ConnectService();
$wechat = $service->getWechatInfo();
return $this->jsonSuccess(['wechat' => $wechat]);
}
}

View File

@ -54,6 +54,18 @@ class TradeController extends Controller
return $this->jsonSuccess($content);
}
/**
* @Post("/mini/create", name="api.trade.mini_create")
*/
public function createMiniTradeAction()
{
$service = new TradeService();
$content = $service->createMiniTrade();
return $this->jsonSuccess($content);
}
/**
* @Post("/app/create", name="api.trade.app_create")
*/
@ -61,7 +73,7 @@ class TradeController extends Controller
{
$service = new TradeService();
$content = $service->createMpTrade();
$content = $service->createAppTrade();
return $this->jsonSuccess($content);
}

View File

@ -0,0 +1,190 @@
<?php
namespace App\Http\Api\Services;
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\Services\Auth\Api as ApiAuthService;
use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
use App\Services\OAuth\QQ as QQAuth;
use App\Services\OAuth\WeChat as WeChatAuth;
use App\Services\OAuth\WeiBo as WeiBoAuth;
use Exception;
class Connect extends Service
{
public function getWechatInfo()
{
return [
'auth_url' => kg_full_url(['for' => 'api.oauth.wechat']),
'auto_login' => 1,
];
}
public function handleCallback($provider)
{
$code = $this->request->getQuery('code');
$state = $this->request->getQuery('state');
$openUser = $this->getOpenUserInfo($code, $state, $provider);
$relation = $this->getConnectRelation($openUser['id'], $provider);
$token = null;
if ($relation) {
$userRepo = new UserRepo();
$user = $userRepo->findById($relation->user_id);
$auth = new ApiAuthService();
$token = $auth->saveAuthInfo($user);
$this->handleLoginNotice($user);
}
return [
'openid' => $openUser['id'],
'token' => $token,
];
}
public function getAuthorizeUrl($provider)
{
$auth = $this->getConnectAuth($provider);
return $auth->getAuthorizeUrl();
}
public function getOpenUserInfo($code, $state, $provider)
{
$auth = $this->getConnectAuth($provider);
$auth->checkState($state);
$token = $auth->getAccessToken($code);
$openId = $auth->getOpenId($token);
return $auth->getUserInfo($token, $openId);
}
public function getConnectRelation($openId, $provider)
{
$connectRepo = new ConnectRepo();
return $connectRepo->findByOpenId($openId, $provider);
}
public function getConnectAuth($provider)
{
$auth = null;
switch ($provider) {
case ConnectModel::PROVIDER_QQ:
$auth = $this->getQQAuth();
break;
case ConnectModel::PROVIDER_WEIBO:
$auth = $this->getWeiBoAuth();
break;
case ConnectModel::PROVIDER_WECHAT:
$auth = $this->getWeChatAuth();
break;
}
if (!$auth) {
throw new Exception('Invalid OAuth Provider');
}
return $auth;
}
protected function getQQAuth()
{
$settings = $this->getSettings('oauth.qq');
$settings['redirect_uri'] = kg_full_url(['for' => 'api.oauth.qq_callback']);
return new QQAuth(
$settings['client_id'],
$settings['client_secret'],
$settings['redirect_uri']
);
}
protected function getWeChatAuth()
{
/**
* 使用的是微信公众号网页授权登录功能
*/
$settings = $this->getSettings('wechat.oa');
$settings['redirect_uri'] = kg_full_url(['for' => 'api.oauth.wechat_callback']);
return new WeChatAuth(
$settings['app_id'],
$settings['app_secret'],
$settings['redirect_uri']
);
}
protected function getWeiBoAuth()
{
$settings = $this->getSettings('oauth.weibo');
$settings['redirect_uri'] = kg_full_url(['for' => 'api.oauth.weibo_callback']);
return new WeiBoAuth(
$settings['client_id'],
$settings['client_secret'],
$settings['redirect_uri']
);
}
protected function handleConnectRelation(UserModel $user, array $openUser)
{
$connectRepo = new ConnectRepo();
$connect = $connectRepo->findByOpenId($openUser['id'], $openUser['provider']);
if ($connect) {
$connect->open_name = $openUser['name'];
$connect->open_avatar = $openUser['avatar'];
if ($connect->user_id != $user->id) {
$connect->user_id = $user->id;
}
if ($connect->deleted == 1) {
$connect->deleted = 0;
}
$connect->update();
} else {
$connect = new ConnectModel();
$connect->user_id = $user->id;
$connect->open_id = $openUser['id'];
$connect->open_name = $openUser['name'];
$connect->open_avatar = $openUser['avatar'];
$connect->provider = $openUser['provider'];
$connect->create();
}
}
protected function handleLoginNotice(UserModel $user)
{
$service = new AccountLoginNoticeService();
$service->createTask($user);
}
}

View File

@ -75,6 +75,45 @@ class Trade extends Service
{
$post = $this->request->getPost();
$order = $this->checkOrderBySn($post['order_sn']);
$user = $this->getLoginUser();
$channel = TradeModel::CHANNEL_WXPAY;
$trade = new TradeModel();
$trade->subject = $order->subject;
$trade->amount = $order->amount;
$trade->channel = $channel;
$trade->order_id = $order->id;
$trade->owner_id = $user->id;
$trade->create();
$wxpay = new Wxpay();
$response = $wxpay->mp($trade, $post['open_id']);
$payment = [
'appId' => $response->appId,
'timeStamp' => $response->timeStamp,
'nonceStr' => $response->nonceStr,
'package' => $response->package,
'signType' => $response->signType,
'paySign' => $response->paySign,
];
return [
'trade' => $this->handleTradeInfo($trade->sn),
'payment' => $payment,
];
}
public function createMiniTrade()
{
$post = $this->request->getPost();
$validator = new ClientValidator();
$platform = $this->getPlatform();
@ -120,7 +159,7 @@ class Trade extends Service
public function createAppTrade()
{
return [];
}
protected function getPlatform()

View File

@ -66,7 +66,7 @@
{%- endmacro %}
{%- macro live_status_info(lesson) %}
{% if lesson.attrs.start_time < time() and lesson.attrs.end_time > time() %}
{% if lesson.attrs.stream.status == 'active' %}
<span class="active">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 直播中</span>
{% elseif lesson.attrs.start_time > time() %}
<span class="pending">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 倒计时</span>

View File

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

View File

@ -708,3 +708,13 @@ function kg_full_url($uri, $args = null)
return $baseUrl . $url->get($uri, $args);
}
/**
* 获取H5首页地址
*
* @return string
*/
function kg_h5_index_url()
{
return kg_site_url() . '/h5/#/pages/index/index';
}

View File

@ -7,12 +7,15 @@
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class Connect extends Model
{
const PROVIDER_QQ = 1; // QQ
const PROVIDER_WEIXIN = 2; // 微信
const PROVIDER_WEIBO = 3; // 微博
const PROVIDER_WEIXIN = 2; // 微信扫码
const PROVIDER_WEIBO = 3; // 新浪微博
const PROVIDER_WECHAT = 4; // 公众号网页
/**
* 主键编号
@ -28,6 +31,13 @@ class Connect extends Model
*/
public $user_id = 0;
/**
* 联合ID
*
* @var string
*/
public $union_id = '';
/**
* 开放ID
*
@ -56,6 +66,13 @@ class Connect extends Model
*/
public $provider = 0;
/**
* 删除标识
*
* @var int
*/
public $deleted = 0;
/**
* 创建时间
*
@ -75,6 +92,18 @@ class Connect extends Model
return 'kg_connect';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();

View File

@ -113,6 +113,7 @@ class QQ extends OAuth
$userInfo['name'] = $data['nickname'];
$userInfo['avatar'] = $data['figureurl'];
$userInfo['provider'] = ConnectModel::PROVIDER_QQ;
$userInfo['unionid'] = '';
return $userInfo;
}

View File

@ -0,0 +1,94 @@
<?php
namespace App\Services\OAuth;
use App\Models\Connect as ConnectModel;
use App\Services\OAuth;
class WeChat extends OAuth
{
const AUTHORIZE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize';
const ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token';
const USER_INFO_URL = 'https://api.weixin.qq.com/sns/userinfo';
public function getAuthorizeUrl()
{
/**
* 参数强制要求按特定顺序排列
*/
$params = [
'appid' => $this->clientId,
'redirect_uri' => $this->redirectUri,
'response_type' => 'code',
'scope' => 'snsapi_userinfo',
'state' => $this->getState(),
];
return self::AUTHORIZE_URL . '?' . http_build_query($params) . '#wechat_redirect';
}
public function getAccessToken($code)
{
$params = [
'code' => $code,
'appid' => $this->clientId,
'secret' => $this->clientSecret,
'grant_type' => 'authorization_code',
];
$response = $this->httpPost(self::ACCESS_TOKEN_URL, $params);
$this->accessToken = $this->parseAccessToken($response);
return $this->accessToken;
}
public function getOpenId($accessToken = null)
{
return $this->openId;
}
public function getUserInfo($accessToken, $openId)
{
$params = [
'access_token' => $accessToken,
'openid' => $openId,
];
$response = $this->httpGet(self::USER_INFO_URL, $params);
return $this->parseUserInfo($response);
}
private function parseAccessToken($response)
{
$data = json_decode($response, true);
if (isset($data['errcode']) && $data['errcode'] != 0) {
throw new \Exception("Fetch Access Token Failed:{$response}");
}
$this->openId = $data['openid'];
return $data['access_token'];
}
private function parseUserInfo($response)
{
$data = json_decode($response, true);
if (isset($data['errcode']) && $data['errcode'] != 0) {
throw new \Exception("Fetch User Info Failed:{$response}");
}
$userInfo['id'] = $data['openid'];
$userInfo['name'] = $data['nickname'];
$userInfo['avatar'] = $data['headimgurl'];
$userInfo['unionid'] = $data['unionid'] ?? '';
$userInfo['provider'] = ConnectModel::PROVIDER_WECHAT;
return $userInfo;
}
}

View File

@ -88,6 +88,7 @@ class WeiBo extends OAuth
$userInfo['name'] = $data['name'];
$userInfo['avatar'] = $data['profile_image_url'];
$userInfo['provider'] = ConnectModel::PROVIDER_WEIBO;
$userInfo['unionid'] = '';
return $userInfo;
}

View File

@ -87,6 +87,7 @@ class WeiXin extends OAuth
$userInfo['id'] = $data['openid'];
$userInfo['name'] = $data['nickname'];
$userInfo['avatar'] = $data['headimgurl'];
$userInfo['unionid'] = $data['unionid'] ?? '';
$userInfo['provider'] = ConnectModel::PROVIDER_WEIXIN;
return $userInfo;

View File

@ -121,6 +121,37 @@ class Wxpay extends PayService
return $result;
}
/**
* 公众号支付
*
* @param TradeModel $trade
* @param string $openId
* @return Collection|bool
*/
public function mp(TradeModel $trade, $openId)
{
try {
$result = $this->gateway->mp([
'out_trade_no' => $trade->sn,
'total_fee' => 100 * $trade->amount,
'body' => $trade->subject,
'openid' => $openId,
]);
} catch (\Exception $e) {
Log::error('Wxpay MP Exception', [
'code' => $e->getCode(),
'message' => $e->getMessage(),
]);
$result = false;
}
return $result;
}
/**
* 小程序支付
*

View File

@ -0,0 +1,56 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
use Phinx\Db\Adapter\MysqlAdapter;
class V20210917093354 extends Phinx\Migration\AbstractMigration
{
public function up()
{
$this->alterConnectTable();
$this->alterWechatSubscribeTable();
}
protected function alterConnectTable()
{
$this->table('kg_connect')
->addColumn('deleted', 'integer', [
'null' => false,
'default' => '0',
'limit' => MysqlAdapter::INT_REGULAR,
'signed' => false,
'comment' => '删除标识',
'after' => 'provider',
])
->save();
}
protected function alterWechatSubscribeTable()
{
$this->table('kg_wechat_subscribe')
->addColumn('union_id', 'string', [
'null' => false,
'default' => '',
'limit' => 64,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
'comment' => '联合ID',
'after' => 'open_id',
])
->addColumn('deleted', 'integer', [
'null' => false,
'default' => '0',
'limit' => MysqlAdapter::INT_REGULAR,
'signed' => false,
'comment' => '删除标识',
'after' => 'open_id',
])
->save();
}
}