From 938bea32c6e3b28caa5b4e083d5be7232606a848 Mon Sep 17 00:00:00 2001 From: Happy Felix Chukwuma Date: Fri, 30 Aug 2024 08:36:55 +0100 Subject: [PATCH] feat: Implemented Total Read Minutes for each Article --- server/apps/research/admin/article_admin.py | 32 +++-- server/apps/research/models/article.py | 6 +- .../serializers/article_serializer.py | 4 +- server/templates/admin/base.html | 136 +++++++++++------- 4 files changed, 105 insertions(+), 73 deletions(-) diff --git a/server/apps/research/admin/article_admin.py b/server/apps/research/admin/article_admin.py index 5e62d2d..f26f119 100644 --- a/server/apps/research/admin/article_admin.py +++ b/server/apps/research/admin/article_admin.py @@ -3,9 +3,19 @@ from apps.research.models import Article, Author from tinymce.widgets import TinyMCE -@admin.register(Article) +class ArticleForm(forms.ModelForm): + class Meta: + model = Article + fields = '__all__' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['acknowledgement'].widget = TinyMCE(attrs={'cols': 80, 'rows': 30, 'id': "acknowledgement_richtext_field", 'placeholder': f"Enter Acknowledgement here"}) + self.fields['content'].widget = TinyMCE(attrs={'cols': 80, 'rows': 30, 'id': "content_richtext_field", 'placeholder': f"Enter Article Content here"}) + class ArticleAdmin(admin.ModelAdmin): """Admin interface for the Article model.""" + form = ArticleForm fieldsets = [ ('Article Details', {'fields': ['title', 'authors', 'acknowledgement', 'categories', 'thumb', 'content', 'summary', 'status', 'scheduled_publish_time']}), ] @@ -15,25 +25,17 @@ class ArticleAdmin(admin.ModelAdmin): list_filter = ('authors', 'status', 'categories', 'created_at') readonly_fields = ('views', 'slug') list_editable = ('status',) - - def get_form(self, request, obj=None, **kwargs): - """Return a form with TinyMCE Widget for the selected fields.""" - form = super().get_form(request, obj, **kwargs) - for field_name in ['content', 'acknowledgement']: - if field_name in form.base_fields: - form.base_fields[field_name].widget = TinyMCE(attrs={'cols': 80, 'rows': 30, 'id': f"{field_name}_richtext_field", 'placeholder': f"Enter {field_name} here"}) - return form - + def display_authors(self, obj): """Return a comma-separated list of authors for the article.""" return ", ".join(author.user.username for author in obj.authors.all()) display_authors.short_description = 'Authors' - + def display_categories(self, obj): """Return a comma-separated list of categories for the article.""" return ", ".join(category.name for category in obj.categories.all()) display_categories.short_description = 'Categories' - + def save_model(self, request, obj, form, change): """Automatically add the logged-in user as the author when creating a new article.""" if not change: # If creating a new article @@ -43,7 +45,7 @@ def save_model(self, request, obj, form, change): obj.authors.add(author) else: super().save_model(request, obj, form, change) - + def has_change_permission(self, request, obj=None): """Check if the user has permission to change the article.""" if request.user.is_superuser: @@ -53,7 +55,7 @@ def has_change_permission(self, request, obj=None): if obj is not None and not obj.authors.filter(user=request.user).exists(): return False return True - + def has_delete_permission(self, request, obj=None): """Check if the user has permission to delete the article.""" if request.user.is_superuser: @@ -63,3 +65,5 @@ def has_delete_permission(self, request, obj=None): if obj is not None and not obj.authors.filter(user=request.user).exists(): return False return True + +admin.site.register(Article, ArticleAdmin) \ No newline at end of file diff --git a/server/apps/research/models/article.py b/server/apps/research/models/article.py index 7fd22d5..ef08f77 100644 --- a/server/apps/research/models/article.py +++ b/server/apps/research/models/article.py @@ -39,14 +39,14 @@ class Article(BaseModel): class Meta: ordering = ('-scheduled_publish_time',) - @property - def min_read(self): - # Compute reading time based on content length + def calculate_min_read(self): word_count = len(self.content.split()) words_per_minute = 300 # Average reading speed (words per minute) minutes = max(1, round(word_count / words_per_minute)) return minutes + min_read = property(calculate_min_read) + def __str__(self): return self.title diff --git a/server/apps/research/serializers/article_serializer.py b/server/apps/research/serializers/article_serializer.py index 3efc448..477edb2 100644 --- a/server/apps/research/serializers/article_serializer.py +++ b/server/apps/research/serializers/article_serializer.py @@ -9,12 +9,14 @@ class ArticleSerializer(serializers.ModelSerializer): categories = CategorySerializer(many=True) slug = serializers.ReadOnlyField() views = serializers.ReadOnlyField() + min_read = serializers.ReadOnlyField() + class Meta: model = Article fields = [ 'id', 'slug', 'title', 'authors', 'thumb', - 'categories', 'summary', 'acknowledgement', 'content', + 'categories', 'summary', 'acknowledgement', 'content', 'min_read', 'status', 'views', 'created_at', 'updated_at', 'scheduled_publish_time' ] diff --git a/server/templates/admin/base.html b/server/templates/admin/base.html index b28f080..0a4b2cb 100644 --- a/server/templates/admin/base.html +++ b/server/templates/admin/base.html @@ -3,63 +3,89 @@ {% block footer %} {{ block.super }} - {% endblock %} \ No newline at end of file