multifilesystem.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # -*- coding: utf-8 -*-
  2. #
  3. # This file is part of Radicale Server - Calendar Server
  4. # Copyright © 2013 Guillaume Ayoub
  5. # Copyright © 2013 Jean-Marc Martins
  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. Multi files per calendar filesystem storage backend.
  21. """
  22. import os
  23. import shutil
  24. import time
  25. from . import filesystem
  26. from .. import ical
  27. class Collection(filesystem.Collection):
  28. """Collection stored in several files per calendar."""
  29. def _create_dirs(self):
  30. if not os.path.exists(self._path):
  31. os.makedirs(self._path)
  32. @property
  33. def headers(self):
  34. return (
  35. ical.Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"),
  36. ical.Header("VERSION:%s" % self.version))
  37. def write(self, headers=None, items=None):
  38. self._create_dirs()
  39. headers = headers or self.headers
  40. items = items if items is not None else self.items
  41. timezones = list(set(i for i in items if isinstance(i, ical.Timezone)))
  42. components = [i for i in items if isinstance(i, ical.Component)]
  43. for component in components:
  44. text = ical.serialize(self.tag, headers, [component] + timezones)
  45. path = os.path.join(self._path, component.name)
  46. with filesystem.open(path, "w") as fd:
  47. fd.write(text)
  48. def delete(self):
  49. shutil.rmtree(self._path)
  50. def remove(self, name):
  51. if os.path.exists(os.path.join(self._path, name)):
  52. os.remove(os.path.join(self._path, name))
  53. @property
  54. def text(self):
  55. components = (
  56. ical.Timezone, ical.Event, ical.Todo, ical.Journal, ical.Card)
  57. items = set()
  58. try:
  59. for filename in os.listdir(self._path):
  60. with filesystem.open(os.path.join(self._path, filename)) as fd:
  61. items.update(self._parse(fd.read(), components))
  62. except IOError:
  63. return ""
  64. else:
  65. return ical.serialize(
  66. self.tag, self.headers, sorted(items, key=lambda x: x.name))
  67. @classmethod
  68. def is_node(cls, path):
  69. path = os.path.join(filesystem.FOLDER, path.replace("/", os.sep))
  70. return os.path.isdir(path) and not os.path.exists(path + ".props")
  71. @classmethod
  72. def is_leaf(cls, path):
  73. path = os.path.join(filesystem.FOLDER, path.replace("/", os.sep))
  74. return os.path.isdir(path) and os.path.exists(path + ".props")
  75. @property
  76. def last_modified(self):
  77. last = max([
  78. os.path.getmtime(os.path.join(self._path, filename))
  79. for filename in os.listdir(self._path)] or [0])
  80. return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(last))