Sabre playground

This commit is contained in:
Timothée Jaussoin 2023-03-01 11:05:16 +01:00
parent 88f0d898fa
commit 4eefa08c4b
9 changed files with 1340 additions and 48 deletions

2
composer.json Normal file
View file

@ -0,0 +1,2 @@
{
}

18
composer.lock generated Normal file
View file

@ -0,0 +1,18 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d751713988987e9331980363e24189ce",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

View file

@ -0,0 +1,229 @@
<?php
declare(strict_types=1);
namespace App\Providers;
use App\Account;
use Sabre\CardDAV;
use Sabre\DAV;
use Sabre\DAV\PropPatch;
use Sabre\CardDAV\Backend\AbstractBackend;
use Sabre\CardDAV\Plugin;
class ContactBackend extends AbstractBackend
{
/**
* Returns the list of addressbooks for a specific user.
*
* @param string $principalUri
*
* @return array
*/
public function getAddressBooksForUser($principalUri)
{
$addressBooks = [[
'id' => '1',
'uri' => 'default',
'principaluri' => 'principals/tester',
'{DAV:}displayname' => 'Contacts',
'{'.Plugin::NS_CARDDAV.'}addressbook-description' => 'User contacts',
'{http://calendarserver.org/ns/}getctag' => '6697',
'{http://sabredav.org/ns}sync-token' => '6697',
]];
return $addressBooks;
}
/**
* Updates properties for an address book.
*
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
* To do the actual updates, you must tell this object which properties
* you're going to process with the handle() method.
*
* Calling the handle method is like telling the PropPatch object "I
* promise I can handle updating this property".
*
* Read the PropPatch documentation for more info and examples.
*
* @param string $addressBookId
*/
public function updateAddressBook($addressBookId, PropPatch $propPatch)
{
return false;
}
/**
* Creates a new address book.
*
* @param string $principalUri
* @param string $url just the 'basename' of the url
*
* @return int Last insert id
*/
public function createAddressBook($principalUri, $url, array $properties)
{
return 'default';
}
/**
* Deletes an entire addressbook and all its contents.
*
* @param int $addressBookId
*/
public function deleteAddressBook($addressBookId)
{
}
/**
* Returns all cards for a specific addressbook id.
*
* This method should return the following properties for each card:
* * carddata - raw vcard data
* * uri - Some unique url
* * lastmodified - A unix timestamp
*
* It's recommended to also return the following properties:
* * etag - A unique etag. This must change every time the card changes.
* * size - The size of the card in bytes.
*
* If these last two properties are provided, less time will be spent
* calculating them. If they are specified, you can also ommit carddata.
* This may speed up certain requests, especially with large cards.
*
* @param mixed $addressbookId
*
* @return array
*/
public function getCards($addressbookId)
{
$result = [];
$row['etag'] = '"etag"';
$row['lastmodified'] = 1680010509;
$row['uri'] = 'hop.vcf';
$row['size'] = '147';
$row['id'] = '2';
$result[] = $row;
// var_dump($result); exit;
return $result;
}
/**
* Returns a specific card.
*
* The same set of properties must be returned as with getCards. The only
* exception is that 'carddata' is absolutely required.
*
* If the card does not exist, you must return false.
*
* @param mixed $addressBookId
* @param string $cardUri
*
* @return array
*/
public function getCard($addressBookId, $cardUri)
{
$result['etag'] = '"123"';
$result['lastmodified'] = 123;
$result['uri'] = 'gnap';
$result['carddata'] = Account::first()->toVcard4();
return $result;
}
/**
* Returns a list of cards.
*
* This method should work identical to getCard, but instead return all the
* cards in the list as an array.
*
* If the backend supports this, it may allow for some speed-ups.
*
* @param mixed $addressBookId
*
* @return array
*/
public function getMultipleCards($addressBookId, array $uris)
{
return $this->getCards($addressBookId);
}
/**
* Creates a new card.
*
* The addressbook id will be passed as the first argument. This is the
* same id as it is returned from the getAddressBooksForUser method.
*
* The cardUri is a base uri, and doesn't include the full path. The
* cardData argument is the vcard body, and is passed as a string.
*
* It is possible to return an ETag from this method. This ETag is for the
* newly created resource, and must be enclosed with double quotes (that
* is, the string itself must contain the double quotes).
*
* You should only return the ETag if you store the carddata as-is. If a
* subsequent GET request on the same card does not have the same body,
* byte-by-byte and you did return an ETag here, clients tend to get
* confused.
*
* If you don't return an ETag, you can just return null.
*
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
*
* @return string|null
*/
public function createCard($addressBookId, $cardUri, $cardData)
{
return null;
}
/**
* Updates a card.
*
* The addressbook id will be passed as the first argument. This is the
* same id as it is returned from the getAddressBooksForUser method.
*
* The cardUri is a base uri, and doesn't include the full path. The
* cardData argument is the vcard body, and is passed as a string.
*
* It is possible to return an ETag from this method. This ETag should
* match that of the updated resource, and must be enclosed with double
* quotes (that is: the string itself must contain the actual quotes).
*
* You should only return the ETag if you store the carddata as-is. If a
* subsequent GET request on the same card does not have the same body,
* byte-by-byte and you did return an ETag here, clients tend to get
* confused.
*
* If you don't return an ETag, you can just return null.
*
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
*
* @return string|null
*/
public function updateCard($addressBookId, $cardUri, $cardData)
{
return null;
}
/**
* Deletes a card.
*
* @param mixed $addressBookId
* @param string $cardUri
*
* @return bool
*/
public function deleteCard($addressBookId, $cardUri)
{
return false;
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace App\Providers;
use App\Account;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use LaravelSabre\LaravelSabre;
use Sabre\DAVACL\PrincipalCollection;
//use Sabre\DAVACL\PrincipalBackend\PDO as PrincipalBackend;
use Sabre\CardDAV\Plugin as CardDAVPlugin;
use Sabre\DAV\Browser\Plugin as BrowserPlugin;
//use Sabre\CardDAV\Backend\PDO
class DAVServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
LaravelSabre::nodes(function () {
return $this->nodes();
});
LaravelSabre::plugins(function () {
return $this->plugins();
});
}
/**
* List of nodes for DAV Collection.
*/
private function nodes() : array
{
$contactBackend = new ContactBackend;
$principalBackend = new PrincipalBackend;
return [
//new \Sabre\DAVACL\PrincipalCollection($principalBackend),
new \Sabre\CardDAV\AddressBookRoot($principalBackend, $contactBackend),
//new PrincipalCollection($contactBackend),
];
//return Account::all()->toArray();
}
private function plugins()
{
yield new BrowserPlugin();
yield new CardDAVPlugin();
}
}

View file

@ -0,0 +1,215 @@
<?php
declare(strict_types=1);
namespace App\Providers;
use Sabre\DAV;
use Sabre\DAV\MkCol;
use Sabre\Uri;
use Sabre\DAVACL\PrincipalBackend\AbstractBackend;
/**
* PDO principal backend.
*
* This backend assumes all principals are in a single collection. The default collection
* is 'principals/', but this can be overridden.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class PrincipalBackend extends AbstractBackend
{
/**
* A list of additional fields to support.
*
* @var array
*/
protected $fieldMap = [
/*
* This property can be used to display the users' real name.
*/
'{DAV:}displayname' => [
'dbField' => 'displayname',
],
/*
* This is the users' primary email-address.
*/
'{http://sabredav.org/ns}email-address' => [
'dbField' => 'email',
],
];
/**
* Returns a list of principals based on a prefix.
*
* This prefix will often contain something like 'principals'. You are only
* expected to return principals that are in this base path.
*
* You are expected to return at least a 'uri' for every user, you can
* return any additional properties if you wish so. Common properties are:
* {DAV:}displayname
* {http://sabredav.org/ns}email-address - This is a custom SabreDAV
* field that's actualy injected in a number of other properties. If
* you have an email address, use this property.
*
* @param string $prefixPath
*
* @return array
*/
public function getPrincipalsByPrefix($prefixPath)
{
return [[
'uri' => 'default'
]];
}
/**
* Returns a specific principal, specified by it's path.
* The returned structure should be the exact same as from
* getPrincipalsByPrefix.
*
* @param string $path
*
* @return array
*/
public function getPrincipalByPath($path)
{
return [
'id' => 'default',
'uri' => 'default'
];
}
/**
* Updates one ore more webdav properties on a principal.
*
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
* To do the actual updates, you must tell this object which properties
* you're going to process with the handle() method.
*
* Calling the handle method is like telling the PropPatch object "I
* promise I can handle updating this property".
*
* Read the PropPatch documentation for more info and examples.
*
* @param string $path
*/
public function updatePrincipal($path, DAV\PropPatch $propPatch)
{
return true;
}
/**
* This method is used to search for principals matching a set of
* properties.
*
* This search is specifically used by RFC3744's principal-property-search
* REPORT.
*
* The actual search should be a unicode-non-case-sensitive search. The
* keys in searchProperties are the WebDAV property names, while the values
* are the property values to search on.
*
* By default, if multiple properties are submitted to this method, the
* various properties should be combined with 'AND'. If $test is set to
* 'anyof', it should be combined using 'OR'.
*
* This method should simply return an array with full principal uri's.
*
* If somebody attempted to search on a property the backend does not
* support, you should simply return 0 results.
*
* You can also just return 0 results if you choose to not support
* searching at all, but keep in mind that this may stop certain features
* from working.
*
* @param string $prefixPath
* @param string $test
*
* @return array
*/
public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof')
{
$principals = [];
return $principals;
}
/**
* Finds a principal by its URI.
*
* This method may receive any type of uri, but mailto: addresses will be
* the most common.
*
* Implementation of this API is optional. It is currently used by the
* CalDAV system to find principals based on their email addresses. If this
* API is not implemented, some features may not work correctly.
*
* This method must return a relative principal path, or null, if the
* principal was not found or you refuse to find it.
*
* @param string $uri
* @param string $principalPrefix
*
* @return string
*/
public function findByUri($uri, $principalPrefix)
{
$uri = null;
return $uri;
}
/**
* Returns the list of members for a group-principal.
*
* @param string $principal
*
* @return array
*/
public function getGroupMemberSet($principal)
{
$result = [];
return $result;
}
/**
* Returns the list of groups a principal is a member of.
*
* @param string $principal
*
* @return array
*/
public function getGroupMembership($principal)
{
$result = [];
return $result;
}
/**
* Updates the list of group members for a group principal.
*
* The principals should be passed as a list of uri's.
*
* @param string $principal
*/
public function setGroupMemberSet($principal, array $members)
{
}
/**
* Creates a new principal.
*
* This method receives a full path for the new principal. The mkCol object
* contains any additional webdav properties specified during the creation
* of the principal.
*
* @param string $path
*/
public function createPrincipal($path, MkCol $mkCol)
{
}
}

View file

@ -14,6 +14,7 @@
"endroid/qr-code": "^4.1",
"fakerphp/faker": "^1.21",
"laravel/framework": "^9.5",
"monicahq/laravel-sabre": "^1.7",
"namoshek/laravel-redis-sentinel": "^0.1.2",
"ovh/ovh": "^3.0",
"parsedown/laravel": "^1.2",

810
flexiapi/composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -228,6 +228,7 @@ return [
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\HelperServiceProvider::class,
App\Providers\DAVServiceProvider::class,
],

View file

@ -0,0 +1,59 @@
<?php
use LaravelSabre\Http\Middleware\Authorize;
return [
/*
|--------------------------------------------------------------------------
| LaravelSabre Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where LaravelSabre will be accessible from. If the
| setting is null, LaravelSabre will reside under the same domain as the
| application. Otherwise, this value will be used as the subdomain.
|
*/
'domain' => null,
/*
|--------------------------------------------------------------------------
| LaravelSabre Path
|--------------------------------------------------------------------------
|
| This is the URI path where LaravelSabre will be accessible from. Feel free
| to change this path to anything you like.
|
*/
'path' => 'dav',
/*
|--------------------------------------------------------------------------
| LaravelSabre Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable LaravelSabre.
|
*/
'enabled' => env('LARAVELSABRE_ENABLED', true),
/*
|--------------------------------------------------------------------------
| LaravelSabre Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every LaravelSabre route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => [
'web',
Authorize::class,
],
];