Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 353
0.00% covered (danger)
0.00%
0 / 25
CRAP
0.00% covered (danger)
0.00%
0 / 1
SubscriptionTrait
0.00% covered (danger)
0.00%
0 / 353
0.00% covered (danger)
0.00%
0 / 25
15252
0.00% covered (danger)
0.00%
0 / 1
 getCurrentPlan
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
72
 getCurrentAddOns
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 getGrammarQuota
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getQuotaUsed
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getFlyAIQuota
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 getFlyCutsQuota
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 getPromptQuota
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 getCurrentSubscription
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
72
 extractStylesFromHtml
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 hasTag
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 hasHyperlink
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 checkIfStyleExists
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 countStyles
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getMediaStorage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 checkStylesTagsPermissions
0.00% covered (danger)
0.00%
0 / 116
0.00% covered (danger)
0.00%
0 / 1
1406
 checkIfGiphyExists
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 getDomainName
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 checkCharacterCount
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 checkFlyCutsCount
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
56
 restrictAdvacedSearch
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 checkCategoriesCount
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
132
 checkSubCategoriesCount
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 checkFlyPlates
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
132
 checkShortcutVersionRollBackCount
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
 retrieveCouponObject
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Traits;
4
5use App\Helpers\Constants;
6use DOMDocument;
7use Stripe\StripeClient;
8use App\Http\Models\Plans;
9use Illuminate\Support\Str;
10use Illuminate\Http\Request;
11use App\Http\Models\Shortcut;
12use App\Http\Models\Auth\User;
13use App\Http\Models\FlyGrammarActions;
14use App\Http\Models\FlyMsgUserDailyUsage;
15use App\Http\Models\Prompts\CustomPrompts;
16use App\Http\Models\ShortcutCategory;
17use App\Http\Models\TemplateCategory;
18use App\Http\Models\ShortcutSubCategoryLv1;
19use App\Http\Models\UserAddOns;
20use App\Traits\AccountCenter\Reporting\FlyMsgAITrackingTrait;
21use Carbon\Carbon;
22use Illuminate\Support\Facades\Log;
23use MongoDB\BSON\UTCDateTime;
24
25trait SubscriptionTrait
26{
27    use FlyMsgAITrackingTrait;
28
29    /**
30     * @param User $user
31     *
32     * @return Plans
33     */
34    public function getCurrentPlan($user)
35    {
36        $currentSubscription = $user->subscription('main');
37
38        if (filled($currentSubscription) && $currentSubscription->valid() && filled($currentSubscription->plan)) {
39            // Team users a not managed on stripe so once subscription
40            // is cancelled in DB then thats it, no grace periods, no nothing.
41            $is_team_user = $currentSubscription->plan->identifier == Plans::ProPlanTeamsSMB || $currentSubscription->plan->identifier == Plans::ProPlanTeamsENT;
42            if (($is_team_user && !$currentSubscription->proTeamEnded()) || !$is_team_user) {
43                return $currentSubscription->plan;
44            }
45        }
46
47        return Plans::select(
48            'title',
49            'identifier',
50            'features',
51            'currency',
52            'interval',
53            'unit_amount',
54            'user_persona_available',
55            'user_custom_prompts',
56            'has_fly_learning',
57            'regenerate_count',
58            'flygrammar_actions',
59            'flycut_deployment',
60            'prompts_per_day',
61            'can_disable_flygrammar',
62            'flycuts_features'
63        )
64            ->firstWhere('identifier', Plans::FREEMIUM_IDENTIFIER);
65    }
66
67    public function getCurrentAddOns(string $userId)
68    {
69        $userAddOns = UserAddOns::where('user_id', $userId)
70            ->where('status', 'active')
71            ->orderBy('created_at', 'desc')
72            ->get()
73            ->load('addOn');
74
75        $userAddOns = $userAddOns->sortBy(function ($userAddOn) {
76            return $userAddOn->addOn->priority ?? 9999;
77        });
78
79        return $userAddOns;
80    }
81
82    public function getGrammarQuota(User $user)
83    {
84        $plan = $this->getCurrentPlan($user);
85
86        $today = now();
87
88        $actionsPerformedToday = FlyGrammarActions::where('user_id', $user->id)->where('created_at', '>=', new UTCDateTime(strtotime($today->startOfDay()->toDateTimeString()) * 1000))->where('created_at', '<=', new UTCDateTime(strtotime($today->endOfDay()->toDateTimeString()) * 1000))->count();
89
90        $remaining = $plan->flygrammar_actions - $actionsPerformedToday;
91
92        return [
93            'total' => $plan->flygrammar_actions,
94            'used' => $actionsPerformedToday,
95            'remaining' => $plan->flygrammar_actions === -1 ? -1 : max($remaining, 0),
96        ];
97    }
98
99    public function getQuotaUsed($userId)
100    {
101        $tracking = $this->getTrackingUserId($userId);
102
103        return $tracking ? $tracking->count() : 0;
104    }
105
106    public function getFlyAIQuota($user)
107    {
108        $currentSubscriptionPlan = $this->getCurrentPlan($user);
109        $total = Constants::CURRENT_SUBSCRIPTION_PLAN_IDENTIFIERS[$currentSubscriptionPlan->identifier];
110
111        $used = $this->getQuotaUsed($user->id);
112
113        return [
114            'used' => $used,
115            'total' => $total,
116            'remaining' => max($total - $used, 0),
117            'seconds_remaining_until_next_prompt_refill' => now()->diffInSeconds(now()->startOfDay()->addDay())
118        ];
119    }
120
121    public function getFlyCutsQuota($user)
122    {
123        $currentSubscriptionPlan = $this->getCurrentPlan($user);
124        $total = $currentSubscriptionPlan['flycut_deployment'] ?? 0;
125        $startDay = Carbon::now()->startOfDay();
126
127        $used = FlyMsgUserDailyUsage::where('user_id', $user->id)
128            ->where("created_at", ">=", new UTCDateTime($startDay->getTimestamp() * 1000))
129            ->first()
130            ->flycut_count ?? 0;
131
132        return [
133            'used' => $used,
134            'total' => $total,
135            'remaining' => max($total - $used, 0),
136            'seconds_remaining_until_next_prompt_refill' => now()->diffInSeconds(now()->startOfDay()->addDay())
137        ];
138    }
139
140    public function getPromptQuota(User $user)
141    {
142        $currentSubscriptionPlan = $this->getCurrentPlan($user);
143        $promptsQuotaUsed = CustomPrompts::where('user_id', $user->id)->count();
144
145        return [
146            'used' => $promptsQuotaUsed,
147            'total' => $currentSubscriptionPlan->user_custom_prompts,
148            'remaining' => max($currentSubscriptionPlan->user_custom_prompts - $promptsQuotaUsed, 0),
149        ];
150    }
151
152    public function getCurrentSubscription($user)
153    {
154        $currentSubscription =  $user->subscription('main');
155
156        if (filled($currentSubscription) && $currentSubscription->valid() && filled($currentSubscription->plan)) {
157            // Team users a not managed on stripe so once subscription
158            // is cancelled in DB then thats it, no grace periods, no nothing.
159            $is_team_user = $currentSubscription->plan->identifier == Plans::ProPlanTeamsSMB || $currentSubscription->plan->identifier == Plans::ProPlanTeamsENT;
160            if ($is_team_user && !$currentSubscription->proTeamEnded()) {
161                return $currentSubscription;
162            } else if (!$is_team_user) {
163                return $currentSubscription;
164            }
165        }
166
167        return null;
168    }
169
170    protected function extractStylesFromHtml($html)
171    {
172        $re = '/style="(.+?)"/m';
173
174        preg_match_all($re, $html, $matches, PREG_SET_ORDER, 0);
175
176        $styles = [];
177
178        collect($matches)->map(function ($match) use (&$styles) {
179            $arr = explode(';', $match[1]);
180
181            foreach ($arr as $prop) {
182                $new_arr_explode = explode(':', $prop);
183                $attr = trim($new_arr_explode[0]);
184
185                if (! array_key_exists($attr, $styles) && $attr != '') {
186                    $styles[$attr] = [];
187                }
188
189                $styles[$attr][] = @trim($new_arr_explode[1]);
190            }
191        });
192
193        return $styles;
194    }
195
196    protected function hasTag($re, $html)
197    {
198        preg_match_all($re, $html, $matches, PREG_SET_ORDER, 0);
199        return !empty($matches);
200    }
201
202    protected function hasHyperlink($re, $html)
203    {
204        $re = '/<a(.+?)<\/a>/m';
205
206        preg_match_all($re, $html, $matches, PREG_SET_ORDER, 0);
207
208        return ! empty($matches);
209    }
210
211    protected function checkIfStyleExists($key, $value, $styles)
212    {
213        return in_array($value, $styles[$key] ?? []) && (count(array_unique($styles[$key] ?? [])) == 1);
214    }
215
216    protected function countStyles($key, $styles)
217    {
218        $targeted_styles = $styles[$key] ?? [];
219
220        return count(array_unique($targeted_styles));
221    }
222
223    protected function getMediaStorage(User $user)
224    {
225        return $user->fileMetaData()->sum('size');
226    }
227
228    protected function checkStylesTagsPermissions(Request $request, $html)
229    {
230        $html = str_replace("\n", '', str_replace(PHP_EOL, '', $html));
231
232        $current_subscription = $this->getCurrentPlan($request->user());
233        $features = $current_subscription->features;
234        /** Check for Bold Text */
235        $bold = $features['Bold'] ?? false;
236        $has_bold_text_in_html = $this->hasTag('/<strong>(.+?)<\/strong>/m', $html);
237
238        if (! $bold && ($has_bold_text_in_html)) {
239            return [
240                'error' => true,
241                'message' => 'You are not authorized to add bold text'
242            ];
243            //abort(403, 'You are not authorized to add bold text');
244        }
245        /** Check for Italic Text */
246        $italic = $features['Italic'] ?? false;
247        $has_italic_text_in_html = $this->hasTag('/<em>(.+?)<\/em>/m', $html);
248
249        if (! $italic && ($has_italic_text_in_html)) {
250            return [
251                'error' => true,
252                'message' => 'You are not authorized to add italic text'
253            ];
254            //abort(403, 'You are not authorized to add italic text');
255        }
256        $html_styles = $this->extractStylesFromHtml($html);
257
258        /** Check for underline */
259        $under_line = $features['Underline'] ?? false;
260        $under_line_exists = $this->checkIfStyleExists('text-decoration', 'underline', $html_styles);
261
262        if ($under_line_exists && ! $under_line) {
263            return [
264                'error' => true,
265                'message' => 'You are not authorized to add underline text'
266            ];
267
268            //abort(403, 'You are not authorized to add underline text');
269        }
270
271        /** Strikethrough */
272        $strike_through = $features['Strikethrough'] ?? false;
273        $strike_through_exists = $this->checkIfStyleExists('text-decoration', 'line-through', $html_styles);
274
275        if ($strike_through_exists && ! $strike_through) {
276            return [
277                'error' => true,
278                'message' => 'You are not authorized to add strikethrough text'
279            ];
280
281            //abort(403, 'You are not authorized to add strikethrough text');
282        }
283
284        /** Hyperlink */
285        $hyperlink = $features['Hyperlink'] ?? false;
286        $has_hyperlink_html = $this->hasTag('/<a(.+?)<\/a>/m', $html);
287
288        if ($has_hyperlink_html && ! $hyperlink) {
289            return [
290                'error' => true,
291                'message' => 'You are not authorized to add hyperlink'
292            ];
293
294            //abort(403, 'You are not authorized to add hyperlink');
295        }
296
297        /** Alignment - Left */
298        $alignment_left = $features['Alignment - Left'] ?? false;
299        $alignment_left_exists = $this->checkIfStyleExists('text-align', 'left', $html_styles);
300
301        if ($alignment_left_exists && ! $alignment_left) {
302            return [
303                'error' => true,
304                'message' => 'You are not authorized to add left alignment text'
305            ];
306
307            //abort(403, 'You are not authorized to add left alignment text');
308        }
309
310        /** Alignment - Centered */
311        $alignment_center = $features['Alignment - Centered'] ?? false;
312        $alignment_center_exists = $this->checkIfStyleExists('text-align', 'center', $html_styles);
313
314        if ($alignment_center_exists && ! $alignment_center) {
315            return [
316                'error' => true,
317                'message' => 'You are not authorized to add center alignment text'
318            ];
319
320            //abort(403, 'You are not authorized to add center alignment text');
321        }
322
323        /** Alignment - Right */
324        $alignment_right = $features['Alignment - Right'] ?? false;
325        $alignment_right_exists = $this->checkIfStyleExists('text-align', 'right', $html_styles);
326
327        if ($alignment_right_exists && ! $alignment_right) {
328            return [
329                'error' => true,
330                'message' => 'You are not authorized to add right alignment text'
331            ];
332
333            //abort(403, 'You are not authorized to add right alignment text');
334        }
335
336        /** Font Size */
337        $font_size = $features['Font Size'] ?? False;
338        if (is_array($font_size)) {
339            if (array_key_exists("font-size", $html_styles)) {
340                $inputString = $html_styles['font-size'][0] ?: '10pt';
341                preg_match('/\d+/', $inputString, $matches);
342                $extractedNumber = (int)$matches[0];
343            } else {
344                $extractedNumber = 10;
345            }
346            if (array_key_exists('font-size', $html_styles) && !in_array($extractedNumber, $font_size)) {
347                return [
348                    'error' => true,
349                    'message' => 'Exceeds font size limit, use 10, 11 or 12pt size or upgrade plan ' . $extractedNumber . 'px'
350                ];
351
352                //abort(403, 'Exceeds font size limit, use 10, 11 or 12pt size or upgrade plan ' . $extractedNumber . 'px');
353            }
354        } else {
355            $font_size_match = $this->checkIfStyleExists('font-size', $font_size . 'px', $html_styles);
356
357            if ($font_size != -1 && !$font_size_match && array_key_exists('font-size', $html_styles)) {
358                return [
359                    'error' => true,
360                    'message' => 'Exceeds font size limit, use 10, 11 or 12pt size or upgrade plan ' . $font_size . 'px'
361                ];
362
363                //abort(403, 'Exceeds font size limit, use 10, 11 or 12pt size or upgrade plan ' . $font_size . 'px');
364            }
365        }
366
367        //** Font Family */
368        $font = $features['Fonts'] ?? False;
369        if (is_array($font)) {
370            if (array_key_exists('font-family', $html_styles)) {
371                $extractedFontFamily = strtolower($html_styles['font-family'][0]);
372                if (!in_array($extractedFontFamily, $font)) {
373                    return [
374                        'error' => true,
375                        'message' => 'You are not authorized to add a font family other than Arial, Sans Serif and Calibri.'
376                    ];
377
378                    //abort(403, 'You are not authorized to add a font family other than Arial, Sans Serif and Calibri.');
379                }
380            }
381        } else {
382            if ($font != -1 && $font) {
383                $count_unique_fonts = $this->countStyles('font-family', $html_styles);
384                if ($count_unique_fonts > $font) {
385                    return [
386                        'error' => true,
387                        'message' => Str::replaceArray('?', [$font], 'You can not add more than ? font per flycut with current plan')
388                    ];
389
390                    //abort(403, Str::replaceArray('?', [$font], 'You can not add more than ? font per flycut with current plan'));
391                }
392            }
393        }
394
395        /** Bullet Points */
396        $bullet_points = $features['Bullet Points'] ?? false;
397        $has_bullet_points_html = $this->hasTag('/<ul(.+?)<\/ul>/m', $html);
398
399        if ($has_bullet_points_html && ! $bullet_points) {
400            return [
401                'error' => true,
402                'message' => 'You are not authorized to add Bullet Points'
403            ];
404
405            //abort(403, 'You are not authorized to add Bullet Points');
406        }
407
408        /** Numbered List */
409        $numbered_list = $features['Numbered List'] ?? false;
410        $has_numbered_list = $this->hasTag('/<ol(.+?)<\/ol>/m', $html);
411
412        if ($has_numbered_list && ! $numbered_list) {
413            return [
414                'error' => true,
415                'message' => 'You are not authorized to add Numbered List'
416            ];
417
418            //abort(403, 'You are not authorized to add Numbered List');
419        }
420
421        /** Increase Indent */
422        $increase_indent = $features['Increase Indent'] ?? false;
423        $has_increase_indent = array_key_exists('padding-left', $html_styles);
424
425        if ($has_increase_indent && ! $increase_indent) {
426            return [
427                'error' => true,
428                'message' => 'You are not authorized to add Increase Indent'
429            ];
430
431            //abort(403, 'You are not authorized to add Increase Indent');
432        }
433
434        // /** Font Color */
435        // $font_color = $features['Font Color'] ?? False;
436        // $font_color_exists = array_key_exists('color', $html_styles);
437
438        // if ($font_color_exists && !$font_color) :
439        //     abort(403, 'You are not authorized to add Font Color');
440        // endif;
441
442        // /** Background Color */
443        // $background_color = $features['Background Color'] ?? False;
444        // $background_color_exists = array_key_exists('background-color', $html_styles);
445
446        // if ($background_color_exists && !$background_color) :
447        //     abort(403, 'You are not authorized to add Background Color');
448        // endif;
449
450        // /** Numbered List */
451        // $headings = $features['Blocks (Headings)'] ?? False;
452        // $has_headings =
453        //     $this->hasTag('/<h1(.+?)<\/h1>/m', $html) || $this->hasTag('/<h2(.+?)<\/h2>/m', $html)
454        //     || $this->hasTag('/<h3(.+?)<\/h3>/m', $html) || $this->hasTag('/<h4(.+?)<\/h4>/m', $html)
455        //     || $this->hasTag('/<h5(.+?)<\/h5>/m', $html) || $this->hasTag('/<h6(.+?)<\/h6>/m', $html)
456        //     || $this->hasTag('/<pre(.+?)<\/pre>/m', $html);
457
458        // if ($has_headings && !$headings) :
459        //     abort(403, 'You are not authorized to add Blocks');
460        // endif;
461        return true;
462    }
463
464    protected function checkIfGiphyExists(Request $request, $html)
465    {
466        $html = str_replace("\n", '', str_replace(PHP_EOL, '', $html));
467
468        $current_subscription = $this->getCurrentPlan($request->user());
469        $features = $current_subscription->features;
470        $allow_giphy = $features['Giphy'] ?? false;
471
472        $doc = new DOMDocument();
473        @$doc->loadHTML($html);
474        $imageTags = $doc->getElementsByTagName('img');
475
476        $gifs = collect($imageTags)->filter(function ($tag) {
477            return (pathinfo(parse_url($tag->getAttribute('src'), PHP_URL_PATH), PATHINFO_EXTENSION) == 'gif')
478                && ($this->getDomainName($tag->getAttribute('src')) == 'media2.giphy.com');
479        });
480
481        if (! $allow_giphy && $gifs->isNotEmpty()) {
482            return [
483                'error' => true,
484                'message' => 'You are not allowed to add giphy with current plan'
485            ];
486
487            //abort(403, 'You are not allowed to add giphy with current plan');
488        }
489        return true;
490    }
491
492    protected function getDomainName($url): string
493    {
494        $arr_url = parse_url($url);
495
496        return $arr_url['host'] ?? '';
497    }
498
499    protected function checkCharacterCount(Request $request, $html)
500    {
501        $current_subscription = $this->getCurrentPlan($request->user());
502        $features = $current_subscription->features;
503
504        $user = $request->user();
505
506        $flycut_char_limit = $features['Number of Characters that can be used per flycut'];
507        $char_count = strlen($html);
508
509        $is_rewardable = (isset($user->rewardable)) ? $user->rewardable : '';
510        $rewards_level = (isset($user->rewards_level)) ? $user->rewards_level : '';
511
512        if ($is_rewardable) {
513            if ($rewards_level >= 2) {
514                $flycut_char_limit = -1;
515            }
516        }
517
518        if ($char_count > $flycut_char_limit && $flycut_char_limit > -1) {
519            return [
520                'error' => true,
521                'message' => Str::replaceArray('?', [$flycut_char_limit], 'You can not add more than ? character per flycut with current plan')
522            ];
523
524
525            //abort(403, Str::replaceArray('?', [$flycut_char_limit], 'You can not add more than ? character per flycut with current plan'));
526        }
527
528        return true;
529    }
530
531    protected function checkFlyCutsCount(Request $request)
532    {
533        $current_subscription = $this->getCurrentPlan($request->user());
534        $features = $current_subscription->features;
535
536        $user = $request->user();
537
538        $total_allowed_shortcuts = $features['Number of FlyCuts that can be created'];
539
540        $is_rewardable = (isset($user->rewardable)) ? $user->rewardable : '';
541        $rewards_level = (isset($user->rewards_level)) ? $user->rewards_level : '';
542
543        if ($is_rewardable) {
544            if ($rewards_level >= 1) {
545                $total_allowed_shortcuts = -1;
546            }
547        }
548
549        $number_of_flyCuts_that_can_be_created = $total_allowed_shortcuts;
550        $current_flycuts_created = Shortcut::where('user_id', $user->id)->count();
551
552        if ($current_flycuts_created >= $number_of_flyCuts_that_can_be_created && $number_of_flyCuts_that_can_be_created > -1) {
553            return [
554                'error' => true,
555                'message' => 'You have reached the limit. The number of flycuts that can be created with the current plan has been exceeded.'
556            ];
557        }
558        return true;
559    }
560
561    protected function restrictAdvacedSearch(Request $request)
562    {
563        $current_subscription = $this->getCurrentPlan($request->user());
564        $features = $current_subscription->features;
565
566        $search_bar = $features['Search Bar'] ?? false;
567
568        if ($search_bar !== 'advanced') {
569            return [
570                'error' => true,
571                'message' => 'You are not allowed to perform advanced search with current plan'
572            ];
573
574            // abort(403, 'You are not allowed to perform advanced search with current plan');
575        }
576        return true;
577    }
578
579    protected function checkCategoriesCount(Request $request)
580    {
581        $current_subscription = $this->getCurrentPlan($request->user());
582        $features = $current_subscription->features;
583
584        $total_allowed_categories = $features['Categories'];
585
586        $user = $request->user();
587
588        $is_rewardable = (isset($user->rewardable)) ? $user->rewardable : '';
589        $rewards_level = (isset($user->rewards_level)) ? $user->rewards_level : '';
590
591        if ($is_rewardable) {
592            if ($rewards_level >= 3) {
593                if (
594                    $current_subscription['identifier'] == Plans::FREEMIUM_IDENTIFIER ||
595                    $current_subscription['identifier'] == Plans::STARTER_MONTHLY_IDENTIFIER ||
596                    $current_subscription['identifier'] == Plans::STARTER_YEARLY_IDENTIFIER
597                ) {
598                    $total_allowed_categories = $total_allowed_categories + 1;
599                }
600            }
601        }
602
603        $categories_limit = $total_allowed_categories ?? 0;
604        $categories_count = ShortcutCategory::where('user_id', request()->user()->id)->count();
605
606        if ($categories_count >= $categories_limit && $categories_limit != -1 && ! $request->category_id) {
607            return [
608                'error' => true,
609                'message' => Str::replaceArray('?', [$categories_limit], 'You can not add more than ? categories with current plan')
610            ];
611
612            //abort(403, Str::replaceArray('?', [$categories_limit], 'You can not add more than ? categories with current plan'));
613        }
614        return true;
615    }
616
617    protected function checkSubCategoriesCount(Request $request)
618    {
619        $current_subscription = $this->getCurrentPlan($request->user());
620        $features = $current_subscription->features;
621
622        $sub_categories_limit = $features['Subcategory'] ?? 0;
623        $sub_categories_count = ShortcutSubCategoryLv1::whereHas('ShortcutCategory')->where('user_id', request()->user()->id)->count();
624
625        if ($sub_categories_count >= $sub_categories_limit && $sub_categories_limit != -1) {
626            return [
627                'error' => true,
628                'message' => Str::replaceArray('?', [$sub_categories_limit], 'You can not add more than ? sub categories with current plan')
629            ];
630
631            //abort(403, Str::replaceArray('?', [$sub_categories_limit], 'You can not add more than ? sub categories with current plan'));
632        }
633        return true;
634    }
635
636    protected function checkFlyPlates(Request $request)
637    {
638        $user = $request->user();
639
640        $is_rewardable = (isset($user->rewardable)) ? $user->rewardable : '';
641        $rewards_level = (isset($user->rewards_level)) ? $user->rewards_level : '';
642
643        if (! $is_rewardable || $rewards_level < 4) {
644            $template_id = $request->template_id;
645            $categorydata = TemplateCategory::with('templates')
646                ->whereHas('templates', function ($q) use ($template_id) {
647                    $searchArray = ['_id' => $template_id];
648
649                    return $q->where($searchArray);
650                })
651                ->first();
652
653            if (!empty($categorydata) && (isset($categorydata->name)) && $categorydata->name != "General") {
654                $current_subscription = $this->getCurrentPlan($request->user());
655                $features = $current_subscription->features;
656
657                $can_access_flyplates = $features['FlyPlates'] ?? false;
658
659                if (! $can_access_flyplates) {
660                    return [
661                        'error' => true,
662                        'message' => 'You are not authorized to add flyplates'
663                    ];
664
665                    //abort(403, 'You are not authorized to add flyplates');
666                }
667
668                $flyplates_count = Shortcut::where(['user_defined' => false])->count();
669
670                if ($flyplates_count > $can_access_flyplates && $can_access_flyplates != -1) {
671                    return [
672                        'error' => true,
673                        'message' => Str::replaceArray('?', [$can_access_flyplates], 'You can not create more than ? flycut from flyplates with current plan')
674                    ];
675
676                    //abort(403, Str::replaceArray('?', [$can_access_flyplates], 'You can not create more than ? flycut from flyplates with current plan'));
677                }
678            }
679        }
680        return true;
681    }
682
683    protected function checkShortcutVersionRollBackCount(Request $request)
684    {
685        $current_subscription = $this->getCurrentPlan($request->user());
686        $features = $current_subscription->features;
687        $rollback_limit = $features['ShortcutVersionRollBack'] ?? 0;
688        $rollback_counts = Shortcut::where('_id', $request->shortcutId)->pluck('rollback_counts')->first();
689        if ($rollback_limit == 0) {
690            return [
691                'error' => true,
692                'message' => 'You are not authorized to roll back shortcut versions'
693            ];
694
695            //abort(403, 'You are not authorized to roll back shortcut versions');
696        }
697
698        if ($rollback_counts && ($rollback_counts >= $rollback_limit) && ($rollback_limit != -1)) {
699            return [
700                'error' => true,
701                'message' => Str::replaceArray('?', [$rollback_limit], 'You can not rollback more than ? shortcut versions')
702            ];
703
704            //abort(403, Str::replaceArray('?', [$rollback_limit], 'You can not rollback more than ? shortcut versions'));
705        }
706        return true;
707    }
708
709    /**
710     * Retrieve coupon object
711     *
712     * @param string $couponCode
713     * @return mixed
714     */
715    private function retrieveCouponObject(string $couponCode)
716    {
717        $stripe = new StripeClient(config('services.stripe.secret'));
718
719        return $stripe->coupons->retrieve($couponCode, ['expand' => ['applies_to']]);
720    }
721}