forked from admin/VolcanicAgenticCore
feat(google-calendar): /calendar_status and /calendar_disconnect, per-chat isolation tests
This commit is contained in:
@@ -32,3 +32,50 @@ internal static class ConnectCommand
|
||||
if (flow is not null) await flow.RunAsync(ctx.Ui, ctx.Logger).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary><c>/calendar_status</c>.</summary>
|
||||
internal static class StatusCommand
|
||||
{
|
||||
public const string Name = "calendar_status";
|
||||
public const string Description = "Show this chat's Google Calendar connection";
|
||||
|
||||
public static CommandDefinition Create(IExtensionApi api, GoogleCalendarExtension extension) => new(Description, (_, ctx, _) =>
|
||||
{
|
||||
var connection = extension.ConnectionFor(ctx.SessionManager.Scope);
|
||||
CommandReply.Send(api, ctx, Name, Describe(connection));
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
internal static string Describe(GoogleCalendarConnection connection)
|
||||
{
|
||||
if (connection.Pending is { } flow)
|
||||
{
|
||||
var d = flow.Device;
|
||||
return $"Waiting for approval: open {d.VerificationUrl} and enter {d.UserCode} ({ConnectFlow.MinutesLeft(d, connection.Settings.Time)} min left).";
|
||||
}
|
||||
if (connection.Store.Read() is not { } token) return "Not connected. Run /calendar_connect.";
|
||||
var since = token.ConnectedAt?.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture) ?? "an unknown date";
|
||||
return $"Connected as {token.Account ?? "an unknown account"} since {since}, time zone {token.TimeZone ?? "unknown"}.";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary><c>/calendar_disconnect</c>: cancel a pending flow, revoke (best effort), delete the file, drop the cache.</summary>
|
||||
internal static class DisconnectCommand
|
||||
{
|
||||
public const string Name = "calendar_disconnect";
|
||||
public const string Description = "Disconnect this chat's Google Calendar";
|
||||
|
||||
public static CommandDefinition Create(IExtensionApi api, GoogleCalendarExtension extension) => new(Description, async (_, ctx, ct) =>
|
||||
{
|
||||
var connection = extension.ConnectionFor(ctx.SessionManager.Scope);
|
||||
connection.CancelPending();
|
||||
var token = connection.Store.Read();
|
||||
var revokeError = token is null ? null : await connection.OAuth.RevokeAsync(token.RefreshToken, ct).ConfigureAwait(false);
|
||||
connection.Store.Delete();
|
||||
connection.Invalidate();
|
||||
var text = "Calendar disconnected.";
|
||||
if (revokeError is not null)
|
||||
text += $" Revoking at Google failed: {revokeError}; remove the app at {GoogleCalendarMessages.PermissionsUrl}.";
|
||||
CommandReply.Send(api, ctx, Name, text);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ public sealed class GoogleCalendarExtension(GoogleCalendarOptions? options = nul
|
||||
_settings = _options.Resolve()!;
|
||||
api.RegisterTool(new CalendarTool(_settings, Connections, CurrentZoneName));
|
||||
api.RegisterCommand(ConnectCommand.Name, ConnectCommand.Create(api, this));
|
||||
api.RegisterCommand(StatusCommand.Name, StatusCommand.Create(api, this));
|
||||
api.RegisterCommand(DisconnectCommand.Name, DisconnectCommand.Create(api, this));
|
||||
api.On<SessionStartEvent>((_, ctx, _) => Track(ctx));
|
||||
api.On<BeforeAgentStartEvent>((_, ctx, _) => Track(ctx));
|
||||
return ValueTask.CompletedTask;
|
||||
|
||||
Reference in New Issue
Block a user