feat: update to support folder inside content folder to easy to manage
This commit is contained in:
parent
8485425d0f
commit
bc49877123
|
|
@ -43,8 +43,8 @@ init)
|
|||
echo "✅ [Skip] Folder content/ sudah ada"
|
||||
else
|
||||
mkdir -p "$PARENT_DIR/content"
|
||||
cp -n "$EXAMPLES_DIR/content/"*.md "$PARENT_DIR/content/"
|
||||
echo "📁 [Buat] Folder content/ ($(ls "$PARENT_DIR/content/"*.md 2>/dev/null | wc -l) materi contoh ditambahkan)"
|
||||
cp -rn "$EXAMPLES_DIR/content/"* "$PARENT_DIR/content/"
|
||||
echo "📁 [Buat] Folder content/ ($(find "$PARENT_DIR/content/" -name "*.md" 2>/dev/null | wc -l) materi contoh ditambahkan)"
|
||||
fi
|
||||
|
||||
# assets/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# Test Slide Feature
|
||||
|
||||
Selamat datang di materi uji coba fitur slide.
|
||||
|
||||
---slide-start---
|
||||
# Slide 1: Pengenalan
|
||||
Ini adalah konten slide pertama.
|
||||
---
|
||||
# Slide 2: Keuntungan
|
||||
- Mudah digunakan
|
||||
- Berbasis Markdown
|
||||
- Interaktif
|
||||
---
|
||||
# Slide 3: Selesai
|
||||
Terima kasih telah mencoba!
|
||||
---slide-end---
|
||||
|
||||
Setelah slide di atas, ini adalah konten materi biasa.
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
printf("Uji coba slide\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
|
@ -18,15 +18,16 @@ Semua materi bisa dikerjakan langsung di browser!
|
|||
3. [Uji Coba Flowchart](lesson/flowchart_test.md)
|
||||
4. [Uji Coba Kuis](lesson/quiz_test.md)
|
||||
5. [Uji Coba LaTeX](lesson/latex_test.md)
|
||||
6. [Uji Coba Slide](lesson/test_slides.md)
|
||||
|
||||
### Elektronika (Hybrid)
|
||||
6. [Rangkaian Dasar](lesson/rangkaian_dasar.md)
|
||||
### Elektronika & Sirkuit (Hybrid)
|
||||
7. [Rangkaian Dasar](lesson/rangkaian_dasar.md)
|
||||
|
||||
### Arduino (Velxio)
|
||||
7. [LED Blink](lesson/led_blink_arduino.md)
|
||||
8. [Hello Serial](lesson/hello_serial_arduino.md)
|
||||
9. [Button Input](lesson/button_input_arduino.md)
|
||||
10. [Traffic Light](lesson/traffic_light_arduino.md)
|
||||
### Arduino & Robotika (Velxio)
|
||||
8. [LED Blink](lesson/led_blink_arduino.md)
|
||||
9. [Hello Serial](lesson/hello_serial_arduino.md)
|
||||
10. [Button Input](lesson/button_input_arduino.md)
|
||||
11. [Traffic Light](lesson/traffic_light_arduino.md)
|
||||
|
||||
----Available_Lessons----
|
||||
|
||||
|
|
@ -34,8 +35,10 @@ Semua materi bisa dikerjakan langsung di browser!
|
|||
2. [Variabel](lesson/variabel.md)
|
||||
3. [Uji Coba Flowchart](lesson/flowchart_test.md)
|
||||
4. [Uji Coba Kuis](lesson/quiz_test.md)
|
||||
5. [Rangkaian Dasar](lesson/rangkaian_dasar.md)
|
||||
6. [LED Blink](lesson/led_blink_arduino.md)
|
||||
7. [Hello Serial](lesson/hello_serial_arduino.md)
|
||||
8. [Button Input](lesson/button_input_arduino.md)
|
||||
9. [Traffic Light](lesson/traffic_light_arduino.md)
|
||||
5. [Uji Coba LaTeX](lesson/latex_test.md)
|
||||
6. [Uji Coba Slide](lesson/test_slides.md)
|
||||
7. [Rangkaian Dasar](lesson/rangkaian_dasar.md)
|
||||
8. [LED Blink](lesson/led_blink_arduino.md)
|
||||
9. [Hello Serial](lesson/hello_serial_arduino.md)
|
||||
10. [Button Input](lesson/button_input_arduino.md)
|
||||
11. [Traffic Light](lesson/traffic_light_arduino.md)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from services.lesson_service import (
|
|||
get_ordered_lessons_with_learning_objectives,
|
||||
render_markdown_content,
|
||||
render_home_content,
|
||||
find_lesson_file,
|
||||
)
|
||||
from services.token_service import get_student_progress
|
||||
|
||||
|
|
@ -52,10 +53,9 @@ def api_lessons():
|
|||
@lessons_bp.route('/lesson/<filename>.json')
|
||||
def api_lesson(filename):
|
||||
"""Return single lesson data as JSON."""
|
||||
safe_filename = secure_filename(filename)
|
||||
full_filename = safe_filename if safe_filename.endswith('.md') else f'{safe_filename}.md'
|
||||
file_path = os.path.join(CONTENT_DIR, full_filename)
|
||||
if not os.path.exists(file_path):
|
||||
full_filename = filename if filename.endswith('.md') else f'{filename}.md'
|
||||
file_path = find_lesson_file(full_filename)
|
||||
if not file_path:
|
||||
return jsonify({'error': 'Lesson not found'}), 404
|
||||
|
||||
parsed_data = render_markdown_content(file_path)
|
||||
|
|
@ -215,9 +215,8 @@ def api_lesson(filename):
|
|||
@lessons_bp.route('/get-key-text/<filename>')
|
||||
def get_key_text(filename):
|
||||
"""Get the key text for a specific lesson."""
|
||||
safe_filename = secure_filename(filename)
|
||||
file_path = os.path.join(CONTENT_DIR, safe_filename)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = find_lesson_file(filename)
|
||||
if not file_path:
|
||||
return jsonify({'success': False, 'error': 'Lesson not found'}), 404
|
||||
|
||||
parsed_data = render_markdown_content(file_path)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,19 @@ def _parse_lesson_links(home_content):
|
|||
# Lesson listing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def find_lesson_file(filename):
|
||||
"""Recursively search for filename in CONTENT_DIR and return its full path."""
|
||||
# Security: Prevent directory traversal
|
||||
if '/' in filename or '\\' in filename:
|
||||
return None
|
||||
|
||||
for root, _, files in os.walk(CONTENT_DIR):
|
||||
if filename in files:
|
||||
return os.path.join(root, filename)
|
||||
return None
|
||||
|
||||
|
||||
@lru_cache(maxsize=32)
|
||||
def get_lessons():
|
||||
"""Get lessons from the Available_Lessons section in home.md."""
|
||||
|
|
@ -52,8 +65,8 @@ def get_lessons():
|
|||
return lessons
|
||||
|
||||
for link_text, filename in _parse_lesson_links(home_content):
|
||||
file_path = os.path.join(CONTENT_DIR, filename)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = find_lesson_file(filename)
|
||||
if not file_path:
|
||||
continue
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
|
|
@ -92,8 +105,8 @@ def get_lesson_names():
|
|||
|
||||
names = []
|
||||
for _link_text, filename in _parse_lesson_links(home_content):
|
||||
file_path = os.path.join(CONTENT_DIR, filename)
|
||||
if os.path.exists(file_path):
|
||||
file_path = find_lesson_file(filename)
|
||||
if file_path:
|
||||
names.append(filename.replace('.md', ''))
|
||||
return names
|
||||
|
||||
|
|
@ -107,8 +120,8 @@ def get_lessons_with_learning_objectives():
|
|||
return lessons
|
||||
|
||||
for link_text, filename in _parse_lesson_links(home_content):
|
||||
file_path = os.path.join(CONTENT_DIR, filename)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = find_lesson_file(filename)
|
||||
if not file_path:
|
||||
continue
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
|
|
|
|||
Loading…
Reference in New Issue