Piki is a minimal wiki
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

page.py 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. from django.conf import settings
  2. import fstools
  3. import logging
  4. from pages import messages, url_page
  5. import mycreole
  6. import os
  7. logger = logging.getLogger(settings.ROOT_LOGGER_NAME).getChild(__name__)
  8. class base_page(object):
  9. FOLDER_CONTENT = 'content'
  10. FILE_NAME = 'page'
  11. SPLITCHAR = ":"
  12. def __init__(self, path):
  13. if path.startswith(settings.PAGES_ROOT):
  14. self._path = path
  15. else:
  16. self._path = os.path.join(settings.PAGES_ROOT, path.replace("/", 2*self.SPLITCHAR))
  17. self._raw_page_src = None
  18. def _load_page_src(self):
  19. if self._raw_page_src is None:
  20. try:
  21. with open(self.filename, 'r') as fh:
  22. self._raw_page_src = fh.read()
  23. except FileNotFoundError:
  24. self._raw_page_src = ""
  25. def update_page(self, page_txt):
  26. from .search import update_item
  27. #
  28. folder = os.path.dirname(self.filename)
  29. if not os.path.exists(folder):
  30. fstools.mkdir(folder)
  31. with open(self.filename, 'w') as fh:
  32. fh.write(page_txt)
  33. update_item(self)
  34. @property
  35. def filename(self):
  36. return os.path.join(self._path, self.FOLDER_CONTENT, self.FILE_NAME)
  37. @property
  38. def rel_path(self):
  39. return os.path.basename(self._path).replace(2*self.SPLITCHAR, "/")
  40. def rel_path_is_valid(self):
  41. return not self.SPLITCHAR in self.rel_path
  42. def is_available(self):
  43. is_a = os.path.isfile(self.filename)
  44. if not is_a:
  45. logger.info("page.is_available: Not available - %s", self.filename)
  46. return is_a
  47. @property
  48. def title(self):
  49. return os.path.basename(self._path).split("::")[-1]
  50. @property
  51. def raw_page_src(self):
  52. self._load_page_src()
  53. return self._raw_page_src
  54. class creole_page(base_page):
  55. FOLDER_ATTACHMENTS = "attachments"
  56. def __init__(self, request, path) -> None:
  57. self._request = request
  58. super().__init__(path)
  59. @property
  60. def attachment_path(self):
  61. return os.path.join(os.path.basename(self._path), self.FOLDER_ATTACHMENTS)
  62. def render_to_html(self):
  63. if self.is_available():
  64. return self.render_text(self._request, self.raw_page_src)
  65. else:
  66. messages.unavailable_msg_page(self._request, self.rel_path)
  67. return ""
  68. def render_text(self, request, txt):
  69. macros = {
  70. "subpages": self.macro_subpages,
  71. "allpages": self.macro_allpages,
  72. }
  73. return mycreole.render(request, txt, self.attachment_path, macros=macros)
  74. def macro_allpages(self, *args, **kwargs):
  75. kwargs["allpages"] = True
  76. return self.macro_subpages(*args, **kwargs)
  77. def macro_subpages(self, *args, **kwargs):
  78. allpages = kwargs.pop("allpages", False)
  79. #
  80. def parse_depth(s: str):
  81. try:
  82. return int(s)
  83. except ValueError:
  84. pass
  85. params = kwargs.get('', '')
  86. startname = ''
  87. depth = parse_depth(params)
  88. if depth is None:
  89. params = params.split(",")
  90. depth = parse_depth(params[0])
  91. if len(params) == 2:
  92. startname = params[1]
  93. elif depth is None:
  94. startname = params[0]
  95. if depth is None:
  96. depth = 9999
  97. #
  98. rv = ""
  99. # create a rel_path list
  100. pathlist = [base_page(path).rel_path for path in fstools.dirlist(settings.PAGES_ROOT, rekursive=False)]
  101. # sort basename
  102. pathlist.sort(key=os.path.basename)
  103. last_char = None
  104. for contentname in pathlist:
  105. #
  106. if (contentname.startswith(self.rel_path) or allpages) and contentname != self.rel_path:
  107. if allpages:
  108. name = contentname
  109. else:
  110. name = contentname[len(self.rel_path)+1:]
  111. if name.count('/') < depth and name.startswith(startname):
  112. if last_char != os.path.basename(name)[0].upper():
  113. last_char = os.path.basename(name)[0].upper()
  114. if last_char is not None:
  115. rv += "</ul>\n"
  116. rv += f'<h3>{last_char}</h3>\n<ul>\n'
  117. rv += f' <li><a href="{url_page(self._request, contentname)}">{name}</a></li>\n'
  118. if len(rv) > 0:
  119. rv += "</ul>\n"
  120. return rv