Newer
Older
class DictConverter:
def __init__(self, factories):
self.factories = factories
def convert(self, item, lang, key = None):
if isinstance(item, dict):
res = {}
for k in item.keys():
res[k] = self.convert(item[k], lang, k)
return res
elif isinstance(item, list):
res = []
for i in item:
res.append(self.convert(i, lang))
return res
# Replace specific string keywords with their referenced objects
elif isinstance(item, str) and key == "link":
return self.factories['link'].get_by_raw(item, lang)
elif isinstance(item, str) and key == "tag":
return self.factories['tag'].get(item, lang)
elif isinstance(item, str) and key == "file":
return self.factories['file'].get(item)
elif isinstance(item, str) and key == "page":
return self.factories['page'].get(item, lang)
#elif isinstance(item, str) and key == "slug": # Doesn't work because 'slug' is used to override the slug of a page in its metadata.
# return self.factories['page'].get(item, lang)
else:
return item
class LocalizedConfigFactory(DictConverter):
def __init__(self, config, factories):
super().__init__(factories)
self.config = config
self.store = {}
def get(self, lang):
if lang not in self.store:
self.store[lang] = self.convert(self.config, lang, None)
return self.store[lang]
class FileFactory:
def __init__(self, config, factories):
self.config = config
self.factories = factories
self.store = {}
def get(self, filename):
if filename not in self.store:
self.store[filename] = File(filename, self.config, self.factories)
return self.store[filename];
def all(self):
return self.store
class File:
def __init__(self, filename, config, factories):
self.name = filename
self._config = config
self._factories = factories
self.initialized = False
def init(self, rawcontents, subpathlist):
if self.initialized:
raise Exception("Tried initializing file twice. Perhaps two files with same name exist? ", self.name)
self.initialized = True
self.rawcontents = rawcontents
self.subpathlist = subpathlist
self.link = self._factories['link'].get_by_type("file", self.name)
def __init__(self, config, factories):
self.config = config
self.factories = factories
for lang in self.config['lang']['supported']:
self.store[lang] = {}
def has(self, slug, lang):
return (slug in self.store[lang])
self.status = "uninitialized"
self.title = "N/A"
self._metadata = {}
self.content = []
def init(self, filename, subpath, raw, metadata, content, title, category, date_created, date_modified, authors, last_modification_author, status):
dictconverter = DictConverter(self._factories)
self._metadata = dictconverter.convert(metadata, self.lang)
self.category = self._factories['tag'].get(category, self.lang)
self.date_created = Date(date_created, self.config)
self.date_modified = Date(date_modified, self.config)
self.authors.add(self._factories['author'].get(local_part + '@' + domain, name))
self.last_modification_author = self._factories['author'].get(last_modification_author[0] + '@' + last_modification_author[1], last_modification_author[2])
else:
self.last_modification_author = None
#print(authors)
#print(last_modification_author)
# category
self.category.reg_page(self, True)
# url
#self.url = self.lang + '/' + self.category.name + '/' + self.slug + ".html"
self.link = self._factories['link'].get_by_type("slug", self.slug, self.lang)
gitlabsettings = self._config["gitlab"]
raw_edit_url = gitlabsettings["edit_url"]["prefix"]
raw_edit_url += '/'.join(self.subpath)
if len(self.subpath):
raw_edit_url += '/'
raw_edit_url += self.filename
raw_edit_url += gitlabsettings["edit_url"]["suffix"]
self.edit_url = self._factories['link'].get_by_raw(raw_edit_url, self.lang)
raw_view_url = gitlabsettings["view_url"]["prefix"]
raw_view_url += '/'.join(self.subpath)
if len(self.subpath):
raw_view_url += '/'
raw_view_url += self.filename
raw_view_url += gitlabsettings["view_url"]["suffix"]
self.view_url = self._factories['link'].get_by_raw(raw_view_url, self.lang)
raw_history_url = gitlabsettings["history_url"]["prefix"]
raw_history_url += '/'.join(self.subpath)
if len(self.subpath):
raw_history_url += '/'
raw_history_url += self.filename
raw_history_url += gitlabsettings["history_url"]["suffix"]
self.history_url = self._factories['link'].get_by_raw(raw_history_url, self.lang)
def get_config(self):
if not self._config:
self._config = self._factories['config'].get(self.lang)
return self._config
config = property(get_config, None, None)
if self.lang == deflang:
return self._metadata
defpage = self._factories['page'].get(self.slug, deflang)
return res
metadata = property(get_metadata, None, None)
if not self.initialized:
raise Exception("Page not initialized.")
res = []
if 'tags' in self.metadata:
rawtags = self.tags_str_to_list(self.metadata['tags'])
for t in rawtags:
if (t != self.category.name):
tag.reg_page(self)
res.append(tag)
res.append(self.category) # the category is also a default tag
return res
tags = property(get_tags, None, None)
def get_relevance(self):
res = {}
res['is_relevant'] = False
res['was_relevant'] = False
res['will_be_relevant'] = False
if 'relevant' in self.metadata:
lrel = self.metadata['relevant']
if not isinstance(lrel, dict):
prio = lrel
lrel = {}
lrel['prio'] = prio
res['is_relevant'] = True
return res
relevance = property(get_relevance, None, None)
def get_template(self):
if 'template' in self.metadata:
return self.metadata['template']
else:
template = property(get_template, None, None)
if not self.initialized:
raise Exception("Page not initialized.")
res = []
l = s.split(',')
for t in l:
t = t.lower()
t = t.lstrip()
t = t.rstrip()
if len(t) > 0:
res.append(t)
return res
def get_prio(self):
if 'prio' in self.metadata:
return self.metadata['prio']
else:
return 0
prio = property(get_prio, None, None)
def __lt__(self, other): # for sorting by date modified (default)
if not self.initialized:
raise Exception("Page not initialized.")
class TagFactory:
def __init__(self, config, factories):
self.config = config
self.factories = factories
self.store = {}
for lang in self.config['lang']['supported']:
self.store[lang] = {}
def get(self, name, lang):
if not isinstance(name, str):
raise Exception("name is not a string", name, type(name))
if lang == None:
raise Exception("cannot get None lang for tag", name)
if name not in self.store[lang]:
self.store[lang][name] = Tag(name, lang, self.factories)
return self.store[lang][name];
def all(self):
return self.store
class Tag:
def __init__(self, name, lang, factories):
self.name = name
self.lang = lang
self.is_category = False
self._link = None
self._factories = factories
def get_config(self):
if not self._config:
self._config = self._factories['config'].get(self.lang)
return self._config
config = property(get_config, None, None)
def get_link(self):
if not self._link:
self._link = self._factories['link'].get_by_type("tag", self.name, self.lang)
return self._link
link = property(get_link, None, None)
def get_page(self):
if self._factories['page'].has('tag-' + self.name, self.lang):
return self._factories['page'].get('tag-' + self.name, self.lang)
else:
return None
page = property(get_page, None, None)
def get_color(self):
color = property(get_color, None, None)
def get_title(self):
if self.page:
return self.page.title
else:
return self.name
title = property(get_title, None, None)
def reg_page(self, page, is_category = False):
if page == None:
return
if page.lang != self.lang:
raise Exception("Page has different lang than Tag.", page.lang, tag.lang)
if page not in self.pages:
self.pages_tuple.append((page.prio, page))
self.pages_tuple.sort(key=lambda x: x[0])
self.pages_tuple.reverse()
if is_category:
self.is_category = is_category
def get_pages(self):
if len(self._pages_cache) != len(self.pages_tuple):
res = []
for prio, page in self.pages_tuple:
res.append(page)
self._pages_cache = res
return self._pages_cache
pages = property(get_pages, None, None)
self.dt = dt
#self.config = config
# TODO various formats
def isoformat(self):
return self.dt.isoformat()
def strftime(self, formatstr):
# https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
return self.dt.strftime(formatstr)
def __lt__(self, other):
return self.dt.timestamp() < other.dt.timestamp()
def __init__(self, config, factories):
self.config = config
self.factories = factories
self.store = {}
def get(self, email, name = None):
if email not in self.store:
self.store[email] = Author(email)
author = self.store[email]
author.reg_name(name)
return author;
self.email = email
self.names = set()
split = email.split('@')
# TODO proper email validation
if len(split) != 2:
raise Exception("Invalid email address: ", email)
self.email_local_part = split[0]
self.email_domain = split[1]
def reg_name(self, name):
if name == None:
return
self.names.add(name)
class LinkFactory:
def __init__(self, config, factories):
self.config = config
self.factories = factories
self.store = {}
def get_by_raw(self, rawurl, deflang):
link = Link(rawurl, self.factories, deflang) # this is dirty
lang = link.lang
if lang == None:
raise Exception("Link lang is None", lang, deflang, link.raw)
if lang not in self.store:
self.store[lang] = {}
if rawurl not in self.store[lang]:
self.store[lang][rawurl] = link
return self.store[lang][rawurl];
def get_by_type(self, reftype, refid, reflang = None):
rawurl = reftype + ':' + refid
if reflang:
rawurl += ':' + reflang
else:
reflang = self.config['lang']['default']
return self.get_by_raw(rawurl=rawurl, deflang=reflang)
class Link:
def __init__(self, rawurl, factories, deflang):
self.raw = rawurl
urlasplit = rawurl.split('#')
self.anchor = None
if len(urlasplit) == 2:
self.anchor = urlasplit[1]
urlwoa = urlasplit[0] # url without anchor
if len(urlwoa) == 0:
# rawurl: '#some-section'
self.type = "local"
else:
components = urlwoa.split(':')
if len(components) == 1:
# rawurl: 'lageplan.uni-goettingen.de'
self.is_external = True
else:
reftype = components[0]
refid = components[1]
reflang = deflang
if len(components) > 2:
reflang = components[2]
if reftype == "slug":
# rawurl: 'slug:some-page:de'
elif reftype == "tag":
# rawurl: 'tag:some-tag:de'
elif reftype == "file":
# rawurl: 'file:logo.png'
self._file = None
self._url = None
self.type = reftype
self.lang = reflang
self.refid = refid
def get_page(self):
if not self._page:
self._page = self._factories['page'].get(self.refid, self.lang)
# handle link/alias pages
if 'link' in self._page.metadata:
self.alias = self._page.metadata['link']
if self.alias.type == "slug":
self.alias.get_page() # make sure that alias knows if it is an alias
def get_tag(self):
if not self._tag:
self._tag = self._factories['tag'].get(self.refid, self.lang)
return self._tag
tag = property(get_tag, None, None)
def get_file(self):
if not self._file:
self._file = self._factories['file'].get(self.refid)
return self._file
file = property(get_file, None, None)
def get_category(self):
if self.type == "slug":
return self.page.category
elif self.type == "tag":
return self.tag
#if self.tag.is_category:
# return self.tag
#else:
# raise Exception("category can only be called on category tags")
else:
raise Exception("category is not allowed to be called here")
category = property(get_category, None, None)
def get_path(self):
if self.type == "slug":
return '/'.join([self.page.lang, self.page.category.name, self.page.slug + '.html'])
elif self.type == "tag":
return '/'.join([self.tag.lang, 'tag', self.tag.name + '.html'])
elif self.type == "file":
return '/'.join(['file', self.file.name])
else:
raise Exception("path is not allowed to be called here", self.type)
path = property(get_path, None, None)
def get_url(self):
if self._url == None:
self._url = self.path
return self._url
url = property(get_url, None, None)
def get_urlwithanchor(self):
if self.anchor:
return self.url + "#" + self.anchor
else:
return self.url
urlwithanchor = property(get_urlwithanchor, None, None)
"""
Get the relation in the context of the rel html attribute for this link
or None if no relation is known.
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel
"""
if self.type != "slug":
return None
if "rel" not in self.page.metadata:
return None
return self.page.metadata["rel"]
rel = property(get_rel, None, None)