diff --git a/fgs/__main__.py b/fgs/__main__.py index 03ac928cedde8975293da8dd1e8abbfebea196ed..266388e986c763587c95a15faae043696f7cc210 100644 --- a/fgs/__main__.py +++ b/fgs/__main__.py @@ -27,8 +27,10 @@ def main(): print(config) factories = {} - factories['page'] = datatypes.PageFactory() - factories['author'] = datatypes.AuthorFactory() + factories['page'] = datatypes.PageFactory(config, factories) + factories['author'] = datatypes.AuthorFactory(config, factories) + factories['tag'] = datatypes.TagFactory(config, factories) + factories['link'] = datatypes.LinkFactory(config, factories) mdreader = reader.MarkdownReader(config, factories) pages = [] @@ -48,7 +50,7 @@ def main(): context = {} - gen = generator.Generator(config, context) + gen = generator.Generator(config, context, factories) gen.generate_context(pages, static_files) wrt = writer.Writer(config, context, OUTPUT_DIR, THEME_DIR) diff --git a/fgs/datatypes.py b/fgs/datatypes.py index 3da0bb197ff5780d2d5bd584f09b09138f9d1b7b..71605d74cc644d9bc03fe7ed247c1ff1a731b515 100644 --- a/fgs/datatypes.py +++ b/fgs/datatypes.py @@ -2,105 +2,126 @@ import datetime from dateutil import parser as dtparser class PageFactory: - def __init__(self): + def __init__(self, config, factories): + self.config = config + self.factories = factories self.store = {} + for lang in self.config['lang']['supported']: + self.store[lang] = {} + + def has(self, slug, lang): + return (slug in self.store[lang]) + def get(self, slug, lang): - if slug not in self.store: - self.store[slug] = {} - if lang not in self.store[slug]: - self.store[slug][lang] = Page(slug, lang) - return self.store[slug][lang]; + if not self.has(slug, lang): + self.store[lang][slug] = Page(slug, lang, self.config, self.factories) + return self.store[lang][slug]; class Page: - def __init__(self, slug, lang): + def __init__(self, slug, lang, config, factories): self.slug = slug self.lang = lang + self._config = config + self._factories = factories self.initialized = False - def init(self, filename, subpath, raw, metadata, content, title, category, date_created, date_modified, authors, last_modification_author, status, config, factories): + def init(self, filename, subpath, raw, metadata, content, title, category, date_created, date_modified, authors, last_modification_author, status): self.initialized = True self.filename = filename self.subpath = subpath self.raw = raw - self.metadata = metadata + self._metadata = metadata self.content = content self.title = title - self.category = category - self.date_created = Date(date_created, config) - self.date_modified = Date(date_modified, config) + 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.status = status - #self.config = config - - # authors self.authors = [] for local_part, domain, name in authors: - self.authors.append(factories['author'].get(local_part + '@' + domain, name)) + self.authors.append(self._factories['author'].get(local_part + '@' + domain, name)) if last_modification_author: - self.last_modification_author = factories['author'].get(last_modification_author[0] + '@' + last_modification_author[1], last_modification_author[2]) + 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) - # tags - self.tags = [] - if 'tags' in metadata: - tags = self.tags_str_to_list(metadata['tags']) - for t in tags: - if (t != category): - self.tags.append(t) - self.tags.append(self.category) # the category is also a default tag - # template - if 'template' in metadata: - self.template = metadata['template'] - else: - self.template = config['theme']['default_template'] + def get_metadata(self): + deflang = self._config['lang']['default'] + if self.lang == deflang: + return self._metadata + defpage = self._factories['page'].get(self.slug, deflang) + res = defpage.metadata.copy() + res.update(self._metadata) + return res + metadata = property(get_metadata, None, None) - # url - self.url = self.lang + '/' + self.category + '/' + self.slug + ".html" - - # relevance - self.relevance = {} - self.relevance['is_relevant'] = False - self.relevance['was_relevant'] = False - self.relevance['will_be_relevant'] = False - if 'relevant' in metadata: - lrel = metadata['relevant'] + def get_tags(self): + 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 = factories['tag'].get(t, self.lang) + 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 if 'prio' in lrel: - self.relevance['prio']= lrel['prio'] + res['prio']= lrel['prio'] else: - self.relevance['prio']= 0 + res['prio']= 0 - start = Date("min", config) + start = Date("min", self._config) if 'start' in lrel: - start = Date(lrel['start'], config) - self.relevance['start'] = start + start = Date(lrel['start'], self._config) + res['start'] = start - end = Date("max", config) + end = Date("max", self._config) if 'end' in lrel: - end = Date(lrel['end'], config) - self.relevance['end'] = end + end = Date(lrel['end'], self._config) + res['end'] = end - build_date = Date("now", config) + build_date = Date("now", self._config) if (build_date > end): - self.relevance['was_relevant'] = True + res['was_relevant'] = True elif (build_date < start): - self.relevance['will_be_relevant'] = True + res['will_be_relevant'] = True else: - self.relevance['is_relevant'] = True - - - - + 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: + return self._config['theme']['default_template'] + template = property(get_template, None, None) def tags_str_to_list(self, s): @@ -123,6 +144,66 @@ class Page: raise Exception("Page not initialized.") return self.date_modified < other.date_modified +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 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.pages = set() + self.is_category = False + self._link = None + self._factories = factories + + + 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): + if 'color' in self.page.metadata: + return self.page.metadata['color'] + else: + return self.config['default_tag_color'] + 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) + self.pages.add(page) + if is_category: + self.is_category = is_category class Date: @@ -148,17 +229,20 @@ class Date: return self.dt.timestamp() < other.dt.timestamp() class AuthorFactory: - def __init__(self): + 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, name) - return self.store[email]; + self.store[email] = Author(email) + author = self.store[email] + author.reg_name(name) + return author; class Author: - def __init__(self, email, name = None): + def __init__(self, email): self.email = email self.names = set() - self.reg_name(name) split = email.split('@') # TODO proper email validation @@ -172,4 +256,124 @@ class Author: 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): + if rawurl not in self.store: + self.store[rawurl] = Link(rawurl, self.factories, deflang) + return self.store[rawurl]; + def get_by_type(self, reftype, refid, reflang): + rawurl = reftype + ':' + refid + ':' + reflang + return self.get_by_raw(rawurl=rawurl, deflang=reflang) +class Link: + def __init__(self, rawurl, factories, deflang): + self.raw = rawurl + self.is_external = False + + 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.url = "" + self.type = "local" + else: + components = urlwoa.split(':') + if len(components) == 1: + # rawurl: 'lageplan.uni-goettingen.de' + self.url = "https://" + urlwoa + 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' + self.page = factories['page'].get(refid, reflang) + # TODO handle link/alias pages + self.path = '/'.join([self.page.lang, self.page.category.name, self.page.slug + '.html']) + self.url = self.path + self.type = reftype + elif reftype == "tag": + # rawurl: 'tag:some-tag:de' + self.tag = factories['tag'].get(refid, reflang) + self.path = '/'.join([self.tag.lang, 'tag', self.tag.name + '.html']) + self.url = self.path + self.type = reftype + else: + # rawurl: 'https://example.com' + self.url = urlwoa + self.is_external = True + + self.urlwithanchor = self.url + if self.anchor: + self.urlwithanchor = self.url + "#" + self.anchor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fgs/generator.py b/fgs/generator.py index ce6ee602fa24507f8928c2e2442520863fe1579c..6115044a7eb012e45a3fd760bb7ccd69e1791a00 100644 --- a/fgs/generator.py +++ b/fgs/generator.py @@ -1,9 +1,10 @@ import datatypes class Generator: - def __init__(self, config, context): + def __init__(self, config, context, factories): self.config = config self.context = context + self.factories = factories def generate_context(self, pages, static_files): # static_files @@ -41,26 +42,17 @@ class Generator: # TODO draft pages # TODO authors - # categories - categories = {} - for page in published_pages: - if page.lang not in categories: - categories[page.lang] = {} - if page.category not in categories[page.lang]: - categories[page.lang][page.category] = [] - categories[page.lang][page.category].append(page) - self.context['categories'] = categories # tags - tags = {} - for page in published_pages: - for tag in page.tags: - if page.lang not in tags: - tags[page.lang] = {} - if tag not in tags[page.lang]: - tags[page.lang][tag] = [] - tags[page.lang][tag].append(page) - self.context['tags'] = tags + self.context['tags'] = self.factories['tag'].all() + + # categories + self.context['categories'] = {} + for lang in self.config['lang']['supported']: + self.context['categories'][lang] = {} + for tag in self.context['tags'][lang].values(): + if tag.is_category: + self.context['categories'][lang][tag.name] = tag # build_date self.context['build_date'] = datatypes.Date("now", self.config) @@ -96,11 +88,11 @@ class Generator: for lang in self.config['lang']['supported']: # all pages for page in self.context['pages'][lang].values(): - writer.write_template(page.template, page.url, lang, {'page': page}) + writer.write_template(page.template, page.link.path, lang, {'page': page}) # all tags - for tag, tagpages in self.context['tags'][lang].items(): - writer.write_template('tag.html', lang + '/tag/' + tag + '.html', lang, {'tag': tag, 'tagpages': tagpages}) + for tag in self.context['tags'][lang].values(): + writer.write_template('tag.html', tag.link.path, lang, {'tag': tag}) # homepages for languages self.generate_homepage(writer, lang, lang + "/index.html") diff --git a/fgs/reader.py b/fgs/reader.py index 3bf9d51bb9d76050cc5487eaeffa2bf9428e152e..a800024e01d26071895f78765b9a900c0b9d11ae 100644 --- a/fgs/reader.py +++ b/fgs/reader.py @@ -125,9 +125,7 @@ class MarkdownReader: date_modified, authors, last_modification_author, - status, - self.config, - self.factories) + status) return p def extract_author(self, raw): diff --git a/fgs/writer.py b/fgs/writer.py index a5eb1e6098b5f427b24e4e72d6ad7eddd6e26d25..314acfc9471d457c117aa02669df7ea2f000fce5 100644 --- a/fgs/writer.py +++ b/fgs/writer.py @@ -43,6 +43,12 @@ class Writer: context["path"] = path context["siteurl"] = siteurl context.update(extra_context) + print("template: ", template) + print("path: ", path) + print("lang: ", lang) + print("context: ", context) + print("context keys: ", context.keys()) + print("tags:", type(context['tags']), context['tags']) out = tmpl.render(context) # write file