From e3619a0f84c6822ac45d095366fe224e6918a9c5 Mon Sep 17 00:00:00 2001
From: philipp lang <philipp@aweos.de>
Date: Fri, 7 Oct 2022 22:41:43 +0200
Subject: [PATCH] Add dav test

---
 app/Dav/AddressBookBackend.php   |  11 ++-
 app/Member/Member.php            |  28 ++++++-
 tests/Feature/Member/DavTest.php | 125 +++++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+), 3 deletions(-)
 create mode 100644 tests/Feature/Member/DavTest.php

diff --git a/app/Dav/AddressBookBackend.php b/app/Dav/AddressBookBackend.php
index 97732d5a..179ee305 100644
--- a/app/Dav/AddressBookBackend.php
+++ b/app/Dav/AddressBookBackend.php
@@ -137,7 +137,11 @@ class AddressBookBackend extends AbstractBackend
      */
     public function getCard($addressBookId, $cardUri)
     {
-        $member = Member::where('slug', $cardUri)->firstOrFail();
+        $member = Member::where('slug', $cardUri)->first();
+
+        if (!$member) {
+            return false;
+        }
 
         return [
             ...$this->cardMeta($member),
@@ -193,7 +197,10 @@ class AddressBookBackend extends AbstractBackend
      */
     public function createCard($addressBookId, $cardUri, $cardData)
     {
-        return null;
+        $member = Member::fromVcard($cardUri, $cardData);
+        $member->save();
+
+        return $member->fresh()->etag;
     }
 
     /**
diff --git a/app/Member/Member.php b/app/Member/Member.php
index f55919d8..76d8ee49 100644
--- a/app/Member/Member.php
+++ b/app/Member/Member.php
@@ -14,6 +14,7 @@ use App\Payment\Subscription;
 use App\Region;
 use App\Setting\NamiSettings;
 use App\Subactivity;
+use Carbon\Carbon;
 use Cviebrock\EloquentSluggable\Sluggable;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -22,6 +23,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Notifications\Notifiable;
 use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Reader;
 use Zoomyboy\LaravelNami\Api;
 use Zoomyboy\LaravelNami\Data\MembershipEntry;
 
@@ -378,7 +380,30 @@ class Member extends Model
             ]);
     }
 
-    public function toVcard(): VCard
+    public static function fromVcard(string $url, string $data): static
+    {
+        $settings = app(NamiSettings::class);
+        $card = Reader::read($data);
+        [$lastname, $firstname] = $card->N->getParts();
+        [$deprecated1, $deprecated2 , $address, $location, $region, $zip, $country] = $card->ADR->getParts();
+
+        return new static([
+            'joined_at' => now(),
+            'send_newspaper' => false,
+            'firstname' => $firstname,
+            'lastname' => $lastname,
+            'birthday' => Carbon::createFromFormat('Ymd', $card->BDAY->getValue()),
+            'slug' => pathinfo($url, PATHINFO_FILENAME),
+            'address' => $address,
+            'zip' => $zip,
+            'location' => $location,
+            'group_id' => $settings->default_group_id,
+            'nationality_id' => Nationality::firstWhere('name', 'deutsch')->id,
+            'subscription_id' => Subscription::firstWhere('name', 'Voll')->id,
+        ]);
+    }
+
+    public function toVcard(): Vcard
     {
         $card = new VCard([
             'VERSION' => '3.0',
@@ -387,6 +412,7 @@ class Member extends Model
             'N' => [$this->lastname, $this->firstname, '', '', ''],
             'BDAY' => $this->birthday->format('Ymd'),
             'CATEGORIES' => 'Scoutrobot',
+            'UID' => $this->slug,
         ]);
 
         $card->add('child.X-ABLABEL', 'Kind');
diff --git a/tests/Feature/Member/DavTest.php b/tests/Feature/Member/DavTest.php
new file mode 100644
index 00000000..35e47829
--- /dev/null
+++ b/tests/Feature/Member/DavTest.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Tests\Feature\Member;
+
+use App\Group;
+use App\Member\Member;
+use App\Nationality;
+use App\Payment\Subscription;
+use App\Setting\NamiSettings;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Tests\TestCase;
+
+class DavTest extends TestCase
+{
+    use DatabaseTransactions;
+
+    public function testItCanStoreAMemberFromAVcard(): void
+    {
+        Nationality::factory()->create(['name' => 'englisch']);
+        $subscription = Subscription::factory()->create(['name' => 'Voll']);
+        $nationality = Nationality::factory()->create(['name' => 'deutsch']);
+        $group = Group::factory()->create();
+        NamiSettings::fake(['default_group_id' => $group->id]);
+        $cardUri = '97266d2e-36e7-4fb6-8b6c-bbf57a061685.vcf';
+        $cardData = <<<VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Thunderbird.net/NONSGML Thunderbird CardBook V77.0//EN-US
+UID:97266d2e-36e7-4fb6-8b6c-bbf57a061685
+CATEGORIES:Scoutrobot
+FN:given familya Silva
+N:familya;given;;;
+BDAY:20221003
+ORG:Silva
+EMAIL:mail@maild.ee
+ITEM1.TEL:+49 176 70342420
+ITEM1.X-ABLABEL:eltern
+ADR:;;Itterstr 3;Solingen;NRW;42719;Germany
+REV:2022-10-07T14:17:06Z
+END:VCARD
+
+VCARD;
+        $member = Member::fromVcard($cardUri, $cardData);
+
+        $member->save();
+
+        $this->assertDatabaseHas('members', [
+            'slug' => '97266d2e-36e7-4fb6-8b6c-bbf57a061685',
+            'firstname' => 'given',
+            'lastname' => 'familya',
+            'address' => 'Itterstr 3',
+            'zip' => '42719',
+            'location' => 'Solingen',
+            'group_id' => $group->id,
+            'nationality_id' => $nationality->id,
+            'subscription_id' => $subscription->id,
+        ]);
+    }
+
+    public function testTheVcardHasTheMembersSlug(): void
+    {
+        $member = Member::factory()->defaults()->create(['firstname' => 'max', 'lastname' => 'muster']);
+
+        $card = $member->toVcard();
+
+        $this->assertEquals('max-muster', $card->UID->getValue());
+    }
+
+    public function testItSetsTheNames(): void
+    {
+        $member = Member::factory()->defaults()->create(['firstname' => 'Max', 'lastname' => 'Muster']);
+
+        $card = $member->toVcard();
+
+        $this->assertEquals(['Muster', 'Max', '', '', ''], $card->N->getParts());
+        $this->assertEquals('Max Muster', $card->FN->getValue());
+    }
+
+    public function testItSetsTheBirthday(): void
+    {
+        $member = Member::factory()->defaults()->create(['birthday' => '1993-05-06']);
+
+        $card = $member->toVcard();
+
+        $this->assertEquals('19930506', $card->BDAY->getValue());
+    }
+
+    public function testItCanSetAndUnsetMobilePhone(): void
+    {
+        $member = Member::factory()->defaults()->create();
+
+        $member->update(['mobile_phone' => '+49 176 555555']);
+
+        $this->assertTrue(count($member->toVcard()->TEL) > 0);
+        foreach ($member->toVcard()->TEL as $t) {
+            if (!$t['TYPE'] || 'cell' !== $t['TYPE']->getValue()) {
+                continue;
+            }
+
+            $this->assertEquals('+49 176 555555', $t->getValue());
+
+            return;
+        }
+
+        $this->assertFalse(true, 'No Phone number found in card');
+    }
+
+    public function testItUnsetsMobilePhoneNumber(): void
+    {
+        $member = Member::factory()->defaults()->create();
+
+        $member->update(['mobile_phone' => '']);
+
+        if (!is_null($member->toVcard()->TEL)) {
+            foreach ($member->toVcard()->TEL as $t) {
+                if ($t['TYPE'] && 'cell' === $t['TYPE']->getValue()) {
+                    $this->assertFalse(true, 'Phone number found');
+                    continue;
+                }
+            }
+        }
+
+        $this->assertTrue(true);
+    }
+}