TencentImFriendService.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. namespace App\Services;
  3. use App\Exceptions\TencentImFriendException;
  4. use App\Models\User;
  5. use App\Models\UserFriendApplyRecord;
  6. use App\Traits\TencentIm;
  7. use Illuminate\Support\Facades\DB;
  8. class TencentImFriendService
  9. {
  10. use TencentIm;
  11. public const ADD_FRIEND_TYPE_SINGLE = 'Add_Type_Single'; // 表示单向加好友
  12. public const ADD_FRIEND_TYPE_BOTH = 'Add_Type_Both'; // 表示双向加好友
  13. public const IM_IDENTIFIER_PREFIX = 'IM_USER_';
  14. public const CHECK_FRIEND_TYPE_SINGLE = 'CheckResult_Type_Single'; // 只会检查 From_Account 的好友表中是否有 To_Account,不会检查 To_Account 的好友表中是否有 From_Account
  15. public const CHECK_FRIEND_TYPE_BOTH = 'CheckResult_Type_Both'; // 既会检查 From_Account 的好友表中是否有 To_Account,也会检查 To_Account 的好友表中是否有 From_Account
  16. public const ADD_FRIEND_ADD_SOURCE_TYPE_ADDRESS_BOOK = 'AddSource_Type_100'; // 加好友来源 通讯录
  17. public const TENCENT_REST_APIS = [
  18. 'friendAddItem' => 'v4/sns/friend_add', // 单个添加好友,
  19. 'friendGet' => 'v4/sns/friend_get', // 拉取好友,
  20. 'friendCheck' => 'v4/sns/friend_check', // 校验好友
  21. ];
  22. public static function verifyUserApplyFriendExists(User $fromUser, User $toUser)
  23. {
  24. }
  25. // 添加好友记录
  26. public function addApplyFriendRecord(User $user, array $options = [])
  27. {
  28. try {
  29. DB::beginTransaction();
  30. $toUser = User::find($options['to_user_id']);
  31. if (!$toUser) {
  32. throw new TencentImFriendException('好友账号不存在');
  33. }
  34. // 检测是否已经有记录
  35. $friendApplyRecordModel = UserFriendApplyRecord::query()
  36. ->where(['from_user_id' => $user->id, 'to_user_id' => $toUser->id])
  37. ->latest()
  38. ->first();
  39. if ($friendApplyRecordModel) {
  40. if (UserFriendApplyRecord::APPLY_STATUS_100 === $friendApplyRecordModel->apply_status) {
  41. throw new TencentImFriendException('已发出好友添加申请,请勿重复操作');
  42. }
  43. if (UserFriendApplyRecord::APPLY_STATUS_101 === $friendApplyRecordModel->apply_status) {
  44. throw new TencentImFriendException('已经是好友关系,请勿重复操作');
  45. }
  46. if (UserFriendApplyRecord::APPLY_STATUS_101 === $friendApplyRecordModel->apply_status) {
  47. throw new TencentImFriendException('已经是好友关系,请勿重复操作');
  48. }
  49. }
  50. if (!$friendApplyRecordModel) {
  51. $friendApplyRecordModel = new UserFriendApplyRecord();
  52. }
  53. // 添加发起申请记录
  54. $applyData = [
  55. 'from_user_id' => $user->id,
  56. 'to_user_id' => $toUser->id,
  57. 'type' => UserFriendApplyRecord::APPLY_TYPE_100,
  58. 'apply_status' => UserFriendApplyRecord::APPLY_STATUS_102,
  59. 'apply_raw_data' => [
  60. 'remark' => $options['remark'] ?? '',
  61. 'group' => $options['group_id'] ?? '',
  62. ],
  63. ];
  64. $friendApplyRecordModel->fill($applyData);
  65. // 添加接收
  66. if (!$friendApplyRecordModel->save()) {
  67. throw new \Exception('写入好友申请记录失败');
  68. }
  69. DB::commit();
  70. return $friendApplyRecordModel;
  71. } catch (\Exception $e) {
  72. DB::rollBack();
  73. return ['error' => $e->getMessage()];
  74. } catch (TencentImFriendException $e) {
  75. DB::rollBack();
  76. return ['error' => $e->getMessage()];
  77. }
  78. }
  79. /**
  80. * 发起添加 IM 好友 (单个用户).
  81. *
  82. * @return \Psr\Http\Message\ResponseInterface
  83. *
  84. * @throws TencentImFriendException
  85. * @throws \App\Exceptions\TencentImAccountException
  86. * @throws \App\Exceptions\TencentImException
  87. * @throws \GuzzleHttp\Exception\GuzzleException
  88. */
  89. public function friendAddItem(string $fromAccount, string $toAccount, array $options = [])
  90. {
  91. // TODO 请求添加好友前先拉取好友状态
  92. $this->restApiName = self::TENCENT_REST_APIS['friendAddItem'];
  93. $baseApiHost = $this->getTencentImRestApiBaseHost();
  94. $params = self::prepareFriendAddItemOptions($fromAccount, $toAccount, $options);
  95. $apiResult = $this->requestApi($baseApiHost, $params);
  96. self::verifyApiResult($apiResult);
  97. if ($apiResult['ResultItem'][0]['ResultInfo'] || (0 != $apiResult['ResultItem'][0]['ResultCode'])) {
  98. throw new TencentImFriendException('添加好友失败: ' . $apiResult['ResultItem'][0]['ResultInfo']);
  99. }
  100. return $apiResult;
  101. }
  102. // 拉取好友
  103. public function friendGet(string $fromAccount, int $pageStartIndex = 0)
  104. {
  105. $this->restApiName = self::TENCENT_REST_APIS['friendGet'];
  106. $baseApiHost = $this->getTencentImRestApiBaseHost();
  107. $params = [
  108. 'From_Account' => $fromAccount,
  109. 'StartIndex' => $pageStartIndex,
  110. 'StandardSequence' => $StandardSequence ?? 0,
  111. 'CustomSequence' => $CustomSequence ?? 0,
  112. ];
  113. $apiResult = $this->requestApi($baseApiHost, $params);
  114. dd($apiResult);
  115. }
  116. // 检验好友
  117. public function friendCheck(string $fromAccount, array $toAccounts, string $checkType = self::ADD_FRIEND_TYPE_BOTH)
  118. {
  119. $this->restApiName = self::TENCENT_REST_APIS['friendCheck'];
  120. $baseApiHost = $this->getTencentImRestApiBaseHost();
  121. $params = [
  122. 'From_Account' => $fromAccount,
  123. 'To_Account' => $toAccounts,
  124. 'CheckType' => 'CheckResult_Type_Both',
  125. ];
  126. $apiResult = $this->requestApi($baseApiHost, $params);
  127. self::verifyApiResult($apiResult);
  128. return $apiResult;
  129. }
  130. /**
  131. * 构建添加好友api 请求数组.
  132. *
  133. * @param string $fromAccount 需要添加好友的用户IM id
  134. * @param string $toAccount 被申请添加好友的用户IM id
  135. * @param string $options ['AddType'] 加好友方式
  136. * @param string $options ['AddSource'] 好友来源
  137. * @param string $options ['ForceAddFlags'] 管理员强制加好友标记:1表示强制加好友,0表示常规加好友方式
  138. * @param string $options ['Remark'] 好友备注
  139. * @param string $options ['AddWording'] 形成好友关系时的附言信息
  140. * @param string $options ['GroupName'] 分组信息,添加好友时只允许设置一个分组
  141. *
  142. * @return array
  143. */
  144. public static function prepareFriendAddItemOptions(string $fromAccount, string $toAccount, array $options)
  145. {
  146. // string $addType = self::ADD_FRIEND_TYPE_BOTH,
  147. // string $addSource = self::ADD_FRIEND_ADD_SOURCE_TYPE_ADDRESS_BOOK,
  148. // string $remark = '',
  149. // bool $forceAddFlags = false
  150. $result = [
  151. 'From_Account' => $fromAccount,
  152. // 'AddSource' => $options['AddSource'] ?? self::ADD_FRIEND_ADD_SOURCE_TYPE_ADDRESS_BOOK, //好友来源
  153. 'AddType' => $options['AddType'] ?? self::ADD_FRIEND_TYPE_BOTH, // 加好友方式
  154. 'ForceAddFlags' => empty($options['ForceAddFlags']) ? 0 : ($options['ForceAddFlags'] ? 1 : 0), // 管理员强制加好友标记:1表示强制加好友,0表示常规加好友方式
  155. ];
  156. $AddFriendItem = [];
  157. $AddFriendItem['To_Account'] = $toAccount;
  158. // 好友来源
  159. $AddFriendItem['AddSource'] = $options['AddSource'] ?? self::ADD_FRIEND_ADD_SOURCE_TYPE_ADDRESS_BOOK;
  160. // 好友备注
  161. if (!empty($options['Remark'])) {
  162. $AddFriendItem['Remark'] = $options['Remark'];
  163. }
  164. // 形成好友关系时的附言信息
  165. if (!empty($options['AddWording'])) {
  166. $AddFriendItem['AddWording'] = $options['AddWording'];
  167. }
  168. // 分组信息,添加好友时只允许设置一个分组
  169. if (!empty($options['GroupName'])) {
  170. $AddFriendItem['GroupName'] = $options['GroupName'] ? 1 : 0;
  171. }
  172. $result['AddFriendItem'][] = $AddFriendItem;
  173. unset($options, $AddFriendItem);
  174. return $result;
  175. }
  176. }