Skip to content

Commit 3a6f200

Browse files
committed
updated telemtry consent
1 parent 6990ead commit 3a6f200

File tree

7 files changed

+618
-38
lines changed

7 files changed

+618
-38
lines changed

ThingConnect.Pulse.Server/Controllers/AuthController.cs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.AspNetCore.Mvc;
44
using ThingConnect.Pulse.Server.Data;
55
using ThingConnect.Pulse.Server.Models;
6+
using ThingConnect.Pulse.Server.Services;
67

78
namespace ThingConnect.Pulse.Server.Controllers;
89

@@ -13,15 +14,18 @@ public sealed class AuthController : ControllerBase
1314
private readonly UserManager<ApplicationUser> _userManager;
1415
private readonly SignInManager<ApplicationUser> _signInManager;
1516
private readonly ILogger<AuthController> _logger;
17+
private readonly ISettingsService _settingsService;
1618

1719
public AuthController(
1820
UserManager<ApplicationUser> userManager,
1921
SignInManager<ApplicationUser> signInManager,
20-
ILogger<AuthController> logger)
22+
ILogger<AuthController> logger,
23+
ISettingsService settingsService)
2124
{
2225
_userManager = userManager;
2326
_signInManager = signInManager;
2427
_logger = logger;
28+
_settingsService = settingsService;
2529
}
2630

2731
/// <summary>
@@ -118,7 +122,14 @@ public async Task<ActionResult<UserInfoDto>> RegisterAsync([FromBody] RegisterRe
118122
return BadRequest(new { message = "Registration failed", errors });
119123
}
120124

121-
_logger.LogInformation("Initial admin user created: {Username} (ID: {UserId})", user.UserName, user.Id);
125+
// Sign in the user immediately after successful registration
126+
await _signInManager.SignInAsync(user, isPersistent: true);
127+
128+
// Update last login time since we just signed them in
129+
user.LastLoginAt = DateTimeOffset.UtcNow;
130+
await _userManager.UpdateAsync(user);
131+
132+
_logger.LogInformation("Initial admin user created and signed in: {Username} (ID: {UserId})", user.UserName, user.Id);
122133

123134
return Ok(new UserInfoDto
124135
{
@@ -250,4 +261,53 @@ public async Task<IActionResult> LogoutAsync()
250261
return StatusCode(500, new { message = "Internal server error" });
251262
}
252263
}
264+
265+
/// <summary>
266+
/// Save telemetry consent settings during onboarding
267+
/// </summary>
268+
[HttpPost("telemetry-consent")]
269+
public async Task<IActionResult> SaveTelemetryConsentAsync([FromBody] TelemetryConsentDto request)
270+
{
271+
try
272+
{
273+
// Save telemetry consent settings
274+
await _settingsService.SetAsync("telemetry_error_diagnostics", request.ErrorDiagnostics.ToString().ToLowerInvariant());
275+
await _settingsService.SetAsync("telemetry_usage_analytics", request.UsageAnalytics.ToString().ToLowerInvariant());
276+
await _settingsService.SetAsync("telemetry_consent_timestamp", DateTimeOffset.UtcNow);
277+
278+
_logger.LogInformation("Telemetry consent saved: ErrorDiagnostics={ErrorDiagnostics}, UsageAnalytics={UsageAnalytics}",
279+
request.ErrorDiagnostics, request.UsageAnalytics);
280+
281+
return Ok(new { message = "Telemetry consent saved successfully" });
282+
}
283+
catch (Exception ex)
284+
{
285+
_logger.LogError(ex, "Error saving telemetry consent");
286+
return StatusCode(500, new { message = "Internal server error" });
287+
}
288+
}
289+
290+
/// <summary>
291+
/// Get current telemetry consent settings
292+
/// </summary>
293+
[HttpGet("telemetry-consent")]
294+
public async Task<ActionResult<TelemetryConsentDto>> GetTelemetryConsentAsync()
295+
{
296+
try
297+
{
298+
string? errorDiagnostics = await _settingsService.GetAsync("telemetry_error_diagnostics");
299+
string? usageAnalytics = await _settingsService.GetAsync("telemetry_usage_analytics");
300+
301+
return Ok(new TelemetryConsentDto
302+
{
303+
ErrorDiagnostics = bool.TryParse(errorDiagnostics, out bool errorValue) && errorValue,
304+
UsageAnalytics = bool.TryParse(usageAnalytics, out bool usageValue) && usageValue
305+
});
306+
}
307+
catch (Exception ex)
308+
{
309+
_logger.LogError(ex, "Error getting telemetry consent");
310+
return StatusCode(500, new { message = "Internal server error" });
311+
}
312+
}
253313
}

ThingConnect.Pulse.Server/Models/AuthDtos.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,10 @@ public sealed class ChangePasswordDto
101101
[Required]
102102
[Compare("NewPassword")]
103103
public string ConfirmPassword { get; set; } = default!;
104+
}
105+
106+
public sealed class TelemetryConsentDto
107+
{
108+
public bool ErrorDiagnostics { get; set; }
109+
public bool UsageAnalytics { get; set; }
104110
}

delete-database.ps1

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Delete ThingConnect Pulse Database
2+
# This script removes the database files from the ProgramData directory
3+
4+
$DatabasePath = "C:\ProgramData\ThingConnect.Pulse\data"
5+
6+
Write-Host "Checking for database at: $DatabasePath" -ForegroundColor Yellow
7+
8+
if (Test-Path $DatabasePath) {
9+
try {
10+
Remove-Item -Path $DatabasePath -Recurse -Force
11+
Write-Host "Database deleted successfully!" -ForegroundColor Green
12+
}
13+
catch {
14+
Write-Host "Error deleting database: $($_.Exception.Message)" -ForegroundColor Red
15+
exit 1
16+
}
17+
}
18+
else {
19+
Write-Host "Database directory not found at: $DatabasePath" -ForegroundColor Yellow
20+
}
21+
22+
Write-Host "Operation completed." -ForegroundColor Cyan

thingconnect.pulse.client/src/features/auth/components/OnboardingPage.tsx

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,23 @@ import { LoadingButton } from '@/components/form/LoadingButton';
1616
import { AuthLayout } from '@/components/layout/AuthLayout';
1717
import { useAuth } from '../context/AuthContext';
1818
import { PageLoader } from '@/components/PageLoader';
19+
import { Switch } from '@/components/ui/switch';
20+
import { useTelemetryConsent } from '../hooks/useTelemetryConsent';
1921

2022
export default function OnboardingPage() {
2123
const { register, isLoading, isAuthenticated, setupRequired } = useAuth();
24+
const { saveTelemetryConsent, isLoading: isSavingConsent } = useTelemetryConsent();
2225
const [currentStep, setCurrentStep] = useState(1);
2326
const [formData, setFormData] = useState({
2427
username: '',
2528
email: '',
2629
password: '',
2730
confirmPassword: ''
2831
});
32+
const [telemetryConsent, setTelemetryConsent] = useState({
33+
errorDiagnostics: true, // Default ON
34+
usageAnalytics: true // Default ON
35+
});
2936
const [error, setError] = useState('');
3037
const [isSubmitting, setIsSubmitting] = useState(false);
3138

@@ -86,6 +93,7 @@ export default function OnboardingPage() {
8693
}
8794
return true;
8895

96+
8997
default:
9098
return true;
9199
}
@@ -109,8 +117,13 @@ export default function OnboardingPage() {
109117
setError('');
110118

111119
try {
120+
// Register the user
112121
await register(formData);
113-
// Navigation handled by auth context change
122+
123+
// Save telemetry consent preferences after successful registration
124+
await saveTelemetryConsent(telemetryConsent);
125+
126+
// Navigation will be handled by auth context change (redirect to dashboard)
114127
} catch (err) {
115128
const errorMessage = err instanceof Error ? err.message : 'Registration failed';
116129
try {
@@ -158,6 +171,56 @@ export default function OnboardingPage() {
158171
/>
159172
</Stack>
160173

174+
{/* Telemetry Consent Section */}
175+
<VStack gap={4} w="full" align="start" p={4} bg="gray.50" rounded="md">
176+
<Box>
177+
<Text fontSize="md" fontWeight="medium" color="gray.800" mb={1}>
178+
Help improve ThingConnect Pulse? (Optional)
179+
</Text>
180+
<Text fontSize="sm" color="gray.600">
181+
Enable anonymous diagnostics to help us fix crashes faster and improve features.
182+
</Text>
183+
</Box>
184+
185+
<Stack gap={3} w="full">
186+
<Flex justify="space-between" align="center">
187+
<VStack align="start" gap={0} flex="1">
188+
<Text fontSize="sm" fontWeight="medium" color="gray.800">
189+
Send sanitized error diagnostics
190+
</Text>
191+
<Text fontSize="xs" color="gray.600">
192+
Exception types, stack traces (no sensitive data)
193+
</Text>
194+
</VStack>
195+
<Switch
196+
checked={telemetryConsent.errorDiagnostics}
197+
onCheckedChange={(details) => setTelemetryConsent(prev => ({ ...prev, errorDiagnostics: details.checked }))}
198+
colorPalette="blue"
199+
size="sm"
200+
disabled={isSubmitting}
201+
/>
202+
</Flex>
203+
204+
<Flex justify="space-between" align="center">
205+
<VStack align="start" gap={0} flex="1">
206+
<Text fontSize="sm" fontWeight="medium" color="gray.800">
207+
Send anonymous usage analytics
208+
</Text>
209+
<Text fontSize="xs" color="gray.600">
210+
Feature usage counts (no personal information)
211+
</Text>
212+
</VStack>
213+
<Switch
214+
checked={telemetryConsent.usageAnalytics}
215+
onCheckedChange={(details) => setTelemetryConsent(prev => ({ ...prev, usageAnalytics: details.checked }))}
216+
colorPalette="blue"
217+
size="sm"
218+
disabled={isSubmitting}
219+
/>
220+
</Flex>
221+
</Stack>
222+
</VStack>
223+
161224
<LoadingButton
162225
size="lg"
163226
w="full"
@@ -230,38 +293,6 @@ export default function OnboardingPage() {
230293
</VStack>
231294
);
232295

233-
const renderStep3 = () => (
234-
<VStack gap={6}>
235-
<Box textAlign="center">
236-
<Heading size="lg" mb={2} color="#076bb3" fontWeight="bold">
237-
Setup Complete!
238-
</Heading>
239-
<Text color="gray.600" fontSize="lg" fontWeight="medium">
240-
Your ThingConnect Pulse system is ready to use
241-
</Text>
242-
</Box>
243-
244-
<VStack gap={4} align="start" maxW="md" w="full">
245-
<Flex align="center" gap={3}>
246-
<Box w={2} h={2} bg="#076bb3" rounded="full" />
247-
<Text color="gray.800" fontWeight="medium">Administrator account created</Text>
248-
</Flex>
249-
<Flex align="center" gap={3}>
250-
<Box w={2} h={2} bg="#076bb3" rounded="full" />
251-
<Text color="gray.800" fontWeight="medium">System authentication configured</Text>
252-
</Flex>
253-
<Flex align="center" gap={3}>
254-
<Box w={2} h={2} bg="#076bb3" rounded="full" />
255-
<Text color="gray.800" fontWeight="medium">Ready to monitor your network</Text>
256-
</Flex>
257-
</VStack>
258-
259-
<Text fontSize="sm" color="gray.600" fontWeight="medium" textAlign="center">
260-
You will be automatically logged in and redirected to the dashboard
261-
</Text>
262-
</VStack>
263-
);
264-
265296

266297
return (
267298
<AuthLayout>
@@ -292,7 +323,6 @@ export default function OnboardingPage() {
292323

293324
{currentStep === 1 && renderStep1()}
294325
{currentStep === 2 && renderStep2()}
295-
{currentStep === 3 && renderStep3()}
296326
</VStack>
297327
</AuthLayout>
298328
);

0 commit comments

Comments
 (0)