33from collections .abc import Callable
44from dataclasses import dataclass
55
6- from sentry import features , quotas
7- from sentry .constants import (
8- ENABLE_PR_REVIEW_TEST_GENERATION_DEFAULT ,
9- HIDE_AI_FEATURES_DEFAULT ,
10- DataCategory ,
11- )
6+ from sentry import features
7+ from sentry .constants import ENABLE_PR_REVIEW_TEST_GENERATION_DEFAULT , HIDE_AI_FEATURES_DEFAULT
128from sentry .models .organization import Organization
13- from sentry .models .organizationcontributors import OrganizationContributors
149from sentry .models .repository import Repository
10+ from sentry .models .repositorysettings import CodeReviewSettings , RepositorySettings
1511
16- from .settings import CodeReviewSettings , get_code_review_settings
12+ from .billing import passes_code_review_billing_check
1713
1814DenialReason = str | None
1915
@@ -31,14 +27,15 @@ def __init__(
3127 organization : Organization ,
3228 repo : Repository ,
3329 integration_id : int | None = None ,
34- external_identifier : str | None = None ,
30+ pr_author_external_id : str | None = None ,
3531 ):
3632 self .organization = organization
3733 self .repo = repo
3834 self .integration_id = integration_id
39- self .external_identifier = external_identifier
40- self ._repo_settings : CodeReviewSettings | None = None
41- self ._repo_settings_loaded = False
35+ self .pr_author_external_id = pr_author_external_id
36+
37+ repo_settings = RepositorySettings .objects .filter (repository = repo ).first ()
38+ self ._repo_settings = repo_settings .get_code_review_settings () if repo_settings else None
4239
4340 def check (self ) -> CodeReviewPreflightResult :
4441 checks : list [Callable [[], DenialReason ]] = [
@@ -53,13 +50,7 @@ def check(self) -> CodeReviewPreflightResult:
5350 if denial_reason is not None :
5451 return CodeReviewPreflightResult (allowed = False , denial_reason = denial_reason )
5552
56- return CodeReviewPreflightResult (allowed = True , settings = self ._get_repo_settings ())
57-
58- def _get_repo_settings (self ) -> CodeReviewSettings | None :
59- if not self ._repo_settings_loaded :
60- self ._repo_settings = get_code_review_settings (self .repo )
61- self ._repo_settings_loaded = True
62- return self ._repo_settings
53+ return CodeReviewPreflightResult (allowed = True , settings = self ._repo_settings )
6354
6455 # -------------------------------------------------------------------------
6556 # Checks - each returns denial reason (str) or None if valid
@@ -90,8 +81,7 @@ def _check_org_feature_enablement(self) -> DenialReason:
9081
9182 def _check_repo_feature_enablement (self ) -> DenialReason :
9283 if self ._is_seat_based_seer_plan_org ():
93- settings = self ._get_repo_settings ()
94- if settings is None or not settings .enabled :
84+ if self ._repo_settings is None or not self ._repo_settings .enabled :
9585 return "repo_code_review_disabled"
9686 return None
9787 elif self ._is_code_review_beta_org ():
@@ -101,28 +91,15 @@ def _check_repo_feature_enablement(self) -> DenialReason:
10191 return "repo_code_review_disabled"
10292
10393 def _check_billing (self ) -> DenialReason :
104- # Check if contributor exists, and if there's either a seat or quota available.
105- # NOTE: We explicitly check billing as the source of truth because if the contributor exists,
106- # then that means that they've opened a PR before, and either have a seat already OR it's their
107- # "Free action."
108- if self .integration_id is None or self .external_identifier is None :
94+ if self .integration_id is None or self .pr_author_external_id is None :
10995 return "billing_missing_contributor_info"
11096
111- try :
112- contributor = OrganizationContributors .objects .get (
113- organization_id = self .organization .id ,
114- integration_id = self .integration_id ,
115- external_identifier = self .external_identifier ,
116- )
117- except OrganizationContributors .DoesNotExist :
118- return "billing_contributor_not_found"
119-
120- has_quota = quotas .backend .check_seer_quota (
121- org_id = self .organization .id ,
122- data_category = DataCategory .SEER_USER ,
123- seat_object = contributor ,
97+ billing_ok = passes_code_review_billing_check (
98+ organization_id = self .organization .id ,
99+ integration_id = self .integration_id ,
100+ external_identifier = self .pr_author_external_id ,
124101 )
125- if not has_quota :
102+ if not billing_ok :
126103 return "billing_quota_exceeded"
127104
128105 return None
0 commit comments