From aa26a3675e0a7197d7ad6edf2ec6ec2ba356668e Mon Sep 17 00:00:00 2001 From: coja Date: Mon, 4 May 2026 10:33:09 +0200 Subject: [PATCH] [Gobal] added flake8 and did format --- .flake8 | 8 +++ AGENTS.md | 15 +++++ Makefile | 8 ++- atom_gen.py | 40 ++++++------- blog.py | 4 +- build_pages.py | 88 +++++++++++++++++++---------- image_poster.py | 103 ++++++++++++++++++++++------------ pages/en/support.html | 4 +- pages/sr/support.html | 2 +- poster.py | 41 ++++++++++---- prep.py | 127 ++++++++++++++++++++++++++++-------------- pyproject.toml | 8 +++ requirements.txt | 10 ++-- 13 files changed, 308 insertions(+), 150 deletions(-) create mode 100644 .flake8 create mode 100644 AGENTS.md create mode 100644 pyproject.toml diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..709fb97 --- /dev/null +++ b/.flake8 @@ -0,0 +1,8 @@ +[tool.black] +line-length = 88 +target-version = ['py312'] + +[tool.flake8] +max-line-length = 88 +extend-ignore = "E203" +exclude = ".venv" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d9dafae --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,15 @@ +# AGENTS.md + +## Core Workflow + +- **Setup**: `make prep` (creates `.venv` and installs `requirements.txt`) +- **Build**: `make build` (runs `atom_gen.py`, `prep.py`, and `build_pages.py`) +- **Events**: Update `dogadjaji.csv` then run `make events` (updates pages and generates images via `image_poster.py`) +- **Development**: `make dev` (starts Nginx using `nginx.dev.conf`) and `make stop` to terminate. + +## Technical Details + +- **Environment**: Uses a local virtual environment in `.venv`. Always use `./.venv/bin/python` or ensure the venv is activated. +- **Output**: The generated website is stored in the `site/` directory. +- **Data**: Events are driven by `dogadjaji.csv`. +- **Web Server**: Uses Nginx for the development server. diff --git a/Makefile b/Makefile index 5197b65..f390e42 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build events dev stop help prep +.PHONY: build events dev stop help prep lint format help: @echo "Available commands:" @@ -29,3 +29,9 @@ dev: stop: nginx -p . -s stop +lint: + ./.venv/bin/flake8 . --config .flake8 --exclude .venv + +format: + ./.venv/bin/black . + diff --git a/atom_gen.py b/atom_gen.py index 52b7485..40f3e84 100755 --- a/atom_gen.py +++ b/atom_gen.py @@ -11,7 +11,7 @@ import os blogs_dir = os.fsencode("blog") -#def blogposts_list_gen(): +# def blogposts_list_gen(): # output_list = [] # for file in os.listdir(blogs_dir): # filename = os.fsdecode(file) @@ -26,46 +26,48 @@ blogs_dir = os.fsencode("blog") # output_list.append([author, title, time, content_html, full_path]) # return output_list + def events_list_gen(): output_list = [] events_file = open("dogadjaji.csv", "r") for line in events_file.readlines(): - date, time, location, title = line.split(", ") - author = "Decentrala" - content_html = f"Event is taking place at {location} on {date} at {time}. For more information see the forum at https://forum.dmz.rs" + date, time, location, title = line.split(", ") + author = "Decentrala" + content_html = f"Event is taking place at {location} on {date} at {time}. For more information see the forum at https://forum.dmz.rs" - output_list.append([author, title, content_html]) + output_list.append([author, title, content_html]) events_file.close() return output_list + def feedgen(blogs, events): fg_blog = FeedGenerator() - fg_blog.id('http://dmz.rs/') - fg_blog.title('Decentrala Blog') - fg_blog.author( {'name':'Decentrala','email':'dmz@dmz.rs'} ) - fg_blog.link( href='https://dmz.rs/atom_blog.xml', rel='self' ) + fg_blog.id("http://dmz.rs/") + fg_blog.title("Decentrala Blog") + fg_blog.author({"name": "Decentrala", "email": "dmz@dmz.rs"}) + fg_blog.link(href="https://dmz.rs/atom_blog.xml", rel="self") fg_events = FeedGenerator() - fg_events.id('http://dmz.rs/') - fg_events.title('Decentrala Blog') - fg_events.author( {'name':'Decentrala','email':'dmz@dmz.rs'} ) - fg_events.link( href='https://dmz.rs/atom_events.xml', rel='self' ) + fg_events.id("http://dmz.rs/") + fg_events.title("Decentrala Blog") + fg_events.author({"name": "Decentrala", "email": "dmz@dmz.rs"}) + fg_events.link(href="https://dmz.rs/atom_events.xml", rel="self") for post in blogs: fe_blogs = fg_blog.add_entry() fe_blogs.id("https://dmz.rs/" + post[4][:-3] + ".html") - fe_blogs.author({'name': post[0]}) + fe_blogs.author({"name": post[0]}) fe_blogs.title(post[1]) fe_blogs.updated(post[2]) - fe_blogs.content(content=post[3], type='html') + fe_blogs.content(content=post[3], type="html") for event in events: fe_events = fg_events.add_entry() fe_events.id("https://dmz.rs/pages/events.html") - fe_events.author({'name': event[0]}) + fe_events.author({"name": event[0]}) fe_events.title(event[1]) fe_events.updated(datetime.datetime.now(datetime.timezone.utc)) - fe_events.content(content=event[2], type='html') + fe_events.content(content=event[2], type="html") - fg_blog.atom_file('site/atom_blog.xml') - fg_events.atom_file('site/atom_events.xml') + fg_blog.atom_file("site/atom_blog.xml") + fg_events.atom_file("site/atom_events.xml") diff --git a/blog.py b/blog.py index 4bfb304..545777f 100755 --- a/blog.py +++ b/blog.py @@ -5,8 +5,8 @@ from markdown import markdown as to_markdown blog = "" -with open('blogs/Lorem Ipsum.md','rt') as file: +with open("blogs/Lorem Ipsum.md", "rt") as file: blog = file.read() -with open('blogs/Lorem Ipsum.html', 'wt') as file: +with open("blogs/Lorem Ipsum.html", "wt") as file: file.write(to_markdown(blog)) diff --git a/build_pages.py b/build_pages.py index 87b1eb7..e9b827d 100755 --- a/build_pages.py +++ b/build_pages.py @@ -2,59 +2,87 @@ from jinja2 import Environment, FileSystemLoader import os PAGES = [ - {'name': 'index', 'titleSR': 'Početna', 'titleEN': 'Home', 'style': 'home'}, - {'name': 'account', 'titleSR': 'Nalog', 'titleEN': 'Account', 'style': 'account'}, - {'name': 'about', 'titleSR': 'O nama', 'titleEN': 'About us', 'style': 'about'}, - {'name': 'statute', 'titleSR': 'Statut', 'titleEN': 'Statute', 'style': 'statute'}, - {'name': 'events', 'titleSR': 'Događaji', 'titleEN': 'Events', 'style': 'events'}, - {'name': 'events_archive', 'titleSR': 'Arhiva događaja', 'titleEN': 'Events archive', 'style': 'events'}, - {'name': 'services', 'titleSR': 'Servisi', 'titleEN': 'Services', 'style': 'services'}, - {'name': 'webring', 'titleSR': 'Webring', 'titleEN': 'Webring', 'style': ''}, - {'name': 'support', 'titleSR': 'Podrška', 'titleEN': 'Support', 'style': 'support'}, - {'name': 'deconference', 'titleSR': 'Dekonferencija', 'titleEN': 'Deconference', 'style': 'deconference'}, + {"name": "index", "titleSR": "Početna", "titleEN": "Home", "style": "home"}, + {"name": "account", "titleSR": "Nalog", "titleEN": "Account", "style": "account"}, + {"name": "about", "titleSR": "O nama", "titleEN": "About us", "style": "about"}, + {"name": "statute", "titleSR": "Statut", "titleEN": "Statute", "style": "statute"}, + {"name": "events", "titleSR": "Događaji", "titleEN": "Events", "style": "events"}, + { + "name": "events_archive", + "titleSR": "Arhiva događaja", + "titleEN": "Events archive", + "style": "events", + }, + { + "name": "services", + "titleSR": "Servisi", + "titleEN": "Services", + "style": "services", + }, + {"name": "webring", "titleSR": "Webring", "titleEN": "Webring", "style": ""}, + {"name": "support", "titleSR": "Podrška", "titleEN": "Support", "style": "support"}, + { + "name": "deconference", + "titleSR": "Dekonferencija", + "titleEN": "Deconference", + "style": "deconference", + }, ] -env = Environment(loader=FileSystemLoader('template')) +env = Environment(loader=FileSystemLoader("template")) + def main(): - os.makedirs('site/en/', exist_ok=True) + os.makedirs("site/en/", exist_ok=True) for page in PAGES: # Build SR Page with open(f'pages/sr/{page["name"]}.html') as f: page_content = "
Studenti su nasli bug
" page_content += f.read() - - sr_html = env.get_template('page-sr.html').render( - title=page['titleSR'], + + sr_html = env.get_template("page-sr.html").render( + title=page["titleSR"], content=page_content, - extra_styles=f'' if page['style'] else '', + extra_styles=( + f'' + if page["style"] + else "" + ), lang="sr", sr_link=f"/en/{page['name']}", - current_path=f"/{page['name']}" if page['name'] != 'index' else "/" + current_path=f"/{page['name']}" if page["name"] != "index" else "/", ) - - sr_filename = "index.html" if page['name'] == 'index' else f"{page['name']}.html" - with open(f'site/{sr_filename}', 'w') as f: + + sr_filename = ( + "index.html" if page["name"] == "index" else f"{page['name']}.html" + ) + with open(f"site/{sr_filename}", "w") as f: f.write(sr_html) # Build EN Page with open(f'pages/en/{page["name"]}.html') as f: page_content = "
Students found the bug
" page_content += f.read() - - en_html = env.get_template('page-en.html').render( - title=page['titleEN'], + + en_html = env.get_template("page-en.html").render( + title=page["titleEN"], content=page_content, - extra_styles=f'' if page['style'] else '', + extra_styles=( + f'' + if page["style"] + else "" + ), lang="en", sr_link=f"/{page['name']}", - current_path=f"/en/{page['name']}" if page['name'] != 'index' else "/en/" + current_path=f"/en/{page['name']}" if page["name"] != "index" else "/en/", ) - - en_filename = "index.html" if page['name'] == 'index' else f"{page['name']}.html" - with open(f'site/en/{en_filename}', 'w') as f: + + en_filename = ( + "index.html" if page["name"] == "index" else f"{page['name']}.html" + ) + with open(f"site/en/{en_filename}", "w") as f: f.write(en_html) -if __name__ == '__main__': - main() +if __name__ == "__main__": + main() diff --git a/image_poster.py b/image_poster.py index 269d2d0..2cd9a9e 100755 --- a/image_poster.py +++ b/image_poster.py @@ -13,10 +13,34 @@ NEXT_MONTH = CURRENT_TIME + relativedelta.relativedelta(months=1, day=1) DAYS_OF_WEEK_SR = ("PON", "UTO", "SRE", "ČET", "PET", "SUB", "NED") DAYS_OF_WEEK_EN = ("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUn") -MONTHS_SR = ("Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", - "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar") -MONTHS_EN = ("January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December") +MONTHS_SR = ( + "Januar", + "Februar", + "Mart", + "April", + "Maj", + "Jun", + "Jul", + "Avgust", + "Septembar", + "Oktobar", + "Novembar", + "Decembar", +) +MONTHS_EN = ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", +) HEADER_SR = "Plan za {}" @@ -36,10 +60,15 @@ All events are always free def parseArgs(parser): """ - Parse all arguments and return the list of argument values + Parse all arguments and return the list of argument values """ - parser.add_argument("month", metavar="MM", - help="two digit number representing the month for which to generate poster", default="empty", nargs="?") + parser.add_argument( + "month", + metavar="MM", + help="two digit number representing the month for which to generate poster", + default="empty", + nargs="?", + ) return parser.parse_args() @@ -51,18 +80,19 @@ def load_events(csv_path: str, month: int) -> list[dict]: next(csv_reader, None) for event in csv_reader: event_date = event[0] - event_date_parsed = dt.datetime.strptime( - event_date, "%d-%m-%Y").date() + event_date_parsed = dt.datetime.strptime(event_date, "%d-%m-%Y").date() event_time = event[1] event_title = event[3] event_title_en = event[3] if len(event) > 6: event_title_en = event[6] - current_event = {"date": event_date_parsed, - "time": event_time, - "title": event_title.strip(), - "title_en": event_title_en.strip()} + current_event = { + "date": event_date_parsed, + "time": event_time, + "title": event_title.strip(), + "title_en": event_title_en.strip(), + } if event_date_parsed >= month and event_date_parsed < monthafter: events.append(current_event) return events @@ -71,8 +101,7 @@ def load_events(csv_path: str, month: int) -> list[dict]: def drawMesh(draw, img, fg, bg, font, W, H): def drawCircle(x, y): r = 50 - draw.ellipse((x - r, y - r, x + r, y+r), - fill=fg, outline=(0, 0, 0), width=0) + draw.ellipse((x - r, y - r, x + r, y + r), fill=fg, outline=(0, 0, 0), width=0) LCX = 415 # logo center x LCY = 4350 # logo center y @@ -84,11 +113,15 @@ def drawMesh(draw, img, fg, bg, font, W, H): drawCircle(LCX + d, LCY) draw.line([(LCX - d, LCY), (LCX + d, LCY)], fill=fg, width=20, joint=None) - draw.line([(LCX, LCY), (LCX, LCY + d), (LCX + d, LCY), - (LCX, LCY - d)], fill=fg, width=20, joint=None) - draw.text((LCX - 1.7*d, LCY + 1.5*d), "dmz.rs", font=font, fill=fg) + draw.line( + [(LCX, LCY), (LCX, LCY + d), (LCX + d, LCY), (LCX, LCY - d)], + fill=fg, + width=20, + joint=None, + ) + draw.text((LCX - 1.7 * d, LCY + 1.5 * d), "dmz.rs", font=font, fill=fg) - mesh_svg = svg2png(url='site/img/mesh-light.svg') + mesh_svg = svg2png(url="site/img/mesh-light.svg") mesh_svg_bytes = io.BytesIO(mesh_svg) mesh_img = Image.open(mesh_svg_bytes) if bg == (0, 0, 0): @@ -107,35 +140,32 @@ def drawMesh(draw, img, fg, bg, font, W, H): def drawPoster(events, bg, fg, month: int, en: bool): - fontFacade = ImageFont.truetype('./site/font/Facade-Sud.woff', size=365) - fontIosevka = ImageFont.truetype( - './site/font/iosevka-regular.woff', size=200) - fontIosevkaSmall = ImageFont.truetype( - './site/font/iosevka-regular.woff', size=150) + fontFacade = ImageFont.truetype("./site/font/Facade-Sud.woff", size=365) + fontIosevka = ImageFont.truetype("./site/font/iosevka-regular.woff", size=200) + fontIosevkaSmall = ImageFont.truetype("./site/font/iosevka-regular.woff", size=150) W = 3508 H = 4960 - img = Image.new('RGB', (W, H), bg) + img = Image.new("RGB", (W, H), bg) draw = ImageDraw.Draw(img) drawMesh(draw, img, fg, bg, fontIosevka, W, H) title = "DECENTRALA" _, _, w, _ = draw.textbbox((0, 0), title, font=fontFacade) - draw.text(((W-w)/2, 165), title, font=fontFacade, fill=fg) + draw.text(((W - w) / 2, 165), title, font=fontFacade, fill=fg) header = HEADER_EN if en else HEADER_SR months = MONTHS_EN if en else MONTHS_SR header = header.format(months[month.month - 1]) _, _, w, _ = draw.textbbox((0, 0), header, font=fontIosevka) - draw.text(((W-w)/2, 560), header, font=fontIosevka, fill=fg) + draw.text(((W - w) / 2, 560), header, font=fontIosevka, fill=fg) height = 890 sub_header = SUBHEADER_EN if en else SUBHEADER_SR - draw.text((165, height), sub_header, - font=fontIosevkaSmall, fill=fg) + draw.text((165, height), sub_header, font=fontIosevkaSmall, fill=fg) height += 800 # Write list of events to sperate text file as well @@ -167,8 +197,7 @@ def drawPoster(events, bg, fg, month: int, en: bool): def main(): # Parse arguments - parser = argparse.ArgumentParser( - description="Generate images of the poster") + parser = argparse.ArgumentParser(description="Generate images of the poster") args = parseArgs(parser) # Set month based on user input @@ -176,22 +205,24 @@ def main(): if args.month.isdigit(): month = dt.date(CURRENT_TIME.year, int(args.month), 1) elif args.month != "empty": - print("Month has to be specified as a number. I will use next month as the default") + print( + "Month has to be specified as a number. I will use next month as the default" + ) # Load events and draw a poseter events = load_events("dogadjaji.csv", month) img = drawPoster(events, (0, 0, 0), (20, 250, 50), month, False) - img.save('poster_dark.png') + img.save("poster_dark.png") img = drawPoster(events, (255, 255, 255), (0, 0, 0), month, False) - img.save('poster_light.png') + img.save("poster_light.png") img = drawPoster(events, (0, 0, 0), (20, 250, 50), month, True) - img.save('poster_dark_en.png') + img.save("poster_dark_en.png") img = drawPoster(events, (255, 255, 255), (0, 0, 0), month, True) - img.save('poster_light_en.png') + img.save("poster_light_en.png") if __name__ == "__main__": diff --git a/pages/en/support.html b/pages/en/support.html index 110e6c3..4b17ec1 100644 --- a/pages/en/support.html +++ b/pages/en/support.html @@ -24,9 +24,7 @@ By simply using services we are hosting, conts as contributing, because in that way you joining the decetralization.

-

- Also, we accept donations in bitcoin and monero to the following addresses: -

+

Also, we accept donations in bitcoin to the following address: