Compare commits

...

1 Commits

Author SHA1 Message Date
Constantin Graf
b8b35b6467 Fixed bug in toggl data importer if import contains invalid timezone 2025-03-04 17:02:36 -05:00
12 changed files with 219 additions and 1 deletions

View File

@@ -5,8 +5,11 @@ declare(strict_types=1);
namespace App\Service\Import\Importers;
use App\Enums\Role;
use App\Service\TimezoneService;
use Exception;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Override;
use Spatie\TemporaryDirectory\TemporaryDirectory;
use ValueError;
@@ -93,11 +96,22 @@ class TogglDataImporter extends DefaultImporter
}
foreach ($workspaceUsers as $workspaceUser) {
$timezone = Str::trim($workspaceUser->timezone);
if ($timezone === '') {
$timezone = 'UTC';
}
if (! app(TimezoneService::class)->isValid($timezone)) {
Log::warning('TogglDateImporter: Invalid timezone', [
'timezone' => $timezone,
]);
$timezone = 'UTC';
}
$userId = $this->userImportHelper->getKey([
'email' => $workspaceUser->email,
], [
'name' => $workspaceUser->name,
'timezone' => $workspaceUser->timezone ?? 'UTC',
'timezone' => $timezone,
'is_placeholder' => true,
], (string) $workspaceUser->uid);
$this->memberImportHelper->getKey([

View File

@@ -0,0 +1,16 @@
[
{
"archived": false,
"creator_id": 201,
"id": 301,
"name": "Big Company",
"wid": 0
},
{
"archived": true,
"creator_id": 201,
"id": 302,
"name": "Other Company (Archived)",
"wid": 0
}
]

View File

@@ -0,0 +1,86 @@
[
{
"active": true,
"actual_hours": null,
"actual_seconds": null,
"auto_estimates": false,
"billable": false,
"cid": null,
"client_id": null,
"color": "#ef5350",
"currency": "EUR",
"estimated_hours": null,
"estimated_seconds": null,
"fixed_fee": null,
"guid": "",
"id": 401,
"is_private": true,
"name": "Project without Client",
"rate": null,
"rate_last_updated": null,
"recurring": false,
"recurring_parameters": null,
"start_date": "2020-01-01",
"status": "active",
"template": false,
"template_id": null,
"wid": 0,
"workspace_id": 0
},
{
"active": true,
"actual_hours": null,
"actual_seconds": null,
"auto_estimates": false,
"billable": true,
"cid": 301,
"client_id": 301,
"color": "#ec407a",
"currency": null,
"estimated_hours": null,
"estimated_seconds": null,
"fixed_fee": null,
"guid": "",
"id": 402,
"is_private": true,
"name": "Project for Big Company",
"rate": 100.01,
"rate_last_updated": null,
"recurring": false,
"recurring_parameters": null,
"start_date": "2020-01-01",
"status": "active",
"template": false,
"template_id": null,
"wid": 0,
"workspace_id": 0
},
{
"active": false,
"actual_hours": null,
"actual_seconds": null,
"auto_estimates": false,
"billable": true,
"cid": 302,
"client_id": 302,
"color": "#6a407f",
"currency": null,
"estimated_hours": null,
"estimated_seconds": null,
"fixed_fee": null,
"guid": "",
"id": 403,
"is_private": false,
"name": "Project (Archived)",
"rate": null,
"rate_last_updated": null,
"recurring": false,
"recurring_parameters": null,
"start_date": "2020-01-01",
"status": "active",
"template": false,
"template_id": null,
"wid": 0,
"workspace_id": 0
}
]

View File

@@ -0,0 +1,14 @@
[
{
"gid": null,
"group_id": null,
"id": 801,
"labour_cost": null,
"manager": true,
"project_id": 402,
"rate": 100.02,
"rate_last_updated": null,
"user_id": 2001,
"workspace_id": 0
}
]

View File

@@ -0,0 +1,14 @@
[
{
"creator_id": 0,
"id": 501,
"name": "Development",
"workspace_id": 0
},
{
"creator_id": 0,
"id": 502,
"name": "Backend",
"workspace_id": 0
}
]

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,24 @@
[
{
"active": true,
"estimated_seconds": 0,
"id": 601,
"name": "Task 1",
"project_id": 402,
"recurring": false,
"tracked_seconds": 0,
"user_id": null,
"workspace_id": 0
},
{
"active": false,
"estimated_seconds": 0,
"id": 602,
"name": "Task 2",
"project_id": 403,
"recurring": false,
"tracked_seconds": 0,
"user_id": null,
"workspace_id": 0
}
]

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,19 @@
[
{
"active": true,
"admin": true,
"email": "peter.test@email.test",
"group_ids": [],
"id": 201,
"inactive": false,
"labour_cost": null,
"name": "Peter Tester",
"rate": null,
"rate_last_updated": null,
"role": "admin",
"timezone": "Etc/UTC",
"uid": 2001,
"wid": 0,
"working_hours_in_minutes": null
}
]

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Tests\Unit\Service\Import\Importers;
use App\Models\Organization;
use App\Models\User;
use App\Service\Import\Importers\DefaultImporter;
use App\Service\Import\Importers\ImportException;
use App\Service\Import\Importers\TogglDataImporter;
@@ -88,4 +89,30 @@ class TogglDataImporterTest extends ImporterTestAbstract
$this->assertSame(0, $report->projectsCreated);
$this->assertSame(0, $report->clientsCreated);
}
public function test_import_of_user_with_unknown_timezone_will_be_mapped_to_utc(): void
{
// Arrange
$zipPath = $this->createTestZip('toggl_data_import_test_2');
$timezone = 'Europe/Vienna';
$organization = Organization::factory()->create();
$importer = new TogglDataImporter;
$importer->init($organization);
$data = file_get_contents($zipPath);
// Act
$importer->importData($data, $timezone);
$report = $importer->getReport();
// Assert
$this->assertSame(0, $report->timeEntriesCreated);
$this->assertSame(2, $report->tagsCreated);
$this->assertSame(2, $report->tasksCreated);
$this->assertSame(1, $report->usersCreated);
$this->assertSame(3, $report->projectsCreated);
$this->assertSame(2, $report->clientsCreated);
$user = User::query()->where('email', '=', 'peter.test@email.test')->first();
$this->assertSame('UTC', $user->timezone);
$this->assertTrue($user->is_placeholder);
}
}