Coverage for backend/tests/utils/table_data.py: 100%

49 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-09-22 15:38 +0000

1"""Centralised test data for both conftest.py and seed_database.py""" 

2 

3from datetime import datetime, timedelta, timezone 

4from itertools import groupby 

5 

6from tests.utils.files import load_all_resource_files 

7 

8RESOURCE_FILES = load_all_resource_files() 

9 

10 

11current_date = datetime.now(timezone.utc) 

12DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z" 

13DATE_FORMAT = "%Y-%m-%d" 

14 

15 

16USER_DATA = [ 

17 { 

18 "email": "test_user@test.com", 

19 "password": "test_password", 

20 "is_admin": True, 

21 }, 

22 { 

23 "email": "emmanuelpean@gmail.com", 

24 "password": "password2", 

25 }, 

26 { 

27 "email": "jessicaaggood@live.co.uk", 

28 "password": "password3", 

29 }, 

30 { 

31 "email": "sarah.wilson@example.com", 

32 "password": "password4", 

33 }, 

34 { 

35 "email": "admin@example.com", 

36 "password": "password5", 

37 }, 

38 { 

39 "email": "developer@techstartup.com", 

40 "password": "password6", 

41 }, 

42] 

43 

44 

45SETTINGS_DATA = [ 

46 { 

47 "name": "allowlist", 

48 "value": ",".join([data["email"] for data in USER_DATA] + ["newuser@user.com"]), 

49 "description": "Emails allowed to sign up", 

50 } 

51] 

52 

53 

54COMPANY_DATA = [ 

55 { 

56 "name": "Tech Corp", 

57 "description": "A leading technology company specializing in web applications", 

58 "url": "https://techcorp.com", 

59 "owner_id": 1, 

60 }, 

61 { 

62 "name": "StartupXYZ", 

63 "description": "An innovative startup focused on AI-driven solutions", 

64 "url": "https://startupxyz.com", 

65 "owner_id": 1, 

66 }, 

67 { 

68 "name": "Oxford PV", 

69 "description": "Oxford-based company specializing in photovoltaic technology", 

70 "url": "https://oxfordpv.com", 

71 "owner_id": 1, 

72 }, 

73 { 

74 "name": "WebSolutions Ltd", 

75 "description": "Full-service web development and digital marketing agency", 

76 "url": "https://websolutions.com", 

77 "owner_id": 1, 

78 }, 

79 { 

80 "name": "DataTech Industries", 

81 "description": "Big data analytics and business intelligence solutions", 

82 "url": "https://datatech.com", 

83 "owner_id": 1, 

84 }, 

85 { 

86 "name": "CloudFirst Inc", 

87 "description": None, 

88 "url": "https://cloudfirst.io", 

89 "owner_id": 1, 

90 }, 

91 { 

92 "name": "Minimal Corp", 

93 "owner_id": 1, # Only required fields 

94 }, 

95 { 

96 "name": "No URL Company", 

97 "description": "Company without website", 

98 "owner_id": 1, 

99 }, 

100 { 

101 "name": "Enterprise Solutions", 

102 "description": "Large enterprise software solutions provider with comprehensive digital transformation services", 

103 "url": "https://enterprise-solutions.com", 

104 "owner_id": 1, 

105 }, 

106 { 

107 "name": "LocalBiz", 

108 "description": "Small local business", 

109 "url": "https://localbiz.com", 

110 "owner_id": 1, 

111 }, 

112] 

113 

114 

115LOCATION_DATA = [ 

116 { 

117 "postcode": "10001", 

118 "city": "New York", 

119 "country": "United States", 

120 "owner_id": 1, 

121 }, 

122 { 

123 "postcode": "90210", 

124 "city": "Beverly Hills", 

125 "country": "United States", 

126 "owner_id": 1, 

127 }, 

128 { 

129 "postcode": "SW1A 1AA", 

130 "city": "London", 

131 "country": "United Kingdom", 

132 "owner_id": 1, 

133 }, 

134 { 

135 "city": "San Francisco", 

136 "country": "United States", 

137 "owner_id": 1, 

138 }, 

139 { 

140 "country": "Germany", 

141 "owner_id": 1, 

142 }, 

143 { 

144 "postcode": "OX1 2JD", 

145 "city": "Oxford", 

146 "country": "United Kingdom", 

147 "owner_id": 1, 

148 }, 

149 { 

150 "country": "Canada", 

151 "owner_id": 1, 

152 }, 

153 { 

154 "postcode": "75001", 

155 "city": "Paris", 

156 "country": "France", 

157 "owner_id": 1, 

158 }, 

159 { 

160 "postcode": "10115", 

161 "country": "Germany", 

162 "owner_id": 1, 

163 }, 

164 { 

165 "city": "Tokyo", 

166 "country": "Japan", 

167 "owner_id": 1, 

168 }, 

169 { 

170 "postcode": "M5V 3A8", 

171 "city": "Toronto", 

172 "country": "Canada", 

173 "owner_id": 1, 

174 }, 

175 { 

176 "city": "Amsterdam", 

177 "country": "Netherlands", 

178 "owner_id": 1, 

179 }, 

180 { 

181 "country": "Brazil", 

182 "owner_id": 1, 

183 }, 

184] 

185 

186 

187AGGREGATOR_DATA = [ 

188 { 

189 "name": "LinkedIn", 

190 "url": "https://linkedin.com/jobs", 

191 "owner_id": 1, 

192 }, 

193 { 

194 "name": "Indeed", 

195 "url": "https://indeed.com", 

196 "owner_id": 1, 

197 }, 

198 { 

199 "name": "Glassdoor", 

200 "url": "https://glassdoor.com", 

201 "owner_id": 1, 

202 }, 

203 { 

204 "name": "AngelList", 

205 "url": "https://angel.co", 

206 "owner_id": 1, 

207 }, 

208 { 

209 "name": "Stack Overflow Jobs", 

210 "url": "https://stackoverflow.com/jobs", 

211 "owner_id": 1, 

212 }, 

213 { 

214 "name": "RemoteOK", 

215 "url": "https://remoteok.io", 

216 "owner_id": 1, 

217 }, 

218 { 

219 "name": "WeWorkRemotely", 

220 "url": "https://weworkremotely.com", 

221 "owner_id": 1, 

222 }, 

223 { 

224 "name": "Upwork", 

225 "url": "https://upwork.com", 

226 "owner_id": 1, 

227 }, 

228 { 

229 "name": "Freelancer", 

230 "url": "https://freelancer.com", 

231 "owner_id": 1, 

232 }, 

233 { 

234 "name": "ZipRecruiter", 

235 "url": "https://ziprecruiter.com", 

236 "owner_id": 1, 

237 }, 

238] 

239 

240 

241KEYWORD_DATA = [ 

242 { 

243 "name": "Python", 

244 "owner_id": 1, 

245 }, 

246 { 

247 "name": "JavaScript", 

248 "owner_id": 1, 

249 }, 

250 { 

251 "name": "React", 

252 "owner_id": 1, 

253 }, 

254 { 

255 "name": "Node.js", 

256 "owner_id": 1, 

257 }, 

258 { 

259 "name": "TypeScript", 

260 "owner_id": 1, 

261 }, 

262 { 

263 "name": "PostgreSQL", 

264 "owner_id": 1, 

265 }, 

266 { 

267 "name": "FastAPI", 

268 "owner_id": 1, 

269 }, 

270 { 

271 "name": "Machine Learning", 

272 "owner_id": 1, 

273 }, 

274 { 

275 "name": "DevOps", 

276 "owner_id": 1, 

277 }, 

278 { 

279 "name": "Docker", 

280 "owner_id": 1, 

281 }, 

282 { 

283 "name": "Kubernetes", 

284 "owner_id": 1, 

285 }, 

286 { 

287 "name": "AWS", 

288 "owner_id": 1, 

289 }, 

290 { 

291 "name": "REST API", 

292 "owner_id": 1, 

293 }, 

294 { 

295 "name": "Git", 

296 "owner_id": 1, 

297 }, 

298 { 

299 "name": "Agile", 

300 "owner_id": 1, 

301 }, 

302 { 

303 "name": "Vue.js", 

304 "owner_id": 1, 

305 }, 

306 { 

307 "name": "Angular", 

308 "owner_id": 1, 

309 }, 

310 { 

311 "name": "MongoDB", 

312 "owner_id": 1, 

313 }, 

314 { 

315 "name": "Redis", 

316 "owner_id": 1, 

317 }, 

318 { 

319 "name": "GraphQL", 

320 "owner_id": 1, 

321 }, 

322 { 

323 "name": "Microservices", 

324 "owner_id": 1, 

325 }, 

326 { 

327 "name": "CI/CD", 

328 "owner_id": 1, 

329 }, 

330 { 

331 "name": "Terraform", 

332 "owner_id": 1, 

333 }, 

334 { 

335 "name": "Jenkins", 

336 "owner_id": 1, 

337 }, 

338 { 

339 "name": "Scrum", 

340 "owner_id": 1, 

341 }, 

342] 

343 

344 

345PERSON_DATA = [ 

346 { 

347 "first_name": "John", 

348 "last_name": "Doe", 

349 "email": "john.doe@techcorp.com", 

350 "phone": "1234567890", 

351 "linkedin_url": "https://linkedin.com/in/johndoe", 

352 "role": "Senior Engineering Manager", 

353 "company_id": 1, # Tech Corp 

354 "owner_id": 1, 

355 }, 

356 { 

357 "first_name": "Jane", 

358 "last_name": "Smith", 

359 "email": "jane.smith@startupxyz.com", 

360 "linkedin_url": "https://linkedin.com/in/janesmith", 

361 "role": "Product Manager", 

362 "company_id": 2, # StartupXYZ 

363 "owner_id": 1, 

364 }, 

365 { 

366 "first_name": "Mike", 

367 "last_name": "Taylor", 

368 "phone": "9876543210", 

369 "role": "Lead Developer", 

370 "company_id": 1, # Tech Corp 

371 "owner_id": 1, 

372 }, 

373 { 

374 "first_name": "Emily", 

375 "last_name": "Davis", 

376 "email": "emily.davis@startupxyz.com", 

377 "role": "DevOps Engineer", 

378 "company_id": 2, # StartupXYZ 

379 "owner_id": 1, 

380 }, 

381 { 

382 "first_name": "Chris", 

383 "last_name": "Brown", 

384 "linkedin_url": "https://linkedin.com/in/chrisbrown", 

385 "role": "Data Science Manager", 

386 "company_id": 1, # Tech Corp 

387 "owner_id": 1, 

388 }, 

389 { 

390 "first_name": "Sarah", 

391 "last_name": "Wilson", 

392 "email": "sarah.wilson@oxfordpv.com", 

393 "role": "Technical Recruiter", 

394 "company_id": 3, # Oxford PV 

395 "owner_id": 1, 

396 }, 

397 { 

398 "first_name": "Anonymous", 

399 "last_name": "Recruiter", 

400 "company_id": None, 

401 "owner_id": 1, 

402 }, 

403 { 

404 "first_name": "Tech", 

405 "last_name": "Recruiter", 

406 "role": "Talent Acquisition", 

407 "company_id": 3, # Oxford PV 

408 "owner_id": 1, 

409 }, 

410 { 

411 "first_name": "Alex", 

412 "last_name": "Johnson", 

413 "email": "alex@cloudfirst.io", 

414 "phone": "5551234567", 

415 "linkedin_url": "https://linkedin.com/in/alexjohnson", 

416 "role": "CTO", 

417 "company_id": 6, # CloudFirst Inc 

418 "owner_id": 1, 

419 }, 

420 { 

421 "first_name": "Maria", 

422 "last_name": "Garcia", 

423 "email": "maria.garcia@enterprise.com", 

424 "role": "HR Director", 

425 "company_id": 9, # Enterprise Solutions 

426 "owner_id": 1, 

427 }, 

428 { 

429 "first_name": "David", 

430 "last_name": "Kim", 

431 "phone": "5559876543", 

432 "linkedin_url": "https://linkedin.com/in/davidkim", 

433 "company_id": None, # Freelancer/Independent 

434 "owner_id": 1, 

435 }, 

436 { 

437 "first_name": "Lisa", 

438 "last_name": "Chen", 

439 "email": "lisa@localbiz.com", 

440 "role": "Founder", 

441 "company_id": 10, # LocalBiz 

442 "owner_id": 1, 

443 }, 

444 { 

445 "first_name": "Robert", 

446 "last_name": "Anderson", 

447 "linkedin_url": "https://linkedin.com/in/robertanderson", 

448 "role": "Senior Developer", 

449 "company_id": 7, # Minimal Corp 

450 "owner_id": 1, 

451 }, 

452 { 

453 "first_name": "Jennifer", 

454 "last_name": "Brown", 

455 "phone": "5555551234", 

456 "role": "Product Owner", 

457 "company_id": 8, # No URL Company 

458 "owner_id": 1, 

459 }, 

460 { 

461 "first_name": "Michael", 

462 "last_name": "Wilson", 

463 "email": "m.wilson@datatech.com", 

464 "phone": "5557778888", 

465 "linkedin_url": "https://linkedin.com/in/michaelwilson", 

466 "role": "Data Scientist", 

467 "company_id": 5, # DataTech Industries 

468 "owner_id": 1, 

469 }, 

470 { 

471 "first_name": "Freelance", 

472 "last_name": "Developer", 

473 "email": "freelance@dev.com", 

474 "owner_id": 1, # No company, minimal info 

475 }, 

476] 

477 

478 

479JOB_DATA = [ 

480 { 

481 "title": "Senior Python Developer", 

482 "salary_min": 80000, 

483 "salary_max": 130000, 

484 "description": "Lead backend development using Python and modern frameworks. Work with a talented team to build scalable web applications.", 

485 "personal_rating": 5, 

486 "url": "https://techcorp.com/jobs/senior_python_developer", 

487 "company_id": 1, 

488 "location_id": 2, 

489 "note": "Excellent opportunity for senior developer", 

490 "attendance_type": "hybrid", 

491 "owner_id": 1, 

492 "source_id": 1, 

493 "application_date": "2024-01-15T10:00:00", 

494 "application_url": "https://techcorp.com/apply/senior-python", 

495 "application_status": "applied", 

496 "applied_via": "aggregator", 

497 "application_note": "Submitted application with cover letter", 

498 "cv_id": 3, 

499 "cover_letter_id": 3, 

500 "application_aggregator_id": 1, 

501 }, 

502 { 

503 "title": "Full Stack JavaScript Developer", 

504 "salary_min": 65000, 

505 "salary_max": 105000, 

506 "description": "Build end-to-end web applications with React and Node.js. Join our dynamic startup environment.", 

507 "personal_rating": 4, 

508 "url": "https://startupxyz.com/jobs/fullstack_js_developer", 

509 "company_id": 2, 

510 "location_id": 1, 

511 "note": "Great team culture mentioned in reviews", 

512 "attendance_type": "on-site", 

513 "owner_id": 1, 

514 "source_id": 2, 

515 "application_date": "2024-01-16T14:30:00", 

516 "application_url": "https://startupxyz.com/apply/fullstack-js", 

517 "application_status": "interview", 

518 "applied_via": "aggregator", 

519 "application_note": "Phone screening scheduled for next week", 

520 "cv_id": 1, 

521 "cover_letter_id": None, 

522 "application_aggregator_id": 5, 

523 }, 

524 { 

525 "title": "Remote React Developer", 

526 "salary_min": 60000, 

527 "salary_max": 95000, 

528 "description": "Build modern React applications for distributed team. Full remote position with flexible hours.", 

529 "personal_rating": 3, 

530 "url": "https://techcorp.com/jobs/remote_react_developer", 

531 "company_id": 1, 

532 "location_id": 4, 

533 "owner_id": 1, 

534 "source_id": 2, 

535 "application_date": "2024-01-17T09:15:00", 

536 "application_url": None, 

537 "application_status": "applied", 

538 "applied_via": "aggregator", 

539 "application_note": "Applied through LinkedIn", 

540 "cv_id": None, 

541 "cover_letter_id": 2, 

542 "application_aggregator_id": 4, 

543 }, 

544 { 

545 "title": "Cloud Engineer", 

546 "salary_min": 75000, 

547 "salary_max": 120000, 

548 "description": "Design and maintain AWS cloud infrastructure. Experience with Kubernetes and Docker required.", 

549 "personal_rating": 4, 

550 "url": "https://startupxyz.com/jobs/cloud_engineer", 

551 "company_id": 2, 

552 "location_id": 3, 

553 "attendance_type": "hybrid", 

554 "owner_id": 1, 

555 "source_id": 2, 

556 "application_date": "2024-01-18T16:45:00", 

557 "application_url": "https://startupxyz.com/careers/cloud-engineer", 

558 "application_status": "rejected", 

559 "applied_via": "aggregator", 

560 "application_note": "Not enough cloud experience", 

561 "cv_id": 4, 

562 "cover_letter_id": 4, 

563 "application_aggregator_id": 7, 

564 }, 

565 { 

566 "title": "Frontend Developer", 

567 "salary_min": 55000, 

568 "salary_max": 85000, 

569 "description": "Create beautiful user interfaces with React and JavaScript. Focus on user experience and modern design.", 

570 "personal_rating": 2, 

571 "url": "https://techcorp.com/jobs/frontend_developer", 

572 "company_id": 1, 

573 "location_id": 5, 

574 "attendance_type": "on-site", 

575 "owner_id": 1, 

576 "source_id": 4, 

577 "application_date": None, 

578 "application_url": None, 

579 "application_status": None, 

580 "applied_via": None, 

581 "application_note": None, 

582 "cv_id": None, 

583 "cover_letter_id": None, 

584 "application_aggregator_id": None, 

585 }, 

586 { 

587 "title": "Backend Developer", 

588 "description": "Looking for a backend developer with Python experience. FastAPI knowledge preferred.", 

589 "location_id": 4, 

590 "attendance_type": "hybrid", 

591 "owner_id": 1, 

592 "source_id": 1, 

593 "application_date": "2024-01-20T13:30:00", 

594 "application_url": None, 

595 "application_status": "applied", 

596 "applied_via": None, 

597 "application_note": "Quick application through company form", 

598 "cv_id": None, 

599 "cover_letter_id": None, 

600 "application_aggregator_id": None, 

601 }, 

602 { 

603 "title": "Software Engineer Intern", 

604 "description": "Summer internship opportunity for computer science students. Great learning environment.", 

605 "personal_rating": 1, 

606 "company_id": 3, 

607 "owner_id": 1, 

608 "source_id": 7, 

609 "application_date": None, 

610 "application_url": None, 

611 "application_status": None, 

612 "applied_via": None, 

613 "application_note": None, 

614 "cv_id": None, 

615 "cover_letter_id": None, 

616 "application_aggregator_id": None, 

617 }, 

618 { 

619 "title": "Developer Position", 

620 "company_id": 3, 

621 "location_id": 5, 

622 "attendance_type": "hybrid", 

623 "owner_id": 1, 

624 "source_id": 9, 

625 "application_date": None, 

626 "application_url": None, 

627 "application_status": None, 

628 "applied_via": None, 

629 "application_note": None, 

630 "cv_id": None, 

631 "cover_letter_id": None, 

632 "application_aggregator_id": None, 

633 "deadline": (current_date + timedelta(days=10)).strftime(DATE_FORMAT), 

634 }, 

635 { 

636 "title": "DevOps Engineer", 

637 "salary_min": 90000, 

638 "salary_max": 140000, 

639 "description": "Build and maintain CI/CD pipelines, manage cloud infrastructure", 

640 "personal_rating": 5, 

641 "url": "https://cloudfirst.io/careers/devops", 

642 "company_id": 6, 

643 "location_id": 8, 

644 "note": "Strong DevOps culture, great tools", 

645 "attendance_type": "hybrid", 

646 "owner_id": 1, 

647 "source_id": 9, 

648 "application_date": "2024-01-21T09:00:00", 

649 "application_url": "https://cloudfirst.io/apply/devops", 

650 "application_status": "interview", 

651 "applied_via": None, 

652 "application_note": "Technical interview scheduled", 

653 "cv_id": 8, 

654 "cover_letter_id": 10, 

655 "application_aggregator_id": None, 

656 }, 

657 { 

658 "title": "Data Scientist", 

659 "salary_min": 85000, 

660 "salary_max": 125000, 

661 "description": "Work with big data to derive insights and build ML models", 

662 "personal_rating": 4, 

663 "company_id": 5, 

664 "location_id": 9, 

665 "attendance_type": "remote", 

666 "owner_id": 1, 

667 "source_id": 1, 

668 "application_date": "2024-01-22T11:15:00", 

669 "application_url": None, 

670 "application_status": "applied", 

671 "applied_via": None, 

672 "application_note": None, 

673 "cv_id": 9, 

674 "cover_letter_id": None, 

675 "application_aggregator_id": None, 

676 }, 

677 { 

678 "title": "Vue.js Frontend Developer", 

679 "salary_min": 50000, 

680 "salary_max": 80000, 

681 "description": "Build modern SPAs with Vue.js and TypeScript", 

682 "url": "https://enterprise-solutions.com/jobs/vue-dev", 

683 "company_id": 9, 

684 "location_id": 10, 

685 "attendance_type": "on-site", 

686 "owner_id": 1, 

687 "source_id": 5, 

688 "application_date": "2024-01-23T15:45:00", 

689 "application_url": "https://enterprise-solutions.com/apply/vue-dev", 

690 "application_status": "rejected", 

691 "applied_via": None, 

692 "application_note": "Position filled internally", 

693 "cv_id": 6, 

694 "cover_letter_id": 12, 

695 "application_aggregator_id": None, 

696 }, 

697 { 

698 "title": "Remote Full Stack Engineer", 

699 "salary_min": 70000, 

700 "salary_max": 110000, 

701 "description": "Work remotely on full stack applications", 

702 "personal_rating": 3, 

703 "url": "https://localbiz.com/jobs/fullstack", 

704 "company_id": 10, 

705 "location_id": 11, 

706 "note": "Small team, lots of autonomy", 

707 "attendance_type": "remote", 

708 "owner_id": 1, 

709 "source_id": 7, 

710 "application_date": "2024-01-24T08:30:00", 

711 "application_url": None, 

712 "application_status": "applied", 

713 "applied_via": None, 

714 "application_note": "Applied directly through website", 

715 "cv_id": 3, 

716 "cover_letter_id": None, 

717 "application_aggregator_id": None, 

718 }, 

719 { 

720 "title": "Junior Developer", 

721 "salary_min": 40000, 

722 "salary_max": 60000, 

723 "description": "Entry-level position for new graduates", 

724 "personal_rating": 2, 

725 "company_id": 7, 

726 "location_id": 12, 

727 "attendance_type": "on-site", 

728 "owner_id": 1, 

729 "source_id": 8, 

730 "application_date": "2024-01-25T10:00:00", 

731 "application_url": None, 

732 "application_status": "interview", 

733 "applied_via": None, 

734 "application_note": None, 

735 "cv_id": 1, 

736 "cover_letter_id": 7, 

737 "application_aggregator_id": None, 

738 "deadline": (current_date + timedelta(days=10)).strftime(DATE_FORMAT), 

739 }, 

740 { 

741 "title": "Freelance Web Developer", 

742 "description": "Contract position for web development projects", 

743 "location_id": 13, 

744 "note": "Flexible hours, project-based", 

745 "attendance_type": "remote", 

746 "owner_id": 1, 

747 "application_date": None, 

748 "application_url": None, 

749 "application_status": None, 

750 "applied_via": None, 

751 "application_note": None, 

752 "cv_id": None, 

753 "cover_letter_id": None, 

754 "application_aggregator_id": None, 

755 }, 

756 { 

757 "title": "Mobile App Developer", 

758 "salary_min": 60000, 

759 "salary_max": 100000, 

760 "description": "Develop iOS and Android applications", 

761 "personal_rating": 4, 

762 "url": "https://websolutions.com/jobs/mobile-dev", 

763 "company_id": 4, 

764 "location_id": 12, 

765 "attendance_type": "hybrid", 

766 "owner_id": 1, 

767 "application_date": "2024-01-26T16:00:00", 

768 "application_url": "https://websolutions.com/apply/mobile-dev", 

769 "application_status": "applied", 

770 "applied_via": None, 

771 "application_note": "Excited about mobile development opportunity", 

772 "cv_id": 11, 

773 "cover_letter_id": None, 

774 "application_aggregator_id": None, 

775 }, 

776 { 

777 "title": "Minimum Required Job", 

778 "attendance_type": "on-site", 

779 "owner_id": 1, 

780 "application_date": "2024-01-27T12:00:00", 

781 "application_url": None, 

782 "application_status": "applied", 

783 "applied_via": None, 

784 "application_note": None, 

785 "cv_id": None, 

786 "cover_letter_id": None, 

787 "application_aggregator_id": None, 

788 }, 

789 { 

790 "title": "High Salary Position", 

791 "salary_min": 150000, 

792 "salary_max": 250000, 

793 "description": "Senior leadership role with high compensation", 

794 "personal_rating": 5, 

795 "company_id": 9, 

796 "location_id": 1, 

797 "attendance_type": "hybrid", 

798 "owner_id": 1, 

799 "application_date": "2024-01-28T14:20:00", 

800 "application_url": "https://enterprise-solutions.com/apply/high-salary", 

801 "application_status": "interview", 

802 "applied_via": None, 

803 "application_note": "Executive-level interview process", 

804 "cv_id": 8, 

805 "cover_letter_id": 2, 

806 "application_aggregator_id": None, 

807 }, 

808] 

809 

810JOB_APPLICATION_DATETIME = [current_date - timedelta(weeks=i) for i in range(len(JOB_DATA))] 

811for job_application, date in zip(JOB_DATA, JOB_APPLICATION_DATETIME): 

812 if job_application.get("application_date"): 

813 job_application["application_date"] = date.strftime(DATETIME_FORMAT) 

814 

815 

816FILE_DATA = [ 

817 { 

818 "filename": "john_doe_cv_2024.pdf", 

819 "owner_id": 1, 

820 **RESOURCE_FILES["CV.pdf"], 

821 }, 

822 { 

823 "filename": "cover_letter_senior_python.docx", 

824 "owner_id": 1, 

825 **RESOURCE_FILES["Cover Letter.docx"], 

826 }, 

827 { 

828 "filename": "fullstack_developer_cv.pdf", 

829 "owner_id": 1, 

830 **RESOURCE_FILES["CV.pdf"], 

831 }, 

832 { 

833 "filename": "portfolio_cover_letter.txt", 

834 "owner_id": 1, 

835 **RESOURCE_FILES["Cover Letter.txt"], 

836 }, 

837 { 

838 "filename": "junior_cloud_cv.docx", 

839 "owner_id": 1, 

840 **RESOURCE_FILES["Cover Letter.docx"], 

841 }, 

842 { 

843 "filename": "frontend_specialist_cv.pdf", 

844 "owner_id": 1, 

845 **RESOURCE_FILES["CV.pdf"], 

846 }, 

847 { 

848 "filename": "frontend_developer_cover_letter.docx", 

849 "owner_id": 1, 

850 **RESOURCE_FILES["Cover Letter.docx"], 

851 }, 

852 { 

853 "filename": "devops_engineer_cv.pdf", 

854 "owner_id": 1, 

855 **RESOURCE_FILES["CV.pdf"], 

856 }, 

857 { 

858 "filename": "data_scientist_resume.pdf", 

859 "owner_id": 1, 

860 **RESOURCE_FILES["CV.pdf"], 

861 }, 

862 { 

863 "filename": "vue_developer_cover_letter.txt", 

864 "owner_id": 1, 

865 **RESOURCE_FILES["Cover Letter.txt"], 

866 }, 

867 { 

868 "filename": "mobile_dev_portfolio.pdf", 

869 "owner_id": 1, 

870 **RESOURCE_FILES["CV.pdf"], 

871 }, 

872 { 

873 "filename": "generic_cover_letter.docx", 

874 "owner_id": 1, 

875 **RESOURCE_FILES["Cover Letter.docx"], 

876 }, 

877] 

878 

879 

880INTERVIEW_DATA = [ 

881 { 

882 "date": "2024-01-20T09:30:00", 

883 "type": "HR", 

884 "location_id": 1, 

885 "job_id": 1, 

886 "note": "First round technical interview", 

887 "attendance_type": "on-site", 

888 "owner_id": 1, 

889 }, 

890 { 

891 "date": "2024-01-21T14:00:00", 

892 "type": "Technical", 

893 "location_id": 2, 

894 "job_id": 2, 

895 "note": "HR screening call", 

896 "attendance_type": "remote", 

897 "owner_id": 1, 

898 }, 

899 { 

900 "date": "2024-01-22T10:15:00", 

901 "type": "Management", 

902 "location_id": 4, # Remote 

903 "job_id": 3, 

904 "note": "Remote technical assessment", 

905 "attendance_type": "remote", 

906 "owner_id": 1, 

907 }, 

908 { 

909 "date": "2024-01-23T16:30:00", 

910 "type": "HR", 

911 "location_id": 1, 

912 "job_id": 4, 

913 "note": "Final round with team lead", 

914 "attendance_type": "on-site", 

915 "owner_id": 1, 

916 }, 

917 { 

918 "date": "2024-01-24T11:45:00", 

919 "type": "Other", 

920 "location_id": 3, 

921 "job_id": 5, 

922 "note": "Cultural fit interview", 

923 "attendance_type": "on-site", 

924 "owner_id": 1, 

925 }, 

926 { 

927 "date": "2024-01-26T09:00:00", 

928 "type": "HR", 

929 "location_id": 7, # Canada location 

930 "job_id": 1, # Same application, second interview 

931 "note": None, 

932 "attendance_type": "on-site", 

933 "owner_id": 1, 

934 }, 

935 { 

936 "date": "2024-01-29T10:30:00", 

937 "type": "Technical", 

938 "location_id": 8, # Paris 

939 "job_id": 6, # DevOps application 

940 "note": "Deep technical dive into infrastructure", 

941 "attendance_type": "on-site", 

942 "owner_id": 1, 

943 }, 

944 { 

945 "date": "2024-01-30T15:00:00", 

946 "type": "Management", 

947 "location_id": 11, # Australia (remote) 

948 "job_id": 8, # Remote Full Stack application 

949 "note": "Meeting with team leads", 

950 "attendance_type": "remote", 

951 "owner_id": 1, 

952 }, 

953 { 

954 "date": "2024-02-01T09:45:00", 

955 "type": "HR", 

956 "location_id": 12, # Toronto 

957 "job_id": 10, # Junior Developer application 

958 "note": "Initial screening for junior position", 

959 "attendance_type": "on-site", 

960 "owner_id": 1, 

961 }, 

962 { 

963 "date": "2024-02-02T11:00:00", 

964 "type": "Technical", 

965 "location_id": 12, # Brazil (remote) 

966 "job_id": 11, # Mobile App Developer 

967 "note": "Technical skills assessment for mobile development", 

968 "attendance_type": "remote", 

969 "owner_id": 1, 

970 }, 

971 { 

972 "date": "2024-02-03T14:15:00", 

973 "type": "Other", 

974 "location_id": 1, # New York 

975 "job_id": 13, # High Salary Position 

976 "note": "Panel interview with executives", 

977 "attendance_type": "on-site", 

978 "owner_id": 1, 

979 }, 

980 { 

981 "date": "2024-02-04T16:30:00", 

982 "type": "Management", 

983 "location_id": 5, # Germany (remote) 

984 "job_id": 7, # Data Scientist application 

985 "attendance_type": "remote", 

986 "owner_id": 1, # Minimal interview info 

987 }, 

988] 

989interviews_sorted = sorted(INTERVIEW_DATA, key=lambda x: x["job_id"]) 

990grouped = {k: list(v) for k, v in groupby(interviews_sorted, key=lambda x: x["job_id"])} 

991for update_key, date in zip(grouped, JOB_APPLICATION_DATETIME): 

992 for i, update in enumerate(grouped[update_key]): 

993 update["date"] = (date + timedelta(weeks=4) * (i + 1)).strftime(DATETIME_FORMAT) 

994 

995 

996JOB_APPLICATION_UPDATE_DATA = [ 

997 { 

998 "date": "2024-01-15 14:30:00", 

999 "job_id": 1, # Tech startup application 

1000 "note": "Received automated confirmation email", 

1001 "type": "received", 

1002 "owner_id": 1, 

1003 }, 

1004 { 

1005 "date": "2024-01-18 09:15:00", 

1006 "job_id": 1, 

1007 "note": "HR recruiter called to schedule phone screening", 

1008 "type": "received", 

1009 "owner_id": 1, 

1010 }, 

1011 { 

1012 "date": "2024-01-22 16:45:00", 

1013 "job_id": 2, # Marketing agency application 

1014 "note": "Application status changed to 'Under Review'", 

1015 "type": "received", 

1016 "owner_id": 1, 

1017 }, 

1018 { 

1019 "date": "2024-01-25 11:20:00", 

1020 "job_id": 3, # Finance corp application 

1021 "note": "Received rejection email - position filled internally", 

1022 "type": "received", 

1023 "owner_id": 1, 

1024 }, 

1025 { 

1026 "date": "2024-01-28 13:10:00", 

1027 "job_id": 4, # Healthcare application 

1028 "note": "Invited to complete online assessment", 

1029 "type": "received", 

1030 "owner_id": 1, 

1031 }, 

1032 { 

1033 "date": "2024-02-01 08:30:00", 

1034 "job_id": 2, 

1035 "note": "Scheduled for first round interview next week", 

1036 "type": "received", 

1037 "owner_id": 1, 

1038 }, 

1039 { 

1040 "date": "2024-02-03 15:45:00", 

1041 "job_id": 5, # Remote consulting application 

1042 "note": "Application acknowledgment received", 

1043 "type": "received", 

1044 "owner_id": 1, 

1045 }, 

1046 { 

1047 "date": "2024-02-05 10:15:00", 

1048 "job_id": 4, 

1049 "note": "Completed technical assessment - awaiting results", 

1050 "type": "sent", 

1051 "owner_id": 1, 

1052 }, 

1053 { 

1054 "date": "2024-02-08 14:20:00", 

1055 "job_id": 6, # Another application 

1056 "note": "Phone screening scheduled for tomorrow", 

1057 "type": "sent", 

1058 "owner_id": 1, 

1059 }, 

1060 { 

1061 "date": "2024-02-12 11:45:00", 

1062 "job_id": 7, 

1063 "note": "Application moved to final review stage", 

1064 "type": "sent", 

1065 "owner_id": 1, 

1066 }, 

1067 { 

1068 "date": "2024-02-15 09:30:00", 

1069 "job_id": 8, 

1070 "note": "Hiring manager wants to schedule video call", 

1071 "type": "sent", 

1072 "owner_id": 1, 

1073 }, 

1074 { 

1075 "date": "2024-02-18 16:10:00", 

1076 "job_id": 9, 

1077 "note": "Received offer letter - salary negotiation in progress", 

1078 "type": "sent", 

1079 "owner_id": 1, 

1080 }, 

1081 { 

1082 "date": "2024-02-20 13:25:00", 

1083 "job_id": 10, 

1084 "note": "Application automatically withdrawn due to inactivity", 

1085 "type": "sent", 

1086 "owner_id": 1, 

1087 }, 

1088 { 

1089 "date": "2024-02-22 10:40:00", 

1090 "job_id": 2, 

1091 "note": "Second round interview scheduled - panel interview", 

1092 "type": "sent", 

1093 "owner_id": 1, 

1094 }, 

1095 { 

1096 "date": "2024-02-25 14:55:00", 

1097 "job_id": 11, 

1098 "note": "Reference check completed", 

1099 "type": "sent", 

1100 "owner_id": 1, 

1101 }, 

1102] 

1103job_application_updates_sorted = sorted(JOB_APPLICATION_UPDATE_DATA, key=lambda x: x["job_id"]) 

1104grouped = {k: list(v) for k, v in groupby(job_application_updates_sorted, key=lambda x: x["job_id"])} 

1105for update_key, date in zip(grouped, JOB_APPLICATION_DATETIME): 

1106 for i, update in enumerate(grouped[update_key]): 

1107 update["date"] = (date + timedelta(weeks=4) * (i + 1)).strftime(DATETIME_FORMAT) 

1108 

1109 

1110JOB_KEYWORD_MAPPINGS = [ 

1111 {"job_id": 1, "keyword_ids": [1, 2, 6, 7]}, # Senior Python Developer - Python, JavaScript, PostgreSQL, FastAPI 

1112 {"job_id": 2, "keyword_ids": [2, 3, 4, 13]}, # Full Stack JS Developer - JavaScript, React, Node.js, REST API 

1113 {"job_id": 3, "keyword_ids": [3, 2, 14]}, # Remote React Developer - React, JavaScript, Git 

1114 {"job_id": 4, "keyword_ids": [12, 10, 11, 9]}, # Cloud Engineer - AWS, Docker, Kubernetes, DevOps 

1115 {"job_id": 5, "keyword_ids": [2, 3, 14, 15]}, # Frontend Developer - JavaScript, React, Git, Agile 

1116 {"job_id": 9, "keyword_ids": [9, 10, 11, 22, 23]}, # DevOps Engineer - DevOps, Docker, Kubernetes, CI/CD, Terraform 

1117 {"job_id": 10, "keyword_ids": [8, 1, 18]}, # Data Scientist - Machine Learning, Python, MongoDB 

1118 {"job_id": 11, "keyword_ids": [16, 5, 2]}, # Vue.js Developer - Vue.js, TypeScript, JavaScript 

1119 {"job_id": 12, "keyword_ids": [2, 3, 4, 1]}, # Remote Full Stack - JavaScript, React, Node.js, Python 

1120 {"job_id": 13, "keyword_ids": [2, 14, 15]}, # Junior Developer - JavaScript, Git, Agile 

1121 {"job_id": 15, "keyword_ids": [2, 3, 17]}, # Mobile App Developer - JavaScript, React, Angular 

1122] 

1123 

1124 

1125JOB_CONTACT_MAPPINGS = [ 

1126 {"job_id": 1, "person_ids": [1, 3]}, # Senior Python Developer - John Doe, Mike Taylor 

1127 {"job_id": 2, "person_ids": [2, 4]}, # Full Stack JS Developer - Jane Smith, Emily Davis 

1128 {"job_id": 3, "person_ids": [1]}, # Remote React Developer - John Doe 

1129 {"job_id": 4, "person_ids": [4]}, # Cloud Engineer - Emily Davis 

1130 {"job_id": 5, "person_ids": [5]}, # Frontend Developer - Chris Brown 

1131 {"job_id": 9, "person_ids": [9]}, # DevOps Engineer - Alex Johnson 

1132 {"job_id": 10, "person_ids": [15]}, # Data Scientist - Michael Wilson 

1133 {"job_id": 11, "person_ids": [10]}, # Vue.js Developer - Maria Garcia 

1134 {"job_id": 12, "person_ids": [12]}, # Remote Full Stack - Lisa Chen 

1135 {"job_id": 13, "person_ids": [13]}, # Junior Developer - Robert Anderson 

1136 {"job_id": 15, "person_ids": [11, 16]}, # Mobile App Developer - David Kim, Freelance Developer 

1137] 

1138 

1139 

1140INTERVIEW_INTERVIEWER_MAPPINGS = [ 

1141 {"interview_id": 1, "person_ids": [1]}, # First round - John Doe 

1142 {"interview_id": 2, "person_ids": [2]}, # HR screening - Jane Smith 

1143 {"interview_id": 3, "person_ids": [3, 5]}, # Remote assessment - Mike Taylor, Chris Brown 

1144 {"interview_id": 4, "person_ids": [1]}, # Final round - John Doe 

1145 {"interview_id": 5, "person_ids": [4]}, # Cultural fit - Emily Davis 

1146 {"interview_id": 7, "person_ids": [9]}, # DevOps technical - Alex Johnson 

1147 {"interview_id": 8, "person_ids": [12, 11]}, # Remote Full Stack - Lisa Chen, David Kim 

1148 {"interview_id": 9, "person_ids": [13]}, # Junior Developer - Robert Anderson 

1149 {"interview_id": 10, "person_ids": [16]}, # Mobile App - Freelance Developer 

1150 {"interview_id": 11, "person_ids": [10, 15]}, # High Salary Position - Maria Garcia, Michael Wilson 

1151 {"interview_id": 12, "person_ids": [15]}, # Data Scientist - Michael Wilson 

1152] 

1153 

1154 

1155JOB_ALERT_EMAIL_DATA = [ 

1156 { 

1157 "owner_id": 1, 

1158 "external_email_id": "linkedin_alert_001", 

1159 "subject": "10 new jobs matching Python Developer", 

1160 "sender": "jobs-noreply@linkedin.com", 

1161 "date_received": "2024-01-15 09:30:00", 

1162 "platform": "linkedin", 

1163 "service_log_id": 1, 

1164 "body": """ 

1165 Hi there, 

1166 

1167 We found 10 new jobs that match your preferences: 

1168 

1169 1. Senior Python Developer at TechCorp 

1170 https://www.linkedin.com/jobs/view/3789012345 

1171 

1172 2. Python Backend Engineer at StartupInc 

1173 https://www.linkedin.com/jobs/view/3789012346 

1174 

1175 3. Full Stack Python Developer at DataSoft 

1176 https://linkedin.com/comm/jobs/view/3789012347 

1177 

1178 Best regards, 

1179 LinkedIn Jobs Team 

1180 """, 

1181 }, 

1182 { 

1183 "owner_id": 1, 

1184 "external_email_id": "indeed_alert_001", 

1185 "subject": "New job alerts for Software Engineer", 

1186 "sender": "noreply@indeed.com", 

1187 "date_received": "2024-01-16 14:45:00", 

1188 "platform": "indeed", 

1189 "service_log_id": 2, 

1190 "body": """ 

1191 New jobs matching your search criteria: 

1192 

1193 Software Engineer - Remote 

1194 Apply here: https://indeed.com/pagead/clk/dl?mo=r&ad=job123456789&source=email 

1195 

1196 Senior Software Engineer - London 

1197 View job: https://uk.indeed.com/rc/clk/dl?jk=job987654321&from=email 

1198 

1199 Python Developer - Manchester 

1200 https://indeed.com/viewjob?jk=job555666777 

1201 

1202 Don't miss out on these opportunities! 

1203 Indeed Team 

1204 """, 

1205 }, 

1206 { 

1207 "owner_id": 2, 

1208 "external_email_id": "linkedin_alert_002", 

1209 "subject": "Data Scientist positions you might like", 

1210 "sender": "jobs-noreply@linkedin.com", 

1211 "date_received": "2024-01-17 11:20:00", 

1212 "platform": "linkedin", 

1213 "service_log_id": 3, 

1214 "body": """ 

1215 Hello, 

1216 

1217 Check out these Data Scientist roles: 

1218 

1219 Machine Learning Engineer 

1220 https://www.linkedin.com/jobs/view/3801234567 

1221 

1222 Senior Data Scientist at FinTech Ltd 

1223 https://linkedin.com/comm/jobs/view/3801234568 

1224 

1225 AI Research Scientist 

1226 https://www.linkedin.com/jobs/view/3801234569 

1227 

1228 Happy job hunting! 

1229 LinkedIn 

1230 """, 

1231 }, 

1232 { 

1233 "owner_id": 2, 

1234 "external_email_id": "indeed_alert_002", 

1235 "subject": "Your weekly job digest - 5 new matches", 

1236 "sender": "alerts@indeed.com", 

1237 "date_received": "2024-01-18 08:15:00", 

1238 "platform": "indeed", 

1239 "service_log_id": 4, 

1240 "body": """ 

1241 Your weekly job digest is here! 

1242 

1243 Data Analyst - Birmingham 

1244 https://indeed.com/pagead/clk/dl?mo=r&ad=data123&ref=email 

1245 

1246 Business Intelligence Developer 

1247 https://uk.indeed.com/viewjob?jk=bi456789&utm_source=email 

1248 

1249 Senior Data Engineer 

1250 https://indeed.com/rc/clk/dl?jk=eng999888&campaign=weekly 

1251 

1252 Python Data Scientist - Edinburgh 

1253 https://uk.indeed.com/pagead/clk/dl?mo=r&ad=sci777666&source=digest 

1254 

1255 ML Engineer - Glasgow 

1256 https://indeed.com/viewjob?jk=ml444333&ref=weekly_digest 

1257 

1258 Best of luck with your job search! 

1259 Indeed 

1260 """, 

1261 }, 

1262 { 

1263 "owner_id": 1, 

1264 "external_email_id": "linkedin_alert_003", 

1265 "subject": "3 jobs similar to ones you've viewed", 

1266 "sender": "jobs-noreply@linkedin.com", 

1267 "date_received": "2024-01-19 16:10:00", 

1268 "platform": "linkedin", 

1269 "service_log_id": 5, 

1270 "body": """ 

1271 Based on your recent activity, here are some similar opportunities: 

1272 

1273 DevOps Engineer at CloudTech 

1274 https://www.linkedin.com/jobs/view/3812345678 

1275 

1276 Site Reliability Engineer 

1277 https://linkedin.com/comm/jobs/view/3812345679 

1278 

1279 Infrastructure Engineer - Remote 

1280 https://www.linkedin.com/jobs/view/3812345680 

1281 

1282 View more jobs on LinkedIn 

1283 """, 

1284 }, 

1285 { 

1286 "owner_id": 2, 

1287 "external_email_id": "indeed_alert_003", 

1288 "subject": "Frontend Developer jobs in your area", 

1289 "sender": "job-alerts@indeed.co.uk", 

1290 "date_received": "2024-01-20 12:30:00", 

1291 "platform": "indeed", 

1292 "service_log_id": 4, 

1293 "body": """ 

1294 New Frontend Developer opportunities: 

1295 

1296 React Developer - London 

1297 https://uk.indeed.com/pagead/clk/dl?mo=r&ad=react123&loc=london 

1298 

1299 Vue.js Developer - Manchester 

1300 https://indeed.com/viewjob?jk=vue456789&location=manchester 

1301 

1302 Angular Developer - Bristol 

1303 https://uk.indeed.com/rc/clk/dl?jk=ng789012&city=bristol 

1304 

1305 Full Stack JavaScript Developer 

1306 https://indeed.com/pagead/clk/dl?mo=r&ad=js345678&type=fullstack 

1307 

1308 Keep applying! 

1309 Indeed UK 

1310 """, 

1311 }, 

1312] 

1313 

1314 

1315JOB_SCRAPED_DATA = [ 

1316 { 

1317 "external_job_id": "3789012345", 

1318 "owner_id": 1, 

1319 "is_scraped": True, 

1320 "is_failed": False, 

1321 "title": "Senior Python Developer", 

1322 "description": "We are looking for an experienced Python developer to join our team...", 

1323 "company": "TechCorp Inc", 

1324 "location": "San Francisco, CA", 

1325 "salary_min": 120000.0, 

1326 "salary_max": 160000.0, 

1327 "url": "https://linkedin.com/jobs/view/3789012345", 

1328 "scrape_datetime": "2025-08-15T14:32:18.123456+00:00", 

1329 }, 

1330 { 

1331 "external_job_id": "987654321", 

1332 "owner_id": 1, 

1333 "is_scraped": True, 

1334 "is_failed": False, 

1335 "title": "Full Stack Engineer", 

1336 "description": "Join our growing startup as a full stack engineer...", 

1337 "company": "StartupXYZ", 

1338 "location": "Remote", 

1339 "salary_min": 90000.0, 

1340 "salary_max": 130000.0, 

1341 "url": "https://indeed.com/viewjob?jk=987654321", 

1342 "scrape_datetime": "2025-08-22T09:45:32.789012+00:00", 

1343 }, 

1344 { 

1345 "external_job_id": "1122334455", 

1346 "owner_id": 1, 

1347 "is_scraped": True, 

1348 "is_failed": False, 

1349 "title": "DevOps Engineer", 

1350 "description": "Looking for a DevOps engineer with AWS experience...", 

1351 "company": "CloudTech Solutions", 

1352 "location": "New York, NY", 

1353 "salary_min": 110000.0, 

1354 "salary_max": 150000.0, 

1355 "url": "https://linkedin.com/jobs/view/1122334455", 

1356 "scrape_datetime": "2025-08-28T16:20:45.456789+00:00", 

1357 }, 

1358 { 

1359 "external_job_id": "5566778899", 

1360 "owner_id": 1, 

1361 "is_scraped": True, 

1362 "is_failed": False, 

1363 "title": "Software Engineer", 

1364 "scrape_datetime": "2025-08-30T11:15:22.234567+00:00", 

1365 }, 

1366 { 

1367 "external_job_id": "1357924680", 

1368 "owner_id": 1, 

1369 "is_scraped": True, 

1370 "is_failed": False, 

1371 "title": "Backend Developer", 

1372 "scrape_datetime": "2025-08-25T13:42:17.345678+00:00", 

1373 }, 

1374 { 

1375 "external_job_id": "2468135790", 

1376 "owner_id": 1, 

1377 "is_scraped": True, 

1378 "is_failed": True, 

1379 "scrape_error": "Page not found - job posting may have been removed", 

1380 "title": "Data Engineer", 

1381 "scrape_datetime": "2025-08-18T08:30:55.567890+00:00", 

1382 }, 

1383 { 

1384 "external_job_id": "9988776655", 

1385 "owner_id": 1, 

1386 "is_scraped": True, 

1387 "is_failed": True, 

1388 "scrape_error": "Scraping blocked - rate limit exceeded", 

1389 "title": "ML Engineer", 

1390 "scrape_datetime": "2025-08-20T19:25:08.678901+00:00", 

1391 }, 

1392] 

1393 

1394 

1395SERVICE_LOG_DATA = [ 

1396 { 

1397 "name": "Email Scraper Service", 

1398 "run_duration": 45.2, 

1399 "run_datetime": "2024-01-15 08:30:00", 

1400 "is_success": True, 

1401 "error_message": None, 

1402 "job_success_n": 25, 

1403 "job_fail_n": 2, 

1404 }, 

1405 { 

1406 "name": "Email Scraper Service", 

1407 "run_duration": 123.8, 

1408 "run_datetime": "2024-01-15 09:15:00", 

1409 "is_success": True, 

1410 "error_message": None, 

1411 "job_success_n": 89, 

1412 "job_fail_n": 5, 

1413 }, 

1414 { 

1415 "name": "Email Scraper Service", 

1416 "run_duration": 67.4, 

1417 "run_datetime": "2024-01-15 10:00:00", 

1418 "is_success": False, 

1419 "error_message": "Rate limit exceeded after 30 requests", 

1420 "job_success_n": 15, 

1421 "job_fail_n": 45, 

1422 }, 

1423 { 

1424 "name": "Email Scraper Service", 

1425 "run_duration": 89.1, 

1426 "run_datetime": "2024-01-15 11:30:00", 

1427 "is_success": True, 

1428 "error_message": None, 

1429 "job_success_n": 73, 

1430 "job_fail_n": 8, 

1431 }, 

1432 { 

1433 "name": "Email Scraper Service", 

1434 "run_duration": 12.3, 

1435 "run_datetime": "2024-01-15 12:00:00", 

1436 "is_success": True, 

1437 "error_message": None, 

1438 "job_success_n": None, 

1439 "job_fail_n": None, 

1440 }, 

1441 { 

1442 "name": "Email Scraper Service", 

1443 "run_duration": 3.7, 

1444 "run_datetime": "2024-01-15 13:45:00", 

1445 "is_success": False, 

1446 "error_message": "SMTP server connection timeout", 

1447 "job_success_n": 0, 

1448 "job_fail_n": 12, 

1449 }, 

1450 { 

1451 "name": "Email Scraper Service", 

1452 "run_duration": 156.9, 

1453 "run_datetime": "2024-01-15 14:20:00", 

1454 "is_success": True, 

1455 "error_message": None, 

1456 "job_success_n": 234, 

1457 "job_fail_n": 18, 

1458 }, 

1459 { 

1460 "name": "Email Scraper Service", 

1461 "run_duration": 78.5, 

1462 "run_datetime": "2024-01-15 15:30:00", 

1463 "is_success": False, 

1464 "error_message": "PDF parsing library crashed on corrupted file", 

1465 "job_success_n": 45, 

1466 "job_fail_n": 67, 

1467 }, 

1468 { 

1469 "name": "Email Scraper Service", 

1470 "run_duration": 34.2, 

1471 "run_datetime": "2024-01-16 08:00:00", 

1472 "is_success": True, 

1473 "error_message": None, 

1474 "job_success_n": 156, 

1475 "job_fail_n": 3, 

1476 }, 

1477] 

1478SERVICE_LOG_DATETIME = [current_date - timedelta(days=i) for i in range(len(SERVICE_LOG_DATA))] 

1479for service_log, date in zip(SERVICE_LOG_DATA, SERVICE_LOG_DATETIME): 

1480 service_log["run_datetime"] = date.strftime(DATETIME_FORMAT) 

1481 

1482 

1483EMAIL_SCRAPEDJOB_MAPPINGS = [ 

1484 {"email_id": 1, "scraped_job_ids": [1, 2, 4]}, # Mix of scraped and unscraped jobs 

1485 {"email_id": 2, "scraped_job_ids": [3, 5]}, # One scraped, one unscraped 

1486 {"email_id": 3, "scraped_job_ids": [6, 7]}, # Both failed scraping attempts 

1487] 

1488 

1489 

1490def add_mappings( 

1491 primary_data: list, 

1492 secondary_data: list, 

1493 mapping_data: list, 

1494 primary_key: str, 

1495 secondary_key: str, 

1496 relationship_attr: str, 

1497) -> None: 

1498 """Generic function to add many-to-many relationships between data objects. 

1499 :param primary_data: List of primary objects (e.g. jobs, interviews) 

1500 :param secondary_data: List of secondary objects (e.g. keywords, persons) 

1501 :param mapping_data: List of mapping dictionaries 

1502 :param primary_key: Key name for primary object ID in mapping (e.g. "job_id", "interview_id") 

1503 :param secondary_key: Key name for secondary object IDs in mapping (e.g. "keyword_ids", "person_ids") 

1504 :param relationship_attr: Attribute name on a primary object for the relationship (e.g. "keywords", "contacts")""" 

1505 

1506 for mapping in mapping_data: 

1507 primary_obj = primary_data[mapping[primary_key] - 1] # Convert to 0-based index 

1508 secondary_ids = mapping[secondary_key] 

1509 

1510 for secondary_id in secondary_ids: 

1511 secondary_obj = secondary_data[secondary_id - 1] # Convert to 0-based index 

1512 getattr(primary_obj, relationship_attr).append(secondary_obj)