Commit bd75c0a5 authored by shadMod's avatar shadMod 💬

refactor all news.utils

parent d4d25075
......@@ -16,25 +16,29 @@
import os
import json
import locale
import shutil
import markdown
from datetime import datetime
from string import digits, ascii_letters
from random import choices as rdm_choices
try:
# check and set with it_IT language
if 'it_it' in locale.locale_alias:
locale.setlocale(locale.LC_TIME, "it_IT.UTF-8")
except Exception as ex:
print(ex) # TODO: replaced print with logger.warning(ex)
class GetNews:
"""
:param base_path: path
:return: [
{
"title": "Lorem Ipsum",
"author": "shadmod",
"mail": "m.allegro@shadmod.com",
"html": "html"
}
]
:rtype: list
:param base_path: data path
Directory route path
news > category > year > month > nr_news.md
Sample file 000.md
# Lorem Ipsum => title of newsletter, if not present takes
......@@ -42,6 +46,8 @@ class GetNews:
shadmod - m.allegro@shadmod.com => author and mail of the same
date: GG/MM/YYYY HH:MM => not obbligatoried - force the date visible
- Lorem ipsum dolor sit amet. => body of newsletter
- Aliquam tincidunt mauris.
"""
......@@ -49,12 +55,214 @@ class GetNews:
def __init__(self, base_path):
self.base_path = base_path
def get_data(self, filename: str, year: int = None):
self._index_news = {}
self._category = []
self._year = []
self._list_files = []
def init_assets_news(self, src_path: str, dst_path: str) -> None:
"""
Method to rm all news in data directory and copy all news with relative indexes
:param src_path: source path
:param dst_path: destination path
:return: None
:rtype: NoneType
"""
# rm all files and clean news dir
for filename in os.listdir(dst_path):
os.remove(os.path.join(dst_path, filename))
# populate news assets
data = []
for category in sorted(os.listdir(src_path), reverse=True):
category_dir = os.path.join(src_path, category)
for year in os.listdir(category_dir):
year_dir = os.path.join(category_dir, year)
for month in os.listdir(year_dir):
month_dir = os.path.join(year_dir, month)
for nr_file in os.listdir(month_dir):
pathfile = os.path.join(month_dir, nr_file)
birth_time, last_edit = self.filename_time(pathfile)
filename = self.random_filename()
data.append(
{
"category": category,
"year": year,
"month": month,
"nr_file": nr_file.replace(".md", ""),
"filename": filename,
"birth_time": birth_time,
"last_edit": last_edit,
}
)
shutil.copy(pathfile, os.path.join(dst_path, filename))
with open(os.path.join(dst_path, "indexes.json"), "w") as fn:
fn.write(json.dumps(data))
@property
def index_news(self) -> list[dict]:
"""
Property to get indexes.json
"""
if not self._index_news:
with open(os.path.join(self.base_path, "indexes.json")) as indexes:
self._index_news = sorted(json.load(indexes), key=lambda x: x['year'], reverse=True)
return self._index_news
@property
def category(self) -> list[str]:
"""
Property to get all category
"""
if not self._category:
self._category = self.get_list_data("category")
return self._category
@property
def years(self) -> list[str]:
"""
Property to get all years
"""
if not self._year:
self._year = self.get_list_data("year")
return self._year
@property
def list_year_month(self) -> list[str]:
data = []
for val in self.index_news:
year_month = f"{val['month']} {val['year']}"
if year_month not in data:
data.append(year_month)
return data
@staticmethod
def random_filename() -> str:
filename = ''.join(rdm_choices(ascii_letters + digits, k=20))
return filename
@staticmethod
def filename_time(pathfile: str, fmt=None) -> (str, str):
if not fmt:
fmt = "%d %B %Y - %H:%M"
_birth_time = os.stat(pathfile).st_birthtime
_birth_time = datetime.fromtimestamp(_birth_time).strftime(fmt)
_last_edit = os.stat(pathfile).st_mtime
_last_edit = datetime.fromtimestamp(_last_edit).strftime(fmt)
return _birth_time, _last_edit
@staticmethod
def clean_html(value: str, html_tag: str):
for _vl in ["", "/"]:
value = value.replace(f"<{_vl}{html_tag}>", "")
return value
def get_list_data(self, key: str) -> list[str]:
data = []
for val in self.index_news:
if val[key] not in data:
data.append(val[key])
return data
def filter_index_news(self, year: str, category: str, nr_file: str = None, month: str = None) -> list:
"""
Method to filter assets news
:param year: year
:param category: category
:param nr_file: nr_file
:param month: month
"""
raw = self.index_news
if year:
raw = list(filter(lambda d: d['year'] == year, raw))
if month:
raw = list(filter(lambda d: d['month'] == month, raw))
if category:
raw = list(filter(lambda d: d['category'] == category, raw))
if nr_file:
raw = list(filter(lambda d: d['nr_file'] == nr_file, raw))
return raw
def list_news(self, year: str, category: str, month: str = None) -> list[dict]:
"""
Method to get a list of news (with filters)
:param year: year
:param category: category
:param month: month
"""
# clean list_files
self._list_files = []
data = self.filter_index_news(year, category, month=month)
# populate _list_files
key_data = ["title", "author", "mail", "html"]
for val in data:
data = self.render_data(val["filename"], val["nr_file"], val["year"])
for key in key_data:
val[key] = data.get(key, "")
if "birth_time" in data:
val["birth_time"] = data["birth_time"]
self._list_files.append(val)
return self._list_files
def get_news(self, nr_file: str, year: str, category: str) -> dict:
"""
Method to get determinate news
:param nr_file: nr_file
:param year: year
:param category: category
:return: [
{
"title": "Lorem Ipsum",
"author": "shadmod",
"mail": "m.allegro@shadmod.com",
"html": "html"
}
]
:rtype: list
"""
val = self.filter_index_news(year, category, nr_file)
if len(val) != 1:
raise ValueError("Errore nell'univocità del numero file")
else:
val = val[0]
data = self.render_data(val["filename"], val["nr_file"], val["year"])
key_data = ["title", "author", "mail", "html"]
for key in key_data:
val[key] = data.get(key, "")
if "birth_time" in data:
val["birth_time"] = data["birth_time"]
return val
def render_data(self, filename: str, nr_file: str, year: str, force_date: bool = True) -> dict:
"""
Method to render markdown file in html
:param filename: the name of the file
:param nr_file: the number of the file (000)
:param year: the year of the directory in which the file is located
:param force_date: if it's True force 'birth_time' value with the one in the file.md
:return: {
"title": "Lorem Ipsum",
"author": "shadmod",
"mail": "m.allegro@shadmod.com",
"birth_time": "birth_time"
"html": "html"
}
:rtype: dict
......@@ -62,81 +270,38 @@ class GetNews:
# init empty data
data = {}
# get complete path
path = os.path.join(self.base_path, str(year), filename)
# clean filename and set with 3 digits
nr_file = str(filename.replace(".md", "")).zfill(3)
# get last edit of file
last_edit = os.stat(path).st_mtime
try:
# check and set with it_IT language
if 'it_it' in locale.locale_alias:
locale.setlocale(locale.LC_TIME, "it_IT.UTF-8")
except Exception as ex:
# TODO: add logger.warning(ex)
pass
# format datetime: 01 Novembre 2023 - 00:00
date_edit = datetime.fromtimestamp(last_edit)
data["last_edit"] = date_edit.strftime("%d %B %Y - %H:%M")
# set nr_news with nr file and relative year folder
data["nr_news"] = f"{nr_file}/{year}"
path = os.path.join(self.base_path, filename)
# 'compile' markdown in html
# compile markdown in html
with open(path, 'r') as f:
tempHtml = markdown.markdown(f.read())
# 'get' header and put in 'title' key
# get header and put in 'title' key
html_tmp = tempHtml.split("\n")
if "<h1>" in html_tmp[0]:
data["title"] = html_tmp.pop(0).replace("<h1>", "").replace("</h1>", "")
data["title"] = self.clean_html(html_tmp.pop(0), "h1")
else:
data["title"] = f"{year}.{nr_file}"
# 'get' signature with author and mail and put in relative key
# get signature with author and mail and put in relative key
if "<p>" in html_tmp[0]:
data["author"], data["mail"] = html_tmp.pop(0).replace("<p>", "").replace("</p>", "").split(" - ")
data["author"], data["mail"] = self.clean_html(html_tmp.pop(0), "p").split(" - ")
# get datetime and put in relative key if force_date is True
if "<p>" in html_tmp[0] and "<p>date:" == html_tmp[0][:8]:
birth_time = html_tmp.pop(0)
if force_date:
birth_time = self.clean_html(birth_time, "p").replace("date: ", "")
birth_time = datetime.strptime(birth_time, "%d/%m/%Y %H:%M")
data["birth_time"] = birth_time.strftime("%d %B %Y - %H:%M")
# what's left I put in html
data["html"] = "".join(html_tmp)
return data
@property
def list_files(self) -> list:
data = []
for list_files in self.get_all_files.values():
data.extend(list_files)
return data
@property
def get_all_files(self) -> dict:
data = {}
for subdir in sorted(os.listdir(self.base_path), reverse=True):
data[subdir] = os.listdir(os.path.join(self.base_path, subdir))
return data
def news_max(self, counter: int) -> list[dict]:
"""
Method used on the Home Page to have a maximum number of items displayed
def get_all_files_counter(self, counter: int) -> dict:
i = 0
data = {}
for year, list_news in self.get_all_files.items():
if year not in data:
data[year] = []
for filename in list_news:
data[year].append(filename)
i += 1
if i == counter:
break
if i == counter:
break
return data
:param counter: counter
:return: a list of news
:rtype: list[dict]
"""
def list_news(self, year=None):
news = []
if year is None:
for year, file_list in self.get_all_files.items():
for file in file_list:
news.append(self.get_data(file, int(year)))
else:
dir_path = os.path.join(self.base_path, str(year))
if os.path.exists(dir_path):
file_list = os.listdir(dir_path)
for file in file_list:
news.append(self.get_data(file, year))
return news
return self.index_news[:counter]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment