Skip to content

Commit

Permalink
documentation done for the members
Browse files Browse the repository at this point in the history
  • Loading branch information
rithikreddypalla committed Jan 4, 2025
1 parent 4f8e057 commit f831584
Show file tree
Hide file tree
Showing 7 changed files with 397 additions and 35 deletions.
16 changes: 16 additions & 0 deletions db.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
"""
MongoDB Initialization Module
This module sets up a connection to a MongoDB database and ensures that the required indexes are created.
This module connects to the MongoDB database using environment variables for authentication.
Ensures that a 'unique_members' index is present on the `cid` and 'uid' fields in the Members collection.
It specifically exports the members collection of the database.
Environment Variables:
`MONGO_USERNAME` (str): MongoDB username. Defaults to "username".
`MONGO_PASSWORD` (str): MongoDB password. Defaults to "password".
`MONGO_PORT` (str): MongoDB port. Defaults to "27017".
`MONGO_DATABASE` (str): MongoDB database name. Defaults to "default".
"""

from os import getenv

from pymongo import MongoClient
Expand Down
8 changes: 8 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
"""
Final Setup
This file is used to setup the final schema for the subgraph.
It imports the resolvers from the queries and mutations files and creates a final GraphQL schema.
It sets up the Fast API for the Members Microservice.
"""

from os import getenv

import strawberry
Expand Down
98 changes: 98 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
"""
Data Models for Members Microservice
This file decides what and how a Members's information is stored in its MongoDB document.
One user could be a part of multiple clubs.
his membership in each club is stored in a separate document.
It defines 2 models:
Member : Used for storing members information.
Roles : Used for storing a member's roles within the same club. Used within Member model.
"""

from typing import Any, List

from bson import ObjectId
Expand All @@ -13,8 +25,28 @@

# for handling mongo ObjectIds
class PyObjectId(ObjectId):
"""
MongoDB ObjectId handler
This class contains clasmethods to validate and serialize ObjectIds.
ObjectIds of documents under the Clubs collection are stored under the 'id' field.
"""

@classmethod
def __get_pydantic_core_schema__(cls, source_type: Any, handler):
"""
Defines custom schema for Pydantic validation
This method is used to define the schema for the Pydantic model.
Args:
source_type (Any): The source type.
handler: The handler.
Returns:
dict: The schema for the Pydantic model.
"""

return core_schema.union_schema(
[
# check if it's an instance first before doing any further work
Expand All @@ -26,16 +58,64 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler):

@classmethod
def validate(cls, v):
"""
Validates the given ObjectId
Args:
v (Any): The value to validate.
Returns:
ObjectId: The validated ObjectId.
Raises:
ValueError: If the given value is not a valid ObjectId.
"""

if not ObjectId.is_valid(v):
raise ValueError("Invalid ObjectId")
return ObjectId(v)

@classmethod
def __get_pydantic_json_schema__(cls, field_schema):
"""
Generates JSON schema
This method is used to generate the JSON schema for the Pydantic model.
Args:
field_schema (dict): The field schema.
"""

field_schema.update(type="string")


class Roles(BaseModel):
"""
Model for storing a member's roles
This model defines the structure to store a member's roles.
Attributes:
rid (str): Unique Identifier for a role, a role id.
name (str): Name of the role
start_year (int): Year the role started
end_year (Optional[int]): Year the role ended
approved (bool): Whether the role is approved
approval_time (Optional[str]): Time the role was approved
rejected (bool): Whether the role was rejected
rejection_time (Optional[str]): Time the role was rejected
deleted (bool): Whether the role is deleted
Field Validators:
check_end_year: Validates the end_year field based on the start_year field.checks if the end_year is smaller than the start_year.
check_status: Validates the status of the role based on the approved and rejected fields.
Raises Errors:
ValueError: If the end_year is smaller than the start_year.
ValueError: If the status of the role is not valid.If both approved and rejeted are True.
"""

rid: str | None = Field(None, description="Unique Identifier for a role")
name: str = Field(..., min_length=1, max_length=99)
start_year: int = Field(..., ge=2010, le=2050)
Expand Down Expand Up @@ -71,6 +151,24 @@ def check_status(cls, value, info: ValidationInfo):


class Member(BaseModel):
"""
Model for storing a member's information
This model defines the structure to store a member's information.
Attributes:
id (PyObjectId): Stores the ObjectId of the member's document.
cid (str): Unique Identifier for a club, a club id.
uid (str): Unique Identifier for a user, a user id.
creation_time (str): Time the member was created.
last_edited_time (str): Time the member's information was last edited.
roles (List[Roles]): List of Roles for that specific person.
poc (bool): Whether the member is a POC(Point of Contact) for the club.
Field Validators:
transform_uid: Transforms the uid field text to lowercase.
"""

id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
cid: str = Field(..., description="Club ID")
uid: str = Field(..., description="User ID")
Expand Down
126 changes: 125 additions & 1 deletion mutations.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
"""
Mutation resolvers
It contains resolvers to create, edit and delete members and to approve/reject their roles.
Resolvers:
createMember: Creates a new member.
editMember: Edits an existing member.
deleteMember: Deletes an existing member.
approveMember: Approves a role of a member.
rejectMember: Rejects a role of a member.
UpdateMembersCid: Updates all members of old_cid to new_cid.
"""

from datetime import datetime
from os import getenv

Expand All @@ -20,7 +34,27 @@
def createMember(memberInput: FullMemberInput, info: Info) -> MemberType:
"""
Mutation to create a new member by that specific 'club' or cc
This method creates a new member in the database.
Inputs:
memberInput (FullMemberInput): Contains the details of the member.
info (Info): Contains the logged in user's details.
Returns:
MemberType: Contains the details of the member.
Accessibility:
CC, original club accounts has full access.
Raises Exception:
Not Authenticated/Not Authenticated to access this API: If the user is not authenticated.
A record with same uid and cid already exists: If a member with the same uid and cid already exists in the database.
Invalid User id: If there does not exist a user with the given uid.
Roles cannot be empty: If the roles list is empty.
Start year cannot be greater than end year: If the start year is greater than the end year.
"""

user = info.context.user
if user is None:
raise Exception("Not Authenticated")
Expand Down Expand Up @@ -94,7 +128,26 @@ def createMember(memberInput: FullMemberInput, info: Info) -> MemberType:
def editMember(memberInput: FullMemberInput, info: Info) -> MemberType:
"""
Mutation to edit an already existing member+roles of that specific 'club'
This method edits an existing member in the database.
It can only be done by the club or cc account.
Inputs:
memberInput (FullMemberInput): Contains the details of the member.
info (Info): Contains the logged in user's details.
Returns:
MemberType: Contains the details of the member.
Accessibility:
CC, original club accounts has full access.
Raises Exception:
Not Authenticated/Not Authenticated to access this API: If the user is not authenticated.
Start year cannot be greater than end year: If the start year is greater than the end year.
No such record : If there is no record with the given uid and cid.
"""

user = info.context.user
if user is None:
raise Exception("Not Authenticated")
Expand Down Expand Up @@ -193,7 +246,25 @@ def editMember(memberInput: FullMemberInput, info: Info) -> MemberType:
def deleteMember(memberInput: SimpleMemberInput, info: Info) -> MemberType:
"""
Mutation to delete an already existing member (role) of that specific 'club'
This method deletes an existing member in the database.
It can only be done by the club or cc account.
Inputs:
memberInput (SimpleMemberInput): Contains the details of the member.
info (Info): Contains the logged in user's details.
Returns:
MemberType: Contains the details of the member.
Accessibility:
CC, original club accounts has full access.
Raises Exception:
Not Authenticated/Not Authenticated to access this API: If the user is not authenticated.
No such record : If there is no record with the given uid and cid.
""" # noqa: E501

user = info.context.user
if user is None:
raise Exception("Not Authenticated")
Expand Down Expand Up @@ -256,7 +327,24 @@ def deleteMember(memberInput: SimpleMemberInput, info: Info) -> MemberType:
def approveMember(memberInput: SimpleMemberInput, info: Info) -> MemberType:
"""
Mutation to approve a member role by 'cc'
This method approves a member role in the database.
Inputs:
memberInput (SimpleMemberInput): Contains the details of the member.cid, uid and rid.
info (Info): Contains the logged in user's details.
Returns:
MemberType: Contains the details of the member.
Accessibility:
only CC has full access.
Raises Exception:
Not Authenticated/Not Authenticated to access this API: If the user is not authenticated.
No such record : If there is no record with the given uid and cid
"""

user = info.context.user
if user is None:
raise Exception("Not Authenticated")
Expand Down Expand Up @@ -284,6 +372,7 @@ def approveMember(memberInput: SimpleMemberInput, info: Info) -> MemberType:
current_time = datetime.now(ist)
time_str = current_time.strftime("%d-%m-%Y %I:%M %p IST")

# approves the role along with entering approval time
roles = []
for i in existing_data["roles"]:
if not member_input["rid"] or i["rid"] == member_input["rid"]:
Expand Down Expand Up @@ -313,7 +402,24 @@ def approveMember(memberInput: SimpleMemberInput, info: Info) -> MemberType:
def rejectMember(memberInput: SimpleMemberInput, info: Info) -> MemberType:
"""
Mutation to reject a member role by 'cc'
This method rejects a member role in the database.
Inputs:
memberInput (SimpleMemberInput): Contains the details of the member.cid, uid and rid.
info (Info): Contains the logged in user's details.
Returns:
MemberType: Contains the details of the member.
Accessibility:
only CC has full access.
Raises Exception:
Not Authenticated/Not Authenticated to access this API: If the user is not authenticated.
No such record : If there is no record with the given uid and cid
"""

user = info.context.user
if user is None:
raise Exception("Not Authenticated")
Expand Down Expand Up @@ -405,8 +511,26 @@ def updateMembersCid(
inter_communication_secret: str | None = None,
) -> int:
"""
update all memberd of old_cid to new_cid
update all members of old_cid to new_cid
It updates all members with old_cid to new_cid
Input:
old_cid: the old cid
new_cid: the new cid
inter_communication_secret (str | None): The inter communication secret.
Returns:
int: The number of updated members.
Accessibility:
only CC has full access.
Raises Exception:
Not Authenticated: If the user is not authenticated.
Authentication Error! Invalid secret!: If the inter communication secret is invalid.
"""

user = info.context.user

if user is None or user["role"] not in ["cc"]:
Expand Down
19 changes: 19 additions & 0 deletions otypes.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
"""
Types and Inputs
It contains both Inputs and Types for taking inputs and returning outputs.
It also contains the Context class which is used to pass the user details to the resolvers.
Types:
Info : used to pass the user details to the resolvers.
PyObjectId : used to return ObjectId of a document.
RolesType : used to return all the details of a role.
MemberType : used to return all the details of a member.
Inputs:
RolesInput : used to input name, start year and end year of the role.
FullMemberInput : used to input cid, uid, roles and poc(Optional) fields of the member.
SimpleMemberInput : used to input cid, uid and rid(Optional) of the member.
SimpleClubInput : used to input cid of the club.
"""

import json
from functools import cached_property
from typing import Dict, Optional, Union
Expand Down
Loading

0 comments on commit f831584

Please sign in to comment.