__init__.py 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # This file is part of Radicale - CalDAV and CardDAV server
  2. # Copyright © 2014 Jean-Marc Martins
  3. # Copyright © 2012-2017 Guillaume Ayoub
  4. # Copyright © 2017-2021 Unrud <unrud@outlook.com>
  5. # Copyright © 2024-2024 Peter Bieringer <pb@bieringer.de>
  6. #
  7. # This library is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This library is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  19. """
  20. Storage backend that stores data in the file system.
  21. Uses one folder per collection and one file per collection entry.
  22. """
  23. import os
  24. import time
  25. from typing import ClassVar, Iterator, Optional, Type
  26. from radicale import config
  27. from radicale.log import logger
  28. from radicale.storage.multifilesystem.base import CollectionBase, StorageBase
  29. from radicale.storage.multifilesystem.cache import CollectionPartCache
  30. from radicale.storage.multifilesystem.create_collection import \
  31. StoragePartCreateCollection
  32. from radicale.storage.multifilesystem.delete import CollectionPartDelete
  33. from radicale.storage.multifilesystem.discover import StoragePartDiscover
  34. from radicale.storage.multifilesystem.get import CollectionPartGet
  35. from radicale.storage.multifilesystem.history import CollectionPartHistory
  36. from radicale.storage.multifilesystem.lock import (CollectionPartLock,
  37. StoragePartLock)
  38. from radicale.storage.multifilesystem.meta import CollectionPartMeta
  39. from radicale.storage.multifilesystem.move import StoragePartMove
  40. from radicale.storage.multifilesystem.sync import CollectionPartSync
  41. from radicale.storage.multifilesystem.upload import CollectionPartUpload
  42. from radicale.storage.multifilesystem.verify import StoragePartVerify
  43. class Collection(
  44. CollectionPartDelete, CollectionPartMeta, CollectionPartSync,
  45. CollectionPartUpload, CollectionPartGet, CollectionPartCache,
  46. CollectionPartLock, CollectionPartHistory, CollectionBase):
  47. _etag_cache: Optional[str]
  48. def __init__(self, storage_: "Storage", path: str,
  49. filesystem_path: Optional[str] = None) -> None:
  50. super().__init__(storage_, path, filesystem_path)
  51. self._etag_cache = None
  52. @property
  53. def path(self) -> str:
  54. return self._path
  55. @property
  56. def last_modified(self) -> str:
  57. def relevant_files_iter() -> Iterator[str]:
  58. yield self._filesystem_path
  59. if os.path.exists(self._props_path):
  60. yield self._props_path
  61. for href in self._list():
  62. yield os.path.join(self._filesystem_path, href)
  63. last = max(map(os.path.getmtime, relevant_files_iter()))
  64. return time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(last))
  65. @property
  66. def etag(self) -> str:
  67. # reuse cached value if the storage is read-only
  68. if self._storage._lock.locked == "w" or self._etag_cache is None:
  69. self._etag_cache = super().etag
  70. return self._etag_cache
  71. class Storage(
  72. StoragePartCreateCollection, StoragePartLock, StoragePartMove,
  73. StoragePartVerify, StoragePartDiscover, StorageBase):
  74. _collection_class: ClassVar[Type[Collection]] = Collection
  75. def __init__(self, configuration: config.Configuration) -> None:
  76. super().__init__(configuration)
  77. self._makedirs_synced(self._filesystem_folder)
  78. logger.info("storage location: %r", self._filesystem_folder);
  79. logger.info("storage cache subfolder usage for item: %s", self._use_cache_subfolder_for_item);