From ac9d70138565b2e9c8cfe6242bd431bbeab85eb4 Mon Sep 17 00:00:00 2001
From: Omar Besbes <86571415+omar-besbes@users.noreply.github.com>
Date: Sat, 12 Oct 2024 01:30:09 +0100
Subject: [PATCH] fix: correctly escape internal/external links in README
---
scripts/CSES/README.template.md | 4 ++--
scripts/CSES/generate.py | 31 ++++++++++++++++++++++-----
scripts/France-IOI/README.template.md | 8 +++----
scripts/France-IOI/generate.py | 31 ++++++++++++++++++++++-----
4 files changed, 58 insertions(+), 16 deletions(-)
diff --git a/scripts/CSES/README.template.md b/scripts/CSES/README.template.md
index 181f101..d439370 100644
--- a/scripts/CSES/README.template.md
+++ b/scripts/CSES/README.template.md
@@ -6,7 +6,7 @@ Accepted solutions of [CSES problemset](https://cses.fi/problemset).
{% for category, problems in categories.items() %}
-- [{{ category }}](#{{ category | lower | replace(' ', '-') }})
+- [{{ category }}](#{{ category | escape_internal_link }})
{% endfor %}
---
@@ -29,7 +29,7 @@ Accepted solutions of [CSES problemset](https://cses.fi/problemset).
{{ problem.id }}
-
+
💻 {{ problem.title }}
|
diff --git a/scripts/CSES/generate.py b/scripts/CSES/generate.py
index af69cce..9190a40 100644
--- a/scripts/CSES/generate.py
+++ b/scripts/CSES/generate.py
@@ -1,12 +1,15 @@
-import os
import logging
+import os
+import re
+import urllib.parse
-from jinja2 import Template
+from jinja2 import Environment, FileSystemLoader
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
CSES_SOLUTIONS_DIR = 'solutions/CSES'
-TEMPLATE_FILE = 'scripts/CSES/README.template.md'
+TEMPLATE_FILE = 'README.template.md'
+TEMPLATE_DIR = 'scripts/CSES'
def generate_data_from_folder(path):
data = {}
@@ -33,11 +36,29 @@ def generate_data_from_folder(path):
return data
+def escape_internal_link(text):
+ # Trim leading/trailing spaces
+ text = text.strip()
+ # Convert to lowercase
+ text = text.lower()
+ # Remove characters that are not word characters, hyphens, or spaces
+ text = re.sub(r'[^\w\- ]+', '', text)
+ # Replace spaces with hyphens
+ text = re.sub(r'\s', '-', text.strip())
+ # Remove trailing hyphens
+ text = re.sub(r'\-+$', '', text)
+ return text
+
+def escape_external_link(text):
+ return urllib.parse.quote(text)
+
if __name__ == '__main__':
# Load the template
logging.info('Loading the template')
- with open(TEMPLATE_FILE, 'r') as file:
- template = Template(file.read())
+ env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))
+ env.filters['escape_internal_link'] = escape_internal_link
+ env.filters['escape_external_link'] = escape_external_link
+ template = env.get_template(TEMPLATE_FILE)
# Generate the data from the folder structure
logging.info('Starting content generation')
diff --git a/scripts/France-IOI/README.template.md b/scripts/France-IOI/README.template.md
index 68da95e..616be29 100644
--- a/scripts/France-IOI/README.template.md
+++ b/scripts/France-IOI/README.template.md
@@ -5,9 +5,9 @@ Accepted solutions of [France-IOI problemset](https://www.france-ioi.org/algo/ch
## Table of Contents
{% for level, chapters in levels.items() %}
-- [{{ level }}](#{{ level | lower | replace(' ', '-') }})
+- [{{ level }}](#{{ level | escape_internal_link }})
{% for chapter, problems in chapters.items() %}
- - [{{ chapter }}](#{{ chapter | lower | replace(' ', '-') }})
+ - [{{ chapter }}](#{{ chapter | escape_internal_link }})
{% endfor %}
{% endfor %}
@@ -22,7 +22,7 @@ Accepted solutions of [France-IOI problemset](https://www.france-ioi.org/algo/ch
### {{ chapter }}
{% for problem in content.problems %}
-1. 💻 {{ problem.title }}
+1. 💻 {{ problem.title }}
{% endfor %}
{% for part in content.parts %}
@@ -30,7 +30,7 @@ Accepted solutions of [France-IOI problemset](https://www.france-ioi.org/algo/ch
1. **{{ part.part }}**
{% for subproblem in part.problems %}
- 1. 💻 {{ subproblem.title }}
+ 1. 💻 {{ subproblem.title }}
{% endfor %}
{% endfor %}
diff --git a/scripts/France-IOI/generate.py b/scripts/France-IOI/generate.py
index a281502..da7f590 100644
--- a/scripts/France-IOI/generate.py
+++ b/scripts/France-IOI/generate.py
@@ -1,12 +1,15 @@
-import os
import logging
+import os
+import re
+import urllib.parse
-from jinja2 import Template
+from jinja2 import Environment, FileSystemLoader
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
FRANCE_IOI_SOLUTIONS_DIR = 'solutions/France-IOI'
-TEMPLATE_FILE = 'scripts/France-IOI/README.template.md'
+TEMPLATE_FILE = 'README.template.md'
+TEMPLATE_DIR = 'scripts/France-IOI'
def generate_data_from_folder(path):
data = {}
@@ -59,11 +62,29 @@ def generate_data_from_folder(path):
return data
+def escape_internal_link(text):
+ # Trim leading/trailing spaces
+ text = text.strip()
+ # Convert to lowercase
+ text = text.lower()
+ # Remove characters that are not word characters, hyphens, or spaces
+ text = re.sub(r'[^\w\- ]+', '', text)
+ # Replace spaces with hyphens
+ text = re.sub(r'\s', '-', text.strip())
+ # Remove trailing hyphens
+ text = re.sub(r'\-+$', '', text)
+ return text
+
+def escape_external_link(text):
+ return urllib.parse.quote(text)
+
if __name__ == '__main__':
# Load the template
logging.info('Loading the template')
- with open(TEMPLATE_FILE, 'r') as file:
- template = Template(file.read())
+ env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))
+ env.filters['escape_internal_link'] = escape_internal_link
+ env.filters['escape_external_link'] = escape_external_link
+ template = env.get_template(TEMPLATE_FILE)
# Generate the data from the folder structure
logging.info('Starting content generation')