Skip to content

Commit

Permalink
Merge pull request #20 from shivamg9/develop
Browse files Browse the repository at this point in the history
Restrict multiple submission from API, fixed odoo server error and display name bugs, filtered dashboards
  • Loading branch information
shibu-narayanan authored May 30, 2024
2 parents 63c1332 + 6b0779d commit b2e9b2f
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 90 deletions.
2 changes: 1 addition & 1 deletion src/openg2p_portal_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class Initializer(Initializer):
def initialize(self, **kwargs):
super().initialize()
# Initialize all Services, Controllers, any utils here.
PartnerService()
MembershipService()
ProgramService()
FormService()
PartnerService()

DiscoveryController().post_init()
ProgramController().post_init()
Expand Down
23 changes: 11 additions & 12 deletions src/openg2p_portal_api/controllers/auth_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from openg2p_fastapi_auth.controllers.auth_controller import AuthController
from openg2p_fastapi_auth.models.orm.login_provider import LoginProvider
from openg2p_fastapi_common.errors.http_exceptions import UnauthorizedError
from sqlalchemy.exc import IntegrityError

from ..config import Settings
from ..dependencies import JwtBearerAuth
Expand All @@ -16,7 +17,7 @@
PartnerPhoneNoORM,
)
from ..models.orm.reg_id_orm import RegIDORM, RegIDTypeORM
from ..models.profile import Profile
from ..models.profile import GetProfile, UpdateProfile
from ..services.partner_service import PartnerService

_config = Settings.get_config()
Expand All @@ -37,13 +38,12 @@ def __init__(self, **kwargs):
self.router.add_api_route(
"/profile",
self.get_profile,
responses={200: {"model": Profile}},
responses={200: {"model": GetProfile}},
methods=["GET"],
)
self.router.add_api_route(
"/profile",
self.update_profile,
responses={200: {"model": Profile}},
methods=["PUT"],
)

Expand Down Expand Up @@ -125,7 +125,7 @@ async def get_profile(
}
)

return Profile(
return GetProfile(
id=partner_data.id,
ids=partner_ids,
email=partner_data.email,
Expand All @@ -142,7 +142,7 @@ async def get_profile(

async def update_profile(
self,
userdata: Profile,
userdata: UpdateProfile,
auth: Annotated[AuthCredentials, Depends(JwtBearerAuth())],
):
"""
Expand All @@ -158,14 +158,13 @@ async def update_profile(
Confirmation or updated profile data after the update.
"""
if userdata.id is None or userdata.id != auth.partner_id:
raise UnauthorizedError(
message="Unauthorized. Partner Not Found in Registry."
try:
await self.partner_service.update_partner_info(
auth.partner_id, userdata.model_dump(exclude={"id"})
)

return await self.partner_service.update_partner_data(
auth.partner_id, userdata.model_dump(exclude={"id"})
)
except IntegrityError:
return "Could not add to registrant to program!!"
return "Updated the partner info"

async def get_login_providers_db(self) -> List[LoginProvider]:
return [
Expand Down
2 changes: 1 addition & 1 deletion src/openg2p_portal_api/models/orm/partner_orm.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class PartnerORM(BaseORMModelWithId):
birth_place: Mapped[str] = mapped_column()
phone: Mapped[str] = mapped_column()
company_id: Mapped[Optional[int]] = mapped_column()
registration_date: Mapped[date] = mapped_column(Date())
registration_date: Mapped[date] = mapped_column(Date(), default=date.today)
reg_ids: Mapped[Optional[List[RegIDORM]]] = relationship(back_populates="partner")

create_date: Mapped[datetime] = mapped_column(DateTime(), default=datetime.utcnow)
Expand Down
12 changes: 11 additions & 1 deletion src/openg2p_portal_api/models/orm/program_orm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class ProgramORM(BaseORMModelWithId):
description: Mapped[str] = mapped_column(String())
state: Mapped[str] = mapped_column(String())
is_multiple_form_submission: Mapped[str] = mapped_column()
is_reimbursement_program: Mapped[bool] = mapped_column()
active: Mapped[bool] = mapped_column()

membership: Mapped[Optional[List["ProgramMembershipORM"]]] = relationship(
back_populates="program"
Expand All @@ -40,7 +42,15 @@ async def get_all_programs(cls) -> List["ProgramORM"]:
async with async_session_maker() as session:
stmt = (
select(cls)
.filter(cls.state != "inactive", cls.state != "ended")
.filter(
cls.state != "inactive",
cls.state != "ended",
cls.active.is_(True),
or_(
cls.is_reimbursement_program.is_(False),
cls.is_reimbursement_program.is_(None),
),
)
.options(selectinload(cls.membership))
.order_by(cls.id.asc())
)
Expand Down
17 changes: 11 additions & 6 deletions src/openg2p_portal_api/models/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,22 @@ class PhoneNumber(BaseModel):


class Profile(BaseModel):
model_config = ConfigDict()

id: Optional[int] = None
ids: List[RegistrantID]
ids: Optional[List[RegistrantID]] = None
email: Optional[str] = None
gender: Optional[str] = None
# address: Optional[dict] = {}
bank_ids: List[BankDetails]
bank_ids: Optional[List[BankDetails]] = None
addl_name: Optional[str] = None
given_name: Optional[str] = None
family_name: Optional[str] = None
birthdate: Optional[date] = None
phone_numbers: List[PhoneNumber]
phone_numbers: Optional[List[PhoneNumber]] = None
birth_place: Optional[str] = None


class UpdateProfile(Profile):
pass


class GetProfile(Profile):
id: Optional[int] = None
2 changes: 2 additions & 0 deletions src/openg2p_portal_api/models/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class Program(ProgramBase):
is_portal_form_mapped: Optional[bool] = False
is_multiple_form_submission: Optional[bool] = False
last_application_status: Optional[str] = None
is_reimbursement_program: Optional[bool] = None
active: Optional[bool] = None

@validator("is_portal_form_mapped", pre=True, always=True)
def is_program_form_mapped(cls, v, values):
Expand Down
79 changes: 34 additions & 45 deletions src/openg2p_portal_api/services/form_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@

from openg2p_fastapi_common.context import dbengine
from openg2p_fastapi_common.service import BaseService
from sqlalchemy import text
from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import async_sessionmaker

from ..context import partner_fields_cache
from ..models.form import ProgramForm
from ..models.orm.partner_orm import PartnerORM
from ..models.orm.program_orm import ProgramORM
from ..models.orm.program_registrant_info_orm import (
ProgramRegistrantInfoDraftORM,
ProgramRegistrantInfoORM,
)
from .membership_service import MembershipService
from .partner_service import PartnerService


class FormService(BaseService):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.membership_service = MembershipService.get_component()
self.partner_service = PartnerService.get_component()

async def get_program_form(self, program_id: int, registrant_id: int):
response_dict = {}
Expand Down Expand Up @@ -96,9 +96,26 @@ async def submit_application_form(
):
async_session_maker = async_sessionmaker(dbengine.get())
async with async_session_maker() as session:
program_membership_id = await self.membership_service.check_and_create_mem(
program_id, registrant_id
existing_application = await session.execute(
select(ProgramRegistrantInfoORM).filter(
ProgramRegistrantInfoORM.program_id == program_id,
ProgramRegistrantInfoORM.registrant_id == registrant_id,
ProgramRegistrantInfoORM.state.in_(
["active", "inprogress", "applied"]
),
)
)
if existing_application.scalars().first():
return "Error: There is already an active or in-progress application for this program."

try:
program_membership_id = (
await self.membership_service.check_and_create_mem(
program_id, registrant_id
)
)
except ValueError as e:
return str(e)
get_draft_reg_info = (
await ProgramRegistrantInfoDraftORM.get_draft_reg_info_by_id(
program_id, registrant_id
Expand All @@ -107,17 +124,12 @@ async def submit_application_form(
application_id = self._compute_application_id()
create_date = datetime.now()

partner_info = await PartnerORM.get_partner_data(registrant_id)
if partner_info:
updated_partner_info = await self.update_partner_info(
session, partner_info, form_data.program_registrant_info
)

cleaned_program_registrant_info = self.clean_program_registrant_info(
form_data.program_registrant_info, updated_partner_info
)
else:
cleaned_program_registrant_info = form_data.program_registrant_info
updated_partner_info = await self.partner_service.update_partner_info(
registrant_id, form_data.program_registrant_info, session=session
)
cleaned_program_registrant_info = self.clean_program_registrant_info(
form_data.program_registrant_info, updated_partner_info
)

program_registrant_info = ProgramRegistrantInfoORM(
program_id=program_id,
Expand Down Expand Up @@ -151,38 +163,15 @@ def _compute_application_id(self):
random_number = str(random.randint(1, 100000))
return d + m + y + random_number.zfill(5)

async def update_partner_info(self, session, partner_info, program_registrant_info):
# Update partner_info with fields from program_registrant_info
updated_fields = {}
partner_fields = await self.get_partner_fields()
for key, value in program_registrant_info.items():
# if hasattr(partner_info, key) and getattr(partner_info, key) != value:
if key in partner_fields:
updated_fields[key] = value
if updated_fields:
set_clause = ", ".join(
[f"{key} = '{value}'" for key, value in updated_fields.items()]
)
await session.execute(
text(
f"UPDATE {PartnerORM.__tablename__} SET {set_clause} WHERE id='{partner_info.id}'"
)
)
return updated_fields

def clean_program_registrant_info(self, program_registrant_info, updated_fields):
def clean_program_registrant_info(
self, program_registrant_info, updated_partner_fields
):
# Remove updated fields from program_registrant_info
if not updated_partner_fields:
return program_registrant_info
cleaned_info = {
key: value
for key, value in program_registrant_info.items()
if key not in updated_fields
if key not in updated_partner_fields
}
return cleaned_info

async def get_partner_fields(self):
partner_field = partner_fields_cache.get()
if partner_field:
return partner_field
partner_field = await PartnerORM.get_partner_fields()
partner_fields_cache.set(partner_field)
return partner_field
3 changes: 2 additions & 1 deletion src/openg2p_portal_api/services/membership_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class MembershipService(BaseService):
def __init__(self, **kwargs):
super().__init__(**kwargs)

async def check_and_create_mem(self, programid: int, partnerid: int):
async def check_and_create_mem(self, programid: int, partnerid: int) -> int:
async_session_maker = async_sessionmaker(dbengine.get())
async with async_session_maker() as session:
membership = await ProgramMembershipORM.get_membership_by_id(
Expand All @@ -25,6 +25,7 @@ async def check_and_create_mem(self, programid: int, partnerid: int):
try:
session.add(membership)
await session.commit()
await session.refresh(membership)
except IntegrityError:
return "Could not add to registrant to program!!"

Expand Down
Loading

0 comments on commit b2e9b2f

Please sign in to comment.