diff --git a/server/apps/research/admin/__init__.py b/server/apps/research/admin/__init__.py index a2df3b1..215fac7 100644 --- a/server/apps/research/admin/__init__.py +++ b/server/apps/research/admin/__init__.py @@ -1,3 +1,4 @@ from .category_admin import CategoryAdmin from .author_admin import AuthorAdmin from .article_admin import ArticleAdmin +from .log_entry import LogEntryAdmin \ No newline at end of file diff --git a/server/apps/research/admin/log_entry.py b/server/apps/research/admin/log_entry.py new file mode 100644 index 0000000..08fc43c --- /dev/null +++ b/server/apps/research/admin/log_entry.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from django.contrib.admin.models import LogEntry +from django.utils.translation import gettext_lazy as _ + +class LogEntryAdmin(admin.ModelAdmin): + list_display = ('action_time', 'user', 'content_type', 'object_id', 'action_flag', 'change_message') + list_filter = ('action_flag', 'user', 'content_type') + search_fields = ('object_id', 'change_message') + +admin.site.register(LogEntry, LogEntryAdmin) \ No newline at end of file diff --git a/server/apps/research/migrations/0019_alter_article_status.py b/server/apps/research/migrations/0019_alter_article_status.py new file mode 100644 index 0000000..d0a51d2 --- /dev/null +++ b/server/apps/research/migrations/0019_alter_article_status.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.8 on 2024-09-02 23:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('research', '0018_alter_article_acknowledgement'), + ] + + operations = [ + migrations.AlterField( + model_name='article', + name='status', + field=models.CharField(choices=[('draft', 'Draft'), ('ready', 'Ready')], db_index=True, default='draft', max_length=10), + ), + ] diff --git a/server/apps/research/models/article.py b/server/apps/research/models/article.py index ef08f77..48225b0 100644 --- a/server/apps/research/models/article.py +++ b/server/apps/research/models/article.py @@ -26,11 +26,11 @@ class Article(BaseModel): summary = models.TextField(blank=True) acknowledgement = HTMLField(blank=True, null=True) authors = models.ManyToManyField(Author, blank=True, related_name='articles') - slug = models.SlugField(blank=True) + slug = models.SlugField(blank=True, db_index=True) categories = models.ManyToManyField(Category, blank=True, related_name='articles') thumb = models.ImageField(upload_to='images/', default=get_default_thumb, blank=True) views = models.PositiveBigIntegerField(default=0) - status = models.CharField(max_length=10, choices=options, default='draft') + status = models.CharField(max_length=10, choices=options, default='draft', db_index=True) scheduled_publish_time = models.DateTimeField(null=True, blank=True, db_index=True) objects = models.Manager() diff --git a/server/apps/research/urls.py b/server/apps/research/urls.py index 40b0bf6..a2ac07a 100644 --- a/server/apps/research/urls.py +++ b/server/apps/research/urls.py @@ -1,16 +1,15 @@ -from django.urls import path, include, re_path -from rest_framework.routers import DefaultRouter -from .views import ArticleViewSet, index +from django.urls import path, re_path, include from django.conf import settings from django.conf.urls.static import static -from django.http import HttpResponse -import requests +from django.views.generic.base import RedirectView +from rest_framework.routers import DefaultRouter +from .views import ArticleViewSet router = DefaultRouter() router.register(r'articles', ArticleViewSet, basename='article') urlpatterns = [ - path('', index, name='index'), + path('', RedirectView.as_view(url='/admin/', permanent=False)), # Redirect root to admin path('api/', include(router.urls)), # Custom URL for retrieving articles by slug or UUID @@ -18,4 +17,4 @@ # Custom URL for retrieving articles by category re_path(r'^api/articles/category/(?P[-\w]+)/$', ArticleViewSet.as_view({'get': 'retrieve_by_category'}), name='article-list-by-category'), -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/server/apps/research/views.py b/server/apps/research/views.py index 6ce5375..17fa237 100644 --- a/server/apps/research/views.py +++ b/server/apps/research/views.py @@ -4,19 +4,19 @@ from rest_framework import viewsets, status from rest_framework.response import Response import uuid +import logging from .models import Article from .permissions import ArticleUserWritePermission from .serializers import ArticleSerializer, ArticleCreateUpdateSerializer, ArticleListSerializer -def index(request): - return render(request, 'index.html') +# Set up logging +logger = logging.getLogger(__name__) class ArticleViewSet(viewsets.ModelViewSet): """API endpoint for articles.""" permission_classes = [ArticleUserWritePermission] - def get_serializer_class(self): """Return appropriate serializer class based on request method.""" if self.action == 'list': @@ -43,7 +43,10 @@ def retrieve_by_identifier(self, request, identifier=None): else: instance = Article.objects.get(slug=identifier) except Article.DoesNotExist: - return Response({'Error': 'Article does not exist'}, status=status.HTTP_404_NOT_FOUND) + return Response({'error': 'Article does not exist'}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + logger.error(f"Error retrieving article by identifier: {e}") + return Response({'error': 'An unexpected error occurred'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) instance.views = F('views') + 1 instance.save(update_fields=['views']) @@ -51,14 +54,17 @@ def retrieve_by_identifier(self, request, identifier=None): serializer = self.get_serializer(instance) return Response({'success': True, 'data': serializer.data}) - #Custom action to retrieve articles by category + # Custom action to retrieve articles by category @action(detail=False, methods=['get'], url_path=r'category/(?P[-\w]+)') def retrieve_by_category(self, request, category=None): - """Retrieve article list by category""" - instances = Article.objects.filter(categories__name=category) - serializer = self.get_serializer(instances, many=True) - return Response({'success': True, 'data': serializer.data}) - + """Retrieve article list by category.""" + try: + instances = Article.objects.filter(categories__name=category) + serializer = self.get_serializer(instances, many=True) + return Response({'success': True, 'data': serializer.data}) + except Exception as e: + logger.error(f"Error retrieving articles by category: {e}") + return Response({'error': 'An unexpected error occurred'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) def is_valid_uuid(self, value): """Check if the value is a valid UUID."""