Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117777105
D5649.1775243621.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
5 KB
Referenced Files
None
Subscribers
None
D5649.1775243621.diff
View Options
diff --git a/src/app/Device.php b/src/app/Device.php
--- a/src/app/Device.php
+++ b/src/app/Device.php
@@ -126,8 +126,24 @@
{
DB::beginTransaction();
- // Create a device record
- $device = self::create(['hash' => $token]);
+ // Check if a device already exists
+ $device = Device::withTrashed()->where('hash', $token)->first();
+
+ if ($device) {
+ // FIXME: Should we remove the user (if it's a role=device user)?
+ // FIXME: Should we bail out if the device is used by a normal user?
+
+ // Remove the device-to-wallet connection
+ $device->entitlements()->delete();
+
+ // Undelete the device if needed
+ if ($device->trashed()) {
+ $device->restore();
+ }
+ } else {
+ // Create a device
+ $device = self::create(['hash' => $token]);
+ }
// Create a special account
while (true) {
@@ -153,10 +169,15 @@
$device->assignPlan($plan, $wallet = $user->wallets()->first());
// Push entitlements.updated_at to one year in the future
- $device->entitlements()->each(static function ($entitlement) {
- $entitlement->updated_at = \now()->addYearWithoutOverflow();
- $entitlement->save();
- });
+ $threshold = (clone $device->created_at)->addYearWithoutOverflow();
+ if ($threshold > \now()) {
+ $device->entitlements()->each(static function ($entitlement) use ($threshold) {
+ $entitlement->updated_at = $threshold;
+ $entitlement->save();
+ });
+ }
+
+ // FIXME: Should this bump signup_tokens.counter, as it does for user signup?
// TODO: Trigger payment mandate creation?
diff --git a/src/app/Http/Controllers/API/V4/DeviceController.php b/src/app/Http/Controllers/API/V4/DeviceController.php
--- a/src/app/Http/Controllers/API/V4/DeviceController.php
+++ b/src/app/Http/Controllers/API/V4/DeviceController.php
@@ -142,11 +142,6 @@
// TODO: Validate that the plan is device-only, don't accept a user plan here
- // Check if a device already exists
- if (Device::withTrashed()->where('hash', $token)->exists()) {
- return $this->errorResponse(500);
- }
-
// TODO: Should we get the password from the device? Then we'd not have to return it back at the end
$password = Utils::generatePassphrase();
diff --git a/src/tests/Feature/Controller/DeviceTest.php b/src/tests/Feature/Controller/DeviceTest.php
--- a/src/tests/Feature/Controller/DeviceTest.php
+++ b/src/tests/Feature/Controller/DeviceTest.php
@@ -196,8 +196,39 @@
$this->assertNotEmpty($json['access_token']);
$device = Device::where('hash', $this->hash)->first();
+ $account = $device->account;
$this->assertTrue(!empty($device));
+ $this->assertSame($account->email, $json['user']['email']);
+ $this->assertSame(User::ROLE_DEVICE, $account->role);
+ $this->assertSame($plan->id, $account->getSetting('plan_id'));
+ $this->assertSame($this->hash, $account->getSetting('signup_token'));
+
+ $entitlements = $device->wallet()->entitlements()->get();
+ $this->assertCount(1, $entitlements);
+ $this->assertSame($sku->id, $entitlements[0]->sku_id);
+ $this->assertStringContainsString('2026-02-02', $entitlements[0]->updated_at->toDateString());
+
+ $device->created_at = \now()->subMonthsWithoutOverflow();
+ $device->save();
+
+ // Note: without this finding the proper wallet may not work because of how Device::wallet() works
+ Carbon::setTestNow(Carbon::createFromDate(2025, 3, 4));
+
+ // Signup again
+ $response = $this->post("api/v4/device/{$this->hash}/signup", $post);
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame('success', $json['status']);
+ $this->assertSame('bearer', $json['token_type']);
+ $this->assertTrue(!empty($json['expires_in']) && is_int($json['expires_in']) && $json['expires_in'] > 0);
+ $this->assertNotEmpty($json['access_token']);
+
+ $device = Device::where('hash', $this->hash)->first();
+
+ $this->assertTrue($device->account->id != $account->id);
$this->assertSame($device->account->email, $json['user']['email']);
$this->assertSame(User::ROLE_DEVICE, $device->account->role);
$this->assertSame($plan->id, $device->account->getSetting('plan_id'));
@@ -206,7 +237,8 @@
$entitlements = $device->wallet()->entitlements()->get();
$this->assertCount(1, $entitlements);
$this->assertSame($sku->id, $entitlements[0]->sku_id);
- $this->assertStringContainsString('2026-02-02', $entitlements[0]->updated_at->toDateString());
+ $this->assertStringContainsString('2025-03-04', $entitlements[0]->created_at->toDateString());
+ $this->assertStringContainsString('2026-01-02', $entitlements[0]->updated_at->toDateString());
}
private function initTestDevice(): array
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 7:13 PM (2 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18825895
Default Alt Text
D5649.1775243621.diff (5 KB)
Attached To
Mode
D5649: Device signup fix
Attached
Detach File
Event Timeline