Skip to content

Commit

Permalink
Merge pull request #13 from now-u/accessible_resources
Browse files Browse the repository at this point in the history
Changes for making resources past their end date accessible in apis
  • Loading branch information
JElgar authored Jan 12, 2025
2 parents e344154 + 0aca2ad commit 41feb96
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 5 deletions.
2 changes: 1 addition & 1 deletion causes_service/blogs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ class BlogViewSet(viewsets.ReadOnlyModelViewSet):
lookup_field = 'slug'

def get_queryset(self):
return Blog.objects.filter_active(is_active_at=timezone.now()).order_by('-release_at')
return Blog.objects.filter_released(is_released_at=timezone.now()).order_by('-release_at')

8 changes: 4 additions & 4 deletions causes_service/causes/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def select(self, request, pk=None) -> Response:

class ActionViewSet(viewsets.ReadOnlyModelViewSet):
# TODO Move this to get_query because idk when datetime.now is called!
queryset = Action.objects.filter_active(is_active_at=timezone.now())
queryset = Action.objects.filter_released(is_released_at=timezone.now())

def get_serializer_class(self):
if self.action == 'list':
Expand Down Expand Up @@ -58,7 +58,7 @@ def get_queryset(self) -> QuerySet[Any]:
# TODO Try and fix these types
if (user is not None and user.is_staff):
return LearningResource.objects.all()
return LearningResource.objects.filter_active(is_active_at=timezone.now())
return LearningResource.objects.filter_released(is_released_at=timezone.now())

@extend_schema(operation_id="learning_resources_complete", request=None, responses=None)
@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])
Expand All @@ -70,7 +70,7 @@ def complete(self, request, pk=None) -> Response:

class CampaignViewSet(viewsets.ReadOnlyModelViewSet):
def get_queryset(self) -> QuerySet[Campaign]:
return Campaign.objects.filter_active(is_active_at=timezone.now())
return Campaign.objects.filter_released(is_released_at=timezone.now())

def get_serializer_class(self):
if self.action == 'list':
Expand All @@ -81,7 +81,7 @@ class NewsArticleViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = NewsArticleSerializer

def get_queryset(self) -> QuerySet[NewsArticle]:
return NewsArticle.objects.filter_active(is_active_at=timezone.now())
return NewsArticle.objects.filter_released(is_released_at=timezone.now())

@extend_schema(operation_id="news_article_complete", request=None, responses=None)
@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])
Expand Down
32 changes: 32 additions & 0 deletions causes_service/tests/integration/blogs_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from datetime import timedelta
import pytest

from tests.factories.blog import BlogFactory
from tests.factories.user import UserFactory
from django.utils import timezone

pytestmark = pytest.mark.django_db

Expand All @@ -24,3 +26,33 @@ def test_get_blog(client):
assert response.data['authors'][0]['id'] == 10
assert response.data['authors'][0]['name'] == "John Doe"
assert response.data['authors'][0]['description'] == "I am an avid blogger"

def test_blog_viewset_filtering(client):
now = timezone.now()
past_date=now - timedelta(days=5)
future_date=now + timedelta(days=3)

#create blogs with release date in the past and future
BlogFactory(release_at = past_date)
BlogFactory(release_at = future_date)

#request the blogs API

response = client.get('/blogs/')

assert response.status_code == 200
assert len(response.data['results']) == 1 # Only the blog with past_date should be returned
assert response.data['results'][0]['release_at'] <= now.isoformat()

def test_blog_viewset_filtering_no_blogs(client):
now = timezone.now()
future_date = now + timedelta(days=3)
#create blog with release date in future
BlogFactory(release_at = future_date)

#request the blogs API

response = client.get('/blogs/')
assert response.status_code == 200
assert len(response.data['results']) == 0 # No Blogs should be returned

127 changes: 127 additions & 0 deletions causes_service/tests/integration/causes_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from datetime import datetime
from datetime import timedelta
from django.utils import timezone
import pytest
import pytz

Expand Down Expand Up @@ -155,3 +157,128 @@ def test_delete_campaign():
assert Campaign.objects.count() == 0
assert Action.objects.count() == 3
assert LearningResource.objects.count() == 3

def test_campaign_viewset_filtering(client):
now = timezone.now()
past_date = now - timedelta(days=10)
future_date = now + timedelta(days=10)

# Create campaigns with release dates in the past and future
CampaignFactory(release_at=past_date)
CampaignFactory(release_at=future_date)

# Request the campaigns API
response = client.get('/campaigns/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 1 # Only one campaign should be returned
assert response.data['results'][0]['release_at'] <= now.isoformat()

def test_campaign_viewset_filtering_no_campaigns(client):
now = timezone.now()
future_date = now + timedelta(days=10)

# Create campaign with release dates in the future
CampaignFactory(release_at=future_date)

# Request the campaigns API
response = client.get('/campaigns/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 0 # No campaign should be returned


def test_news_article_viewset_filtering(client):
now = timezone.now()
past_date = now - timedelta(days=20)
future_date = now + timedelta(days=5)

# Create news articles with release dates in the past and future
NewsArticleFactory(release_at=past_date)
NewsArticleFactory(release_at=future_date)

# Request the news articles API
response = client.get('/news_articles/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 1
assert response.data['results'][0]['release_at'] <= now.isoformat()

def test_news_article_viewset_filtering_no_news_article(client):
now = timezone.now()
future_date = now + timedelta(days=5)

# Create news articles with release dates in future
NewsArticleFactory(release_at=future_date)

# Request the news articles API
response = client.get('/news_articles/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 0

def test_learning_resource_viewset_filtering(client):
now = timezone.now()
past_date = now - timedelta(days=15)
future_date = now + timedelta(days=7)

# Create learning resources with release dates in the past and future
LearningResourceFactory(release_at=past_date)
LearningResourceFactory(release_at=future_date)

# Request the learning resources API
response = client.get('/learning_resources/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 1
assert response.data['results'][0]['release_at'] <= now.isoformat()

def test_learning_resource_viewset_filtering_no_learning_resource(client):
now = timezone.now()
future_date = now + timedelta(days=7)

# Create learning resources with release dates in the future
LearningResourceFactory(release_at=future_date)

# Request the learning resources API
response = client.get('/learning_resources/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 0

def test_action_viewset_filtering(client):
now = timezone.now()
past_date = now - timedelta(days=30)
future_date = now + timedelta(days=15)

# Create actions with release dates in the past and future
ActionFactory(release_at=past_date)
ActionFactory(release_at=future_date)

# Request the actions API
response = client.get('/actions/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 1
assert response.data['results'][0]['release_at'] <= now.isoformat()

def test_action_viewset_filtering_no_actions(client):
now = timezone.now()
future_date = now + timedelta(days=15)

# Create actions with release dates in the future
ActionFactory(release_at=future_date)

# Request the actions API
response = client.get('/actions/')

# Assertions
assert response.status_code == 200
assert len(response.data['results']) == 0
7 changes: 7 additions & 0 deletions causes_service/utils/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class TimeStampedMixin(models.Model):
class Meta:
abstract = True

def filter_released_for_releaseable_queryset(queryset: models.QuerySet | models.Manager, is_released_at: datetime):
return queryset.filter(
Q(release_at__lte=is_released_at)
)

def filter_active_for_releaseable_queryset(
queryset: models.QuerySet | models.Manager,
is_active_at: datetime,
Expand All @@ -44,6 +49,8 @@ def filter_active_for_releaseable_queryset(
class ReleaseControlManager(models.Manager):
def filter_active(self, is_active_at: datetime, is_active=True):
return filter_active_for_releaseable_queryset(self, is_active_at, is_active)
def filter_released(self, is_released_at: datetime):
return filter_released_for_releaseable_queryset(self, is_released_at)

class ReleaseControlMixin(TimeStampedMixin, models.Model):
release_at = models.DateTimeField(help_text=_('The date from which this resource should be available in the app. If not provided the resource will not be visible'))
Expand Down

0 comments on commit 41feb96

Please sign in to comment.