feat(server): add flag for calendar enable (#14896)

#### PR Dependency Tree


* **PR #14896** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added configuration option to manage Google Calendar account linking
access. Administrators can now disable new account connections to
control calendar service integrations. When disabled, the Google
provider is hidden from available options and new linking attempts are
blocked, while existing accounts remain fully functional.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-05-04 03:45:49 +08:00
committed by GitHub
parent 027d163921
commit fa66139230
5 changed files with 117 additions and 2 deletions
@@ -154,6 +154,11 @@ export class CalendarService {
const provider = this.requireProvider(params.provider);
const tokens = await provider.exchangeCode(params.code, params.redirectUri);
const profile = await provider.getAccountProfile(tokens.accessToken);
await this.assertCanPersistProviderAccount(
params.userId,
params.provider,
profile.providerAccountId
);
const account = await this.models.calendarAccount.upsert({
userId: params.userId,
@@ -565,6 +570,19 @@ export class CalendarService {
return true;
}
async assertCanLinkProvider(userId: string, provider: CalendarProviderName) {
if (this.canCreateNewAccounts(provider)) {
return;
}
const accounts = await this.models.calendarAccount.listByUser(userId);
if (accounts.some(account => account.provider === provider)) {
return;
}
throw this.providerLinkDisabledError(provider);
}
getAuthUrl(
provider: CalendarProviderName,
state: string,
@@ -580,6 +598,41 @@ export class CalendarService {
return instance.getAuthUrl(state, redirectUri);
}
private async assertCanPersistProviderAccount(
userId: string,
provider: CalendarProviderName,
providerAccountId: string
) {
if (this.canCreateNewAccounts(provider)) {
return;
}
const account = await this.models.calendarAccount.getByProviderAccount(
userId,
provider,
providerAccountId
);
if (account) {
return;
}
throw this.providerLinkDisabledError(provider);
}
private canCreateNewAccounts(provider: CalendarProviderName) {
return (
provider !== CalendarProviderName.Google ||
this.config.calendar.google.allowNewAccounts !== false
);
}
private providerLinkDisabledError(provider: CalendarProviderName) {
return new GraphqlBadRequest({
code: 'calendar_provider_link_disabled',
message: `${provider} calendar account linking is disabled.`,
});
}
private async syncWithProvider(params: {
provider: CalendarProvider;
subscriptionId: string;