mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-02-02 19:09:23 +00:00
Fix FLEXIAPI-164 Add vcards-storage endpoints
This commit is contained in:
parent
faf33f5ac3
commit
debf668e77
13 changed files with 681 additions and 18 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
v1.5
|
||||
----
|
||||
- Fix FLEXIAPI-164 Add vcards-storage endpoints
|
||||
- Fix FLEXIAPI-162 Drop the aliases table and migrate the data to the phone column
|
||||
- Fix FLEXIAPI-161 Complete the Dictionary tests to cover the collection accessor
|
||||
- Fix FLEXIAPI-158 Restrict the phone number change API endpoint to return 403 if the account doesn't have a validated Account Creation Token
|
||||
|
|
|
|||
|
|
@ -130,6 +130,11 @@ class Account extends Authenticatable
|
|||
return $this->belongsToMany(Account::class, 'contacts', 'account_id', 'contact_id');
|
||||
}
|
||||
|
||||
public function vcardsStorage()
|
||||
{
|
||||
return $this->hasMany(VcardStorage::class);
|
||||
}
|
||||
|
||||
public function contactsLists()
|
||||
{
|
||||
return $this->belongsToMany(ContactsList::class, 'account_contacts_list', 'account_id', 'contacts_list_id');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class VcardsStorageController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($this->vcardRequested($request)) {
|
||||
$vcards = '';
|
||||
|
||||
foreach ($request->user()->vcardsStorage()->get() as $vcard) {
|
||||
$vcards .= $vcard->vcard . "\n";
|
||||
}
|
||||
|
||||
return $vcards;
|
||||
}
|
||||
|
||||
abort(404);
|
||||
}
|
||||
|
||||
public function show(Request $request, string $uuid)
|
||||
{
|
||||
return ($this->vcardRequested($request))
|
||||
? $request->user()->vcardsStorage()->where('uuid', $uuid)->firstOrFail()->vcard
|
||||
: abort(404);
|
||||
}
|
||||
|
||||
private function vcardRequested(Request $request): bool
|
||||
{
|
||||
return $request->hasHeader('content-type') == 'text/vcard'
|
||||
&& $request->hasHeader('accept') == 'text/vcard';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\Vcard;
|
||||
use App\VcardStorage;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
class VcardsStorageController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
return $request->user()->vcardsStorage()->get()->keyBy('uuid');
|
||||
}
|
||||
|
||||
public function show(Request $request, string $uuid)
|
||||
{
|
||||
return $request->user()->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'vcard' => ['required', new Vcard()]
|
||||
]);
|
||||
|
||||
$vcardo = VObject\Reader::read($request->get('vcard'));
|
||||
|
||||
if ($request->user()->vcardsStorage()->where('uuid', $vcardo->UID)->first()) {
|
||||
abort(409, 'Vcard already exists');
|
||||
}
|
||||
|
||||
$vcard = new VcardStorage();
|
||||
$vcard->account_id = $request->user()->id;
|
||||
$vcard->uuid = $vcardo->UID;
|
||||
$vcard->vcard = preg_replace('/\r\n?/', "\n", $vcardo->serialize());
|
||||
$vcard->save();
|
||||
|
||||
return $vcard->vcard;
|
||||
}
|
||||
|
||||
public function update(Request $request, string $uuid)
|
||||
{
|
||||
$request->validate([
|
||||
'vcard' => ['required', new Vcard()]
|
||||
]);
|
||||
|
||||
$vcardo = VObject\Reader::read($request->get('vcard'));
|
||||
|
||||
if ($vcardo->UID != $uuid) {
|
||||
abort(422, 'UUID should be the same');
|
||||
}
|
||||
|
||||
$vcard = $request->user()->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
$vcard->vcard = preg_replace('/\r\n?/', "\n", $vcardo->serialize());
|
||||
$vcard->save();
|
||||
|
||||
return $vcard->vcard;
|
||||
}
|
||||
|
||||
public function destroy(Request $request, string $uuid)
|
||||
{
|
||||
$vcard = $request->user()->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
|
||||
return $vcard->delete();
|
||||
}
|
||||
}
|
||||
35
flexiapi/app/Rules/Vcard.php
Normal file
35
flexiapi/app/Rules/Vcard.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Sabre\VObject;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class Vcard implements Rule
|
||||
{
|
||||
private $message = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function passes($attribute, $value): bool
|
||||
{
|
||||
try {
|
||||
$vcard = VObject\Reader::read($value);
|
||||
|
||||
if (!empty($vcard->validate())) return false;
|
||||
if ($vcard->UID == null) return false;
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $th) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function message()
|
||||
{
|
||||
return 'Invalid vcard passed';
|
||||
}
|
||||
}
|
||||
20
flexiapi/app/VcardStorage.php
Normal file
20
flexiapi/app/VcardStorage.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class VcardStorage extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'vcards_storage';
|
||||
protected $hidden = ['id', 'account_id', 'uuid'];
|
||||
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
"phpunit/phpunit": "^9.6",
|
||||
"react/socket": "^1.14",
|
||||
"respect/validation": "^2.2",
|
||||
"sabre/vobject": "^4.5",
|
||||
"scyllaly/hcaptcha": "^4.4"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
|
|||
263
flexiapi/composer.lock
generated
263
flexiapi/composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "daf1c028cc9a6eb9b5d28ba1bd25cec5",
|
||||
"content-hash": "e9d79f33a899fd2dcde3de88c243e800",
|
||||
"packages": [
|
||||
{
|
||||
"name": "awobaz/compoships",
|
||||
|
|
@ -2716,16 +2716,16 @@
|
|||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "2.9.2",
|
||||
"version": "2.9.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f"
|
||||
"reference": "a30bfe2e142720dfa990d0a7e573997f5d884215"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/437cb3628f4cf6042cc10ae97fc2b8472e48ca1f",
|
||||
"reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/a30bfe2e142720dfa990d0a7e573997f5d884215",
|
||||
"reference": "a30bfe2e142720dfa990d0a7e573997f5d884215",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2746,8 +2746,8 @@
|
|||
"mongodb/mongodb": "^1.8",
|
||||
"php-amqplib/php-amqplib": "~2.4 || ^3",
|
||||
"phpspec/prophecy": "^1.15",
|
||||
"phpstan/phpstan": "^0.12.91",
|
||||
"phpunit/phpunit": "^8.5.14",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^8.5.38 || ^9.6.19",
|
||||
"predis/predis": "^1.1 || ^2.0",
|
||||
"rollbar/rollbar": "^1.3 || ^2 || ^3",
|
||||
"ruflin/elastica": "^7",
|
||||
|
|
@ -2802,7 +2802,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Seldaek/monolog/issues",
|
||||
"source": "https://github.com/Seldaek/monolog/tree/2.9.2"
|
||||
"source": "https://github.com/Seldaek/monolog/tree/2.9.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2814,7 +2814,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-10-27T15:25:26+00:00"
|
||||
"time": "2024-04-12T20:52:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
|
|
@ -5400,6 +5400,239 @@
|
|||
},
|
||||
"time": "2023-02-15T01:05:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/uri",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/uri.git",
|
||||
"reference": "1774043c843f1db7654ecc93368a98be29b07544"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/1774043c843f1db7654ecc93368a98be29b07544",
|
||||
"reference": "1774043c843f1db7654ecc93368a98be29b07544",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.17",
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpstan/phpstan-strict-rules": "^1.5",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Sabre\\Uri\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Evert Pot",
|
||||
"email": "me@evertpot.com",
|
||||
"homepage": "http://evertpot.com/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Functions for making sense out of URIs.",
|
||||
"homepage": "http://sabre.io/uri/",
|
||||
"keywords": [
|
||||
"rfc3986",
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"support": {
|
||||
"forum": "https://groups.google.com/group/sabredav-discuss",
|
||||
"issues": "https://github.com/sabre-io/uri/issues",
|
||||
"source": "https://github.com/fruux/sabre-uri"
|
||||
},
|
||||
"time": "2023-06-09T07:04:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/vobject",
|
||||
"version": "4.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/vobject.git",
|
||||
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
|
||||
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"sabre/xml": "^2.1 || ^3.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "~2.17.1",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/php-invoker": "^2.0 || ^3.1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"hoa/bench": "If you would like to run the benchmark scripts"
|
||||
},
|
||||
"bin": [
|
||||
"bin/vobject",
|
||||
"bin/generate_vcards"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sabre\\VObject\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Evert Pot",
|
||||
"email": "me@evertpot.com",
|
||||
"homepage": "http://evertpot.com/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Dominik Tobschall",
|
||||
"email": "dominik@fruux.com",
|
||||
"homepage": "http://tobschall.de/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Ivan Enderlin",
|
||||
"email": "ivan.enderlin@hoa-project.net",
|
||||
"homepage": "http://mnt.io/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
|
||||
"homepage": "http://sabre.io/vobject/",
|
||||
"keywords": [
|
||||
"availability",
|
||||
"freebusy",
|
||||
"iCalendar",
|
||||
"ical",
|
||||
"ics",
|
||||
"jCal",
|
||||
"jCard",
|
||||
"recurrence",
|
||||
"rfc2425",
|
||||
"rfc2426",
|
||||
"rfc2739",
|
||||
"rfc4770",
|
||||
"rfc5545",
|
||||
"rfc5546",
|
||||
"rfc6321",
|
||||
"rfc6350",
|
||||
"rfc6351",
|
||||
"rfc6474",
|
||||
"rfc6638",
|
||||
"rfc6715",
|
||||
"rfc6868",
|
||||
"vCalendar",
|
||||
"vCard",
|
||||
"vcf",
|
||||
"xCal",
|
||||
"xCard"
|
||||
],
|
||||
"support": {
|
||||
"forum": "https://groups.google.com/group/sabredav-discuss",
|
||||
"issues": "https://github.com/sabre-io/vobject/issues",
|
||||
"source": "https://github.com/fruux/sabre-vobject"
|
||||
},
|
||||
"time": "2023-11-09T12:54:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/xml",
|
||||
"version": "4.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/xml.git",
|
||||
"reference": "c29e49fcf9ca8ca058b1e350ee9abe4205c0de89"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/c29e49fcf9ca8ca058b1e350ee9abe4205c0de89",
|
||||
"reference": "c29e49fcf9ca8ca058b1e350ee9abe4205c0de89",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"lib-libxml": ">=2.6.20",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"sabre/uri": ">=2.0,<4.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.51",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/Deserializer/functions.php",
|
||||
"lib/Serializer/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Sabre\\Xml\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Evert Pot",
|
||||
"email": "me@evertpot.com",
|
||||
"homepage": "http://evertpot.com/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Markus Staab",
|
||||
"email": "markus.staab@redaxo.de",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "sabre/xml is an XML library that you may not hate.",
|
||||
"homepage": "https://sabre.io/xml/",
|
||||
"keywords": [
|
||||
"XMLReader",
|
||||
"XMLWriter",
|
||||
"dom",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"forum": "https://groups.google.com/group/sabredav-discuss",
|
||||
"issues": "https://github.com/sabre-io/xml/issues",
|
||||
"source": "https://github.com/fruux/sabre-xml"
|
||||
},
|
||||
"time": "2024-04-18T10:44:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "scyllaly/hcaptcha",
|
||||
"version": "4.4.5",
|
||||
|
|
@ -9014,16 +9247,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "barryvdh/laravel-debugbar",
|
||||
"version": "v3.13.3",
|
||||
"version": "v3.13.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-debugbar.git",
|
||||
"reference": "241e9bddb04ab42a04a5fe8b2b9654374c864229"
|
||||
"reference": "00201bcd1eaf9b1d3debddcdc13c219e4835fb61"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/241e9bddb04ab42a04a5fe8b2b9654374c864229",
|
||||
"reference": "241e9bddb04ab42a04a5fe8b2b9654374c864229",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/00201bcd1eaf9b1d3debddcdc13c219e4835fb61",
|
||||
"reference": "00201bcd1eaf9b1d3debddcdc13c219e4835fb61",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -9082,7 +9315,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
|
||||
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.13.3"
|
||||
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.13.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -9094,7 +9327,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-04T02:42:49+00:00"
|
||||
"time": "2024-04-10T09:15:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('vcards_storage', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->index();
|
||||
$table->text('vcard');
|
||||
|
||||
$table->integer('account_id')->unsigned();
|
||||
$table->foreign('account_id')->references('id')
|
||||
->on('accounts')->onDelete('cascade');
|
||||
|
||||
$table->unique(['account_id', 'uuid']);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('vcards_storage');
|
||||
}
|
||||
};
|
||||
|
|
@ -436,6 +436,41 @@ Return the user contacts.
|
|||
|
||||
Return a user contact.
|
||||
|
||||
## Account vCards storage
|
||||
|
||||
### `POST /accounts/me/vcards-storage`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Store a vCard.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
* `vcard`, mandatory, a valid vCard having a mandatory `UID` parameter that is uniquelly identifying it. This `UID` parameter will then be used to manipulate the vcard through the following endpoints as `uuid`.
|
||||
|
||||
### `PUT /accounts/me/vcards-storage/{uuid}`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Update a vCard.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
* `vcard`, mandatory, a valid vCard having a mandatory `UID` parameter that is uniquelly identifying it and is the same as the `uuid` parameter.
|
||||
|
||||
### `GET /accounts/me/vcards-storage`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Return the list of stored vCards
|
||||
|
||||
### `GET /accounts/me/vcards-storage/{uuid}`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Return a stored vCard
|
||||
|
||||
### `DELETE /accounts/me/vcards-storage/{uuid}`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Delete a stored vCard
|
||||
|
||||
## Contacts
|
||||
|
||||
### `GET /accounts/{id}/contacts`
|
||||
|
|
@ -724,4 +759,24 @@ END:VCARD
|
|||
### `GET /contacts/vcard/{sip}`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Return a specific user authenticated contact, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350).
|
||||
Return a specific user authenticated contact, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350).
|
||||
|
||||
## vCards Storage
|
||||
|
||||
The following headers are mandatory to access the following endpoints:
|
||||
|
||||
```
|
||||
> content-type: text/vcard
|
||||
> accept: text/vcard
|
||||
```
|
||||
|
||||
### `GET /vcards-storage`
|
||||
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Return the list of stored vCards
|
||||
|
||||
### `GET /vcards-storage/{uuid}`
|
||||
<span class="badge badge-info">User</span>
|
||||
|
||||
Return a stored vCard
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use App\Http\Controllers\Api\Account\VcardsStorageController;
|
||||
use App\Http\Controllers\Api\Admin\AccountActionController;
|
||||
use App\Http\Controllers\Api\Admin\AccountContactController;
|
||||
use App\Http\Controllers\Api\Admin\AccountController as AdminAccountController;
|
||||
|
|
@ -78,6 +79,8 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
|
|||
|
||||
Route::get('contacts/{sip}', 'Api\Account\ContactController@show');
|
||||
Route::get('contacts', 'Api\Account\ContactController@index');
|
||||
|
||||
Route::apiResource('vcards-storage', VcardsStorageController::class);
|
||||
});
|
||||
|
||||
Route::group(['middleware' => ['auth.admin']], function () {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ use App\Http\Controllers\Admin\AccountStatisticsController;
|
|||
use App\Http\Controllers\Admin\ContactsListController;
|
||||
use App\Http\Controllers\Admin\ContactsListContactController;
|
||||
use App\Http\Controllers\Admin\StatisticsController;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::redirect('/', 'login')->name('account.home');
|
||||
|
|
@ -60,9 +59,13 @@ Route::group(['middleware' => 'web_panel_enabled'], function () {
|
|||
Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key']], function () {
|
||||
Route::get('provisioning/me', 'Account\ProvisioningController@me')->name('provisioning.me');
|
||||
|
||||
// Vcard 4.0
|
||||
// vCard 4.0
|
||||
Route::get('contacts/vcard/{sip}', 'Account\ContactVcardController@show')->name('account.contacts.vcard.show');
|
||||
Route::get('contacts/vcard', 'Account\ContactVcardController@index')->name('account.contacts.vcard.index');
|
||||
|
||||
// vCards Storage
|
||||
Route::get('vcards-storage/{uuid}', 'Account\VcardsStorageController@show')->name('account.vcards-storage.show');
|
||||
Route::get('vcards-storage/', 'Account\VcardsStorageController@index')->name('account.vcards-storage.index');
|
||||
});
|
||||
|
||||
Route::name('provisioning.')->prefix('provisioning')->controller(ProvisioningController::class)->group(function () {
|
||||
|
|
|
|||
171
flexiapi/tests/Feature/ApiAccountVcardsStorageTest.php
Normal file
171
flexiapi/tests/Feature/ApiAccountVcardsStorageTest.php
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Account;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ApiAccountVcardsStorageTest extends TestCase
|
||||
{
|
||||
protected $route = '/api/accounts/me/vcards-storage';
|
||||
protected $method = 'POST';
|
||||
|
||||
public function testCrud()
|
||||
{
|
||||
$account = Account::factory()->create();
|
||||
$account->generateApiKey();
|
||||
|
||||
$uid = 'urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6';
|
||||
$lastVcard =
|
||||
'BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:Simone Perreault
|
||||
UID:' . $uid . '
|
||||
END:VCARD
|
||||
';
|
||||
$uid2 = 'urn:uuid: a5b33443-687c-4d19-bdd0-b30cf76bf96d';
|
||||
$secondVcard =
|
||||
'BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:Simone Perreault
|
||||
UID:' . $uid2 . '
|
||||
END:VCARD
|
||||
';
|
||||
|
||||
// Missing vcard
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'foo' => 'bar'
|
||||
])
|
||||
->assertJsonValidationErrors(['vcard']);
|
||||
|
||||
// Missing UID
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'vcard' =>
|
||||
'BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:Simon Perreault
|
||||
END:VCARD'
|
||||
])->assertJsonValidationErrors(['vcard']);
|
||||
|
||||
// Create
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'vcard' =>
|
||||
'BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:Simon Perreault
|
||||
UID:' . $uid . '
|
||||
END:VCARD'
|
||||
])->assertStatus(200);
|
||||
|
||||
// Again...
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'vcard' =>
|
||||
'BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:Simon Perreault
|
||||
UID:' . $uid . '
|
||||
END:VCARD'
|
||||
])->assertStatus(409);
|
||||
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'vcard' => $secondVcard
|
||||
])->assertStatus(200);
|
||||
|
||||
$this->assertDatabaseHas('vcards_storage', [
|
||||
'uuid' => $uid
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('vcards_storage', [
|
||||
'uuid' => $uid2
|
||||
]);
|
||||
|
||||
// Update
|
||||
$this->keyAuthenticated($account)
|
||||
->json('PUT', $this->route . '/' . $uid, [
|
||||
'vcard' => $lastVcard
|
||||
])->assertStatus(200);
|
||||
|
||||
// Update with wrong UID
|
||||
$this->keyAuthenticated($account)
|
||||
->json('PUT', $this->route . '/' . $uid, [
|
||||
'vcard' =>
|
||||
'BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:Simone Perreault
|
||||
UID:123
|
||||
END:VCARD'
|
||||
])->assertStatus(422);
|
||||
|
||||
// Index
|
||||
$this->keyAuthenticated($account)
|
||||
->get($this->route)
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
$uid => ['vcard' => $lastVcard],
|
||||
$uid2 => ['vcard' => $secondVcard]
|
||||
]);
|
||||
|
||||
// Get
|
||||
$this->keyAuthenticated($account)
|
||||
->get($this->route . '/' . $uid)
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'vcard' => $lastVcard
|
||||
]);
|
||||
|
||||
// Vcard format endpoints
|
||||
$this->keyAuthenticated($account)
|
||||
->get('vcards-storage')
|
||||
->assertStatus(404);
|
||||
|
||||
$this->keyAuthenticated($account)
|
||||
->withHeaders([
|
||||
'content-type' => 'text/vcard',
|
||||
'accept' => 'text/vcard',
|
||||
])
|
||||
->get('vcards-storage')
|
||||
->assertStatus(200)
|
||||
->assertSee($lastVcard)
|
||||
->assertSee($secondVcard);
|
||||
|
||||
$this->keyAuthenticated($account)
|
||||
->withHeaders([
|
||||
'content-type' => 'text/vcard',
|
||||
'accept' => 'text/vcard',
|
||||
])
|
||||
->get('vcards-storage/' . $uid)
|
||||
->assertStatus(200)
|
||||
->assertSee($lastVcard);
|
||||
|
||||
// Delete
|
||||
$this->keyAuthenticated($account)
|
||||
->delete($this->route . '/' . $uid)
|
||||
->assertStatus(200);
|
||||
|
||||
$this->keyAuthenticated($account)
|
||||
->get($this->route . '/' . $uid)
|
||||
->assertStatus(404);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue