Skip to content

Commit

Permalink
Feature: Implement API route for "Project" section (#40)
Browse files Browse the repository at this point in the history
* add Project dataclass to models

* implement API route for 'Project' section

* test 'Project' API route

* fix linting error: app.py:184:0: R0911: Too many return statements
  • Loading branch information
bedre7 authored Oct 11, 2024
1 parent 262c29a commit f0efad4
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 2 deletions.
124 changes: 122 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

from flask import Flask, jsonify, request
from models import Experience, Education, Skill, User
from models import Experience, Education, Project, Skill, User
from utils import get_suggestion, check_phone_number, correct_spelling


Expand Down Expand Up @@ -39,7 +39,19 @@
"example-logo.png",
)
],
"skill": [Skill("Python", "1-2 Years", "example-logo.png")],
"skill": [
Skill("Python",
"1-2 Years",
"example-logo.png")
],
"project": [
Project(
title="Sample Project",
description="A sample project",
technologies=["Python", "Flask"],
link="https://github.com/username/sample-project"
)
]
}


Expand Down Expand Up @@ -168,6 +180,114 @@ def skill():
return jsonify({})


@app.route('/resume/project', methods=['GET', 'POST', 'PUT', 'DELETE'])
def project():
'''
Handles Project requests
'''
def validate_id(project_id):
'''
Validates the id
'''
if project_id is None:
raise ValueError("Missing id")

if not project_id.isdigit():
raise ValueError("Invalid id")

# check if the id is within the range of the project list
int_id = int(project_id)
if int_id < 0 or int_id >= len(data['project']):
raise ValueError("Project not found")

return int_id

def get_project(project_id):
'''
Get project by id
'''
if project_id is not None:
try:
project_id = validate_id(project_id)
return jsonify(data['project'][project_id]), 200
except ValueError as error:
return jsonify({"error": str(error)}), 400

return jsonify([
{**project.__dict__, "id": str(index)}
for index, project in enumerate(data['project'])
]), 200

def add_project(body):
'''
Add project
'''
mandatory_fields = ['title', 'description', 'technologies', 'link']
missing_fields = [field for field in mandatory_fields if field not in body]

if missing_fields:
return jsonify({"error": f"Missing fields: {', '.join(missing_fields)}"}), 400

new_project = Project(
body['title'],
body['description'],
body['technologies'],
body['link']
)
data['project'].append(new_project)

return jsonify({**new_project.__dict__, "id": str(len(data['project']) - 1)}), 201

def edit_project(project_id, body):
'''
Edit project
'''
try:
project_id = validate_id(project_id)
except ValueError as error:
return jsonify({"error": str(error)}), 400

for key, value in body.items():
if hasattr(data['project'][project_id], key):
setattr(data['project'][project_id], key, value)
else:
return jsonify({"error": f"invalid field: {key}"}), 400

return jsonify({**data['project'][project_id].__dict__, "id": str(project_id)}), 200

def delete_project(project_id):
'''
Delete project
'''
try:
project_id = validate_id(project_id)
except ValueError as error:
return jsonify({"error": str(error)}), 400

del data['project'][project_id]
return jsonify({}), 204

if request.method == 'GET':
project_id = request.args.get('id', None)
return get_project(project_id)

if request.method == 'POST':
body = request.get_json()
return add_project(body)

if request.method == 'PUT':
project_id = request.args.get('id', None)
body = request.get_json()

return edit_project(project_id, body)

if request.method == 'DELETE':
project_id = request.args.get('id', None)

return delete_project(project_id)

return jsonify({"error": "Unsupported request method"}), 405

@app.route("/resume/spellcheck", methods=["POST"])
def spellcheck():
"""
Expand Down
11 changes: 11 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
'''

from dataclasses import dataclass
from typing import List

@dataclass
class User:
Expand Down Expand Up @@ -49,3 +50,13 @@ class Skill:
name: str
proficiency: str
logo: str

@dataclass
class Project:
'''
Project Class
'''
title: str
description: str
technologies: List[str]
link: str
82 changes: 82 additions & 0 deletions test_pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,88 @@ def test_skill():
assert response.json["skills"][item_id] == example_skill


def test_get_project():
'''
Test the get_project function
Check that it returns a list of projects
'''
response = app.test_client().get('/resume/project')
assert response.status_code == 200
assert isinstance(response.json, list)

def test_add_project():
'''
Test the add_project function
Check that it returns the new project
Check that it returns an error when missing fields
'''
new_project = {
'title': 'Sample Project',
'description': 'A sample project',
'technologies': ['Python', 'Flask'],
'link': 'https://github.com/username/sample-project'
}
response = app.test_client().post('/resume/project', json=new_project)
assert response.status_code == 201
assert response.json == {**new_project, 'id': '1'}

new_project.pop('title')
response = app.test_client().post('/resume/project', json=new_project)
assert response.status_code == 400
assert response.json == {'error': 'Missing fields: title'}

def test_edit_project():
'''
Test the edit_project function
Check that it returns the updated project
Check that it returns an error when the project id is invalid
'''
new_project = {
'title': 'Sample Project',
'description': 'A sample project',
'technologies': ['Python', 'Flask'],
'link': 'https://github.com/username/sample-project'
}
new_project_id = app.test_client().post('/resume/project', json=new_project).json['id']
new_project['title'] = 'New Project'
new_project['description'] = 'A new project'
new_project['technologies'] = ['Python', 'Flask', 'Docker']

response = app.test_client().\
put('/resume/project', json=new_project, query_string={'id': new_project_id})

assert response.status_code == 200
assert response.json == {**new_project, 'id': new_project_id}

response = app.test_client().\
put('/resume/project', json=new_project, query_string={'id': 'invalid-id'})
assert response.status_code == 400
assert response.json == {'error': 'Invalid id'}

def test_delete_project():
'''
Test the delete_project function
Check that it returns a 204 status code
Check that it returns an error when the project id is invalid
'''
new_project = {
'title': 'Sample Project',
'description': 'A sample project',
'technologies': ['Python', 'Flask'],
'link': 'https://github.com/username/sample-project'
}
new_project_id = app.test_client().post('/resume/project', json=new_project).json['id']
response = app.test_client().delete('/resume/project', query_string={'id': new_project_id})
assert response.status_code == 204

response = app.test_client().delete('/resume/project', query_string={'id': 'invalid-id'})
assert response.status_code == 400
assert response.json == {'error': 'Invalid id'}

@pytest.mark.parametrize('text, expected', [
('thiss is an exmple of spell chcking.',
'this is an example of spell checking.'),
Expand Down

0 comments on commit f0efad4

Please sign in to comment.