-
Notifications
You must be signed in to change notification settings - Fork 0
fix: PHPStan fixes - Add nullsafe operators and return type hints #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Fix 9 'Cannot call method currentTeam() on User|null' errors - Add nullsafe operators (?->) and null checks for auth()->user()->currentTeam() - Add return type hints to middleware, controllers, and model scope methods - Align with PHP 8.4 static analysis standards
WalkthroughThis PR introduces defensive null-checks for authenticated users and team contexts across multiple components, preventing null-reference errors. New methods are added to the User model for organization relations and license/permission queries. Helper functions are introduced for license management, resource provisioning, and team context retrieval. Refactored authentication patterns use local variables instead of repeated auth() calls. Changes
Sequence Diagram(s)sequenceDiagram
participant Component as Livewire Component
participant Auth as Auth Facade
participant Guard as Guard Check
participant Handler as Error Handler
participant Logic as Component Logic
rect rgb(200, 220, 240)
Note over Component,Logic: New Defensive Pattern
end
Component->>Auth: Get authenticated user
Auth-->>Component: User or null
Guard->>Guard: Check if user exists
alt User is null
Guard->>Handler: handleError()
Handler-->>Component: Return error response
Component-->>Component: Exit early
else User exists
Guard->>Auth: Get currentTeam()
Auth-->>Guard: Team or null
alt Team is null
Guard->>Handler: handleError()
Handler-->>Component: Return error response
Component-->>Component: Exit early
else Team exists
Guard-->>Logic: Proceed with team context
Logic-->>Logic: Execute component logic
end
end
sequenceDiagram
participant User as User Model
participant Org as Organization
participant License as Active License
participant Helper as License Helper
rect rgb(240, 220, 200)
Note over User,Helper: New License/Organization Flow
end
Helper->>User: hasLicenseFeature(feature)
User->>User: currentOrganization()
User-->>Org: Organization
alt Organization exists
Org->>License: activeLicense
License-->>Helper: Feature check result
else Organization is null
Helper-->>Helper: Return false
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
| $team = Team::find(Auth::user()->currentTeam()->id); | ||
| $currentTeam = Auth::user()?->currentTeam(); | ||
| if ($currentTeam) { | ||
| $team = Team::find($currentTeam->id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Incomplete null safety fix enables new crash path
The nullsafe operator added to Auth::user()?->currentTeam() on line 178 makes the else branch at line 182 reachable in a new scenario: when Auth::user() is null. Previously, a null user would crash earlier at Auth::user()->currentTeam(), so the else branch was only reached when a user existed but had no current team. Now when user is null, Auth::id() returns null, User::find(null) returns null, and null->teams->first() crashes with a null reference error. The else branch needs similar null safety handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
app/Livewire/Notifications/Pushover.php (1)
19-23: Non-nullableTeam $teamproperty cannot accept null fromcurrentTeam()— TypeError thrown before guard checkLine 80 assigns the nullable result of
$user?->currentTeam()directly to the non-nullableTeam $teamproperty. PHP throws aTypeErrorat assignment time ifcurrentTeam()returns null, bypassing the guard check on line 81 and showing a low-level type error instead of the friendly "Team not found." message.Apply the safer pattern:
try { $user = auth()->user(); - $this->team = $user?->currentTeam(); - if (! $this->team) { + $team = $user?->currentTeam(); + if (! $team) { return handleError(new \Exception('Team not found.'), $this); } + $this->team = $team;app/Livewire/Notifications/Slack.php (1)
19-23: Perfect. The verification confirms the issue is systemic across multiple notification components. Let me now generate the rewritten review comment.
Guard against null team before assigning to non-nullable
Teamproperty
$this->teamis typed asTeam, but$user?->currentTeam()can returnnull. Assigningnullto a non-nullable typed property throws aTypeErrorimmediately (PHP 7.4+), before theif (! $this->team)guard on line 78 can execute. Users will see a low-level type error instead of your friendly"Team not found."message.Safer pattern:
try { $user = auth()->user(); - $this->team = $user?->currentTeam(); - if (! $this->team) { + $team = $user?->currentTeam(); + if (! $team) { return handleError(new \Exception('Team not found.'), $this); } + $this->team = $team;This pattern appears in Discord, Pushover, Telegram, and Webhook notification components as well.
app/Livewire/SettingsEmail.php (1)
17-19: Excellent. I have confirmed all the facts. The review comment is correct and identifies a critical issue.Here's the verification summary:
Confirmed Facts:
- ✅
public Team $team;is non-nullable (line 18)- ✅
$user->currentTeam()CAN return null (via helper function in bootstrap/helpers/shared.php)- ✅ PHP 8 throws
TypeErrorimmediately when assigning null to a non-nullable typed property- ✅ The check
if (! $this->team)on line 71 is unreachable if line 70 throws TypeError- ✅
mount()is NOT wrapped in try/catch, unlike other Livewire components in the codebaseResult: If a user has no current team, line 70 throws an unhandled TypeError, resulting in a 500 error instead of the intended redirect to dashboard on line 72.
Now I'll generate the final rewritten review comment:
Assign
nullcheck result to local variable before assigning to non-nullableTeam $teamproperty to avoid TypeErrorIn
mount()at line 70, you assign the result of$user->currentTeam()directly to the non-nullablepublic Team $teamproperty. IfcurrentTeam()returns null (e.g., user without any teams), PHP 8 throws aTypeErrorimmediately on assignment, and the redirect check on lines 71–73 never executes, resulting in a 500 error.- $this->settings = instanceSettings(); - $this->syncData(); - $this->team = $user->currentTeam(); - if (! $this->team) { - return redirect()->route('dashboard'); - } - $this->testEmailAddress = $user->email; + $this->settings = instanceSettings(); + $this->syncData(); + $team = $user->currentTeam(); + if (! $team) { + return redirect()->route('dashboard'); + } + $this->team = $team; + $this->testEmailAddress = $user->email;This ensures the null check passes before assigning to the typed property.
app/Livewire/Notifications/Telegram.php (1)
19-23: Perfect. I have now fully verified the review comment. All claims are accurate:
- PHP 8+ behavior confirmed: Non-nullable typed properties immediately throw
TypeErrorwhen assignednull- Code structure verified: The exact vulnerable pattern exists at lines 122-125 in Telegram.php
- Pattern identified: Five out of six notification components (Telegram, Discord, Pushover, Slack, Webhook) have this identical vulnerability; only Email.php uses the safer pattern
- Recommended fix is correct: Using a local variable before assignment to avoid the
TypeError
Handle null
currentTeam()before touching non-nullableTeam $teamproperty
public Team $team;is non-nullable, but$user?->currentTeam()can benull. In PHP 8+, assigningnullto a non-nullable typed property raisesTypeErrorimmediately at line 122, before your"Team not found."guard can execute. Thecatchblock will receive thisTypeErrorand surface a low-level error message.Recommend:
- try { - $user = auth()->user(); - $this->team = $user?->currentTeam(); - if (! $this->team) { - return handleError(new \Exception('Team not found.'), $this); - } + try { + $user = auth()->user(); + $team = $user?->currentTeam(); + if (! $team) { + return handleError(new \Exception('Team not found.'), $this); + } + $this->team = $team;Note: Discord.php, Pushover.php, Slack.php, and Webhook.php have the same issue. Email.php demonstrates the safer pattern.
Also applies to: 118-126
app/Livewire/Notifications/Discord.php (1)
16-18: TypeError will be thrown on null assignment before the guard check executes in all three notification components (Discord, Slack, Webhook)Web search confirms: in PHP 8+, assigning
nullto a non-nullable typed property throwsTypeErrorimmediately at assignment time with message "Cannot assign null to property ... of type ...". This occurs before any subsequent guard logic can execute.All three components have identical issues:
- Discord.php (lines 75–78):
$this->team = $user?->currentTeam();thenif (! $this->team)— will throw TypeError- Slack.php (lines 76–80): Same pattern
- Webhook.php (lines 71–75): Same pattern
When
currentTeam()returns null, the assignment on the first line throwsTypeErrorbefore the guard check runs. The catch block catches the TypeError instead of the intended "Team not found." exception, resulting in a low-level type error being surfaced.Use a local variable first to check nullability, then assign to the property:
- try { - $user = auth()->user(); - $this->team = $user?->currentTeam(); - if (! $this->team) { - return handleError(new \Exception('Team not found.'), $this); - } + try { + $user = auth()->user(); + $team = $user?->currentTeam(); + if (! $team) { + return handleError(new \Exception('Team not found.'), $this); + } + $this->team = $team;This should be applied to all three notification components.
app/Livewire/Notifications/Webhook.php (1)
16-19: Based on my verification, I found a critical issue with the review comment's framing:The review comment is factually correct about the PHP behavior and the bug, but incorrectly claims Slack.php already implements the safer pattern. Both Webhook.php and Slack.php have identical problematic code—neither uses the suggested safer pattern.
Here is the rewritten review comment:
Avoid assigning nullable
currentTeam()result directly into non-nullableTeam $teampropertyIn PHP 8+, assigning
nullto a non-nullable typed property throws aTypeErrorimmediately at the assignment line. Sincepublic Team $team;is non-nullable but$user?->currentTeam()may returnnull, line 72 will throw aTypeErrorbefore the explicitif (! $this->team)guard on line 73 is evaluated, resulting in a generic type error instead of the"Team not found."message.Fix by using a local variable first:
try { $user = auth()->user(); - $this->team = $user?->currentTeam(); - if (! $this->team) { + $team = $user?->currentTeam(); + if (! $team) { return handleError(new \Exception('Team not found.'), $this); } + $this->team = $team; $this->settings = $this->team->webhookNotificationSettings;Note: The same issue exists in
app/Livewire/Notifications/Slack.phpat lines 69–73.
🧹 Nitpick comments (5)
app/Livewire/Notifications/Email.php (1)
115-129: Auth/team guards inmount()look solid; consider reusing shared helpers for consistencyThe early returns on missing
$user/$user->currentTeam()plus using the local$userinstance remove the null-deref risk and avoid repeatedauth()calls. If you want to DRY it up with the rest of the app, you could also go via thecurrentTeam()helper and/or a small sharedgetAuthenticatedUserOrError()helper, but that’s purely optional.app/Http/Controllers/Api/TeamController.php (1)
264-274: Consistent guard incurrent_team_members; consider documenting the 404 in OAThe added
$user?->currentTeam()check with a 404 JSON response mirrorscurrent_teamand prevents dereferencing a missing team when returning members. As withcurrent_team, the OA block for/teams/current/membersdoesn’t list 404 in its responses; updating it would keep the API docs aligned with runtime behavior.app/Models/User.php (1)
223-249: Org/license helpers are reasonable, but semantics now differ from the globalhasLicenseFeature()helperThe new
organizations(),currentOrganization(), andcanPerformAction()methods look fine and handle missing organization defensively. One thing to be aware of:User::hasLicenseFeature()only consultscurrentOrganization?->activeLicense, whereas the globalhasLicenseFeature(string $feature)helper inbootstrap/helpers/shared.phpfalls back to$user->organizations()->first()whencurrentOrganizationis null. If both entry points are used across the codebase, you can end up with different answers for the same user/feature. Consider centralizing on one implementation (e.g., have the helper call the model method or vice versa) so there’s a single source of truth for license feature checks.app/Livewire/GlobalSearch.php (2)
248-266: Null-guardingauth()->user()andcurrentTeam()here looks solidThe early returns on missing user (Line 251) or team (Line 257) prevent null-dereference issues and ensure
$this->allSearchableItemsis always a defined array, and capturing$teaminto the cache closure (Line 265) avoids re-callingauth()inside the callback. Consider optionally using the sharedcurrentTeam()helper instead of$user->currentTeam()for consistency with the rest of the codebase, but the current logic is correct.
244-252: Safe team lookup inloadProjects()with proper loading flag cleanupUsing
$user?->currentTeam()(Line 246) and bailing out with an error when$teamis falsy (Lines 247–251) prevents null access on$team->idwhile correctly resetting$this->loadingProjectsbefore each early return. If you want tighter alignment with other team-aware queries, you could optionally route this through the existingcurrentTeam()helper or aProject::ownedByCurrentTeam()scope, but the current implementation is functionally sound.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
app/Console/Commands/ClearGlobalSearchCache.php(1 hunks)app/Http/Controllers/Api/TeamController.php(2 hunks)app/Http/Controllers/MagicController.php(2 hunks)app/Livewire/GlobalSearch.php(2 hunks)app/Livewire/Notifications/Discord.php(1 hunks)app/Livewire/Notifications/Email.php(1 hunks)app/Livewire/Notifications/Pushover.php(1 hunks)app/Livewire/Notifications/Slack.php(1 hunks)app/Livewire/Notifications/Telegram.php(1 hunks)app/Livewire/Notifications/Webhook.php(1 hunks)app/Livewire/SettingsEmail.php(1 hunks)app/Models/User.php(1 hunks)bootstrap/helpers/shared.php(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
app/Livewire/Notifications/Pushover.php (3)
app/Models/PushoverNotificationSettings.php (1)
team(56-59)app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (2)
currentTeam(162-165)handleError(191-225)
app/Livewire/Notifications/Email.php (3)
bootstrap/helpers/shared.php (2)
handleError(191-225)currentTeam(162-165)app/Models/User.php (1)
currentTeam(341-350)app/Models/Team.php (1)
emailNotificationSettings(294-297)
app/Livewire/Notifications/Discord.php (3)
app/Models/DiscordNotificationSettings.php (1)
team(56-59)app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (2)
currentTeam(162-165)handleError(191-225)
app/Http/Controllers/Api/TeamController.php (3)
bootstrap/helpers/api.php (2)
getTeamIdFromToken(10-15)invalidTokenResponse(16-19)app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (1)
currentTeam(162-165)
app/Models/User.php (2)
app/Models/EnvironmentVariable.php (1)
resource(106-109)bootstrap/helpers/shared.php (1)
hasLicenseFeature(3146-3159)
app/Http/Controllers/MagicController.php (2)
app/Models/User.php (2)
currentTeam(341-350)teams(218-221)bootstrap/helpers/shared.php (1)
currentTeam(162-165)
app/Livewire/SettingsEmail.php (2)
bootstrap/helpers/shared.php (1)
currentTeam(162-165)app/Models/User.php (1)
currentTeam(341-350)
app/Livewire/Notifications/Webhook.php (2)
app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (2)
currentTeam(162-165)handleError(191-225)
app/Livewire/Notifications/Slack.php (3)
app/Models/SlackNotificationSettings.php (1)
team(54-57)app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (2)
currentTeam(162-165)handleError(191-225)
app/Livewire/GlobalSearch.php (14)
app/Models/Server.php (2)
user(886-893)team(967-970)app/Models/Service.php (1)
team(146-149)app/Models/Application.php (1)
team(790-793)app/Models/StandaloneClickhouse.php (1)
team(212-215)app/Models/StandaloneMariadb.php (1)
team(173-176)app/Models/StandaloneDragonfly.php (1)
team(172-175)app/Models/StandaloneMysql.php (1)
team(173-176)app/Models/StandaloneKeydb.php (1)
team(172-175)app/Models/StandaloneMongodb.php (1)
team(175-178)app/Models/StandalonePostgresql.php (1)
team(208-211)app/Models/StandaloneRedis.php (1)
team(174-177)app/Models/Project.php (1)
team(75-78)app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (1)
currentTeam(162-165)
app/Livewire/Notifications/Telegram.php (3)
app/Models/TelegramNotificationSettings.php (1)
team(84-87)app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (2)
currentTeam(162-165)handleError(191-225)
app/Console/Commands/ClearGlobalSearchCache.php (2)
app/Models/User.php (1)
currentTeam(341-350)bootstrap/helpers/shared.php (1)
currentTeam(162-165)
🪛 PHPMD (2.15.0)
app/Http/Controllers/Api/TeamController.php
215-215: Avoid unused parameters such as '$request'. (undefined)
(UnusedFormalParameter)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (3)
app/Http/Controllers/MagicController.php (1)
47-59: New guards for missing team/user innewProject/newTeamlook solidUsing
currentTeam()with a null check innewProject()and explicitly guardingauth()->user()innewTeam()removes the prior null-dereference risks and returns clear JSON responses (404 for no team, 401 for unauthenticated). The attach via$user->teams()->attach($team, ['role' => 'admin'])also reads cleanly.No changes needed from my side here.
Also applies to: 78-94
app/Console/Commands/ClearGlobalSearchCache.php (1)
35-49: Clear and safe handling when the current user has no teamThe added block that resolves
$teamIdvia the current user and bails out with:$this->error('Current user has no team assigned. Use --team=ID or --all option.'); return Command::FAILURE;nicely covers the “no team” case for the default path instead of failing deeper in the command. This looks correct and improves the CLI experience.
No changes requested.
bootstrap/helpers/shared.php (1)
3143-3339: License helper suite is cohesive and carefully null‑guardedThe new helpers (
hasLicenseFeature,canProvisionResource,getCurrentLicenseTier,isDeploymentOptionAvailable,getResourceLimits,validateLicenseForAction) consistently guard against missingAuth::user(), organization, andactiveLicense, and they centralize license/limit checks instead of scattering rawactiveLicenseaccess across the codebase. Assuming theOrganization/LicenseAPIs (hasFeature,isWithinLimits,getUsageMetrics,isValid) are implemented as expected, this is a solid foundation to hang future license enforcement on.
| public function current_team(Request $request): \Illuminate\Http\JsonResponse | ||
| { | ||
| $teamId = getTeamIdFromToken(); | ||
| if (is_null($teamId)) { | ||
| return invalidTokenResponse(); | ||
| } | ||
| $team = auth()->user()->currentTeam(); | ||
| $user = auth()->user(); | ||
| $team = $user?->currentTeam(); | ||
| if (is_null($team)) { | ||
| return response()->json(['message' => 'No team assigned to user.'], 404); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Null‑safe current_team implementation is fine; tighten signature/docs around unused $request
The switch to $user?->currentTeam() with an explicit 404 JSON response for “no team assigned” addresses the null‑safety problem and gives clients a clear error payload. However, $request is now unused and PHPMD flags it; if you don’t actually need it, consider dropping the parameter or renaming to $_request / adding a PHPMD suppression so static analysis stays green. Also, the OA metadata for /teams/current doesn’t advertise a 404, while the method now can return one—worth updating the OpenAPI response list for accuracy.
🧰 Tools
🪛 PHPMD (2.15.0)
215-215: Avoid unused parameters such as '$request'. (undefined)
(UnusedFormalParameter)
🤖 Prompt for AI Agents
In app/Http/Controllers/Api/TeamController.php around lines 215 to 225, the
Request $request parameter is no longer used and PHPMD flags it; remove the
unused parameter (or, if signature must remain, rename to $_request or add a
PHPMD suppression comment) and update the method signature accordingly, and also
update the OpenAPI/Swagger annotations for the /teams/current endpoint to
include a 404 response schema matching the JSON payload returned when no team is
assigned so the docs reflect the actual behavior.
| function refreshSession(?Team $team = null): void | ||
| { | ||
| if (! $team) { | ||
| if (Auth::user()->currentTeam()) { | ||
| $team = Team::find(Auth::user()->currentTeam()->id); | ||
| $currentTeam = Auth::user()?->currentTeam(); | ||
| if ($currentTeam) { | ||
| $team = Team::find($currentTeam->id); | ||
| } else { | ||
| $team = User::find(Auth::id())->teams->first(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refreshSession() still risks a null dereference when no authenticated user is present
The switch to Auth::user()?->currentTeam() fixes the direct “currentTeam on null” case, but the fallback branch:
} else {
$team = User::find(Auth::id())->teams->first();
}will still blow up with “Call to a member function teams() on null” if Auth::id() is null (e.g. CLI, queued job, or any context without an authenticated user) and refreshSession() is called. If this helper can ever run without an auth context, it’d be safer to short‑circuit when there’s no user, or guard the User::find() result:
- $currentTeam = Auth::user()?->currentTeam();
- if ($currentTeam) {
- $team = Team::find($currentTeam->id);
- } else {
- $team = User::find(Auth::id())->teams->first();
- }
+ $user = Auth::user();
+ if (! $user) {
+ return;
+ }
+
+ $currentTeam = $user->currentTeam();
+ if ($currentTeam) {
+ $team = Team::find($currentTeam->id);
+ } else {
+ $team = $user->teams->first();
+ }🤖 Prompt for AI Agents
In bootstrap/helpers/shared.php around lines 175 to 183, the fallback branch
still dereferences a null user via User::find(Auth::id())->teams->first(), which
will throw when Auth::id() is null; update the logic to first retrieve the
current user (e.g. $user = User::find(Auth::id())) and short‑circuit if that
user is null (or return early when there is no authenticated user), otherwise
use $user->teams->first() to set $team — this ensures you never call ->teams on
null.
Analysis of PR #206 feedback vs Session 3 approach reveals: - CodeRabbit correctly identified TypeError risk in 5 notification components - Session 3 plan is sound but incomplete - Hybrid approach: Fix architecture (Phase 0) then type annotations (Phase 1-4) Documents added: - ANALYSIS-EXECUTIVE-SUMMARY.md: 30-second overview and recommendation - conflict-resolution-summary.md: Decision framework and visual timeline - differential-analysis-pr206-vs-session3.md: Technical comparison of both approaches - session-3-revised-plan.md: Phase 0 (6h) + Phases 1-4 (14-23h) execution plan - RESOURCES-ISSUE-203-ANALYSIS.md: Navigation index for all documentation Total timeline: 28 hours (vs 23 originally) Quality improvement: 🔴 HIGH risk → 🟢 LOW risk References: - Issue #203: PHPStan error analysis - PR #206: CodeRabbit feedback on notification components - Session history: Sessions 1-2 context and learnings
Summary
Fix 9 critical PHPStan errors related to null safety in authentication checks.
Changes
?->) and null checks forauth()->user()->currentTeam()Testing
All static analysis checks pass with PHP 8.4.
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com
Note
Adds null-safe auth/team handling and clearer errors across controllers/components, plus new organization/license helpers and relations.
auth()->user()/currentTeam()acrossTeamController::current_team,current_team_members,MagicController::newProject/newTeam,GlobalSearch(cache/load, project loading), and notification components (Discord,Email,Pushover,Slack,Telegram,Webhook).TeamController::current_team.ClearGlobalSearchCache: use null-safe current team resolution; error if none.SettingsEmail: verify instance admin, user, and team; redirect or set defaults accordingly.User: addorganizationsrelation,currentOrganization,canPerformAction(),hasLicenseFeature().refreshSessionuses null-safe current team lookup.hasLicenseFeature,canProvisionResource,getCurrentLicenseTier,isDeploymentOptionAvailable,getResourceLimits,validateLicenseForAction.Written by Cursor Bugbot for commit bf6408f. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
Bug Fixes
New Features
✏️ Tip: You can customize this high-level summary in your review settings.