Skip to content

Commit 8c8d5c7

Browse files
author
serverpod_cloud
committed
feat(scloud): 6a9207869896eb2c3a88c9f6512b4afab7ac4a6d
1 parent 304765a commit 8c8d5c7

6 files changed

Lines changed: 83 additions & 3 deletions

File tree

serverpod_cloud_cli/lib/command_runner/cloud_cli_command.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:config/config.dart';
66
import 'package:serverpod_cloud_cli/command_logger/command_logger.dart';
77
import 'package:serverpod_cloud_cli/command_runner/cloud_cli_command_runner.dart';
88
import 'package:serverpod_cloud_cli/commands/auth/auth_login.dart';
9+
import 'package:serverpod_cloud_cli/commands/billing/billing_commands.dart';
910
import 'package:serverpod_cloud_cli/shared/exceptions/cloud_cli_usage_exception.dart';
1011
import 'package:serverpod_cloud_cli/shared/exceptions/exit_exceptions.dart';
1112
import 'package:serverpod_cloud_cli/shared/helpers/common_exceptions_handler.dart'
@@ -22,6 +23,10 @@ abstract class CloudCliCommand<O extends OptionDefinition>
2223
/// The default is true, subclasses can override to false.
2324
final bool requireLogin = true;
2425

26+
/// Whether to warn the user if their account is not in good standing.
27+
/// The default is true, subclasses can override to false.
28+
final bool warnIfBillingOverdue = true;
29+
2530
CloudCliCommand({required this.logger, super.options = const []})
2631
: super(wrapTextColumn: logger.wrapTextColumn);
2732

@@ -70,6 +75,15 @@ See the full documentation at: https://docs.serverpod.cloud/references/cli/comma
7075
);
7176
}
7277

78+
if (isAuthenticated &&
79+
warnIfBillingOverdue &&
80+
globalConfiguration.warnBillingOverdue) {
81+
await BillingCommands.warnIfOverdue(
82+
logger: logger,
83+
billing: runner.serviceProvider.cloudApiClient.billing,
84+
);
85+
}
86+
7387
await _runCommand();
7488
}
7589

serverpod_cloud_cli/lib/command_runner/cloud_cli_command_runner.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,15 @@ enum GlobalOption<V> implements OptionDefinition<V> {
483483
hide: true,
484484
),
485485
),
486+
warnBillingOverdue(
487+
FlagOption(
488+
argName: 'warn-billing-overdue',
489+
helpText: 'Enable / disable warning if the account has overdue payments.',
490+
defaultsTo: true,
491+
negatable: true,
492+
hide: true,
493+
),
494+
),
486495
consoleServer(
487496
StringOption(
488497
argName: 'console-url',
@@ -546,5 +555,7 @@ class GlobalConfiguration extends Configuration<GlobalOption> {
546555

547556
bool get skipConfirmation => value(GlobalOption.skipConfirmation);
548557

558+
bool get warnBillingOverdue => value(GlobalOption.warnBillingOverdue);
559+
549560
String? get authToken => optionalValue(GlobalOption.authToken);
550561
}

serverpod_cloud_cli/lib/command_runner/commands/auth_command.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import 'package:ground_control_client/ground_control_client.dart' show Client;
33
import 'package:serverpod_cloud_cli/command_runner/cloud_cli_command.dart';
44
import 'package:serverpod_cloud_cli/command_runner/helpers/command_options.dart';
55
import 'package:serverpod_cloud_cli/commands/auth/auth_login.dart';
6-
import 'package:serverpod_cloud_cli/shared/exceptions/exit_exceptions.dart';
76
import 'package:serverpod_cloud_cli/persistent_storage/resource_manager.dart';
7+
import 'package:serverpod_cloud_cli/shared/exceptions/exit_exceptions.dart';
88

99
import '../../commands/auth/auth.dart';
1010
import 'categories.dart';
@@ -75,6 +75,9 @@ class CloudLoginCommand extends CloudCliCommand<LoginCommandOption> {
7575
@override
7676
bool get requireLogin => false;
7777

78+
@override
79+
bool get warnIfBillingOverdue => false;
80+
7881
@override
7982
final name = 'login';
8083

serverpod_cloud_cli/lib/command_runner/commands/version_command.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ class VersionCommand extends CloudCliCommand {
77
@override
88
bool get requireLogin => false;
99

10+
@override
11+
bool get warnIfBillingOverdue => false;
12+
1013
@override
1114
final name = 'version';
1215

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'package:ground_control_client/ground_control_client.dart';
2+
import 'package:serverpod_cloud_cli/command_logger/command_logger.dart';
3+
4+
abstract class BillingCommands {
5+
/// Checks if the owner is in good standing and warns if not.
6+
static Future<void> warnIfOverdue({
7+
required final CommandLogger logger,
8+
required final EndpointBilling billing,
9+
}) async {
10+
final bool isInGoodStanding;
11+
try {
12+
isInGoodStanding = await billing.ownerIsInGoodStanding();
13+
} catch (e) {
14+
logger.debug('Failed to call [ownerIsInGoodStanding]: $e');
15+
return;
16+
}
17+
18+
if (isInGoodStanding) return;
19+
20+
Uri? billingPortalUrl;
21+
try {
22+
final Owner owner = await billing.readOwner();
23+
billingPortalUrl = owner.billingPortalUrl;
24+
} catch (e) {
25+
logger.debug('Failed to call [readOwner]: $e');
26+
}
27+
28+
_printOverdueWarning(logger: logger, billingPortalUrl: billingPortalUrl);
29+
}
30+
31+
static void _printOverdueWarning({
32+
required final CommandLogger logger,
33+
final Uri? billingPortalUrl,
34+
}) {
35+
var message =
36+
'Payment Overdue\n'
37+
'Update your payment method to avoid service interruption.';
38+
39+
if (billingPortalUrl != null) {
40+
message = '$message\n\nManage billing: $billingPortalUrl';
41+
}
42+
43+
logger.box(message, level: LogLevel.warning);
44+
}
45+
}

serverpod_cloud_cli/test_integration/commands/custom_domain_command/custom_domain_command_test.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import 'dart:async';
22
import 'dart:convert';
33
import 'dart:io';
44

5+
import 'package:ground_control_client/ground_control_client.dart';
56
import 'package:path/path.dart' as p;
67
import 'package:serverpod_cloud_cli/command_runner/cloud_cli_command_runner.dart';
78
import 'package:serverpod_cloud_cli/command_runner/commands/custom_domain_command.dart';
8-
import 'package:serverpod_cloud_cli/shared/exceptions/exit_exceptions.dart';
99
import 'package:serverpod_cloud_cli/persistent_storage/models/serverpod_cloud_auth_data.dart';
1010
import 'package:serverpod_cloud_cli/persistent_storage/resource_manager.dart';
11-
import 'package:ground_control_client/ground_control_client.dart';
11+
import 'package:serverpod_cloud_cli/shared/exceptions/exit_exceptions.dart';
1212
import 'package:test/test.dart';
1313

1414
import '../../../test_utils/command_logger_matchers.dart';
@@ -80,6 +80,7 @@ void main() {
8080
projectId,
8181
'--api-url',
8282
localServerAddress.toString(),
83+
'--no-warn-billing-overdue',
8384
'--config-dir',
8485
testCacheFolderPath,
8586
]);
@@ -116,6 +117,7 @@ void main() {
116117
projectId,
117118
'--api-url',
118119
localServerAddress.toString(),
120+
'--no-warn-billing-overdue',
119121
'--config-dir',
120122
testCacheFolderPath,
121123
]);
@@ -154,6 +156,7 @@ void main() {
154156
projectId,
155157
'--api-url',
156158
localServerAddress.toString(),
159+
'--no-warn-billing-overdue',
157160
'--config-dir',
158161
testCacheFolderPath,
159162
]);
@@ -191,6 +194,7 @@ void main() {
191194
projectId,
192195
'--api-url',
193196
localServerAddress.toString(),
197+
'--no-warn-billing-overdue',
194198
'--config-dir',
195199
testCacheFolderPath,
196200
]);

0 commit comments

Comments
 (0)