Skip to content

Commit 88f332c

Browse files
committed
Added documentation.
1 parent ee3bad1 commit 88f332c

File tree

11 files changed

+537
-84
lines changed

11 files changed

+537
-84
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Ignore Python bytecode cache directories recursively
2+
**/__pycache__/

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# TaskOps API
22

33
## Overview
4-
TaskOps (Task Operations) API is a RESTful backend API built with Flask and MongoDB, designed to streamline task management operations. It provides endpoints for user registration and authentication, as well as creating, retrieving, updating, and deleting tasks. The API ensures secure authentication and authorization using JWT tokens, serving various web and mobile applications requiring efficient and easy task management capabilities.
4+
TaskOps (Task Operations) API is a RESTful backend API built with Flask and MongoDB, using Python programming language. It is designed to streamline task management operations for various web and mobile applications. The API provides endpoints for user registration and authentication, as well as creating, retrieving, updating, and deleting tasks. The API ensures secure authentication and authorization using JWT tokens, serving as an efficient and easy task management solution.
55

66
## Description
7-
TaskOps API offers a comprehensive solution for efficient and easy task management, focusing on user account management and secure operations. Leveraging Flask for its lightweight and flexible framework and MongoDB for its scalable NoSQL database capabilities, the API ensures seamless user registration and authentication, as well as CRUD (Create, Read, Update, Delete) operations for tasks. Authentication and authorization are handled securely using JWT tokens, ensuring that only authorized users can access and manipulate task data.
7+
TaskOps API offers a comprehensive solution for efficient and easy task management, focusing on user account management and secure operations. Utilizing Flask for its lightweight and flexible framework and MongoDB for its scalable NoSQL database capabilities, the API, developed with Python, ensures seamless user registration and authentication, as well as CRUD (Create, Read, Update, Delete) operations for tasks. Authentication and authorization are handled securely using JWT tokens, ensuring that only authorized users can access and manipulate task data.
88

99
The API adheres to RESTful principles, employing HTTP methods for predictable and intuitive endpoint design. It supports functionalities such as:
1010
- User registration and authentication: Enables users to create accounts and securely authenticate using their credentials to access the task management features.

controllers/task_controller.py

Lines changed: 114 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,179 @@
1+
# Import the necessary modules.
2+
13
from models.task_model import Task
24
from database.__init__ import conn
35
from bson.objectid import ObjectId
46
import app_config as config
57

6-
# TODO: Manpreet Kaur
78
def create_task(task_info):
9+
"""
10+
Create a new task in the database.
11+
12+
Args:
13+
task_info (dict): A dictionary containing the task information.
14+
Required keys:
15+
- 'created_by_uid': The ID of the user who created the task.
16+
- 'assigned_to_uid': The ID of the user to whom the task is assigned.
17+
- 'description': The description of the task.
18+
19+
Returns:
20+
pymongo.results.InsertOneResult: The result of the insert operation.
21+
22+
Raises:
23+
ValueError: If the user information is invalid.
24+
"""
825
try:
9-
# Access the database to get user information
10-
created_by_user = conn.database[config.CONST_USER_COLLECTION].find_one({'_id': ObjectId(task_info['created_by_uid'])})
11-
assigned_to_user = conn.database[config.CONST_USER_COLLECTION].find_one({'_id': ObjectId(task_info['assigned_to_uid'])})
12-
13-
# print("created_by_user", created_by_user)
14-
# print("assigned_to_user", assigned_to_user)
26+
# Find the users by their IDs
27+
created_by_user = conn.database[config.CONST_USER_COLLECTION].find_one(
28+
{'_id': ObjectId(task_info['created_by_uid'])})
29+
assigned_to_user = conn.database[config.CONST_USER_COLLECTION].find_one(
30+
{'_id': ObjectId(task_info['assigned_to_uid'])})
1531

32+
# Check if the user information is valid
1633
if not created_by_user or not assigned_to_user:
1734
raise ValueError('Invalid user information')
1835

1936
# Create a new task object
2037
new_task = Task()
21-
new_task.createdByUid = task_info['created_by_uid']
22-
new_task.createdByName = created_by_user['name']
23-
new_task.assignedToUid = task_info['assigned_to_uid']
24-
new_task.assignedToName = assigned_to_user['name']
25-
new_task.description = task_info['description']
38+
new_task.createdByUid = task_info['created_by_uid'] # Set the created by user ID
39+
new_task.createdByName = created_by_user['name'] # Set the created by user name
40+
new_task.assignedToUid = task_info['assigned_to_uid'] # Set the assigned to user ID
41+
new_task.assignedToName = assigned_to_user['name'] # Set the assigned to user name
42+
new_task.description = task_info['description'] # Set the description of the task
2643

2744
# Save the task to the database
2845
created_task = conn.database[config.CONST_TASK_COLLECTION].insert_one(new_task.__dict__)
2946

3047
return created_task
3148

32-
except ValueError as err:
49+
except ValueError as err: # If there is an invalid user information, raise a ValueError
3350
raise ValueError(str(err))
34-
except Exception as err:
51+
except Exception as err: # If there is any other exception, raise a ValueError
3552
raise ValueError(str(err))
3653

37-
# TODO: Dil Raval
3854
def get_task_created_by_user(user_id):
55+
"""
56+
Get tasks created by the user.
57+
58+
This function retrieves tasks created by the user with the given user ID.
59+
60+
Args:
61+
user_id (str): The ID of the user.
62+
63+
Returns:
64+
list: A list of tasks created by the user, with each task's '_id' field converted to a string.
65+
66+
Raises:
67+
ValueError: If there is an error in fetching the tasks.
68+
"""
3969
try:
40-
70+
# Connect to the tasks collection of the database.
4171
task_collection = conn.database.get_collection(config.CONST_TASK_COLLECTION)
4272

73+
# Retrieve tasks created by the user.
74+
# Find tasks where the 'createdByUid' field matches the given user ID.
4375
task_list = list(task_collection.find({"createdByUid": user_id}))
44-
# print(task_list)
4576

77+
# Convert the '_id' field of each task to a string.
78+
# This is done to ensure that the '_id' field is serialized as a string when returned.
4679
for task in task_list:
4780
task["_id"] = str(task["_id"])
4881

49-
return task_list
82+
return task_list # Return the list of tasks created by the user
5083

5184
except Exception as error:
85+
# Raise a ValueError with an appropriate error message if there is an error in fetching the tasks.
5286
raise ValueError("Error on trying to fetch tasks created by user.", error)
5387

54-
# TODO: Aryan Handa
5588
def get_tasks_assigned_to_user(assignedToUid):
89+
"""
90+
Get tasks assigned to the user.
91+
92+
This function retrieves tasks assigned to the user with the given assignedToUid.
93+
94+
Args:
95+
assignedToUid (str): The ID of the user.
96+
97+
Returns:
98+
list: A list of tasks assigned to the user, with each task's '_id' field converted to a string.
99+
100+
Raises:
101+
ValueError: If there is an error in fetching the tasks.
102+
"""
56103
try:
57-
58104
# Retrieve tasks assigned to the user
59-
tasks = conn.database[config.CONST_TASK_COLLECTION].find({"assignedToUid": assignedToUid})
105+
tasks = conn.database[config.CONST_TASK_COLLECTION].find(
106+
{"assignedToUid": assignedToUid}) # Find tasks assigned to the user
60107

108+
# Convert the tasks to a list
61109
user_tasks = list(tasks)
62110

111+
# Convert the '_id' field of each task to a string
63112
for task in user_tasks:
64-
task["_id"] = str(task["_id"])
113+
task["_id"] = str(task["_id"]) # Convert task ID to string
65114

66-
return user_tasks
115+
return user_tasks # Return the list of tasks assigned to the user
67116

68117
except Exception as err:
118+
# Raise a ValueError with an appropriate error message if there is an error in fetching the tasks.
69119
raise ValueError("Error fetching tasks assigned to user: ", err)
70120

71-
# TODO: Payal Rangra
72-
def update_task(user_info, task_id, done ):
73-
121+
def update_task(user_info, task_id, done):
122+
"""
123+
Update the status of a task in the database.
124+
125+
Args:
126+
user_info (dict): A dictionary containing user-related information retrieved from the token, including the user's ID.
127+
task_id (str): The ID of the task to be updated.
128+
done (bool): The new status of the task.
129+
130+
Returns:
131+
pymongo.results.UpdateResult: The result of the update operation.
132+
133+
Raises:
134+
ValueError: If the task is not found or the user is not authorized to update the task.
135+
"""
74136
try:
137+
# Connect to the tasks collection of the database.
75138
task_collection = conn.database[config.CONST_TASK_COLLECTION]
76-
77-
current_task = task_collection.find_one({"_id":ObjectId(task_id)})
78-
79-
if(current_task == None):
139+
140+
# Find the task with _id = task_id.
141+
current_task = task_collection.find_one({"_id": ObjectId(task_id)})
142+
143+
# Check if the task exists.
144+
if current_task is None:
80145
raise ValueError('Task not found')
81-
146+
147+
# Check if the user is authorized to update the task.
82148
if str(current_task['assignedToUid']) != str(user_info["id"]):
83149
raise ValueError('Users can only change status when task is assigned to them.')
84-
85-
updated_result = task_collection.update_one({"_id":ObjectId(task_id)}, {"$set": {"done": done}})
86-
150+
151+
# Update the 'done' field of the task with _id = task_id to the new status.
152+
# The $set operator is used to update the value of the 'done' field.
153+
updated_result = task_collection.update_one(
154+
{"_id": ObjectId(task_id)}, # Query to find the task
155+
{"$set": {"done": done}} # Update operation to set the 'done' field
156+
)
157+
158+
# Return the result of the update operation.
87159
return updated_result
88-
160+
89161
except Exception as err:
162+
# Raise a ValueError with an appropriate error message if there is an error in updating the task.
90163
raise ValueError('Error on updating task: ' f'{err}')
91164

92-
# TODO: Viraj Patel
93165
def delete_task(user_information, task_id):
94166
"""Delete a task from the database.
95167
96168
Args:
97169
user_information (dict): A dictionary containing user-related information retrieved from the token, including the user's ID.
98170
task_id (str): The ID of the task to be deleted.
171+
172+
Returns:
173+
pymongo.results.DeleteResult: The result of the delete operation.
174+
175+
Raises:
176+
ValueError: If the task is not found or the user is not authorized to delete the task.
99177
"""
100178
try:
101179

controllers/user_controller.py

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,75 +6,149 @@
66
import jwt # pip install pyjwt
77

88
def generate_hash_password(password):
9+
"""
10+
Generate a hashed password using bcrypt.
11+
12+
Args:
13+
password (str): The password to be hashed.
14+
15+
Returns:
16+
bytes: The hashed password.
17+
"""
18+
# Generate a salt for hashing the password
919
salt = bcrypt.gensalt()
20+
21+
# Hash the password using the generated salt
1022
hashed_password = bcrypt.hashpw(password.encode("utf-8"), salt)
23+
24+
# Return the hashed password
1125
return hashed_password
1226

1327
def create_user(user_information):
28+
"""
29+
Create a new user in the database.
30+
31+
Args:
32+
user_information (dict): A dictionary containing user information.
33+
Required keys:
34+
- 'name': The name of the user.
35+
- 'email': The email of the user.
36+
- 'password': The password of the user.
37+
38+
Returns:
39+
pymongo.results.InsertOneResult: The result of the insert operation.
40+
41+
Raises:
42+
ValueError: If there is an error creating the user.
43+
"""
1444
try:
45+
# Create a new User object
1546
new_user = User()
47+
48+
# Set the user's name, email, and hashed password
1649
new_user.name = user_information["name"]
1750
new_user.email = user_information["email"]
1851
new_user.password = generate_hash_password(user_information["password"])
1952

53+
# Connect to the user collection of the database
2054
db_collection = conn.database[config.CONST_USER_COLLECTION]
2155

56+
# Check if a user with the same email already exists
2257
if db_collection.find_one({'email': new_user.email}):
2358
return 'Duplicated User'
2459

60+
# Insert the new user into the database
2561
created_user = db_collection.insert_one(new_user.__dict__)
2662

63+
# Return the result of the insert operation
2764
return created_user
65+
2866
except Exception as err:
67+
# If there is an error creating the user, raise a ValueError
2968
raise ValueError("Error on creating user.", err)
3069

3170
def login_user(user_information):
71+
"""
72+
Handles the user login process by checking the provided credentials against the database.
73+
74+
Args:
75+
user_information (dict): A dictionary containing user information.
76+
Required keys:
77+
- 'email': The email of the user.
78+
- 'password': The password of the user.
79+
80+
Returns:
81+
dict: A dictionary containing the JWT token, expiration time, and logged user information.
82+
"""
3283
try:
84+
# Extract user information from the request
3385
email = user_information["email"]
3486
password = user_information["password"].encode('utf-8')
3587

88+
# Connect to the user collection of the database
3689
db_collection = conn.database[config.CONST_USER_COLLECTION]
3790

91+
# Find the user with the provided email
3892
current_user = db_collection.find_one({'email': email})
3993

94+
# Check if the user exists
4095
if not current_user:
4196
return "Invalid Email"
4297

98+
# Check if the provided password matches the hashed password in the database
4399
if not bcrypt.checkpw(password, current_user["password"]):
44100
return "Invalid Password"
45101

102+
# Create a dictionary with the logged user information
46103
logged_user = {}
47104
logged_user['id'] = str(current_user['_id'])
48105
logged_user['email'] = current_user['email']
49106
logged_user['name'] = current_user['name']
50107

108+
# Calculate the expiration time for the JWT token
51109
expiration = datetime.utcnow() + timedelta(seconds = config.JWT_EXPIRATION)
52110

111+
# Create the JWT token data
53112
jwt_data = {'email': logged_user['email'], 'id': logged_user['id'], 'exp': expiration}
54113

55-
jwt_to_return = jwt.encode(payload = jwt_data, key = config.TOKEN_SECRET)
114+
# Encode the JWT token with the secret key
115+
jwt_to_return = jwt.encode(payload=jwt_data, key=config.TOKEN_SECRET)
56116

57-
#print(jwt_to_return)
58-
117+
# Return the JWT token, expiration time, and logged user information
59118
return {'token': jwt_to_return, 'expiration': config.JWT_EXPIRATION, 'logged_user': logged_user}
60119

61120
except Exception as err:
121+
# If there is an error logging in the user, raise a ValueError with the error message
62122
raise ValueError("Error on trying to login.", err)
63123

64124

65125
def fetch_all_users():
126+
"""
127+
Fetches all users from the database and returns them as a list of dictionaries.
128+
129+
Returns:
130+
List[Dict[str, str]]: A list of dictionaries representing the users. Each dictionary contains the user's ID, email, and name.
131+
132+
Raises:
133+
ValueError: If there is an error fetching the users.
134+
"""
66135
try:
136+
# Connect to the user collection of the database
67137
db_collection = conn.database[config.CONST_USER_COLLECTION]
68138
users = []
69139

140+
# Iterate over each user in the database, create a dictionary with their ID, email, and name,
141+
# and add it to the list of users
70142
for user in db_collection.find():
71143
current_user = {}
72144
current_user["id"] = str(user["_id"])
73145
current_user["email"] = user["email"]
74146
current_user["name"] = user["name"]
75147
users.append(current_user)
76148

149+
# Return the fetch users.
77150
return users
78151

79152
except Exception as err:
80-
raise ValueError("Error on trying to fetch users.", err)
153+
# If there is an error fetching the users, raise a ValueError with the error message
154+
raise ValueError("Error on trying to fetch users.", err)

0 commit comments

Comments
 (0)