verify.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  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-2018 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. import contextlib
  19. from radicale import pathutils, storage
  20. from radicale.log import logger
  21. class CollectionVerifyMixin:
  22. @classmethod
  23. def verify(cls):
  24. item_errors = collection_errors = 0
  25. @contextlib.contextmanager
  26. def exception_cm(sane_path, href=None):
  27. nonlocal item_errors, collection_errors
  28. try:
  29. yield
  30. except Exception as e:
  31. if href:
  32. item_errors += 1
  33. name = "item %r in %r" % (href, sane_path)
  34. else:
  35. collection_errors += 1
  36. name = "collection %r" % sane_path
  37. logger.error("Invalid %s: %s", name, e, exc_info=True)
  38. remaining_sane_paths = [""]
  39. while remaining_sane_paths:
  40. sane_path = remaining_sane_paths.pop(0)
  41. path = pathutils.unstrip_path(sane_path, True)
  42. logger.debug("Verifying collection %r", sane_path)
  43. with exception_cm(sane_path):
  44. saved_item_errors = item_errors
  45. collection = None
  46. uids = set()
  47. has_child_collections = False
  48. for item in cls.discover(path, "1", exception_cm):
  49. if not collection:
  50. collection = item
  51. collection.get_meta()
  52. continue
  53. if isinstance(item, storage.BaseCollection):
  54. has_child_collections = True
  55. remaining_sane_paths.append(item.path)
  56. elif item.uid in uids:
  57. cls.logger.error(
  58. "Invalid item %r in %r: UID conflict %r",
  59. item.href, sane_path, item.uid)
  60. else:
  61. uids.add(item.uid)
  62. logger.debug("Verified item %r in %r",
  63. item.href, sane_path)
  64. if item_errors == saved_item_errors:
  65. collection.sync()
  66. if has_child_collections and collection.get_meta("tag"):
  67. cls.logger.error("Invalid collection %r: %r must not have "
  68. "child collections", sane_path,
  69. collection.get_meta("tag"))
  70. return item_errors == 0 and collection_errors == 0