Compare commits

...

2 Commits

Author SHA1 Message Date
4d77be2721 Instructions moved to piki website 2024-10-16 07:09:34 +02:00
18dd102fe2 Tree view added 2024-10-16 07:09:06 +02:00
9 changed files with 96 additions and 84 deletions

View File

@ -1,62 +1,2 @@
# piki # piki
Piki is a minimal wiki. You find further information under https://piki.mount-mockery.de
Piki is a minimal wiki.
## Installation
### Get the repository
####Go to the subfolder, where you want to create your new Piki-Application (here ~/tmp)
cd ~/tmp
#### Clone the repository
git clone https://git.mount-mockery.de/application/piki.git
#### Change to your repository and initialise it completely
cd piki
git submodule init
git submodule update
### Create your virtual environment
#### Create python3 environment
python3 -m venv venv
#### Activate the environment
source venv/bin/activate
#### Install PaTT Requirements
pip install -r requirements.txt
## Configuration and Initialisation of Piki
### Create your config File
#### Copy the config example
cp config_example/config.py .
chmod 700 config.py
#### Set a secret key
Edit config.py and add a SECRET_KEY. Generate the secret e.g by executing the following command:
python manage.py
At the End of the error message you'll see a random secret:
KeyError: "You need to create a config.py file including at least a SECRET_KEY definition (e.g.: --> **'HERE IS THE RANDOM SECRET ;-)'** <--)."
### Create your initial database and first user for Patt
python manage.py migrate
python manage.py createsuperuser
### Finalise Configuration
Now there are two ways to finalise your configuration. The first way is for a test or development system. The other is for a production System.
1. **Test or development System:** Edit config.py and set the Variable DEBUG to True.
2. **Production System:** Edit config.py and set the Variable ALLOWED_HOSTS. Execute "python manage.py collectstatic" to create a folder including all static files. Then add PaTT to your server configuration. See also [Django Documnetation](https://docs.djangoproject.com/en/3.1/howto/deployment/) for further information.
## Start the Test or development System
### Go to the folder, where your PaTT-Application is locates (here ~/tmp/piki)
cd ~/tmp/piki
###Activate your Virtual Environment
source activate
###Start the Server
python manage.py runserver

View File

@ -0,0 +1,5 @@
{
"modified_time": 1729022206,
"modified_user": "system-page",
"creation_time": 1729022206
}

View File

@ -0,0 +1,2 @@
= Tree
<<allpagestree>>

View File

@ -10,15 +10,15 @@ def params(**kwargs):
return params return params
def url_page(request, rel_path, **kwargs): def url_page(rel_path, **kwargs):
return reverse('page-page', kwargs={'rel_path': rel_path}) + params(**kwargs) return reverse('page-page', kwargs={'rel_path': rel_path}) + params(**kwargs)
def url_helpview(request, page): def url_helpview(page):
return reverse('page-helpview', kwargs={'page': page}) return reverse('page-helpview', kwargs={'page': page})
def url_edit(request, rel_path, **kwargs): def url_edit(rel_path, **kwargs):
return reverse('page-edit', kwargs={'rel_path': rel_path}) + params(**kwargs) return reverse('page-edit', kwargs={'rel_path': rel_path}) + params(**kwargs)

View File

@ -20,6 +20,7 @@ BACK_UID = 'back'
EDIT_UID = 'edit' EDIT_UID = 'edit'
HELP_UID = 'help' HELP_UID = 'help'
INDEX_UID = 'index' INDEX_UID = 'index'
TREE_UID = 'tree'
NAVIGATION_ENTRY_UID = 'navigation-%s' NAVIGATION_ENTRY_UID = 'navigation-%s'
@ -65,7 +66,7 @@ def menubar(context, request, caller_name, **kwargs):
if not cms_mode_active(request): if not cms_mode_active(request):
menubar_users(bar, request) menubar_users(bar, request)
add_help_menu(request, bar, "current_help_page" in kwargs) add_help_menu(request, bar, "current_help_page" in kwargs)
add_index_menu(request, bar, kwargs.get("rel_path", '')) add_nav_links(request, bar, kwargs.get("rel_path", ''))
finalise_bar(request, bar) finalise_bar(request, bar)
@ -100,7 +101,7 @@ def navigation_entry_parameters(request, path):
NAVIGATION_ENTRY_UID % os.path.basename(path), # uid NAVIGATION_ENTRY_UID % os.path.basename(path), # uid
'/' + os.path.basename(path), # name '/' + os.path.basename(path), # name
None, # icon None, # icon
pages.url_page(request, path), # url pages.url_page(path), # url
False, # left False, # left
False # active False # active
) )
@ -111,21 +112,29 @@ def add_help_menu(request, bar, active):
HELP_UID, # uid HELP_UID, # uid
_('Help'), # name _('Help'), # name
color_icon_url(request, 'help.png'), # icon color_icon_url(request, 'help.png'), # icon
pages.url_helpview(request, 'main'), # url pages.url_helpview('main'), # url
True, # left True, # left
active # active active # active
) )
def add_index_menu(request, bar, rel_path): def add_nav_links(request, bar, rel_path):
bar.append_entry( bar.append_entry(
INDEX_UID, # uid INDEX_UID, # uid
_('Index'), # name _('Index'), # name
color_icon_url(request, 'edit.png'), # icon color_icon_url(request, 'edit.png'), # icon
pages.url_page(request, 'index'), # url pages.url_page('index'), # url
True, # left True, # left
request.path == "/page/index" # active request.path == "/page/index" # active
) )
bar.append_entry(
TREE_UID, # uid
_('Tree'), # name
color_icon_url(request, 'tree.png'), # icon
pages.url_page('tree'), # url
True, # left
request.path == "/page/tree" # active
)
def add_edit_menu(request, bar, rel_path): def add_edit_menu(request, bar, rel_path):
@ -133,7 +142,7 @@ def add_edit_menu(request, bar, rel_path):
EDIT_UID, # uid EDIT_UID, # uid
_('Edit'), # name _('Edit'), # name
color_icon_url(request, 'edit2.png'), # icon color_icon_url(request, 'edit2.png'), # icon
pages.url_edit(request, rel_path), # url pages.url_edit(rel_path), # url
True, # left True, # left
False # active False # active
) )
@ -156,7 +165,7 @@ def add_meta_menu(request, bar, rel_path):
EDIT_UID, # uid EDIT_UID, # uid
_('Page'), # name _('Page'), # name
color_icon_url(request, 'display.png'), # icon color_icon_url(request, 'display.png'), # icon
pages.url_page(request, rel_path), # url pages.url_page(rel_path), # url
True, # left True, # left
False # active False # active
) )
@ -165,7 +174,7 @@ def add_meta_menu(request, bar, rel_path):
EDIT_UID, # uid EDIT_UID, # uid
_('Meta'), # name _('Meta'), # name
color_icon_url(request, 'info.png'), # icon color_icon_url(request, 'info.png'), # icon
pages.url_page(request, rel_path, meta=None), # url pages.url_page(rel_path, meta=None), # url
True, # left True, # left
False # active False # active
) )

View File

@ -131,7 +131,7 @@ def actionbar(context, request, current_help_page=None, **kwargs):
HELP_UID + '-%s' % name.lower(), # uid HELP_UID + '-%s' % name.lower(), # uid
_(name), # name _(name), # name
color_icon_url(request, num + '.png'), # icon color_icon_url(request, num + '.png'), # icon
pages.url_helpview(request, name.lower()), # url pages.url_helpview(name.lower()), # url
True, # left True, # left
name.lower() == current_help_page, # active name.lower() == current_help_page, # active
) )

View File

@ -22,6 +22,7 @@ def full_path_all_pages(expression="*"):
system_pages = fstools.dirlist(settings.SYSTEM_PAGES_ROOT, expression=expression, rekursive=False) system_pages = fstools.dirlist(settings.SYSTEM_PAGES_ROOT, expression=expression, rekursive=False)
system_pages = [os.path.join(settings.PAGES_ROOT, os.path.basename(path)) for path in system_pages] system_pages = [os.path.join(settings.PAGES_ROOT, os.path.basename(path)) for path in system_pages]
pages = fstools.dirlist(settings.PAGES_ROOT, expression=expression, rekursive=False) pages = fstools.dirlist(settings.PAGES_ROOT, expression=expression, rekursive=False)
# TODO: strip path, if page or meta.json is missing
return list(set(system_pages + pages)) return list(set(system_pages + pages))
@ -197,15 +198,15 @@ class page_django(page_data):
name = _("Current") name = _("Current")
meta += f"| {name} \ meta += f"| {name} \
| {timestamp_to_datetime(self._request, mtime)} \ | {timestamp_to_datetime(self._request, mtime)} \
| [[{url_page(self._request, self.rel_path)} | Page]] \ | [[{url_page(self.rel_path)} | Page]] \
| [[{url_page(self._request, self.rel_path, meta=None)} | Meta]]\n" | [[{url_page(self.rel_path, meta=None)} | Meta]]\n"
# History # History
for num in reversed(hnl): for num in reversed(hnl):
p = page_wrapped(self._request, self._path, history_version=num) p = page_wrapped(self._request, self._path, history_version=num)
meta += f"| {num} \ meta += f"| {num} \
| {timestamp_to_datetime(self._request, p.modified_time)} \ | {timestamp_to_datetime(self._request, p.modified_time)} \
| [[{url_page(self._request, p.rel_path, history=num)} | Page]] \ | [[{url_page(p.rel_path, history=num)} | Page]] \
| [[{url_page(self._request, p.rel_path, meta=None, history=num)} | Meta]] (with page changes)\n" | [[{url_page(p.rel_path, meta=None, history=num)} | Meta]] (with page changes)\n"
# Diff # Diff
html_diff = "" html_diff = ""
if self._history_version: if self._history_version:
@ -222,6 +223,8 @@ class page_django(page_data):
macros = { macros = {
"subpages": self.macro_subpages, "subpages": self.macro_subpages,
"allpages": self.macro_allpages, "allpages": self.macro_allpages,
"subpagetree": self.macro_subpagetree,
"allpagestree": self.macro_allpagestree,
} }
return mycreole.render(request, txt, self.attachment_path, macros=macros) return mycreole.render(request, txt, self.attachment_path, macros=macros)
@ -231,6 +234,7 @@ class page_django(page_data):
def macro_subpages(self, *args, **kwargs): def macro_subpages(self, *args, **kwargs):
allpages = kwargs.pop("allpages", False) allpages = kwargs.pop("allpages", False)
tree = kwargs.pop("tree", False)
# #
def parse_depth(s: str): def parse_depth(s: str):
@ -263,7 +267,19 @@ class page_django(page_data):
self._request, self._request,
[page_django(self._request, path) for path in full_path_all_pages(expression)] [page_django(self._request, path) for path in full_path_all_pages(expression)]
) )
return pl.html_list(depth=depth, filter_str=filter_str, parent_rel_path=parent_rel_path) if tree:
return page_tree(pl).html()
else:
return pl.html_list(depth=depth, filter_str=filter_str, parent_rel_path=parent_rel_path)
def macro_allpagestree(self, *args, **kwargs):
kwargs["allpages"] = True
kwargs["tree"] = True
return self.macro_subpages(*args, **kwargs)
def macro_subpagetree(self, * args, **kwargs):
kwargs["tree"] = True
return self.macro_subpages(*args, **kwargs)
class page_list(list): class page_list(list):
@ -290,13 +306,50 @@ class page_list(list):
if last_char != first_char: if last_char != first_char:
last_char = first_char last_char = first_char
rv += f"=== {first_char}\n" rv += f"=== {first_char}\n"
rv += f"* [[{url_page(self._request, page.rel_path)} | {name} ]]\n" rv += f"* [[{url_page(page.rel_path)} | {name} ]]\n"
return rv return rv
def html_list(self, depth=9999, filter_str='', parent_rel_path=''): def html_list(self, depth=9999, filter_str='', parent_rel_path=''):
return mycreole.render_simple(self.creole_list(depth, filter_str, parent_rel_path)) return mycreole.render_simple(self.creole_list(depth, filter_str, parent_rel_path))
class page_tree(dict):
T_PATTERN = "├── "
L_PATTERN = "└── "
I_PATTERN = "│   "
D_PATTERN = "   &nbsp;&nbsp;&nbsp;"
def __init__(self, pl: page_list):
super().__init__()
for page in pl:
store_item = self
for entry in page.rel_path.split("/"):
if not entry in store_item:
store_item[entry] = {}
store_item = store_item[entry]
def html(self, rel_path=None, fill=""):
base = self
try:
for key in rel_path.split("/"):
base = base[key]
except AttributeError:
rel_path = ''
#
rv = ""
#
l = len(base)
for entry in sorted(list(base.keys())):
l -= 1
page_path = os.path.join(rel_path, entry)
page = page_wrapped(None, page_path)
if page.is_available():
entry = f'<a href="{url_page(page_path)}">{entry}</a>'
rv += fill + (self.L_PATTERN if l == 0 else self.T_PATTERN) + entry + "<br>\n"
rv += self.html(page_path, fill=fill+(self.D_PATTERN if l == 0 else self.I_PATTERN))
return rv
class page_wrapped(object): class page_wrapped(object):
""" """
This class holds different page and meta instances and decides which will be used in which case. This class holds different page and meta instances and decides which will be used in which case.
@ -395,6 +448,9 @@ class page_wrapped(object):
rv = page.attachment_path rv = page.attachment_path
return rv return rv
def is_available(self):
return self._page.is_available() or self._system_page.is_available()
@property @property
def raw_page_src(self): def raw_page_src(self):
page = self.__page_choose__() page = self.__page_choose__()

View File

@ -23,7 +23,7 @@ logger = logging.getLogger(settings.ROOT_LOGGER_NAME).getChild(__name__)
def root(request): def root(request):
return HttpResponseRedirect(url_page(request, config.STARTPAGE)) return HttpResponseRedirect(url_page(config.STARTPAGE))
def page(request, rel_path): def page(request, rel_path):
@ -92,7 +92,7 @@ def edit(request, rel_path):
messages.edit_success(request) messages.edit_success(request)
else: else:
messages.edit_no_change(request) messages.edit_no_change(request)
return HttpResponseRedirect(url_page(request, rel_path)) return HttpResponseRedirect(url_page(rel_path))
elif preview is not None: elif preview is not None:
form = EditForm(page_data=page_txt, page_tags=tags) form = EditForm(page_data=page_txt, page_tags=tags)
# #
@ -107,10 +107,10 @@ def edit(request, rel_path):
) )
return render(request, 'pages/page_form.html', context=context) return render(request, 'pages/page_form.html', context=context)
else: else:
return HttpResponseRedirect(url_page(request, rel_path)) return HttpResponseRedirect(url_page(rel_path))
else: else:
messages.permission_denied_msg_page(request, rel_path) messages.permission_denied_msg_page(request, rel_path)
return HttpResponseRedirect(url_page(request, rel_path)) return HttpResponseRedirect(url_page(rel_path))
def search(request): def search(request):

2
themes

@ -1 +1 @@
Subproject commit c63d8731fe85374ef74abf24b0d205bce24f66b1 Subproject commit c13b45a7f736c0e8658fbd24ff826ad9b5d336e6