storage/filesystem: implement more operations
Everything except QueryAddressObjects is now functional, though not feature-complete. Simple operations work, e.g. via Evolution.
This commit is contained in:
parent
65346f0317
commit
8b46585109
@ -2,6 +2,8 @@ package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -56,6 +58,31 @@ func (b *filesystemBackend) pathForContext(ctx context.Context) (string, error)
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func etagForFile(path string) (string, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
csum := md5.Sum(data)
|
||||
return base64.StdEncoding.EncodeToString(csum[:]), nil
|
||||
}
|
||||
|
||||
func vcardFromFile(path string) (*vcard.Card, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
dec := vcard.NewDecoder(f)
|
||||
card, err := dec.Decode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &card, nil
|
||||
}
|
||||
|
||||
func createDefaultAddressBook(path string) error {
|
||||
// TODO what should the default address book look like?
|
||||
defaultAB := carddav.AddressBook{
|
||||
@ -105,30 +132,114 @@ func (b *filesystemBackend) AddressBook(ctx context.Context) (*carddav.AddressBo
|
||||
return &addressBook, nil
|
||||
}
|
||||
|
||||
func (*filesystemBackend) GetAddressObject(ctx context.Context, path string, req *carddav.AddressDataRequest) (*carddav.AddressObject, error) {
|
||||
//TODO
|
||||
log.Fatalf("PutAddressObject(ctx, '%s', req): not implemented", path)
|
||||
return nil, nil
|
||||
func (b *filesystemBackend) GetAddressObject(ctx context.Context, path string, req *carddav.AddressDataRequest) (*carddav.AddressObject, error) {
|
||||
basePath, err := b.pathForContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path = filepath.Join(basePath, path)
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
card, err := vcardFromFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
etag, err := etagForFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj := carddav.AddressObject{
|
||||
Path: "/" + filepath.Base(path),
|
||||
ModTime: info.ModTime(),
|
||||
ETag: etag,
|
||||
Card: *card,
|
||||
}
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (*filesystemBackend) ListAddressObjects(ctx context.Context, req *carddav.AddressDataRequest) ([]carddav.AddressObject, error) {
|
||||
return []carddav.AddressObject{}, nil
|
||||
//panic("TODO")
|
||||
func (b *filesystemBackend) ListAddressObjects(ctx context.Context, req *carddav.AddressDataRequest) ([]carddav.AddressObject, error) {
|
||||
result := []carddav.AddressObject{}
|
||||
|
||||
path, err := b.pathForContext(ctx)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
err = filepath.Walk(path, func(filename string, info os.FileInfo, err error) error {
|
||||
// TODO this heuristic will not work for all clients
|
||||
if filepath.Ext(filename) != ".vcf" {
|
||||
return nil
|
||||
}
|
||||
|
||||
card, err := vcardFromFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
etag, err := etagForFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj := carddav.AddressObject{
|
||||
Path: "/" + filepath.Base(filename),
|
||||
ModTime: info.ModTime(),
|
||||
ETag: etag,
|
||||
Card: *card,
|
||||
}
|
||||
result = append(result, obj)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (*filesystemBackend) QueryAddressObjects(ctx context.Context, query *carddav.AddressBookQuery) ([]carddav.AddressObject, error) {
|
||||
// TODO
|
||||
log.Println("QueryAddressObjects called, not implemented")
|
||||
return []carddav.AddressObject{}, nil
|
||||
//panic("TODO")
|
||||
}
|
||||
|
||||
func (*filesystemBackend) PutAddressObject(ctx context.Context, path string, card vcard.Card) (loc string, err error) {
|
||||
//TODO
|
||||
log.Fatalf("PutAddressObject(ctx, '%s', card): not implemented", path)
|
||||
return "", nil
|
||||
func (b *filesystemBackend) PutAddressObject(ctx context.Context, path string, card vcard.Card) (loc string, err error) {
|
||||
basePath, err := b.pathForContext(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
path = filepath.Join(basePath, path)
|
||||
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
enc := vcard.NewEncoder(f)
|
||||
err = enc.Encode(card)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (*filesystemBackend) DeleteAddressObject(ctx context.Context, path string) error {
|
||||
//TODO
|
||||
log.Fatalf("DeleteAddressObject(ctx, '%s'): not implemented", path)
|
||||
func (b *filesystemBackend) DeleteAddressObject(ctx context.Context, path string) error {
|
||||
basePath, err := b.pathForContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path = filepath.Join(basePath, path)
|
||||
//TODO does this need more security/sanity checks?
|
||||
err = os.Remove(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user