Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
syntax = "proto3";

package sentry_protos.billing.v1.services.account_status.v1;

import "sentry_protos/billing/v1/services/account_status/v1/account_status.proto";

// Creates or updates the account status for an organization. If no record
// exists for the given organization_id, one is created. If a record already
// exists, it is updated with the provided fields.
message UpsertAccountStatusRequest {
uint64 organization_id = 1;
optional Status status = 2;
optional string suspension_reason = 3;
optional OnDemandStatus ondemand_status = 4;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request duplicates entity fields instead of embedding message

Medium Severity

UpsertAccountStatusRequest duplicates every field from AccountStatus (same types, tags, and optionality) instead of embedding AccountStatus as a nested message — the pattern already used by GetAccountStatusResponse. If AccountStatus gains a new field in the future, it would need to be manually added to this request message as well, risking silent data loss on upserts when the two definitions fall out of sync.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 41ca379. Configure here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's okay, we don't want the caller to need to know the shape of the account status proto


message UpsertAccountStatusResponse {
// True if a new record was created or an existing record was modified.
// False if the record already existed with identical field values.
bool updated = 1;
}
54 changes: 54 additions & 0 deletions py/tests/test_billing_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
GetAccountStatusRequest,
GetAccountStatusResponse,
)
from sentry_protos.billing.v1.services.account_status.v1.endpoint_upsert_account_status_pb2 import (
UpsertAccountStatusRequest,
UpsertAccountStatusResponse,
)
from sentry_protos.billing.v1.data_category_pb2 import DataCategory
from sentry_protos.billing.v1.quota_config_pb2 import QuotaConfig, QuotaScope

Expand Down Expand Up @@ -624,3 +628,53 @@ def test_get_account_status_response_empty():
assert not response.HasField("account_status")


def test_upsert_account_status_request():
request = UpsertAccountStatusRequest(
organization_id=12345,
status=Status.STATUS_ACTIVE,
ondemand_status=OnDemandStatus.ON_DEMAND_STATUS_ENABLED,
)
assert request.organization_id == 12345
assert request.HasField("status")
assert request.status == Status.STATUS_ACTIVE
assert not request.HasField("suspension_reason")
assert request.HasField("ondemand_status")
assert request.ondemand_status == OnDemandStatus.ON_DEMAND_STATUS_ENABLED

serialized = request.SerializeToString()
parsed = UpsertAccountStatusRequest()
parsed.ParseFromString(serialized)
assert parsed.organization_id == 12345
assert parsed.status == Status.STATUS_ACTIVE
assert parsed.ondemand_status == OnDemandStatus.ON_DEMAND_STATUS_ENABLED

partial_request = UpsertAccountStatusRequest(organization_id=99)
assert not partial_request.HasField("status")
assert not partial_request.HasField("suspension_reason")
assert not partial_request.HasField("ondemand_status")


def test_upsert_account_status_request_with_suspension():
request = UpsertAccountStatusRequest(
organization_id=99,
status=Status.STATUS_SUSPENDED,
suspension_reason="tos_violation",
ondemand_status=OnDemandStatus.ON_DEMAND_STATUS_DISABLED,
)
assert request.status == Status.STATUS_SUSPENDED
assert request.HasField("suspension_reason")
assert request.suspension_reason == "tos_violation"
assert request.ondemand_status == OnDemandStatus.ON_DEMAND_STATUS_DISABLED


def test_upsert_account_status_response():
updated_response = UpsertAccountStatusResponse(updated=True)
assert updated_response.updated is True

not_updated_response = UpsertAccountStatusResponse(updated=False)
assert not_updated_response.updated is False

default_response = UpsertAccountStatusResponse()
assert default_response.updated is False


21 changes: 21 additions & 0 deletions rust/src/sentry_protos.billing.v1.services.account_status.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,24 @@ pub struct GetAccountStatusResponse {
#[prost(message, optional, tag = "1")]
pub account_status: ::core::option::Option<AccountStatus>,
}
/// Creates or updates the account status for an organization. If no record
/// exists for the given organization_id, one is created. If a record already
/// exists, it is updated with the provided fields.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpsertAccountStatusRequest {
#[prost(uint64, tag = "1")]
pub organization_id: u64,
#[prost(enumeration = "Status", optional, tag = "2")]
pub status: ::core::option::Option<i32>,
#[prost(string, optional, tag = "3")]
pub suspension_reason: ::core::option::Option<::prost::alloc::string::String>,
#[prost(enumeration = "OnDemandStatus", optional, tag = "4")]
pub ondemand_status: ::core::option::Option<i32>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpsertAccountStatusResponse {
/// True if a new record was created or an existing record was modified.
/// False if the record already existed with identical field values.
#[prost(bool, tag = "1")]
pub updated: bool,
}
Loading