|
3 | 3 | from django.utils import timezone |
4 | 4 | from rest_framework.test import APIRequestFactory, force_authenticate |
5 | 5 |
|
| 6 | +from courses.models import Course, CourseAccessType, CourseContentStatus |
6 | 7 | from partner_programs.models import ( |
7 | 8 | PartnerProgram, |
8 | 9 | PartnerProgramField, |
|
11 | 12 | ) |
12 | 13 | from partner_programs.serializers import PartnerProgramFieldValueUpdateSerializer |
13 | 14 | from partner_programs.services import publish_finished_program_projects |
14 | | -from partner_programs.views import PartnerProgramProjectSubmitView |
| 15 | +from partner_programs.views import PartnerProgramDetail, PartnerProgramProjectSubmitView |
15 | 16 | from projects.models import Project |
16 | 17 |
|
17 | 18 |
|
@@ -412,3 +413,138 @@ def test_file_valid_url(self): |
412 | 413 | data = {"field_id": field.id, "value_text": "https://example.com/file.pdf"} |
413 | 414 | serializer = PartnerProgramFieldValueUpdateSerializer(data=data) |
414 | 415 | self.assertTrue(serializer.is_valid()) |
| 416 | + |
| 417 | + |
| 418 | +class PartnerProgramDetailCoursesTests(TestCase): |
| 419 | + def setUp(self): |
| 420 | + self.factory = APIRequestFactory() |
| 421 | + self.view = PartnerProgramDetail.as_view() |
| 422 | + self.now = timezone.now() |
| 423 | + |
| 424 | + def create_program(self, **overrides): |
| 425 | + defaults = { |
| 426 | + "name": "Program with courses", |
| 427 | + "tag": "program_with_courses", |
| 428 | + "description": "Program description", |
| 429 | + "city": "Moscow", |
| 430 | + "data_schema": {}, |
| 431 | + "draft": False, |
| 432 | + "projects_availability": "all_users", |
| 433 | + "datetime_registration_ends": self.now + timezone.timedelta(days=10), |
| 434 | + "datetime_started": self.now - timezone.timedelta(days=1), |
| 435 | + "datetime_finished": self.now + timezone.timedelta(days=30), |
| 436 | + } |
| 437 | + defaults.update(overrides) |
| 438 | + return PartnerProgram.objects.create(**defaults) |
| 439 | + |
| 440 | + def create_user(self, email: str): |
| 441 | + return get_user_model().objects.create_user( |
| 442 | + email=email, |
| 443 | + password="pass", |
| 444 | + first_name="Test", |
| 445 | + last_name="User", |
| 446 | + birthday="1990-01-01", |
| 447 | + ) |
| 448 | + |
| 449 | + def create_course(self, program: PartnerProgram, **overrides): |
| 450 | + defaults = { |
| 451 | + "title": "Program course", |
| 452 | + "partner_program": program, |
| 453 | + "access_type": CourseAccessType.ALL_USERS, |
| 454 | + "status": CourseContentStatus.PUBLISHED, |
| 455 | + } |
| 456 | + defaults.update(overrides) |
| 457 | + return Course.objects.create(**defaults) |
| 458 | + |
| 459 | + def test_detail_includes_related_courses_with_availability_for_member(self): |
| 460 | + program = self.create_program() |
| 461 | + member = self.create_user("member-program@example.com") |
| 462 | + PartnerProgramUserProfile.objects.create( |
| 463 | + user=member, |
| 464 | + partner_program=program, |
| 465 | + project=None, |
| 466 | + partner_program_data={}, |
| 467 | + ) |
| 468 | + all_users_course = self.create_course( |
| 469 | + program, |
| 470 | + title="Open course", |
| 471 | + access_type=CourseAccessType.ALL_USERS, |
| 472 | + ) |
| 473 | + member_course = self.create_course( |
| 474 | + program, |
| 475 | + title="Members course", |
| 476 | + access_type=CourseAccessType.PROGRAM_MEMBERS, |
| 477 | + ) |
| 478 | + self.create_course( |
| 479 | + program, |
| 480 | + title="Draft course", |
| 481 | + access_type=CourseAccessType.ALL_USERS, |
| 482 | + status=CourseContentStatus.DRAFT, |
| 483 | + ) |
| 484 | + |
| 485 | + request = self.factory.get(f"/programs/{program.id}/") |
| 486 | + force_authenticate(request, user=member) |
| 487 | + response = self.view(request, pk=program.id) |
| 488 | + |
| 489 | + self.assertEqual(response.status_code, 200) |
| 490 | + self.assertEqual( |
| 491 | + response.data["courses"], |
| 492 | + [ |
| 493 | + { |
| 494 | + "id": all_users_course.id, |
| 495 | + "title": "Open course", |
| 496 | + "is_available": True, |
| 497 | + }, |
| 498 | + { |
| 499 | + "id": member_course.id, |
| 500 | + "title": "Members course", |
| 501 | + "is_available": True, |
| 502 | + }, |
| 503 | + ], |
| 504 | + ) |
| 505 | + |
| 506 | + def test_detail_includes_empty_courses_list_when_program_has_no_related_courses(self): |
| 507 | + program = self.create_program() |
| 508 | + user = self.create_user("plain-user@example.com") |
| 509 | + |
| 510 | + request = self.factory.get(f"/programs/{program.id}/") |
| 511 | + force_authenticate(request, user=user) |
| 512 | + response = self.view(request, pk=program.id) |
| 513 | + |
| 514 | + self.assertEqual(response.status_code, 200) |
| 515 | + self.assertEqual(response.data["courses"], []) |
| 516 | + |
| 517 | + def test_detail_marks_program_only_courses_as_unavailable_for_non_member(self): |
| 518 | + program = self.create_program() |
| 519 | + outsider = self.create_user("outsider-program@example.com") |
| 520 | + open_course = self.create_course( |
| 521 | + program, |
| 522 | + title="Open course", |
| 523 | + access_type=CourseAccessType.ALL_USERS, |
| 524 | + ) |
| 525 | + member_course = self.create_course( |
| 526 | + program, |
| 527 | + title="Members course", |
| 528 | + access_type=CourseAccessType.PROGRAM_MEMBERS, |
| 529 | + ) |
| 530 | + |
| 531 | + request = self.factory.get(f"/programs/{program.id}/") |
| 532 | + force_authenticate(request, user=outsider) |
| 533 | + response = self.view(request, pk=program.id) |
| 534 | + |
| 535 | + self.assertEqual(response.status_code, 200) |
| 536 | + self.assertEqual( |
| 537 | + response.data["courses"], |
| 538 | + [ |
| 539 | + { |
| 540 | + "id": open_course.id, |
| 541 | + "title": "Open course", |
| 542 | + "is_available": True, |
| 543 | + }, |
| 544 | + { |
| 545 | + "id": member_course.id, |
| 546 | + "title": "Members course", |
| 547 | + "is_available": False, |
| 548 | + }, |
| 549 | + ], |
| 550 | + ) |
0 commit comments