Coverage for backend/app/routers/data_tables.py: 87%
31 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-22 15:38 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-22 15:38 +0000
1"""Module for generating CRUD routers for the JAM data tables"""
3import base64
5from fastapi import Depends, status, HTTPException, Response
6from sqlalchemy.orm import Session
8from app import models, database, oauth2, schemas
9from app.routers import generate_data_table_crud_router
11# Settings router
12settings_router = generate_data_table_crud_router(
13 table_model=models.Setting,
14 create_schema=schemas.SettingCreate,
15 update_schema=schemas.SettingUpdate,
16 out_schema=schemas.SettingOut,
17 endpoint="settings",
18 not_found_msg="Setting not found",
19 admin_only=True,
20)
22# Keyword router
23keyword_router = generate_data_table_crud_router(
24 table_model=models.Keyword,
25 create_schema=schemas.KeywordCreate,
26 update_schema=schemas.KeywordUpdate,
27 out_schema=schemas.KeywordOut,
28 endpoint="keywords",
29 not_found_msg="Keyword not found",
30)
32# Aggregator router
33aggregator_router = generate_data_table_crud_router(
34 table_model=models.Aggregator,
35 create_schema=schemas.AggregatorCreate,
36 update_schema=schemas.AggregatorUpdate,
37 out_schema=schemas.AggregatorOut,
38 endpoint="aggregators",
39 not_found_msg="Aggregator not found",
40)
42# Company router
43company_router = generate_data_table_crud_router(
44 table_model=models.Company,
45 create_schema=schemas.CompanyCreate,
46 update_schema=schemas.CompanyUpdate,
47 out_schema=schemas.CompanyOut,
48 endpoint="companies",
49 not_found_msg="Company not found",
50)
52# Location router
53location_router = generate_data_table_crud_router(
54 table_model=models.Location,
55 create_schema=schemas.LocationCreate,
56 update_schema=schemas.LocationUpdate,
57 out_schema=schemas.LocationOut,
58 endpoint="locations",
59 not_found_msg="Location not found",
60)
62# Person router
63person_router = generate_data_table_crud_router(
64 table_model=models.Person,
65 create_schema=schemas.PersonCreate,
66 update_schema=schemas.PersonUpdate,
67 out_schema=schemas.PersonOut,
68 endpoint="persons",
69 not_found_msg="Person not found",
70)
72# Job router
73job_router = generate_data_table_crud_router(
74 table_model=models.Job,
75 create_schema=schemas.JobCreate,
76 update_schema=schemas.JobUpdate,
77 out_schema=schemas.JobOut,
78 endpoint="jobs",
79 not_found_msg="Job not found",
80 many_to_many_fields={
81 "keywords": {"table": models.job_keyword_mapping, "local_key": "job_id", "remote_key": "keyword_id"},
82 "contacts": {"table": models.job_contact_mapping, "local_key": "job_id", "remote_key": "person_id"},
83 },
84)
86# Interview router
87interview_router = generate_data_table_crud_router(
88 table_model=models.Interview,
89 create_schema=schemas.InterviewCreate,
90 update_schema=schemas.InterviewUpdate,
91 out_schema=schemas.InterviewOut,
92 endpoint="interviews",
93 not_found_msg="Interview not found",
94 many_to_many_fields={
95 "interviewers": {
96 "table": models.interview_interviewer_mapping,
97 "local_key": "interview_id",
98 "remote_key": "person_id",
99 },
100 },
101)
103# Job Application Update router
104job_application_update_router = generate_data_table_crud_router(
105 table_model=models.JobApplicationUpdate,
106 create_schema=schemas.JobApplicationUpdateCreate,
107 update_schema=schemas.JobApplicationUpdateUpdate,
108 out_schema=schemas.JobApplicationUpdateOut,
109 endpoint="jobapplicationupdates",
110 not_found_msg="Job Application Update not found",
111)
113# File router
114file_router = generate_data_table_crud_router(
115 table_model=models.File,
116 create_schema=schemas.FileCreate,
117 update_schema=schemas.FileUpdate,
118 out_schema=schemas.FileOut,
119 endpoint="files",
120 not_found_msg="File not found",
121)
124@file_router.get("/{file_id}/download")
125def download_file(
126 file_id: int,
127 db: Session = Depends(database.get_db),
128 current_user: models.User = Depends(oauth2.get_current_user),
129):
130 """Download a file by ID.
131 :param file_id: The file ID.
132 :param db: The database session.
133 :param current_user: The current user."""
135 # Get file record from the database
136 # noinspection PyTypeChecker
137 file_record = (
138 db.query(models.File).filter(models.File.id == file_id, models.File.owner_id == current_user.id).first()
139 )
141 if not file_record:
142 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found")
144 if not file_record.content:
145 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File content not found")
147 try:
148 # Content is already a base64 string - just decode it
149 if file_record.content.startswith("data:"):
150 encoded_data = file_record.content.split(",", 1)[1]
151 file_content = base64.b64decode(encoded_data)
152 else:
153 # Pure base64 string
154 file_content = base64.b64decode(file_record.content)
156 except Exception as e:
157 raise HTTPException(
158 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error decoding file content: {str(e)}"
159 )
161 content_type = file_record.type if file_record.type else "application/octet-stream"
163 return Response(
164 content=file_content,
165 media_type=content_type,
166 headers={
167 "Content-Disposition": f'attachment; filename="{file_record.filename}"',
168 "Content-Length": str(len(file_content)),
169 },
170 )