|
36 | 36 | from openedx.core.djangoapps.notifications.models import ( |
37 | 37 | CourseNotificationPreference, |
38 | 38 | Notification, |
39 | | - get_course_notification_preference_config_version |
| 39 | + get_course_notification_preference_config_version, NotificationPreference |
40 | 40 | ) |
41 | 41 | from openedx.core.djangoapps.notifications.serializers import NotificationCourseEnrollmentSerializer |
42 | 42 | from openedx.core.djangoapps.user_api.models import UserPreference |
43 | 43 | from openedx.core.djangoapps.notifications.email.utils import update_user_preferences_from_patch |
44 | 44 | from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase |
45 | 45 | from xmodule.modulestore.tests.factories import CourseFactory |
46 | 46 |
|
47 | | -from ..base_notification import COURSE_NOTIFICATION_APPS, COURSE_NOTIFICATION_TYPES, NotificationAppManager |
| 47 | +from ..base_notification import COURSE_NOTIFICATION_APPS, COURSE_NOTIFICATION_TYPES, NotificationAppManager, \ |
| 48 | + NotificationTypeManager |
48 | 49 | from ..utils import get_notification_types_with_visibility_settings |
49 | 50 |
|
50 | 51 | User = get_user_model() |
@@ -1414,3 +1415,306 @@ def test_non_editable_is_added_in_api_response(self): |
1414 | 1415 | prefs = response.data['data'] |
1415 | 1416 | self.assertDictEqual(prefs['updates']['non_editable'], {'course_updates': ['email']}) |
1416 | 1417 | self.assertDictEqual(prefs['discussion']['non_editable'], {'core': ['web']}) |
| 1418 | + |
| 1419 | + |
| 1420 | +class TestNotificationPreferencesView(APITestCase): |
| 1421 | + """ |
| 1422 | + Tests for the NotificationPreferencesView API view. |
| 1423 | + """ |
| 1424 | + |
| 1425 | + def setUp(self): |
| 1426 | + # Set up a user and API client |
| 1427 | + self.default_data = { |
| 1428 | + "status": "success", |
| 1429 | + "message": "Notification preferences retrieved successfully.", |
| 1430 | + "data": { |
| 1431 | + "discussion": { |
| 1432 | + "enabled": True, |
| 1433 | + "core_notification_types": [ |
| 1434 | + "new_comment_on_response", |
| 1435 | + "new_comment", |
| 1436 | + "new_response", |
| 1437 | + "response_on_followed_post", |
| 1438 | + "comment_on_followed_post", |
| 1439 | + "response_endorsed_on_thread", |
| 1440 | + "response_endorsed" |
| 1441 | + ], |
| 1442 | + "notification_types": { |
| 1443 | + "new_discussion_post": { |
| 1444 | + "web": False, |
| 1445 | + "email": False, |
| 1446 | + "push": False, |
| 1447 | + "email_cadence": "Daily" |
| 1448 | + }, |
| 1449 | + "new_question_post": { |
| 1450 | + "web": False, |
| 1451 | + "email": False, |
| 1452 | + "push": False, |
| 1453 | + "email_cadence": "Daily" |
| 1454 | + }, |
| 1455 | + "content_reported": { |
| 1456 | + "web": True, |
| 1457 | + "email": True, |
| 1458 | + "push": True, |
| 1459 | + "email_cadence": "Daily" |
| 1460 | + }, |
| 1461 | + "new_instructor_all_learners_post": { |
| 1462 | + "web": True, |
| 1463 | + "email": False, |
| 1464 | + "push": False, |
| 1465 | + "email_cadence": "Daily" |
| 1466 | + }, |
| 1467 | + "core": { |
| 1468 | + "web": True, |
| 1469 | + "email": True, |
| 1470 | + "push": True, |
| 1471 | + "email_cadence": "Daily" |
| 1472 | + } |
| 1473 | + }, |
| 1474 | + "non_editable": {} |
| 1475 | + }, |
| 1476 | + "updates": { |
| 1477 | + "enabled": True, |
| 1478 | + "core_notification_types": [], |
| 1479 | + "notification_types": { |
| 1480 | + "course_updates": { |
| 1481 | + "web": True, |
| 1482 | + "email": False, |
| 1483 | + "push": True, |
| 1484 | + "email_cadence": "Daily" |
| 1485 | + }, |
| 1486 | + "core": { |
| 1487 | + "web": True, |
| 1488 | + "email": True, |
| 1489 | + "push": True, |
| 1490 | + "email_cadence": "Daily" |
| 1491 | + } |
| 1492 | + }, |
| 1493 | + "non_editable": {} |
| 1494 | + }, |
| 1495 | + "grading": { |
| 1496 | + "enabled": True, |
| 1497 | + "core_notification_types": [], |
| 1498 | + "notification_types": { |
| 1499 | + "ora_staff_notifications": { |
| 1500 | + "web": True, |
| 1501 | + "email": False, |
| 1502 | + "push": False, |
| 1503 | + "email_cadence": "Daily" |
| 1504 | + }, |
| 1505 | + "ora_grade_assigned": { |
| 1506 | + "web": True, |
| 1507 | + "email": True, |
| 1508 | + "push": False, |
| 1509 | + "email_cadence": "Daily" |
| 1510 | + }, |
| 1511 | + "core": { |
| 1512 | + "web": True, |
| 1513 | + "email": True, |
| 1514 | + "push": True, |
| 1515 | + "email_cadence": "Daily" |
| 1516 | + } |
| 1517 | + }, |
| 1518 | + "non_editable": {} |
| 1519 | + } |
| 1520 | + } |
| 1521 | + } |
| 1522 | + self.user = User.objects.create_user(username='testuser', password='testpass') |
| 1523 | + self.client = APIClient() |
| 1524 | + self.client.force_authenticate(user=self.user) |
| 1525 | + self.url = reverse('notification-preferences-aggregated-v2') # Adjust with the actual name |
| 1526 | + |
| 1527 | + def test_get_notification_preferences(self): |
| 1528 | + """ |
| 1529 | + Test case: Get notification preferences for the authenticated user |
| 1530 | + """ |
| 1531 | + response = self.client.get(self.url) |
| 1532 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1533 | + self.assertEqual(response.data['status'], 'success') |
| 1534 | + self.assertIn('data', response.data) |
| 1535 | + self.assertEqual(response.data['data'], self.default_data['data']) |
| 1536 | + |
| 1537 | + def test_if_data_is_correctly_aggregated(self): |
| 1538 | + """ |
| 1539 | + Test case: Check if the data is correctly formatted |
| 1540 | + """ |
| 1541 | + |
| 1542 | + self.client.get(self.url) |
| 1543 | + NotificationPreference.objects.all().update( |
| 1544 | + web=False, |
| 1545 | + push=False, |
| 1546 | + email=False, |
| 1547 | + ) |
| 1548 | + response = self.client.get(self.url) |
| 1549 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1550 | + self.assertEqual(response.data['status'], 'success') |
| 1551 | + self.assertIn('data', response.data) |
| 1552 | + data = { |
| 1553 | + "status": "success", |
| 1554 | + "message": "Notification preferences retrieved successfully.", |
| 1555 | + "data": { |
| 1556 | + "discussion": { |
| 1557 | + "enabled": True, |
| 1558 | + "core_notification_types": [ |
| 1559 | + "new_comment_on_response", |
| 1560 | + "new_comment", |
| 1561 | + "new_response", |
| 1562 | + "response_on_followed_post", |
| 1563 | + "comment_on_followed_post", |
| 1564 | + "response_endorsed_on_thread", |
| 1565 | + "response_endorsed" |
| 1566 | + ], |
| 1567 | + "notification_types": { |
| 1568 | + "new_discussion_post": { |
| 1569 | + "web": False, |
| 1570 | + "email": False, |
| 1571 | + "push": False, |
| 1572 | + "email_cadence": "Daily" |
| 1573 | + }, |
| 1574 | + "new_question_post": { |
| 1575 | + "web": False, |
| 1576 | + "email": False, |
| 1577 | + "push": False, |
| 1578 | + "email_cadence": "Daily" |
| 1579 | + }, |
| 1580 | + "content_reported": { |
| 1581 | + "web": False, |
| 1582 | + "email": False, |
| 1583 | + "push": False, |
| 1584 | + "email_cadence": "Daily" |
| 1585 | + }, |
| 1586 | + "new_instructor_all_learners_post": { |
| 1587 | + "web": False, |
| 1588 | + "email": False, |
| 1589 | + "push": False, |
| 1590 | + "email_cadence": "Daily" |
| 1591 | + }, |
| 1592 | + "core": { |
| 1593 | + "web": False, |
| 1594 | + "email": False, |
| 1595 | + "push": False, |
| 1596 | + "email_cadence": "Daily" |
| 1597 | + } |
| 1598 | + }, |
| 1599 | + "non_editable": {} |
| 1600 | + }, |
| 1601 | + "updates": { |
| 1602 | + "enabled": True, |
| 1603 | + "core_notification_types": [], |
| 1604 | + "notification_types": { |
| 1605 | + "course_updates": { |
| 1606 | + "web": False, |
| 1607 | + "email": False, |
| 1608 | + "push": False, |
| 1609 | + "email_cadence": "Daily" |
| 1610 | + }, |
| 1611 | + "core": { |
| 1612 | + "web": True, |
| 1613 | + "email": True, |
| 1614 | + "push": True, |
| 1615 | + "email_cadence": "Daily" |
| 1616 | + } |
| 1617 | + }, |
| 1618 | + "non_editable": {} |
| 1619 | + }, |
| 1620 | + "grading": { |
| 1621 | + "enabled": True, |
| 1622 | + "core_notification_types": [], |
| 1623 | + "notification_types": { |
| 1624 | + "ora_staff_notifications": { |
| 1625 | + "web": False, |
| 1626 | + "email": False, |
| 1627 | + "push": False, |
| 1628 | + "email_cadence": "Daily" |
| 1629 | + }, |
| 1630 | + "ora_grade_assigned": { |
| 1631 | + "web": False, |
| 1632 | + "email": False, |
| 1633 | + "push": False, |
| 1634 | + "email_cadence": "Daily" |
| 1635 | + }, |
| 1636 | + "core": { |
| 1637 | + "web": True, |
| 1638 | + "email": True, |
| 1639 | + "push": True, |
| 1640 | + "email_cadence": "Daily" |
| 1641 | + } |
| 1642 | + }, |
| 1643 | + "non_editable": {} |
| 1644 | + } |
| 1645 | + } |
| 1646 | + } |
| 1647 | + self.assertEqual(response.data, data) |
| 1648 | + |
| 1649 | + def test_api_view_permissions(self): |
| 1650 | + """ |
| 1651 | + Test case: Ensure the API view has the correct permissions |
| 1652 | + """ |
| 1653 | + # Check if the view requires authentication |
| 1654 | + self.client.logout() |
| 1655 | + response = self.client.get(self.url) |
| 1656 | + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) |
| 1657 | + |
| 1658 | + # Re-authenticate and check again |
| 1659 | + self.client.force_authenticate(user=self.user) |
| 1660 | + response = self.client.get(self.url) |
| 1661 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1662 | + |
| 1663 | + def test_update_preferences_core(self): |
| 1664 | + """ |
| 1665 | + Test case: Update notification preferences for the authenticated user |
| 1666 | + """ |
| 1667 | + update_data = { |
| 1668 | + "notification_app": "discussion", |
| 1669 | + "notification_type": "core", |
| 1670 | + "notification_channel": "email_cadence", |
| 1671 | + "email_cadence": "Weekly" |
| 1672 | + } |
| 1673 | + __, core_types = NotificationTypeManager().get_notification_app_preference('discussion') |
| 1674 | + self.client.get(self.url) |
| 1675 | + response = self.client.put(self.url, update_data, format='json') |
| 1676 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1677 | + self.assertEqual(response.data['status'], 'success') |
| 1678 | + cadence_set = NotificationPreference.objects.filter(type__in=core_types).values_list('email_cadence', flat=True) |
| 1679 | + self.assertEqual(len(set(cadence_set)), 1) |
| 1680 | + self.assertIn('Weekly', set(cadence_set)) |
| 1681 | + |
| 1682 | + def test_update_preferences(self): |
| 1683 | + """ |
| 1684 | + Test case: Update notification preferences for the authenticated user |
| 1685 | + """ |
| 1686 | + update_data = { |
| 1687 | + "notification_app": "discussion", |
| 1688 | + "notification_type": "new_discussion_post", |
| 1689 | + "notification_channel": "web", |
| 1690 | + "value": True |
| 1691 | + } |
| 1692 | + self.client.get(self.url) |
| 1693 | + response = self.client.put(self.url, update_data, format='json') |
| 1694 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1695 | + self.assertEqual(response.data['status'], 'success') |
| 1696 | + preference = NotificationPreference.objects.get( |
| 1697 | + type='new_discussion_post', |
| 1698 | + user__id=self.user.id |
| 1699 | + ) |
| 1700 | + self.assertEqual(preference.web, True) |
| 1701 | + |
| 1702 | + def test_update_preferences_non_core_email(self): |
| 1703 | + """ |
| 1704 | + Test case: Update notification preferences for the authenticated user |
| 1705 | + """ |
| 1706 | + update_data = { |
| 1707 | + "notification_app": "discussion", |
| 1708 | + "notification_type": "new_discussion_post", |
| 1709 | + "notification_channel": "email_cadence", |
| 1710 | + "email_cadence": 'Weekly' |
| 1711 | + } |
| 1712 | + self.client.get(self.url) |
| 1713 | + response = self.client.put(self.url, update_data, format='json') |
| 1714 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1715 | + self.assertEqual(response.data['status'], 'success') |
| 1716 | + preference = NotificationPreference.objects.get( |
| 1717 | + type='new_discussion_post', |
| 1718 | + user__id=self.user.id |
| 1719 | + ) |
| 1720 | + self.assertEqual(preference.email_cadence, 'Weekly') |
0 commit comments