__init__.py 3.6 KB

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