User.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <?php
  2. namespace App\Models;
  3. use App\Casts\data_rate;
  4. use App\Casts\money;
  5. use App\Utils\Helpers;
  6. use App\Utils\QQInfo;
  7. use Hash;
  8. use Illuminate\Database\Eloquent\Builder;
  9. use Illuminate\Database\Eloquent\Factories\HasFactory;
  10. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  11. use Illuminate\Database\Eloquent\Relations\BelongsToMany;
  12. use Illuminate\Database\Eloquent\Relations\HasMany;
  13. use Illuminate\Database\Eloquent\Relations\HasManyThrough;
  14. use Illuminate\Database\Eloquent\Relations\HasOne;
  15. use Illuminate\Foundation\Auth\User as Authenticatable;
  16. use Illuminate\Notifications\Notifiable;
  17. use Kyslik\ColumnSortable\Sortable;
  18. use Laravel\Sanctum\HasApiTokens;
  19. use Spatie\Permission\Traits\HasRoles;
  20. /**
  21. * 用户信息.
  22. */
  23. class User extends Authenticatable
  24. {
  25. use HasApiTokens, HasFactory, Notifiable, HasRoles, Sortable;
  26. public array $sortable = ['id', 'credit', 'port', 't', 'expired_at'];
  27. protected $table = 'user';
  28. protected $casts = ['credit' => money::class, 'speed_limit' => data_rate::class, 'expired_at' => 'date:Y-m-d', 'reset_time' => 'date:Y-m-d', 'ban_time' => 'date:Y-m-d'];
  29. protected $guarded = [];
  30. public function routeNotificationForMail($notification)
  31. {
  32. return $this->username;
  33. }
  34. public function usedTrafficPercentage(): float
  35. {
  36. return round($this->used_traffic / $this->transfer_enable, 2);
  37. }
  38. public function getUsedTrafficAttribute(): int
  39. {
  40. return $this->d + $this->u;
  41. }
  42. public function getExpirationDateAttribute()
  43. {
  44. return $this->attributes['expired_at'];
  45. }
  46. public function getResetDateAttribute()
  47. {
  48. return $this->attributes['reset_time'];
  49. }
  50. public function getTelegramUserIdAttribute()
  51. {
  52. $telegram = $this->userAuths()->whereType('telegram')->first();
  53. return $telegram->identifier ?? null;
  54. }
  55. public function userAuths(): HasMany
  56. {
  57. return $this->hasMany(UserOauth::class);
  58. }
  59. public function onlineIpLogs(): HasMany
  60. {
  61. return $this->hasMany(NodeOnlineIp::class);
  62. }
  63. public function payments(): HasMany
  64. {
  65. return $this->hasMany(Payment::class);
  66. }
  67. public function commissionSettlements(): HasMany
  68. {
  69. return $this->hasMany(ReferralApply::class);
  70. }
  71. public function commissionLogs(): HasMany
  72. {
  73. return $this->hasMany(ReferralLog::class, 'inviter_id');
  74. }
  75. public function ruleLogs(): HasMany
  76. {
  77. return $this->hasMany(RuleLog::class);
  78. }
  79. public function tickets(): HasMany
  80. {
  81. return $this->hasMany(Ticket::class);
  82. }
  83. public function ticketReplies(): HasMany
  84. {
  85. return $this->hasMany(TicketReply::class);
  86. }
  87. public function banedLogs(): HasMany
  88. {
  89. return $this->hasMany(UserBanedLog::class);
  90. }
  91. public function creditLogs(): HasMany
  92. {
  93. return $this->hasMany(UserCreditLog::class);
  94. }
  95. public function dailyDataFlows(): HasMany
  96. {
  97. return $this->hasMany(UserDailyDataFlow::class);
  98. }
  99. public function dataFlowLogs(): HasMany
  100. {
  101. return $this->hasMany(UserDataFlowLog::class);
  102. }
  103. public function dataModifyLogs(): HasMany
  104. {
  105. return $this->hasMany(UserDataModifyLog::class);
  106. }
  107. public function hourlyDataFlows(): HasMany
  108. {
  109. return $this->HasMany(UserHourlyDataFlow::class);
  110. }
  111. public function loginLogs(): HasMany
  112. {
  113. return $this->HasMany(UserLoginLog::class);
  114. }
  115. public function subscribe(): HasOne
  116. {
  117. return $this->hasOne(UserSubscribe::class);
  118. }
  119. public function subUrl(): string
  120. {
  121. return route('sub', $this->subscribe->code);
  122. }
  123. public function subscribeLogs(): HasManyThrough
  124. {
  125. return $this->hasManyThrough(UserSubscribeLog::class, UserSubscribe::class);
  126. }
  127. public function verify(): HasMany
  128. {
  129. return $this->hasMany(Verify::class);
  130. }
  131. public function inviter(): BelongsTo
  132. {
  133. return $this->belongsTo(__CLASS__);
  134. }
  135. public function invites(): HasMany
  136. {
  137. return $this->hasMany(Invite::class, 'inviter_id');
  138. }
  139. public function invitees(): HasMany
  140. {
  141. return $this->hasMany(__CLASS__, 'inviter_id');
  142. }
  143. public function getLevelNameAttribute(): string
  144. {
  145. return Level::whereLevel($this->level)->first()->name;
  146. }
  147. public function getCreditTagAttribute(): string
  148. {
  149. return Helpers::getPriceTag($this->credit);
  150. }
  151. public function getTransferEnableFormattedAttribute(): string
  152. {
  153. return formatBytes($this->attributes['transfer_enable']);
  154. }
  155. public function setPasswordAttribute(string $password): string
  156. {
  157. return $this->attributes['password'] = Hash::make($password);
  158. }
  159. public function getAvatarAttribute(): string
  160. {
  161. if ($this->qq) {
  162. $url = QQInfo::getQQAvatar($this->qq);
  163. } elseif (stripos(strtolower($this->username), '@qq.com') !== false) {
  164. $url = QQInfo::getQQAvatar($this->username);
  165. } else {
  166. // $url = 'https://gravatar.loli.net/avatar/'.md5(strtolower(trim($this->username)))."?&d=identicon";
  167. // $url = 'https://robohash.org/'.md5(strtolower(trim($this->username))).'?set=set4&bgset=bg2&size=400x400';
  168. // $url = 'https://api.dicebear.com/6.x/thumbs/svg?seed='.$this->username.'&radius=50';
  169. $url = 'https://api.btstu.cn/sjtx/api.php?lx=c1&format=images&method=zsy';
  170. }
  171. return $url;
  172. }
  173. public function scopeActiveUser(Builder $query): Builder
  174. {
  175. return $query->where('status', '<>', -1)->whereEnable(1);
  176. }
  177. public function scopeBannedUser(Builder $query): Builder
  178. {
  179. return $query->where('status', '<>', -1)->whereEnable(0);
  180. }
  181. public function nodes(?int $userLevel = null, ?int $userGroupId = null): Node|Builder|BelongsToMany
  182. {
  183. if ($userGroupId === null && $this->user_group_id) { // 使用默认的用户分组
  184. $query = $this->userGroup->nodes();
  185. } elseif ($userGroupId) { // 使用给的用户分组
  186. $query = UserGroup::findOrFail($userGroupId)->nodes();
  187. } else { // 无用户分组
  188. $query = Node::query();
  189. }
  190. return $query->whereStatus(1)->where('level', '<=', $userLevel ?? $this->level ?? 0);
  191. }
  192. public function userGroup(): BelongsTo
  193. {
  194. return $this->belongsTo(UserGroup::class);
  195. }
  196. public function getIsAvailableAttribute(): bool
  197. {
  198. return ! $this->ban_time && $this->transfer_enable && $this->expired_at > time();
  199. }
  200. public function updateCredit(float $credit): bool
  201. {
  202. $this->credit += $credit;
  203. return $this->credit >= 0 && $this->save();
  204. }
  205. public function incrementData(int $data): bool
  206. { // 添加用户流量
  207. $this->transfer_enable += $data;
  208. return $this->save();
  209. }
  210. public function isNotCompleteOrderByUserId(int $userId): bool
  211. {
  212. return Order::uid($userId)->whereIn('status', [0, 1])->exists();
  213. }
  214. public function trafficFetch(int $u, int $d): bool
  215. {
  216. $this->u += $u;
  217. $this->d += $d;
  218. return $this->save();
  219. }
  220. public function expiration_status(): int
  221. {
  222. $today = date('Y-m-d');
  223. $nextMonth = date('Y-m-d', strtotime('next month'));
  224. if ($this->expiration_date < $today) {
  225. $status = 0; // 已过期
  226. } elseif ($this->expiration_date === $today) {
  227. $status = 1; // 今日过期
  228. } elseif ($this->expiration_date <= $nextMonth) {
  229. $status = 2; // 一个月内过期
  230. }
  231. return $status ?? 3;
  232. }
  233. public function isTrafficWarning(): bool
  234. { // 流量异常警告
  235. return ((int) sysConfig('traffic_ban_value') * GiB) <= $this->recentTrafficUsed();
  236. }
  237. public function recentTrafficUsed()
  238. {
  239. return UserHourlyDataFlow::userRecentUsed($this->id)->sum(\DB::raw('u + d'));
  240. }
  241. public function orders(): HasMany
  242. {
  243. return $this->hasMany(Order::class);
  244. }
  245. public function routeNotificationForTelegram()
  246. {
  247. return $this->telegram_user_id;
  248. }
  249. }