Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ server/dist

# prompts
prompts/debug

venv
7 changes: 7 additions & 0 deletions backend/authentication/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Conversation


from authentication.models import CustomUser

Expand Down Expand Up @@ -40,3 +42,8 @@ def make_inactive(self, request, queryset):


admin.site.register(CustomUser, CustomUserAdmin)

class ConversationAdmin(admin.ModelAdmin):
list_display = ('id', 'summary') # Including the new field

admin.site.register(Conversation, ConversationAdmin)
20 changes: 20 additions & 0 deletions backend/authentication/migrations/0002_conversation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.1.1 on 2024-09-07 17:29

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('authentication', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Conversation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('summary', models.TextField(blank=True, null=True)),
],
),
]
6 changes: 6 additions & 0 deletions backend/authentication/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):

def __str__(self):
return self.email
class Conversation(models.Model):
content = models.TextField()
summary = models.TextField(null=True, blank=True) # New field
class FileUpload(models.Model):
file = models.FileField(upload_to='uploads/')
uploaded_at = models.DateTimeField(auto_now_add=True)
10 changes: 10 additions & 0 deletions backend/authentication/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from rest_framework.permissions import BasePermission

class IsAdminOrReadOnly(BasePermission):
"""
Custom permission to only allow admin users to delete objects.
"""
def has_permission(self, request, view):
if request.method in ['GET', 'HEAD', 'OPTIONS']:
return True
return request.user and request.user.is_staff
12 changes: 12 additions & 0 deletions backend/authentication/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from rest_framework import serializers
from .models import Conversation, FileUpload

class ConversationSerializer(serializers.ModelSerializer):
class Meta:
model = Conversation
fields = ['id', 'content', 'summary']

class FileUploadSerializer(serializers.ModelSerializer):
class Meta:
model = FileUpload
fields = ['id', 'file', 'uploaded_at']
11 changes: 11 additions & 0 deletions backend/authentication/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Conversation
from .utils import generate_summary # Import a utility function to generate summaries

@receiver(post_save, sender=Conversation)
def generate_and_store_summary(sender, instance, **kwargs):
if kwargs.get('created', False): # this will only generate summary for new instances
summary = generate_summary(instance)
instance.summary = summary
instance.save()
10 changes: 9 additions & 1 deletion backend/authentication/urls.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
from django.urls import path

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ConversationViewSet, FileUploadViewSet
from authentication import views

router = DefaultRouter()
router.register(r'conversations', ConversationViewSet)
router.register(r'file-uploads', FileUploadViewSet)

urlpatterns = [
path("", views.auth_root_view, name="auth_root"),
path("csrf_token/", views.csrf_token, name="csrf_token"),
path("login/", views.login_view, name="login"),
path("logout/", views.logout_view, name="logout"),
path("register/", views.register_view, name="register"),
path("verify_session/", views.verify_session, name="verify_session"),
path('', include(router.urls)),

]
65 changes: 65 additions & 0 deletions backend/authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,71 @@
from rest_framework.decorators import api_view

from authentication.models import CustomUser
from rest_framework import viewsets
from rest_framework.response import Response
from .models import Conversation, FileUpload
from .serializers import ConversationSerializer, FileUploadSerializer
from .permissions import IsAdminOrReadOnly
import logging
from django.core.cache import cache
from rest_framework.response import Response

class ConversationViewSet(viewsets.ModelViewSet):
queryset = Conversation.objects.all()
serializer_class = ConversationSerializer

def list(self, request, *args, **kwargs):
cache_key = 'all_conversations'
cached_data = cache.get(cache_key)
if cached_data is None:
response = super().list(request, *args, **kwargs)
cache.set(cache_key, response.data, timeout=60*15) # Cache for 15 minutes
return Response(response.data)
return Response(cached_data)


logger = logging.getLogger(__name__)

class FileUploadViewSet(viewsets.ModelViewSet):
queryset = FileUpload.objects.all()
serializer_class = FileUploadSerializer
permission_classes = [IsAdminOrReadOnly]

def create(self, request, *args, **kwargs):
response = super().create(request, *args, **kwargs)
logger.info(f'File uploaded by {request.user} with filename {response.data["file"]}')
return response

def destroy(self, request, *args, **kwargs):
file = self.get_object()
logger.info(f'File deleted by {request.user} with filename {file.file.name}')
return super().destroy(request, *args, **kwargs)

class FileUploadViewSet(viewsets.ModelViewSet):
queryset = FileUpload.objects.all()
serializer_class = FileUploadSerializer
permission_classes = [IsAdminOrReadOnly]

def create(self, request, *args, **kwargs):
# Your file upload logic
return super().create(request, *args, **kwargs)

class ConversationViewSet(viewsets.ModelViewSet):
queryset = Conversation.objects.all()
serializer_class = ConversationSerializer

class FileUploadViewSet(viewsets.ModelViewSet):
queryset = FileUpload.objects.all()
serializer_class = FileUploadSerializer

def create(self, request, *args, **kwargs):
file = request.FILES.get('file')
if file:
# Handle file duplication and other custom logic here
# For example, check if a file with the same name already exists
if FileUpload.objects.filter(file=file.name).exists():
return Response({'error': 'File with this name already exists'}, status=400)
return super().create(request, *args, **kwargs)


@api_view(["GET"])
Expand Down
52 changes: 52 additions & 0 deletions backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Base directory of the project
BASE_DIR = Path(__file__).resolve().parent.parent
# Load environment variables from the .env file
load_dotenv(os.path.join(BASE_DIR, '.env'))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
Expand All @@ -29,6 +34,8 @@

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = os.getenv('DEBUG', 'False') == 'True'


ALLOWED_HOSTS = []

Expand All @@ -47,8 +54,22 @@
"authentication",
"chat",
"gpt",



]

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}


MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
Expand All @@ -58,8 +79,13 @@
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"corsheaders.middleware.CorsMiddleware",
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]

CORS_ALLOW_ALL_ORIGINS = True


ROOT_URLCONF = "backend.urls"

TEMPLATES = [
Expand Down Expand Up @@ -88,6 +114,10 @@
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
'USER': os.getenv('DATABASE_USER'),
'PASSWORD': os.getenv('DATABASE_PASSWORD'),
'HOST': 'localhost',
'PORT': '5432',
}
}

Expand Down Expand Up @@ -149,3 +179,25 @@
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = "None"
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'django_debug.log',
},
},
'root': {
'handlers': ['file'],
'level': 'DEBUG',
},
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}

2 changes: 2 additions & 0 deletions backend/backend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ def root_view(request):
path("gpt/", include("gpt.urls")),
path("auth/", include("authentication.urls")),
path("", root_view),
path('nested_admin/', include('nested_admin.urls')),

] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
13 changes: 13 additions & 0 deletions backend/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.test import TestCase
from .models import Conversation
from .utils import generate_summary

class ConversationModelTest(TestCase):
def setUp(self):
self.conversation = Conversation.objects.create(content="Test content")

def test_summary_generation(self):
# Assuming generate_summary sets a summary based on content
self.conversation.summary = generate_summary(self.conversation)
self.conversation.save()
self.assertEqual(self.conversation.summary, "Generated summary based on content")