diff --git a/.gitignore b/.gitignore index 3550eba..b265086 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ venv/ # VSCode settings .vscode/ +plugins + diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..4956bb1 --- /dev/null +++ b/cli.py @@ -0,0 +1,17 @@ +import click +from notion_client.api import NotionClient +from notion_client.config import ConfigManager + +@click.group() +def cli(): + pass + +@cli.command() +@click.option('--schema', required=True, help='Schema name without extension.') +@click.option('--tasks', required=True, help='Tasks name without extension.') +def create_database(schema, tasks): + # Implementation as above + pass + +if __name__ == "__main__": + cli() diff --git a/config/database_configs/client_engagement_tracker.json b/config/database_configs/client_engagement_tracker.json deleted file mode 100644 index 64cd093..0000000 --- a/config/database_configs/client_engagement_tracker.json +++ /dev/null @@ -1,288 +0,0 @@ -{ - "schema": { - "title": "Client Engagement Tracker", - "properties": { - "Name": { - "title": {} - }, - "Description": { - "rich_text": {} - }, - "Status": { - "select": { - "options": [ - { "name": "Not started", "color": "default" }, - { "name": "In progress", "color": "blue" }, - { "name": "Completed", "color": "green" } - ] - } - }, - "Due Date": { - "date": {} - }, - "Engagement Type": { - "select": { - "options": [ - { "name": "Email", "color": "red" }, - { "name": "Meeting", "color": "green" }, - { "name": "Call", "color": "yellow" }, - { "name": "Social Media", "color": "blue" } - ] - } - }, - "Client": { - "people": {} - }, - "Notes": { - "rich_text": {} - } - } - }, - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Initial Consultation" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Schedule and conduct an initial consultation with the client." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-10" - } - }, - "Engagement Type": { - "select": { - "name": "Meeting" - } - }, - "Client": { - "people": [] - }, - "Notes": { - "rich_text": [ - { - "text": { - "content": "Prepare questions and materials for the initial consultation." - } - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Follow-Up Email" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Send a follow-up email summarizing the initial consultation and next steps." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-12" - } - }, - "Engagement Type": { - "select": { - "name": "Email" - } - }, - "Client": { - "people": [] - }, - "Notes": { - "rich_text": [ - { - "text": { - "content": "Include summary of the meeting, agreed actions, and any additional information requested." - } - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Weekly Check-In Call" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Conduct a weekly check-in call to discuss progress and address any issues." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-14" - } - }, - "Engagement Type": { - "select": { - "name": "Call" - } - }, - "Client": { - "people": [] - }, - "Notes": { - "rich_text": [ - { - "text": { - "content": "Prepare a brief agenda for the call." - } - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Monthly Progress Report" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Compile and send a monthly progress report to the client." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-16" - } - }, - "Engagement Type": { - "select": { - "name": "Email" - } - }, - "Client": { - "people": [] - }, - "Notes": { - "rich_text": [ - { - "text": { - "content": "Include metrics and qualitative feedback on progress." - } - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Social Media Engagement" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Engage with the client on social media platforms." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-18" - } - }, - "Engagement Type": { - "select": { - "name": "Social Media" - } - }, - "Client": { - "people": [] - }, - "Notes": { - "rich_text": [ - { - "text": { - "content": "Like, comment, and share relevant posts to boost engagement." - } - } - ] - } - } - } - ] -} diff --git a/config/database_configs/email-capture-validation-task.json b/config/database_configs/email-capture-validation-task.json deleted file mode 100644 index 1fae55b..0000000 --- a/config/database_configs/email-capture-validation-task.json +++ /dev/null @@ -1,52 +0,0 @@ - -{ - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Validate Email Address in Capture Form" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Implement email validation logic in the email-capture form to ensure proper email format and prevent invalid submissions." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-15" - } - }, - "Task Type": { - "select": { - "name": "Frontend Development" - } - }, - "Priority": { - "select": { - "name": "High" - } - }, - "Estimated Time": { - "select": { - "name": "More than 3 hours" - } - } - } - } - ] -} diff --git a/config/database_configs/fashion_recommender_tasks.json b/config/database_configs/fashion_recommender_tasks.json deleted file mode 100644 index 6f5db29..0000000 --- a/config/database_configs/fashion_recommender_tasks.json +++ /dev/null @@ -1,239 +0,0 @@ -{ - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Photograph and Catalog Clothing Items" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Take high-quality photographs of each clothing item and catalog them with attributes like color, pattern, and image URL." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-14" - } - }, - "Task Type": { - "select": { - "name": "Cataloging" - } - }, - "Priority": { - "select": { - "name": "High" - } - }, - "Estimated Time": { - "select": { - "name": "More than 3 hours" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Design the Database Schema" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Design a scalable database schema that includes user profiles, clothing items, and recommendation logic." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-17" - } - }, - "Task Type": { - "select": { - "name": "Database Design" - } - }, - "Priority": { - "select": { - "name": "High" - } - }, - "Estimated Time": { - "select": { - "name": "2-3 hours" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Set Up the Backend API" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Develop the backend API to handle operations like adding, retrieving, and updating clothing items, and implementing recommendation logic." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-21" - } - }, - "Task Type": { - "select": { - "name": "Backend Development" - } - }, - "Priority": { - "select": { - "name": "High" - } - }, - "Estimated Time": { - "select": { - "name": "More than 3 hours" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Develop the User Interface" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Create the frontend of the app, focusing on ease of use and clear presentation of recommendations." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-28" - } - }, - "Task Type": { - "select": { - "name": "Frontend Development" - } - }, - "Priority": { - "select": { - "name": "Medium" - } - }, - "Estimated Time": { - "select": { - "name": "2-3 hours" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Testing and Iteration" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Test the app with your data, gather feedback, and iterate on the design and functionality." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-09-05" - } - }, - "Task Type": { - "select": { - "name": "Testing" - } - }, - "Priority": { - "select": { - "name": "Medium" - } - }, - "Estimated Time": { - "select": { - "name": "More than 3 hours" - } - } - } - } - ] -} diff --git a/config/database_configs/gym_strength_ifbb_training.json b/config/database_configs/gym_strength_ifbb_training.json deleted file mode 100644 index bf55fd7..0000000 --- a/config/database_configs/gym_strength_ifbb_training.json +++ /dev/null @@ -1,299 +0,0 @@ -{ - "schema": { - "title": "Pro Physique Workout Plan", - "properties": { - "Name": { - "title": {} - }, - "Description": { - "rich_text": {} - }, - "Status": { - "select": { - "options": [ - { "name": "To Do", "color": "default" }, - { "name": "In Progress", "color": "blue" }, - { "name": "Done", "color": "green" } - ] - } - }, - "Day": { - "select": { - "options": [ - { "name": "Monday", "color": "red" }, - { "name": "Tuesday", "color": "green" }, - { "name": "Wednesday", "color": "yellow" }, - { "name": "Thursday", "color": "blue" }, - { "name": "Friday", "color": "purple" }, - { "name": "Saturday", "color": "orange" }, - { "name": "Sunday", "color": "gray" } - ] - } - }, - "Warm-Up": { - "rich_text": {} - }, - "Exercises": { - "rich_text": {} - }, - "Cool-Down": { - "rich_text": {} - }, - "Duration": { - "number": { - "format": "number" - } - } - } - }, - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Chest Workout" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "A comprehensive chest workout routine." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Day": { - "select": { - "name": "Monday" - } - }, - "Warm-Up": { - "rich_text": [ - { - "text": { - "content": "### Warm-Up\n- 5 minutes of light cardio (jogging in place, jumping jacks)\n- 2 sets of 10 push-ups" - } - } - ] - }, - "Exercises": { - "rich_text": [ - { - "text": { - "content": "### Exercises\n- **Flat Dumbbell Press**: 4 sets of 10 reps\n- **Incline Dumbbell Press**: 4 sets of 12 reps\n- **Smith Machine Bench Press**: 3 sets of 8 reps\n- **Cable Flyes**: 3 sets of 15 reps\n- **Push-Ups**: 3 sets to failure" - } - } - ] - }, - "Cool-Down": { - "rich_text": [ - { - "text": { - "content": "### Cool-Down\n- 5 minutes of light stretching focusing on the chest and shoulders" - } - } - ] - }, - "Duration": { - "number": 60 - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Back Workout" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "A comprehensive back workout routine." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Day": { - "select": { - "name": "Wednesday" - } - }, - "Warm-Up": { - "rich_text": [ - { - "text": { - "content": "### Warm-Up\n- 5 minutes of light cardio (rowing machine or jumping jacks)\n- 2 sets of 10 pull-ups" - } - } - ] - }, - "Exercises": { - "rich_text": [ - { - "text": { - "content": "### Exercises\n- **Pull-Ups**: 4 sets of 8 reps\n- **Dumbbell Rows**: 4 sets of 12 reps\n- **Smith Machine Bent Over Rows**: 3 sets of 10 reps\n- **Cable Lat Pulldowns**: 3 sets of 15 reps\n- **Face Pulls**: 3 sets of 12 reps" - } - } - ] - }, - "Cool-Down": { - "rich_text": [ - { - "text": { - "content": "### Cool-Down\n- 5 minutes of light stretching focusing on the back and shoulders" - } - } - ] - }, - "Duration": { - "number": 60 - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Leg Workout" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "A comprehensive leg workout routine." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Day": { - "select": { - "name": "Friday" - } - }, - "Warm-Up": { - "rich_text": [ - { - "text": { - "content": "### Warm-Up\n- 5 minutes of light cardio (jogging or cycling)\n- 2 sets of 10 bodyweight squats" - } - } - ] - }, - "Exercises": { - "rich_text": [ - { - "text": { - "content": "### Exercises\n- **Smith Machine Squats**: 4 sets of 10 reps\n- **Dumbbell Lunges**: 4 sets of 12 reps per leg\n- **Leg Press (if available)**: 3 sets of 12 reps\n- **Leg Curls**: 3 sets of 15 reps\n- **Calf Raises**: 4 sets of 20 reps" - } - } - ] - }, - "Cool-Down": { - "rich_text": [ - { - "text": { - "content": "### Cool-Down\n- 5 minutes of light stretching focusing on the legs" - } - } - ] - }, - "Duration": { - "number": 60 - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Arms Workout" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "A comprehensive arms workout routine." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Day": { - "select": { - "name": "Saturday" - } - }, - "Warm-Up": { - "rich_text": [ - { - "text": { - "content": "### Warm-Up\n- 5 minutes of light cardio (jumping jacks or light jogging)\n- 2 sets of 10 bicep curls with light weights" - } - } - ] - }, - "Exercises": { - "rich_text": [ - { - "text": { - "content": "### Exercises\n- **Dumbbell Bicep Curls**: 4 sets of 12 reps\n- **Tricep Dips (bench)**: 4 sets of 12 reps\n- **Smith Machine Overhead Press**: 3 sets of 10 reps\n- **Cable Tricep Extensions**: 3 sets of 15 reps\n- **Hammer Curls**: 3 sets of 12 reps" - } - } - ] - }, - "Cool-Down": { - "rich_text": [ - { - "text": { - "content": "### Cool-Down\n- 5 minutes of light stretching focusing on the arms" - } - } - ] - }, - "Duration": { - "number": 60 - } - } - } - ] -} diff --git a/config/database_configs/mlb_training_plan.json b/config/database_configs/mlb_training_plan.json deleted file mode 100644 index 3dd8871..0000000 --- a/config/database_configs/mlb_training_plan.json +++ /dev/null @@ -1,278 +0,0 @@ -{ - "schema": { - "title": "MLB Training Plan", - "properties": { - "Name": { - "title": {} - }, - "Description": { - "rich_text": {} - }, - "Status": { - "select": { - "options": [ - { "name": "Not started", "color": "default" }, - { "name": "In progress", "color": "blue" }, - { "name": "Completed", "color": "green" } - ] - } - }, - "Due Date": { - "date": {} - }, - "Exercise Type": { - "select": { - "options": [ - { "name": "Strength", "color": "red" }, - { "name": "Cardio", "color": "green" }, - { "name": "Flexibility", "color": "yellow" }, - { "name": "Skill", "color": "blue" } - ] - } - }, - "Duration": { - "number": { - "format": "number" - } - }, - "Coach": { - "people": {} - }, - "Video Link": { - "url": {} - } - } - }, - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Strength Training: Squats" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Perform squats with a focus on proper form and increasing weight gradually." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-10" - } - }, - "Exercise Type": { - "select": { - "name": "Strength" - } - }, - "Duration": { - "number": 1 - }, - "Coach": { - "people": [] - }, - "Video Link": { - "url": "https://www.youtube.com/watch?v=1y5G-MWn8A0" - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Cardio: Interval Running" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Perform interval running sessions to improve cardiovascular fitness." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-12" - } - }, - "Exercise Type": { - "select": { - "name": "Cardio" - } - }, - "Duration": { - "number": 0.5 - }, - "Coach": { - "people": [] - }, - "Video Link": { - "url": "https://www.youtube.com/watch?v=5z1afR6rjS4" - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Flexibility: Yoga Session" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Participate in a yoga session to improve flexibility and reduce injury risk." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-14" - } - }, - "Exercise Type": { - "select": { - "name": "Flexibility" - } - }, - "Duration": { - "number": 1 - }, - "Coach": { - "people": [] - }, - "Video Link": { - "url": "https://www.youtube.com/watch?v=Jw5rAxQ8mB0" - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Skill Training: Batting Practice" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Focus on improving batting technique through drills and practice sessions." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-16" - } - }, - "Exercise Type": { - "select": { - "name": "Skill" - } - }, - "Duration": { - "number": 1.5 - }, - "Coach": { - "people": [] - }, - "Video Link": { - "url": "https://www.youtube.com/watch?v=htVfYX3W9hI" - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Recovery: Ice Bath" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Use ice baths to reduce muscle soreness and speed up recovery." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-18" - } - }, - "Exercise Type": { - "select": { - "name": "Recovery" - } - }, - "Duration": { - "number": 0.5 - }, - "Coach": { - "people": [] - }, - "Video Link": { - "url": "https://www.youtube.com/watch?v=IcY1GAj6uZc" - } - } - } - ] -} diff --git a/config/database_configs/schema.json b/config/database_configs/schema.json deleted file mode 100644 index 87d2431..0000000 --- a/config/database_configs/schema.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "title": "Fashion Recommender App Development", - "properties": { - "Name": { - "title": {} - }, - "Description": { - "rich_text": {} - }, - "Status": { - "select": { - "options": [ - { "name": "To Do", "color": "default" }, - { "name": "In Progress", "color": "blue" }, - { "name": "Done", "color": "green" } - ] - } - }, - "Due Date": { - "date": {} - }, - "Task Type": { - "select": { - "options": [ - { "name": "Cataloging", "color": "red" }, - { "name": "Database Design", "color": "green" }, - { "name": "Backend Development", "color": "yellow" }, - { "name": "Frontend Development", "color": "blue" }, - { "name": "Testing", "color": "purple" } - ] - } - }, - "Priority": { - "select": { - "options": [ - { "name": "High", "color": "red" }, - { "name": "Medium", "color": "orange" }, - { "name": "Low", "color": "green" } - ] - } - }, - "Estimated Time": { - "select": { - "options": [ - { "name": "Less than 1 hour", "color": "yellow" }, - { "name": "1-2 hours", "color": "orange" }, - { "name": "2-3 hours", "color": "red" }, - { "name": "More than 3 hours", "color": "purple" } - ] - } - } - } -} diff --git a/config/database_configs/ui_ux_improvement_plan.json b/config/database_configs/ui_ux_improvement_plan.json deleted file mode 100644 index 5986a8d..0000000 --- a/config/database_configs/ui_ux_improvement_plan.json +++ /dev/null @@ -1,221 +0,0 @@ -{ - "schema": { - "title": "UI/UX Improvements for Hue Lighting Demo", - "properties": { - "Name": { - "title": {} - }, - "Description": { - "rich_text": {} - }, - "Status": { - "select": { - "options": [ - { "name": "To Do", "color": "default" }, - { "name": "In Progress", "color": "blue" }, - { "name": "Done", "color": "green" } - ] - } - }, - "Due Date": { - "date": {} - }, - "Task Type": { - "select": { - "options": [ - { "name": "Design", "color": "red" }, - { "name": "Development", "color": "green" }, - { "name": "Review", "color": "yellow" } - ] - } - } - } - }, - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Update Button Colors to Match Scene Themes" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Adjust the button colors to more accurately represent the 'Wind Down' and 'Work From Home' scenes." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-12" - } - }, - "Task Type": { - "select": { - "name": "Design" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Improve Button Styling" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Add shadow, border-radius, and hover effects to buttons for a more modern look and feel." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-13" - } - }, - "Task Type": { - "select": { - "name": "Design" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Adjust Layout and Spacing" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Increase vertical spacing between elements and adjust layout for better readability and balance." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-14" - } - }, - "Task Type": { - "select": { - "name": "Design" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Refine Font and Text Styling" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Update button text to sentence case, increase font size, and improve letter-spacing for better readability." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-15" - } - }, - "Task Type": { - "select": { - "name": "Design" - } - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Add Subtle Background Gradient" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Implement a subtle background color or gradient to make the UI feel more cohesive and polished." - } - } - ] - }, - "Status": { - "select": { - "name": "To Do" - } - }, - "Due Date": { - "date": { - "start": "2024-08-16" - } - }, - "Task Type": { - "select": { - "name": "Development" - } - } - } - } - ] -} diff --git a/config/database_configs/union_find_study_plan.json b/config/database_configs/union_find_study_plan.json deleted file mode 100644 index 71b378e..0000000 --- a/config/database_configs/union_find_study_plan.json +++ /dev/null @@ -1,336 +0,0 @@ -{ - "schema": { - "title": "Union-Find Study Plan", - "properties": { - "Name": { - "title": {} - }, - "Description": { - "rich_text": {} - }, - "Status": { - "select": { - "options": [ - { "name": "Not started", "color": "default" }, - { "name": "In progress", "color": "blue" }, - { "name": "Completed", "color": "green" } - ] - } - }, - "Due Date": { - "date": {} - }, - "Resource": { - "select": { - "options": [ - { "name": "Video", "color": "red" }, - { "name": "Article", "color": "green" }, - { "name": "Code Practice", "color": "yellow" }, - { "name": "Documentation", "color": "blue" } - ] - } - }, - "Link": { - "url": {} - }, - "Estimated Time": { - "select": { - "options": [ - { "name": "Less than 1 hour", "color": "yellow" }, - { "name": "1-2 hours", "color": "orange" }, - { "name": "2-3 hours", "color": "red" }, - { "name": "More than 3 hours", "color": "purple" } - ] - } - }, - "Tags": { - "multi_select": { - "options": [ - { "name": "Basics", "color": "blue" }, - { "name": "Advanced", "color": "purple" }, - { "name": "Optimization", "color": "orange" }, - { "name": "Practice", "color": "pink" }, - { "name": "Theory", "color": "gray" } - ] - } - } - } - }, - "tasks": [ - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Introduction to Union-Find" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Understand the basics of the Union-Find data structure, including its operations and applications." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-10" - } - }, - "Resource": { - "select": { - "name": "Article" - } - }, - "Link": { - "url": "https://www.geeksforgeeks.org/union-find/" - }, - "Estimated Time": { - "select": { - "name": "1-2 hours" - } - }, - "Tags": { - "multi_select": [ - { - "name": "Basics" - }, - { - "name": "Theory" - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Union Operation" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Learn about the union operation in the Union-Find data structure and its implementation." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-12" - } - }, - "Resource": { - "select": { - "name": "Video" - } - }, - "Link": { - "url": "https://www.youtube.com/watch?v=3Gb3faOzvBk" - }, - "Estimated Time": { - "select": { - "name": "1-2 hours" - } - }, - "Tags": { - "multi_select": [ - { - "name": "Basics" - }, - { - "name": "Practice" - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Find Operation" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Learn about the find operation in the Union-Find data structure and its implementation." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-15" - } - }, - "Resource": { - "select": { - "name": "Video" - } - }, - "Link": { - "url": "https://www.youtube.com/watch?v=zQeY8nP4AEI" - }, - "Estimated Time": { - "select": { - "name": "1-2 hours" - } - }, - "Tags": { - "multi_select": [ - { - "name": "Basics" - }, - { - "name": "Practice" - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "Applications of Union-Find" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Explore various applications of the Union-Find data structure." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-18" - } - }, - "Resource": { - "select": { - "name": "Article" - } - }, - "Link": { - "url": "https://www.geeksforgeeks.org/applications-of-disjoint-set-data-structure/" - }, - "Estimated Time": { - "select": { - "name": "2-3 hours" - } - }, - "Tags": { - "multi_select": [ - { - "name": "Advanced" - }, - { - "name": "Theory" - } - ] - } - } - }, - { - "properties": { - "Name": { - "title": [ - { - "text": { - "content": "LeetCode Practice: Number of Connected Components in an Undirected Graph" - } - } - ] - }, - "Description": { - "rich_text": [ - { - "text": { - "content": "Practice using Union-Find to solve LeetCode problems." - } - } - ] - }, - "Status": { - "select": { - "name": "Not started" - } - }, - "Due Date": { - "date": { - "start": "2024-07-20" - } - }, - "Resource": { - "select": { - "name": "Code Practice" - } - }, - "Link": { - "url": "https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/" - }, - "Estimated Time": { - "select": { - "name": "1-2 hours" - } - }, - "Tags": { - "multi_select": [ - { - "name": "Practice" - }, - { - "name": "Advanced" - } - ] - } - } - } - ] -} diff --git a/notion.txt b/notion.txt new file mode 100644 index 0000000..f0c1b16 --- /dev/null +++ b/notion.txt @@ -0,0 +1,156 @@ + + +# File: .gitignore +# Environment Variables +.env + +# Python virtual environment +venv/ + +# Byte-compiled Python files +**/__pycache__/ +**/*.pyc + +# VSCode settings +.vscode/ + +plugins + + + +# File: README.md +# Notion Automation + +This repository contains scripts and configurations to automate task creation in Notion. It is designed to be extensible for future automations. + +## Setup + +1. **Clone the repository:** + ```bash + git clone https://github.com/atxtechbro/notion-automation.git + cd notion-automation + ``` + +2. **Create and activate a virtual environment:** + ```bash + python -m venv venv + source venv/bin/activate # On Windows, use `venv\Scripts\activate` + ``` + +3. **Install the required packages:** + ```bash + pip install -r requirements.txt + ``` + +4. **Set up environment variables:** + Create a `.env` file in the root of the repository and add your Notion API key and the Notion page ID where the database will be created: + ```env + NOTION_API_KEY=your_notion_api_key + NOTION_PAGE_ID=your_notion_page_id + ``` + +5. **Ensure your directory structure is as follows:** + ``` + notion-automation/ + ├── venv/ + ├── scripts/ + │ ├── __init__.py + │ └── create_database.py + ├── config/ + │ └── database_configs/ + │ └── gym_strength_ifbb_training.json + ├── .env + ├── requirements.txt + └── main.py + ``` + +6. **Run the script:** + ```bash + python -m scripts.create_database gym_strength_ifbb_training + ``` + +### Example Usage + +To create a database using the `gym_strength_ifbb_training` configuration, use the following command: +```bash +python -m scripts.create_database gym_strength_ifbb_training +``` + +This will create a Notion database and tasks based on the `gym_strength_ifbb_training.json` configuration file located in the `config/database_configs/` directory. + +### Notes + +- Ensure that your Notion API key and page ID are correctly set in the `.env` file. +- The JSON configuration files should be placed in the `config/database_configs/` directory. +- You can add more configurations by creating additional JSON files in the `config/database_configs/` directory and running the script with the respective configuration name. + +By following these steps, you should be able to automate the creation of databases and tasks in Notion efficiently. + +# File: requirements.txt +requests +python-dotenv +pydantic +click + +# File: scripts/create_database.py +import argparse +import os +from notion_client.api import NotionClient +from notion_client.config import ConfigManager + +def main(schema_name, tasks_name): + config_manager = ConfigManager(config_path='plugins') + schema = config_manager.load_schema(schema_name) + tasks = config_manager.load_tasks(tasks_name) + + notion_api_key = os.getenv('NOTION_API_KEY') + notion_page_id = os.getenv('NOTION_PAGE_ID') + + notion_client = NotionClient(api_key=notion_api_key) + database_id = notion_client.create_database(parent_id=notion_page_id, schema=schema) + + for task in tasks: + notion_client.create_task(database_id=database_id, task=task) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Create a Notion database.") + parser.add_argument('schema', type=str, help="Schema name without extension.") + parser.add_argument('tasks', type=str, help="Tasks name without extension.") + args = parser.parse_args() + main(args.schema, args.tasks) + + +# File: scripts/update_database.py +import argparse +from notion_utils.NotionUtils import load_schema, load_tasks, update_database, create_task + +def main(database_id, schema_name, tasks_name): + try: + # Load schema and tasks configuration + schema = load_schema(schema_name) + tasks = load_tasks(tasks_name) + + # Update the database with the provided schema + update_database(database_id, schema) + + # Add tasks to the updated database + schema_properties = schema["properties"] + for task in tasks["tasks"]: + create_task(database_id, task, schema_properties) + + except FileNotFoundError as e: + print(e) + except ValueError as e: + print(f"Validation Error: {e}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Update an existing Notion database using specified schema and tasks templates.") + parser.add_argument('database_id', type=str, help="The ID of the database to update.") + parser.add_argument('schema', type=str, help="The name of the schema template to use (without .json extension).") + parser.add_argument('tasks', type=str, help="The name of the tasks template to use (without .json extension).") + + args = parser.parse_args() + main(args.database_id, args.schema, args.tasks) + + +# File: setup.sh diff --git a/notion_automation.log b/notion_automation.log new file mode 100644 index 0000000..e69de29 diff --git a/notion_client/api.py b/notion_client/api.py new file mode 100644 index 0000000..07f0126 --- /dev/null +++ b/notion_client/api.py @@ -0,0 +1,53 @@ +import requests +from .models import SchemaConfig, TaskConfig + +from .logger import logger + +class NotionClient: + # Existing code... + + def create_database(self, parent_id: str, schema: SchemaConfig) -> str: + url = 'https://api.notion.com/v1/databases' + data = { + "parent": {"page_id": parent_id}, + "title": [{"type": "text", "text": {"content": schema.title}}], + "properties": schema.to_notion_properties() + } + try: + response = requests.post(url, headers=self.headers, json=data) + response.raise_for_status() + database_id = response.json()["id"] + logger.info(f"Database '{schema.title}' created with ID: {database_id}") + return database_id + except requests.exceptions.HTTPError as e: + logger.error(f"Failed to create database: {e.response.text}") + raise + + def update_database(self, database_id: str, schema: SchemaConfig): + url = f'https://api.notion.com/v1/databases/{database_id}' + data = { + "title": [{"type": "text", "text": {"content": schema.title}}], + "properties": schema.to_notion_properties() + } + try: + response = requests.patch(url, headers=self.headers, json=data) + response.raise_for_status() + logger.info(f"Database '{schema.title}' updated successfully.") + except requests.exceptions.HTTPError as e: + logger.error(f"Failed to update database: {e.response.text}") + raise + + def create_task(self, database_id: str, task: TaskConfig): + url = 'https://api.notion.com/v1/pages' + data = { + "parent": {"database_id": database_id}, + "properties": task.to_notion_properties() + } + try: + response = requests.post(url, headers=self.headers, json=data) + response.raise_for_status() + task_name = task.properties["Name"].value[0].text.content + logger.info(f"Task '{task_name}' created in database '{database_id}'.") + except requests.exceptions.HTTPError as e: + logger.error(f"Failed to create task: {e.response.text}") + raise diff --git a/notion_client/config.py b/notion_client/config.py new file mode 100644 index 0000000..67ddd86 --- /dev/null +++ b/notion_client/config.py @@ -0,0 +1,27 @@ +import os +import json +from typing import List +from .models import SchemaConfig, TaskConfig +import os +import json + +class ConfigManager: + def __init__(self, config_path='plugins'): + self.config_path = config_path + + def load_schema(self, schema_name: str) -> SchemaConfig: + file_path = os.path.join(self.config_path, f"{schema_name}.json") + if not os.path.exists(file_path): + raise FileNotFoundError(f"Schema file '{file_path}' not found.") + with open(file_path, 'r') as file: + data = json.load(file) + return SchemaConfig(**data) + + def load_tasks(self, tasks_name: str) -> list: + file_path = os.path.join(self.config_path, f"{tasks_name}.json") + if not os.path.exists(file_path): + raise FileNotFoundError(f"Tasks file '{file_path}' not found.") + with open(file_path, 'r') as file: + data = json.load(file) + tasks = [TaskConfig(**task) for task in data.get("tasks", [])] + return tasks diff --git a/notion_client/logger.py b/notion_client/logger.py new file mode 100644 index 0000000..f518c52 --- /dev/null +++ b/notion_client/logger.py @@ -0,0 +1,24 @@ +# File: notion_client/logger.py +import logging +import sys + +# Create a logger +logger = logging.getLogger('notion_automation') +logger.setLevel(logging.DEBUG) + +# Create handlers +c_handler = logging.StreamHandler(sys.stdout) +f_handler = logging.FileHandler('notion_automation.log') +c_handler.setLevel(logging.INFO) +f_handler.setLevel(logging.DEBUG) + +# Create formatters +c_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') +f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +c_handler.setFormatter(c_format) +f_handler.setFormatter(f_format) + +# Add handlers to the logger +logger.addHandler(c_handler) +logger.addHandler(f_handler) diff --git a/notion_client/models.py b/notion_client/models.py new file mode 100644 index 0000000..c04ff13 --- /dev/null +++ b/notion_client/models.py @@ -0,0 +1,30 @@ +from pydantic import BaseModel +from typing import List, Dict, Any, Optional + +class PropertyOption(BaseModel): + name: str + color: Optional[str] = None + +class PropertyConfig(BaseModel): + property_type: str + options: Optional[List[PropertyOption]] = None + def to_notion_format(self): + # Convert PropertyConfig to Notion API property format + pass + +class SchemaConfig(BaseModel): + title: str + properties: Dict[str, PropertyConfig] + + def to_notion_properties(self): + notion_properties = {} + for name, prop in self.properties.items(): + notion_properties[name] = prop.to_notion_format() + return notion_properties + +class TaskProperty(BaseModel): + type: str + value: Any + +class TaskConfig(BaseModel): + properties: Dict[str, TaskProperty] diff --git a/requirements.txt b/requirements.txt index d44fe44..5246ef3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,5 @@ requests -python-dotenv \ No newline at end of file +python-dotenv +pydantic +click +pytest \ No newline at end of file diff --git a/scripts/create_database.py b/scripts/create_database.py index 6b07452..cf97974 100644 --- a/scripts/create_database.py +++ b/scripts/create_database.py @@ -1,25 +1,27 @@ import argparse -from notion_utils.NotionUtils import load_schema, load_tasks, create_database, create_task +import os +from notion_client.api import NotionClient +from notion_client.config import ConfigManager def main(schema_name, tasks_name): - try: - schema = load_schema(schema_name) # Load schema configuration - tasks = load_tasks(tasks_name) # Load tasks configuration + config_manager = ConfigManager(config_path=args.config_path) - database_id = create_database(schema) - if database_id: - schema_properties = schema["properties"] - for task in tasks["tasks"]: - create_task(database_id, task, schema_properties) - except FileNotFoundError as e: - print(e) - except ValueError as e: - print(f"Validation Error: {e}") + schema = config_manager.load_schema(schema_name) + tasks = config_manager.load_tasks(tasks_name) + + notion_api_key = os.getenv('NOTION_API_KEY') + notion_page_id = os.getenv('NOTION_PAGE_ID') + + notion_client = NotionClient(api_key=notion_api_key) + database_id = notion_client.create_database(parent_id=notion_page_id, schema=schema) + + for task in tasks: + notion_client.create_task(database_id=database_id, task=task) if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Create a Notion database using a specified schema and tasks template.") - parser.add_argument('schema', type=str, help="The name of the schema template to use (without .json extension).") - parser.add_argument('tasks', type=str, help="The name of the tasks template to use (without .json extension).") - + parser = argparse.ArgumentParser(description="Create a Notion database.") + parser.add_argument('schema', type=str, help="Schema name without extension.") + parser.add_argument('tasks', type=str, help="Tasks name without extension.") + parser.add_argument('--config-path', type=str, default='plugins', help="Path to the configuration directory.") args = parser.parse_args() main(args.schema, args.tasks) diff --git a/scripts/notion_utils/NotionUtils.py b/scripts/notion_utils/NotionUtils.py deleted file mode 100644 index 6618058..0000000 --- a/scripts/notion_utils/NotionUtils.py +++ /dev/null @@ -1,135 +0,0 @@ -import os -import json -import requests -from dotenv import load_dotenv - -# Load environment variables -load_dotenv() - -NOTION_API_KEY = os.getenv('NOTION_API_KEY') -NOTION_PAGE_ID = os.getenv('NOTION_PAGE_ID') - -HEADERS = { - "Authorization": f"Bearer {NOTION_API_KEY}", - "Content-Type": "application/json", - "Notion-Version": "2021-08-16" -} - -def load_json_file(file_path): - """Load a JSON file and return its content.""" - if not os.path.exists(file_path): - raise FileNotFoundError(f"File '{file_path}' not found.") - with open(file_path, 'r') as file: - return json.load(file) - -def load_schema(schema_name="schema"): - """Load the schema configuration from a JSON file.""" - schema_path = f'config/database_configs/{schema_name}.json' - return load_json_file(schema_path) - -def load_tasks(tasks_name="tasks"): - """Load the tasks configuration from a JSON file.""" - tasks_path = f'config/database_configs/{tasks_name}.json' - return load_json_file(tasks_path) - -def get_property_type(property_config): - """Determine the type of a property based on its configuration.""" - for property_type in ["title", "rich_text", "select", "date", "people", "url", "number", "multi_select"]: - if property_type in property_config: - return property_type - return None - -def validate_task_properties(task, schema_properties): - """Validate the properties of a task against the schema properties.""" - task_properties = task["properties"] - for key, value in schema_properties.items(): - if key not in task_properties: - raise ValueError(f"Task property '{key}' is missing.") - expected_type = get_property_type(value) - actual_type = get_property_type(task_properties[key]) - if expected_type != actual_type: - raise ValueError(f"Task property '{key}' has incorrect type. Expected: {expected_type}, Got: {actual_type}") - if expected_type == 'people' and not task_properties[key].get('people'): - task_properties[key] = {"people": []} - -def create_database(config): - """Create a new Notion database using the provided configuration.""" - create_url = 'https://api.notion.com/v1/databases' - data = { - "parent": {"type": "page_id", "page_id": NOTION_PAGE_ID}, - "title": [{"type": "text", "text": {"content": config["title"]}}], - "properties": config["properties"] - } - response = requests.post(create_url, headers=HEADERS, json=data) - if response.status_code == 200: - database_id = response.json()["id"] - print(f"Database created successfully with ID: {database_id}") - return database_id - else: - print(f"Failed to create database: {response.text}") - return None - -def update_database(database_id, config): - """Update an existing Notion database with the provided configuration.""" - update_url = f'https://api.notion.com/v1/databases/{database_id}' - - data = {} - - # Only include title if it's provided in the config - if "title" in config: - data["title"] = [{"type": "text", "text": {"content": config["title"]}}] - - # Check if properties exist in the database schema before updating - if "properties" in config: - # Get the existing properties from the database - existing_schema_response = requests.get(update_url, headers=HEADERS) - if existing_schema_response.status_code != 200: - raise ValueError(f"Failed to retrieve database schema: {existing_schema_response.text}") - - existing_properties = existing_schema_response.json().get("properties", {}) - - # Filter properties to only include those that exist in the current schema - data["properties"] = {k: v for k, v in config["properties"].items() if k in existing_properties} - - # Log missing properties - missing_properties = [k for k in config["properties"] if k not in existing_properties] - if missing_properties: - print(f"Warning: The following properties are missing in the current database schema and won't be updated: {', '.join(missing_properties)}") - else: - raise ValueError("The configuration must include 'properties' to update the database.") - - if not data.get("properties"): - raise ValueError("No valid properties found to update in the database schema.") - - response = requests.patch(update_url, headers=HEADERS, json=data) - if response.status_code == 200: - print(f"Database updated successfully.") - else: - print(f"Failed to update database: {response.status_code} - {response.text}") - -def create_task(database_id, task, schema_properties): - """Create a new task in the specified Notion database.""" - validate_task_properties(task, schema_properties) - create_url = 'https://api.notion.com/v1/pages' - data = { - "parent": {"database_id": database_id}, - "properties": task["properties"] - } - response = requests.post(create_url, headers=HEADERS, json=data) - if response.status_code == 200: - task_name = task["properties"]["Name"]["title"][0]["text"]["content"] - print(f"Task '{task_name}' created successfully.") - else: - print(f"Failed to create task: {response.text}") - -def update_task(database_id, task, schema_properties): - """Update an existing task in the specified Notion database.""" - validate_task_properties(task, schema_properties) - update_url = f'https://api.notion.com/v1/pages/{task["id"]}' - data = {"properties": task["properties"]} - response = requests.patch(update_url, headers=HEADERS, json=data) - if response.status_code == 200: - task_name = task["properties"]["Name"]["title"][0]["text"]["content"] - print(f"Task '{task_name}' updated successfully.") - else: - print(f"Failed to update task: {response.text}") diff --git a/scripts/update_database.py b/scripts/update_database.py index 24e43d2..6d1e21f 100644 --- a/scripts/update_database.py +++ b/scripts/update_database.py @@ -1,30 +1,27 @@ +# File: scripts/update_database.py import argparse -from notion_utils.NotionUtils import load_schema, load_tasks, update_database, create_task +import os +from notion_client.api import NotionClient +from notion_client.config import ConfigManager def main(database_id, schema_name, tasks_name): - try: - # Load schema and tasks configuration - schema = load_schema(schema_name) - tasks = load_tasks(tasks_name) + config_manager = ConfigManager(config_path=args.config_path) + schema = config_manager.load_schema(schema_name) + tasks = config_manager.load_tasks(tasks_name) - # Update the database with the provided schema - update_database(database_id, schema) + notion_api_key = os.getenv('NOTION_API_KEY') - # Add tasks to the updated database - schema_properties = schema["properties"] - for task in tasks["tasks"]: - create_task(database_id, task, schema_properties) + notion_client = NotionClient(api_key=notion_api_key) + notion_client.update_database(database_id=database_id, schema=schema) - except FileNotFoundError as e: - print(e) - except ValueError as e: - print(f"Validation Error: {e}") + for task in tasks: + notion_client.create_task(database_id=database_id, task=task) if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Update an existing Notion database using specified schema and tasks templates.") + parser = argparse.ArgumentParser(description="Update an existing Notion database.") parser.add_argument('database_id', type=str, help="The ID of the database to update.") - parser.add_argument('schema', type=str, help="The name of the schema template to use (without .json extension).") - parser.add_argument('tasks', type=str, help="The name of the tasks template to use (without .json extension).") - + parser.add_argument('schema', type=str, help="Schema name without extension.") + parser.add_argument('tasks', type=str, help="Tasks name without extension.") + parser.add_argument('--config-path', type=str, default='plugins', help="Path to the configuration directory.") args = parser.parse_args() main(args.database_id, args.schema, args.tasks) diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..2275daa --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,31 @@ +# File: tests/test_api.py +import pytest +from notion_client.api import NotionClient +from notion_client.models import SchemaConfig, TaskConfig + +import sys +import os + +@pytest.fixture +def notion_client(): + return NotionClient(api_key="fake_api_key") + +def test_create_database(notion_client, requests_mock): + schema = SchemaConfig(title="Test DB", properties={}) + requests_mock.post( + 'https://api.notion.com/v1/databases', + json={"id": "fake_database_id"}, + status_code=200 + ) + database_id = notion_client.create_database(parent_id="fake_page_id", schema=schema) + assert database_id == "fake_database_id" + +def test_create_database_failure(notion_client, requests_mock): + schema = SchemaConfig(title="Test DB", properties={}) + requests_mock.post( + 'https://api.notion.com/v1/databases', + json={"error": "Unauthorized"}, + status_code=401 + ) + with pytest.raises(Exception): + notion_client.create_database(parent_id="fake_page_id", schema=schema) diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..10c3659 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,15 @@ +# File: tests/test_config.py +import os +from notion_client.config import ConfigManager +from notion_client.models import SchemaConfig + +def test_load_schema(tmp_path): + # Create a temporary schema file + schema_content = '{"title": "Test Schema", "properties": {}}' + schema_file = tmp_path / "test_schema.json" + schema_file.write_text(schema_content) + + config_manager = ConfigManager(config_path=str(tmp_path)) + schema = config_manager.load_schema("test_schema") + assert isinstance(schema, SchemaConfig) + assert schema.title == "Test Schema" diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..c8ea4a8 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,24 @@ +# File: tests/test_models.py +from notion_client.models import SchemaConfig, PropertyConfig + +def test_schema_config(): + data = { + "title": "Test Schema", + "properties": { + "Name": PropertyConfig(property_type="title"), + "Description": PropertyConfig(property_type="rich_text") + } + } + schema = SchemaConfig(**data) + assert schema.title == "Test Schema" + assert "Name" in schema.properties + assert schema.properties["Name"].property_type == "title" + +def test_invalid_property_config(): + data = { + "property_type": "invalid_type" + } + try: + prop = PropertyConfig(**data) + except ValueError as e: + assert str(e) == "Invalid property type: invalid_type"