inital creation
This commit is contained in:
166
dta_service/core/migrations/0001_initial.py
Normal file
166
dta_service/core/migrations/0001_initial.py
Normal file
@@ -0,0 +1,166 @@
|
||||
# Generated by Django 5.2.4 on 2025-07-07 14:51
|
||||
|
||||
import core.models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('email', models.EmailField(max_length=254, unique=True)),
|
||||
('first_name', models.CharField(max_length=30)),
|
||||
('last_name', models.CharField(max_length=30)),
|
||||
('user_type', models.CharField(choices=[('property_owner', 'Property Owner'), ('vendor', 'Vendor'), ('admin', 'Admin')], max_length=20)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('is_staff', models.BooleanField(default=False)),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Conversation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Property',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('address', models.CharField(max_length=200)),
|
||||
('city', models.CharField(max_length=100)),
|
||||
('state', models.CharField(max_length=2)),
|
||||
('zip_code', models.CharField(max_length=10)),
|
||||
('market_value', models.DecimalField(decimal_places=2, max_digits=12)),
|
||||
('loan_amount', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True)),
|
||||
('loan_interest_rate', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)),
|
||||
('loan_term', models.IntegerField(blank=True, null=True)),
|
||||
('loan_start_date', models.DateField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VideoCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PropertyOwner',
|
||||
fields=[
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
|
||||
('phone_number', models.CharField(blank=True, max_length=20, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Vendor',
|
||||
fields=[
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
|
||||
('business_name', models.CharField(max_length=100)),
|
||||
('business_type', models.CharField(choices=[('contractor', 'Contractor'), ('inspector', 'Inspector'), ('lender', 'Lender'), ('other', 'Other')], max_length=20)),
|
||||
('phone_number', models.CharField(blank=True, max_length=20, null=True)),
|
||||
('address', models.CharField(max_length=200)),
|
||||
('city', models.CharField(max_length=100)),
|
||||
('state', models.CharField(max_length=2)),
|
||||
('zip_code', models.CharField(max_length=10)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Message',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.TextField()),
|
||||
('attachment', models.FileField(blank=True, null=True, upload_to=core.models.message_file_path)),
|
||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||
('read', models.BooleanField(default=False)),
|
||||
('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='core.conversation')),
|
||||
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PasswordResetToken',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('token', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('expires_at', models.DateTimeField()),
|
||||
('used', models.BooleanField(default=False)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='conversation',
|
||||
name='property',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversations', to='core.property'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Video',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=200)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('link', models.URLField()),
|
||||
('duration', models.IntegerField(help_text='Duration in seconds')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='videos', to='core.videocategory')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='owner',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='properties', to='core.propertyowner'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='conversation',
|
||||
name='property_owner',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversations', to='core.propertyowner'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='conversation',
|
||||
name='vendor',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversations', to='core.vendor'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserVideoProgress',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('progress', models.IntegerField(default=0, help_text='Progress in seconds')),
|
||||
('status', models.CharField(choices=[('not_started', 'Not Started'), ('in_progress', 'In Progress'), ('completed', 'Completed')], default='not_started', max_length=20)),
|
||||
('last_watched', models.DateTimeField(auto_now=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='video_progress', to=settings.AUTH_USER_MODEL)),
|
||||
('video', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_progress', to='core.video')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('user', 'video')},
|
||||
},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='conversation',
|
||||
unique_together={('property_owner', 'vendor', 'property')},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.4 on 2025-07-09 19:42
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='conversation',
|
||||
unique_together=set(),
|
||||
),
|
||||
]
|
||||
@@ -151,8 +151,8 @@ class Conversation(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('property_owner', 'vendor', 'property')
|
||||
# class Meta:
|
||||
# unique_together = ('property_owner', 'vendor', 'property')
|
||||
|
||||
def __str__(self):
|
||||
return f"Conversation between {self.property_owner} and {self.vendor} about {self.property}"
|
||||
|
||||
@@ -106,25 +106,44 @@ class VendorSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Vendor
|
||||
fields = ['user', 'business_name', 'business_type', 'phone_number',
|
||||
'address', 'city', 'state', 'zip_code']
|
||||
'address', 'city', 'state', 'zip_code']
|
||||
|
||||
|
||||
def create(self, validated_data):
|
||||
# Extract user data
|
||||
user_data = validated_data.pop('user')
|
||||
user = User.objects.create_user(**user_data)
|
||||
|
||||
# Get or create category
|
||||
user, _ = User.objects.get_or_create(**user_data)
|
||||
|
||||
# Create video with the category
|
||||
vendor = Vendor.objects.create(user=user, **validated_data)
|
||||
return vendor
|
||||
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
user_data = validated_data.pop('user', None)
|
||||
|
||||
# Update Vendor fields
|
||||
for attr, value in validated_data.items():
|
||||
setattr(instance, attr, value)
|
||||
instance.save()
|
||||
|
||||
# Update nested User fields if provided
|
||||
if user_data:
|
||||
user = instance.user
|
||||
email = user_data.get('email', None)
|
||||
|
||||
# Only validate email uniqueness if it's being changed
|
||||
if email and email != user.email:
|
||||
if User.objects.filter(email=email).exists():
|
||||
raise serializers.ValidationError({
|
||||
'email': 'A user with this email already exists.'
|
||||
})
|
||||
|
||||
for attr, value in user_data.items():
|
||||
setattr(user, attr, value)
|
||||
user.save()
|
||||
|
||||
for attr, value in validated_data.items():
|
||||
setattr(instance, attr, value)
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
class PropertySerializer(serializers.ModelSerializer):
|
||||
@@ -148,24 +167,73 @@ class VideoSerializer(serializers.ModelSerializer):
|
||||
model = Video
|
||||
fields = ['id', 'category', 'title', 'description', 'link', 'duration', 'created_at', 'updated_at']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
def create(self, validated_data):
|
||||
# Extract category data
|
||||
category_data = validated_data.pop('category')
|
||||
|
||||
# Get or create category
|
||||
category, _ = VideoCategory.objects.get_or_create(**category_data)
|
||||
|
||||
# Create video with the category
|
||||
video = Video.objects.create(category=category, **validated_data)
|
||||
return video
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# Handle category update if provided
|
||||
category_data = validated_data.pop('category', None)
|
||||
if category_data:
|
||||
category, _ = VideoCategory.objects.get_or_create(**category_data)
|
||||
instance.category = category
|
||||
|
||||
# Update other fields
|
||||
for attr, value in validated_data.items():
|
||||
setattr(instance, attr, value)
|
||||
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
class UserVideoProgressSerializer(serializers.ModelSerializer):
|
||||
video = VideoSerializer()
|
||||
|
||||
class Meta:
|
||||
model = UserVideoProgress
|
||||
fields = ['video', 'progress', 'status', 'last_watched']
|
||||
fields = ['video', 'progress', 'status', 'last_watched', 'user']
|
||||
read_only_fields = ['status', 'last_watched']
|
||||
|
||||
def create(self, validated_data):
|
||||
# Extract video data
|
||||
video_data = validated_data.pop('video')
|
||||
|
||||
# Get or create video
|
||||
video_serializer = VideoSerializer(data=video_data)
|
||||
video_serializer.is_valid(raise_exception=True)
|
||||
video = video_serializer.save()
|
||||
user = validated_data.pop('user')
|
||||
# Create progress record
|
||||
progress = UserVideoProgress.objects.create(
|
||||
user=user,
|
||||
video=video,
|
||||
**validated_data
|
||||
)
|
||||
return progress
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# Handle video update if provided
|
||||
video_data = validated_data.pop('video', None)
|
||||
if video_data:
|
||||
video_serializer = VideoSerializer(instance.video, data=video_data, partial=True)
|
||||
video_serializer.is_valid(raise_exception=True)
|
||||
video_serializer.save()
|
||||
|
||||
# Update progress
|
||||
instance.progress = validated_data.get('progress', instance.progress)
|
||||
instance.save()
|
||||
|
||||
return instance
|
||||
|
||||
class ConversationSerializer(serializers.ModelSerializer):
|
||||
property_owner = PropertyOwnerSerializer()
|
||||
vendor = VendorSerializer()
|
||||
property = PropertySerializer()
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Conversation
|
||||
@@ -173,7 +241,7 @@ class ConversationSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
class MessageSerializer(serializers.ModelSerializer):
|
||||
sender = UserSerializer(read_only=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Message
|
||||
@@ -181,8 +249,34 @@ class MessageSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ['id', 'timestamp']
|
||||
|
||||
def create(self, validated_data):
|
||||
message = Message.objects.create(**validated_data)
|
||||
# Extract user data
|
||||
sender = validated_data.pop('sender')
|
||||
|
||||
message = Message.objects.create(sender=sender, **validated_data)
|
||||
return message
|
||||
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""
|
||||
Handle updates to message fields.
|
||||
Note: sender and conversation are typically read-only in updates
|
||||
"""
|
||||
# Update text if provided
|
||||
instance.text = validated_data.get('text', instance.text)
|
||||
|
||||
# Update read status if provided
|
||||
if 'read' in validated_data:
|
||||
instance.read = validated_data['read']
|
||||
|
||||
# Handle attachment updates (if needed)
|
||||
if 'attachment' in validated_data:
|
||||
# Delete old attachment if exists
|
||||
if instance.attachment:
|
||||
instance.attachment.delete()
|
||||
instance.attachment = validated_data['attachment']
|
||||
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
class PasswordResetRequestSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField()
|
||||
@@ -210,6 +304,7 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
|
||||
new_password2 = serializers.CharField(write_only=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
|
||||
try:
|
||||
token = PasswordResetToken.objects.get(token=attrs['token'])
|
||||
except PasswordResetToken.DoesNotExist:
|
||||
|
||||
20
dta_service/core/templates/password_reset_email.html
Normal file
20
dta_service/core/templates/password_reset_email.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Password Reset</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello {{ user.first_name }},</p>
|
||||
|
||||
<p>You're receiving this email because you requested a password reset for your account.</p>
|
||||
|
||||
<p>Please click the following link to reset your password:</p>
|
||||
|
||||
<p><a href="{{ reset_url }}">{{ reset_url }}</a></p>
|
||||
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
|
||||
<p>Thanks,<br>
|
||||
The Real Estate App Team</p>
|
||||
</body>
|
||||
</html>
|
||||
0
dta_service/core/urls/__init__.py
Normal file
0
dta_service/core/urls/__init__.py
Normal file
21
dta_service/core/urls/conversation.py
Normal file
21
dta_service/core/urls/conversation.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from django.urls import path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from core.views import ConversationViewSet, MessageViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'', ConversationViewSet, basename='conversation')
|
||||
|
||||
urlpatterns = [
|
||||
path('<int:conversation_id>/messages/', MessageViewSet.as_view({
|
||||
'get': 'list',
|
||||
'post': 'create'
|
||||
}), name='conversation-messages'),
|
||||
path('<int:conversation_id>/messages/<int:pk>/', MessageViewSet.as_view({
|
||||
'get': 'retrieve',
|
||||
'put': 'update',
|
||||
'patch': 'partial_update',
|
||||
'delete': 'destroy'
|
||||
}), name='message-detail'),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
8
dta_service/core/urls/property.py
Normal file
8
dta_service/core/urls/property.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from core.views import PropertyViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'', PropertyViewSet, basename='property')
|
||||
|
||||
urlpatterns = router.urls
|
||||
8
dta_service/core/urls/property_owner.py
Normal file
8
dta_service/core/urls/property_owner.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from core.views import PropertyOwnerViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'', PropertyOwnerViewSet, basename='property-owner')
|
||||
|
||||
urlpatterns = router.urls
|
||||
8
dta_service/core/urls/vendor.py
Normal file
8
dta_service/core/urls/vendor.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from core.views import VendorViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'', VendorViewSet, basename='vendor')
|
||||
|
||||
urlpatterns = router.urls
|
||||
10
dta_service/core/urls/video.py
Normal file
10
dta_service/core/urls/video.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.urls import path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from core.views import VideoCategoryViewSet, VideoViewSet, UserVideoProgressViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'categories', VideoCategoryViewSet, basename='video-category')
|
||||
router.register(r'', VideoViewSet, basename='video')
|
||||
router.register(r'progress', UserVideoProgressViewSet, basename='video-progress')
|
||||
|
||||
urlpatterns = router.urls
|
||||
@@ -32,7 +32,8 @@ class UserRegisterView(generics.CreateAPIView):
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
||||
class LogoutView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
authentication_classes = ()
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
@@ -118,10 +119,11 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
filterset_fields = ['category']
|
||||
|
||||
class UserVideoProgressViewSet(viewsets.ModelViewSet):
|
||||
queryset = UserVideoProgress.objects.all()
|
||||
serializer_class = UserVideoProgressSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self):
|
||||
return UserVideoProgress.objects.filter(user=self.request.user)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
|
||||
@@ -11,6 +11,10 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
from datetime import timedelta
|
||||
from decouple import config
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
@@ -25,7 +29,7 @@ SECRET_KEY = 'django-insecure-d!3*0+eki$pqv1n^)_v6&t^o@+-x2-i+8lzf5f%itsnngm3@y7
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
@@ -37,6 +41,16 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
# Third-party apps
|
||||
'rest_framework',
|
||||
'rest_framework_simplejwt',
|
||||
'rest_framework_simplejwt.token_blacklist',
|
||||
'channels',
|
||||
'django_filters',
|
||||
|
||||
# Local apps
|
||||
'core',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -58,6 +72,7 @@ TEMPLATES = [
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
@@ -67,6 +82,7 @@ TEMPLATES = [
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'dta_service.wsgi.application'
|
||||
ASGI_APPLICATION = 'config.asgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
@@ -108,15 +124,89 @@ TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
FRONTEND_URL = config("FRONTEND_URL")
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
# Static files
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||
|
||||
# Media files
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
# Custom user model
|
||||
AUTH_USER_MODEL = 'core.User'
|
||||
|
||||
# REST Framework
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
),
|
||||
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
||||
}
|
||||
|
||||
# JWT Settings
|
||||
SIMPLE_JWT = {
|
||||
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
|
||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
||||
'ROTATE_REFRESH_TOKENS': True,
|
||||
'BLACKLIST_AFTER_ROTATION': True,
|
||||
'UPDATE_LAST_LOGIN': False,
|
||||
|
||||
'ALGORITHM': 'HS256',
|
||||
'SIGNING_KEY': SECRET_KEY,
|
||||
'VERIFYING_KEY': None,
|
||||
'AUDIENCE': None,
|
||||
'ISSUER': None,
|
||||
'JWK_URL': None,
|
||||
'LEEWAY': 0,
|
||||
|
||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
|
||||
'USER_ID_FIELD': 'id',
|
||||
'USER_ID_CLAIM': 'user_id',
|
||||
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
|
||||
|
||||
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
|
||||
'TOKEN_TYPE_CLAIM': 'token_type',
|
||||
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
|
||||
|
||||
'JTI_CLAIM': 'jti',
|
||||
|
||||
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
|
||||
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
|
||||
}
|
||||
|
||||
# Email settings
|
||||
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
# EMAIL_HOST = config('SMTP2GO_HOST')
|
||||
# EMAIL_PORT = config('SMTP2GO_PORT', cast=int)
|
||||
# EMAIL_USE_TLS = True
|
||||
# EMAIL_HOST_USER = config('SMTP2GO_USERNAME')
|
||||
# EMAIL_HOST_PASSWORD = config('SMTP2GO_PASSWORD')
|
||||
# DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL')
|
||||
|
||||
|
||||
# CHANNEL_LAYERS = {
|
||||
# 'default': {
|
||||
# 'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||||
# 'CONFIG': {
|
||||
# "hosts": [(config('REDIS_HOST'), config('REDIS_PORT', cast=int))],
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
TEST_DISCOVER_PATTERN = "test_*.py"
|
||||
@@ -21,8 +21,17 @@ from rest_framework_simplejwt.views import (
|
||||
)
|
||||
from core.views import (
|
||||
CustomTokenObtainPairView, LogoutView,
|
||||
PasswordResetRequestView, PasswordResetConfirmView
|
||||
PasswordResetRequestView, PasswordResetConfirmView,
|
||||
UserRegisterView
|
||||
)
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from core.views import VideoCategoryViewSet, VideoViewSet, UserVideoProgressViewSet, VendorViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'categories', VideoCategoryViewSet, basename='video-category')
|
||||
router.register(r'', VideoViewSet, basename='video')
|
||||
router.register(r'progress', UserVideoProgressViewSet, basename='video-progress')
|
||||
router.register(r'', VendorViewSet, basename='vendor')
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
|
||||
4
dta_service/tests/__init__.py
Normal file
4
dta_service/tests/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# core/tests/__init__.py
|
||||
from .test_models import *
|
||||
from .test_serializers import *
|
||||
from .test_views import *
|
||||
328
dta_service/tests/test_models.py
Normal file
328
dta_service/tests/test_models.py
Normal file
@@ -0,0 +1,328 @@
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
from core.models import (
|
||||
PropertyOwner, Vendor, Property, VideoCategory, Video,
|
||||
UserVideoProgress, Conversation, Message, PasswordResetToken
|
||||
)
|
||||
from datetime import datetime, timedelta
|
||||
from django.utils import timezone
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class UserModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='test@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
|
||||
def test_user_creation(self):
|
||||
self.assertEqual(self.user.email, 'test@example.com')
|
||||
self.assertEqual(self.user.first_name, 'Test')
|
||||
self.assertEqual(self.user.last_name, 'User')
|
||||
self.assertEqual(self.user.user_type, 'property_owner')
|
||||
self.assertTrue(self.user.check_password('testpass123'))
|
||||
|
||||
def test_user_str(self):
|
||||
self.assertEqual(str(self.user), 'test@example.com')
|
||||
|
||||
class PropertyOwnerModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(
|
||||
user=self.user,
|
||||
phone_number='1234567890'
|
||||
)
|
||||
|
||||
def test_property_owner_creation(self):
|
||||
self.assertEqual(self.owner.user, self.user)
|
||||
self.assertEqual(self.owner.phone_number, '1234567890')
|
||||
|
||||
def test_property_owner_str(self):
|
||||
self.assertEqual(str(self.owner), 'Property Owner')
|
||||
|
||||
class VendorModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor',
|
||||
phone_number='1234567890',
|
||||
address='123 Test St',
|
||||
city='Testville',
|
||||
state='TS',
|
||||
zip_code='12345'
|
||||
)
|
||||
|
||||
def test_vendor_creation(self):
|
||||
self.assertEqual(self.vendor.user, self.user)
|
||||
self.assertEqual(self.vendor.business_name, 'Test Vendor')
|
||||
self.assertEqual(self.vendor.business_type, 'contractor')
|
||||
self.assertEqual(self.vendor.phone_number, '1234567890')
|
||||
self.assertEqual(self.vendor.address, '123 Test St')
|
||||
self.assertEqual(self.vendor.city, 'Testville')
|
||||
self.assertEqual(self.vendor.state, 'TS')
|
||||
self.assertEqual(self.vendor.zip_code, '12345')
|
||||
|
||||
def test_vendor_str(self):
|
||||
self.assertEqual(str(self.vendor), 'Test Vendor')
|
||||
|
||||
class PropertyModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.user)
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00,
|
||||
loan_amount=400000.00,
|
||||
loan_interest_rate=3.5,
|
||||
loan_term=30,
|
||||
loan_start_date='2020-01-01'
|
||||
)
|
||||
|
||||
def test_property_creation(self):
|
||||
self.assertEqual(self.property.owner, self.owner)
|
||||
self.assertEqual(self.property.address, '123 Main St')
|
||||
self.assertEqual(self.property.city, 'Anytown')
|
||||
self.assertEqual(self.property.state, 'CA')
|
||||
self.assertEqual(self.property.zip_code, '90210')
|
||||
self.assertEqual(self.property.market_value, 500000.00)
|
||||
self.assertEqual(self.property.loan_amount, 400000.00)
|
||||
self.assertEqual(self.property.loan_interest_rate, 3.5)
|
||||
self.assertEqual(self.property.loan_term, 30)
|
||||
self.assertEqual(str(self.property.loan_start_date), '2020-01-01')
|
||||
|
||||
def test_property_str(self):
|
||||
self.assertEqual(str(self.property), '123 Main St, Anytown, CA 90210')
|
||||
|
||||
class VideoModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.category = VideoCategory.objects.create(
|
||||
name='Test Category',
|
||||
description='Test Description'
|
||||
)
|
||||
self.video = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video',
|
||||
description='Test Video Description',
|
||||
link='https://example.com/video',
|
||||
duration=300
|
||||
)
|
||||
|
||||
def test_video_creation(self):
|
||||
self.assertEqual(self.video.category, self.category)
|
||||
self.assertEqual(self.video.title, 'Test Video')
|
||||
self.assertEqual(self.video.description, 'Test Video Description')
|
||||
self.assertEqual(self.video.link, 'https://example.com/video')
|
||||
self.assertEqual(self.video.duration, 300)
|
||||
|
||||
def test_video_str(self):
|
||||
self.assertEqual(str(self.video), 'Test Video')
|
||||
|
||||
class UserVideoProgressModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.category = VideoCategory.objects.create(name='Test Category')
|
||||
self.video = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video',
|
||||
link='https://example.com/video',
|
||||
duration=300
|
||||
)
|
||||
self.progress = UserVideoProgress.objects.create(
|
||||
user=self.user,
|
||||
video=self.video,
|
||||
progress=150
|
||||
)
|
||||
|
||||
def test_progress_creation(self):
|
||||
self.assertEqual(self.progress.user, self.user)
|
||||
self.assertEqual(self.progress.video, self.video)
|
||||
self.assertEqual(self.progress.progress, 150)
|
||||
self.assertEqual(self.progress.status, 'in_progress')
|
||||
|
||||
def test_status_update(self):
|
||||
# Test not started
|
||||
self.progress.progress = 0
|
||||
self.progress.save()
|
||||
self.assertEqual(self.progress.status, 'not_started')
|
||||
|
||||
# Test completed
|
||||
self.progress.progress = 300
|
||||
self.progress.save()
|
||||
self.assertEqual(self.progress.status, 'completed')
|
||||
|
||||
# Test in progress
|
||||
self.progress.progress = 150
|
||||
self.progress.save()
|
||||
self.assertEqual(self.progress.status, 'in_progress')
|
||||
|
||||
def test_progress_str(self):
|
||||
self.assertEqual(str(self.progress), 'user@example.com - Test Video - in_progress')
|
||||
|
||||
class ConversationModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
|
||||
self.vendor_user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.vendor_user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor'
|
||||
)
|
||||
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
self.conversation = Conversation.objects.create(
|
||||
property_owner=self.owner,
|
||||
vendor=self.vendor,
|
||||
property=self.property
|
||||
)
|
||||
|
||||
def test_conversation_creation(self):
|
||||
self.assertEqual(self.conversation.property_owner, self.owner)
|
||||
self.assertEqual(self.conversation.vendor, self.vendor)
|
||||
self.assertEqual(self.conversation.property, self.property)
|
||||
|
||||
def test_conversation_str(self):
|
||||
expected_str = f"Conversation between {self.owner} and {self.vendor} about {self.property}"
|
||||
self.assertEqual(str(self.conversation), expected_str)
|
||||
|
||||
class MessageModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
|
||||
self.vendor_user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.vendor_user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor'
|
||||
)
|
||||
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
self.conversation = Conversation.objects.create(
|
||||
property_owner=self.owner,
|
||||
vendor=self.vendor,
|
||||
property=self.property
|
||||
)
|
||||
|
||||
self.message = Message.objects.create(
|
||||
conversation=self.conversation,
|
||||
sender=self.owner_user,
|
||||
text='Test message'
|
||||
)
|
||||
|
||||
def test_message_creation(self):
|
||||
self.assertEqual(self.message.conversation, self.conversation)
|
||||
self.assertEqual(self.message.sender, self.owner_user)
|
||||
self.assertEqual(self.message.text, 'Test message')
|
||||
self.assertFalse(self.message.read)
|
||||
|
||||
def test_message_str(self):
|
||||
expected_str = f"Message from {self.owner_user} in {self.conversation}"
|
||||
self.assertEqual(str(self.message), expected_str)
|
||||
|
||||
class PasswordResetTokenModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.token = PasswordResetToken.objects.create(
|
||||
user=self.user,
|
||||
expires_at=timezone.now() + timedelta(hours=24)
|
||||
)
|
||||
|
||||
def test_token_creation(self):
|
||||
self.assertEqual(self.token.user, self.user)
|
||||
self.assertFalse(self.token.used)
|
||||
self.assertTrue(self.token.is_valid())
|
||||
|
||||
def test_token_invalid_after_use(self):
|
||||
self.token.used = True
|
||||
self.token.save()
|
||||
self.assertFalse(self.token.is_valid())
|
||||
|
||||
def test_token_invalid_after_expiry(self):
|
||||
self.token.expires_at = timezone.now() - timedelta(hours=1)
|
||||
self.token.save()
|
||||
self.assertFalse(self.token.is_valid())
|
||||
|
||||
def test_token_str(self):
|
||||
self.assertEqual(str(self.token), f"Password reset token for {self.user.email}")
|
||||
511
dta_service/tests/test_serializers.py
Normal file
511
dta_service/tests/test_serializers.py
Normal file
@@ -0,0 +1,511 @@
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from core.serializers import (
|
||||
UserRegisterSerializer, PropertyOwnerSerializer, VendorSerializer,
|
||||
PropertySerializer, VideoSerializer, UserVideoProgressSerializer,
|
||||
ConversationSerializer, MessageSerializer, PasswordResetRequestSerializer,
|
||||
PasswordResetConfirmSerializer
|
||||
)
|
||||
from core.models import (
|
||||
PropertyOwner, Vendor, Property, VideoCategory, Video,
|
||||
UserVideoProgress, Conversation, Message, PasswordResetToken
|
||||
)
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class UserRegisterSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.valid_data = {
|
||||
'email': 'test@example.com',
|
||||
'first_name': 'Test',
|
||||
'last_name': 'User',
|
||||
'user_type': 'property_owner',
|
||||
'password': 'testpass123',
|
||||
'password2': 'testpass123'
|
||||
}
|
||||
|
||||
def test_valid_serializer(self):
|
||||
serializer = UserRegisterSerializer(data=self.valid_data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
user = serializer.save()
|
||||
self.assertEqual(user.email, 'test@example.com')
|
||||
self.assertEqual(user.first_name, 'Test')
|
||||
self.assertEqual(user.last_name, 'User')
|
||||
self.assertEqual(user.user_type, 'property_owner')
|
||||
|
||||
def test_password_mismatch(self):
|
||||
invalid_data = self.valid_data.copy()
|
||||
invalid_data['password2'] = 'differentpass'
|
||||
serializer = UserRegisterSerializer(data=invalid_data)
|
||||
with self.assertRaises(ValidationError):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
class PropertyOwnerSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user_data = {
|
||||
'email': 'owner@example.com',
|
||||
'first_name': 'Property',
|
||||
'last_name': 'Owner',
|
||||
'user_type': 'property_owner',
|
||||
'password': 'testpass123'
|
||||
}
|
||||
self.owner_data = {
|
||||
'user': self.user_data,
|
||||
'phone_number': '1234567890'
|
||||
}
|
||||
|
||||
def test_create_property_owner(self):
|
||||
serializer = PropertyOwnerSerializer(data=self.owner_data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
owner = serializer.save()
|
||||
self.assertEqual(owner.user.email, 'owner@example.com')
|
||||
self.assertEqual(owner.phone_number, '1234567890')
|
||||
|
||||
def test_update_property_owner(self):
|
||||
user = User.objects.create_user(**self.user_data)
|
||||
owner = PropertyOwner.objects.create(user=user, phone_number='1234567890')
|
||||
|
||||
update_data = {
|
||||
'user': {
|
||||
'first_name': 'NewName',
|
||||
'last_name': 'NewLast',
|
||||
'email': 'newowner@example.com'
|
||||
},
|
||||
'phone_number': '9876543210'
|
||||
}
|
||||
|
||||
serializer = PropertyOwnerSerializer(instance=owner, data=update_data, partial=True)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
updated_owner = serializer.save()
|
||||
|
||||
self.assertEqual(updated_owner.user.first_name, 'NewName')
|
||||
self.assertEqual(updated_owner.user.last_name, 'NewLast')
|
||||
self.assertEqual(updated_owner.phone_number, '9876543210')
|
||||
|
||||
class VendorSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user_data = {
|
||||
'email': 'vendor@example.com',
|
||||
'first_name': 'Vendor',
|
||||
'last_name': 'User',
|
||||
'user_type': 'vendor',
|
||||
'password': 'testpass123'
|
||||
}
|
||||
self.vendor_data = {
|
||||
'user': self.user_data,
|
||||
'business_name': 'Test Vendor',
|
||||
'business_type': 'contractor',
|
||||
'phone_number': '1234567890',
|
||||
'address': '123 Test St',
|
||||
'city': 'Testville',
|
||||
'state': 'TS',
|
||||
'zip_code': '12345'
|
||||
}
|
||||
|
||||
def test_create_vendor(self):
|
||||
serializer = VendorSerializer(data=self.vendor_data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
vendor = serializer.save()
|
||||
self.assertEqual(vendor.user.email, 'vendor@example.com')
|
||||
self.assertEqual(vendor.business_name, 'Test Vendor')
|
||||
self.assertEqual(vendor.business_type, 'contractor')
|
||||
self.assertEqual(vendor.phone_number, '1234567890')
|
||||
self.assertEqual(vendor.address, '123 Test St')
|
||||
self.assertEqual(vendor.city, 'Testville')
|
||||
self.assertEqual(vendor.state, 'TS')
|
||||
self.assertEqual(vendor.zip_code, '12345')
|
||||
|
||||
def test_update_vendor(self):
|
||||
user = User.objects.create_user(**self.user_data)
|
||||
vendor = Vendor.objects.create(
|
||||
user=user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor',
|
||||
phone_number='1234567890',
|
||||
address='123 Test St',
|
||||
city='Testville',
|
||||
state='TS',
|
||||
zip_code='12345'
|
||||
)
|
||||
|
||||
update_data = {
|
||||
'user': {
|
||||
'first_name': 'NewVendor',
|
||||
'last_name': 'NewUser',
|
||||
'email': 'newvendor@example.com'
|
||||
},
|
||||
'business_name': 'Updated Vendor',
|
||||
'phone_number': '9876543210'
|
||||
}
|
||||
|
||||
serializer = VendorSerializer(instance=vendor, data=update_data, partial=True)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
updated_vendor = serializer.save()
|
||||
|
||||
self.assertEqual(updated_vendor.user.first_name, 'NewVendor')
|
||||
self.assertEqual(updated_vendor.user.last_name, 'NewUser')
|
||||
self.assertEqual(updated_vendor.business_name, 'Updated Vendor')
|
||||
self.assertEqual(updated_vendor.phone_number, '9876543210')
|
||||
|
||||
class PropertySerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.user)
|
||||
self.property_data = {
|
||||
'owner': self.owner.pk,
|
||||
'address': '123 Main St',
|
||||
'city': 'Anytown',
|
||||
'state': 'CA',
|
||||
'zip_code': '90210',
|
||||
'market_value': '500000.00',
|
||||
'loan_amount': '400000.00',
|
||||
'loan_interest_rate': '3.50',
|
||||
'loan_term': 30,
|
||||
'loan_start_date': '2020-01-01'
|
||||
}
|
||||
|
||||
def test_create_property(self):
|
||||
serializer = PropertySerializer(data=self.property_data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
property = serializer.save()
|
||||
self.assertEqual(property.owner, self.owner)
|
||||
self.assertEqual(property.address, '123 Main St')
|
||||
self.assertEqual(property.city, 'Anytown')
|
||||
self.assertEqual(property.state, 'CA')
|
||||
self.assertEqual(property.zip_code, '90210')
|
||||
self.assertEqual(str(property.market_value), '500000.00')
|
||||
self.assertEqual(str(property.loan_amount), '400000.00')
|
||||
self.assertEqual(str(property.loan_interest_rate), '3.50')
|
||||
self.assertEqual(property.loan_term, 30)
|
||||
self.assertEqual(str(property.loan_start_date), '2020-01-01')
|
||||
|
||||
def test_update_property(self):
|
||||
property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
update_data = {
|
||||
'address': '456 New St',
|
||||
'city': 'Newtown',
|
||||
'state': 'NY',
|
||||
'zip_code': '10001',
|
||||
'market_value': '600000.00'
|
||||
}
|
||||
|
||||
serializer = PropertySerializer(instance=property, data=update_data, partial=True)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
updated_property = serializer.save()
|
||||
|
||||
self.assertEqual(updated_property.address, '456 New St')
|
||||
self.assertEqual(updated_property.city, 'Newtown')
|
||||
self.assertEqual(updated_property.state, 'NY')
|
||||
self.assertEqual(updated_property.zip_code, '10001')
|
||||
self.assertEqual(str(updated_property.market_value), '600000.00')
|
||||
|
||||
class VideoSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.category = VideoCategory.objects.create(
|
||||
name='Test Category',
|
||||
description='Test Description'
|
||||
)
|
||||
self.video_data = {
|
||||
'category': {
|
||||
'id': self.category.id,
|
||||
'name': self.category.name,
|
||||
'description': self.category.description
|
||||
},
|
||||
'title': 'Test Video',
|
||||
'description': 'Test Video Description',
|
||||
'link': 'https://example.com/video',
|
||||
'duration': 300
|
||||
}
|
||||
|
||||
def test_video_serializer(self):
|
||||
serializer = VideoSerializer(data=self.video_data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
video = serializer.save()
|
||||
self.assertEqual(video.category, self.category)
|
||||
self.assertEqual(video.title, 'Test Video')
|
||||
self.assertEqual(video.description, 'Test Video Description')
|
||||
self.assertEqual(video.link, 'https://example.com/video')
|
||||
self.assertEqual(video.duration, 300)
|
||||
|
||||
class UserVideoProgressSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.category = VideoCategory.objects.create(name='Test Category')
|
||||
self.video = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video',
|
||||
link='https://example.com/video',
|
||||
duration=300
|
||||
)
|
||||
self.progress_data = {
|
||||
'video': {
|
||||
'id': self.video.id,
|
||||
'title': self.video.title,
|
||||
'link': self.video.link,
|
||||
'duration': self.video.duration,
|
||||
'category': {
|
||||
'id': self.category.id,
|
||||
'name': self.category.name
|
||||
}
|
||||
},
|
||||
'user': self.user.pk,
|
||||
'progress': 150
|
||||
}
|
||||
|
||||
def test_progress_serializer(self):
|
||||
serializer = UserVideoProgressSerializer(data=self.progress_data)
|
||||
|
||||
self.assertTrue(serializer.is_valid())
|
||||
progress = serializer.save(user=self.user)
|
||||
self.assertEqual(progress.user, self.user)
|
||||
self.assertEqual(progress.video.title, self.video.title)
|
||||
self.assertEqual(progress.video.category.name, self.video.category.name)
|
||||
self.assertEqual(progress.progress, 150)
|
||||
self.assertEqual(progress.status, 'in_progress')
|
||||
|
||||
def test_many_progress_serializer(self):
|
||||
categories = [VideoCategory.objects.create(name='Category One'),
|
||||
VideoCategory.objects.create(name='Category Two')]
|
||||
|
||||
videos = [
|
||||
Video.objects.create(
|
||||
category=categories[0],
|
||||
title='Test Video 1',
|
||||
link='https://example.com/video1',
|
||||
duration=300
|
||||
),
|
||||
Video.objects.create(
|
||||
category=categories[0],
|
||||
title='Test Video 2',
|
||||
link='https://example.com/video2',
|
||||
duration=300
|
||||
),
|
||||
Video.objects.create(
|
||||
category=categories[0],
|
||||
title='Test Video 3',
|
||||
link='https://example.com/video3',
|
||||
duration=300
|
||||
),
|
||||
Video.objects.create(
|
||||
category=categories[1],
|
||||
title='Test Video 4',
|
||||
link='https://example.com/video4',
|
||||
duration=300
|
||||
)
|
||||
]
|
||||
|
||||
progress_data = [
|
||||
UserVideoProgress.objects.create(
|
||||
video=videos[0],
|
||||
user=self.user,
|
||||
progress=100
|
||||
),
|
||||
UserVideoProgress.objects.create(
|
||||
video=videos[1],
|
||||
user=self.user,
|
||||
progress=30
|
||||
),
|
||||
UserVideoProgress.objects.create(
|
||||
video=videos[2],
|
||||
user=self.user,
|
||||
progress=0
|
||||
),
|
||||
UserVideoProgress.objects.create(
|
||||
video=videos[3],
|
||||
user=self.user,
|
||||
progress=0
|
||||
),
|
||||
]
|
||||
|
||||
serializer = UserVideoProgressSerializer(UserVideoProgress.objects.filter(user=self.user), many=True)
|
||||
self.assertEqual(len(serializer.data), len(progress_data))
|
||||
for i in range(len(serializer.data)):
|
||||
self.assertEqual(serializer.data[i]['video']['title'], progress_data[i].video.title)
|
||||
self.assertEqual(serializer.data[i]['video']['description'], progress_data[i].video.description)
|
||||
self.assertEqual(serializer.data[i]['video']['link'], progress_data[i].video.link)
|
||||
self.assertEqual(serializer.data[i]['video']['duration'], progress_data[i].video.duration)
|
||||
|
||||
|
||||
|
||||
class ConversationSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
|
||||
self.vendor_user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.vendor_user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor'
|
||||
)
|
||||
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
self.conversation_data = {
|
||||
'property_owner': self.owner.pk,
|
||||
'vendor': self.vendor.pk,
|
||||
'property': self.property.pk
|
||||
}
|
||||
|
||||
def test_conversation_serializer(self):
|
||||
serializer = ConversationSerializer(data=self.conversation_data)
|
||||
self.assertTrue(serializer.is_valid(), serializer.errors)
|
||||
conversation = serializer.save()
|
||||
self.assertEqual(conversation.property_owner, self.owner)
|
||||
self.assertEqual(conversation.vendor, self.vendor)
|
||||
self.assertEqual(conversation.property, self.property)
|
||||
|
||||
class MessageSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
|
||||
self.vendor_user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.vendor_user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor'
|
||||
)
|
||||
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
self.conversation = Conversation.objects.create(
|
||||
property_owner=self.owner,
|
||||
vendor=self.vendor,
|
||||
property=self.property
|
||||
)
|
||||
|
||||
self.message_data = {
|
||||
'text': 'Test message'
|
||||
}
|
||||
|
||||
def test_message_serializer(self):
|
||||
|
||||
context = {'sender': self.owner_user.pk, 'conversation': self.conversation.pk, 'text': 'Test message'}
|
||||
serializer = MessageSerializer(data=context)
|
||||
self.assertTrue(serializer.is_valid(), serializer.errors)
|
||||
|
||||
message = serializer.save()
|
||||
self.assertEqual(message.conversation, self.conversation)
|
||||
self.assertEqual(message.sender, self.owner_user)
|
||||
self.assertEqual(message.text, 'Test message')
|
||||
self.assertFalse(message.read)
|
||||
|
||||
class PasswordResetRequestSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.valid_data = {'email': 'user@example.com'}
|
||||
self.invalid_data = {'email': 'nonexistent@example.com'}
|
||||
|
||||
def test_valid_email(self):
|
||||
serializer = PasswordResetRequestSerializer(data=self.valid_data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
|
||||
def test_invalid_email(self):
|
||||
serializer = PasswordResetRequestSerializer(data=self.invalid_data)
|
||||
with self.assertRaises(ValidationError):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
class PasswordResetConfirmSerializerTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.token = uuid.uuid4()
|
||||
self.valid_data = {
|
||||
'token': self.token,
|
||||
'new_password': 'newpass123',
|
||||
'new_password2': 'newpass123'
|
||||
}
|
||||
self.mismatch_data = {
|
||||
'token': self.token,
|
||||
'new_password': 'newpass123',
|
||||
'new_password2': 'differentpass'
|
||||
}
|
||||
|
||||
def test_valid_password_reset(self):
|
||||
PasswordResetToken.objects.create(
|
||||
user=self.user,
|
||||
token=self.token,
|
||||
expires_at=datetime.now() + timedelta(hours=24)
|
||||
)
|
||||
serializer = PasswordResetConfirmSerializer(data=self.valid_data)
|
||||
|
||||
self.assertTrue(serializer.is_valid())
|
||||
|
||||
def test_password_mismatch(self):
|
||||
serializer = PasswordResetConfirmSerializer(data=self.mismatch_data)
|
||||
with self.assertRaises(ValidationError):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
588
dta_service/tests/test_views.py
Normal file
588
dta_service/tests/test_views.py
Normal file
@@ -0,0 +1,588 @@
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework import status
|
||||
from django.contrib.auth import get_user_model
|
||||
from core.models import (
|
||||
PropertyOwner, Vendor, Property, VideoCategory, Video,
|
||||
UserVideoProgress, Conversation, Message, PasswordResetToken
|
||||
)
|
||||
from datetime import datetime, timedelta
|
||||
from django.utils import timezone
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class AuthenticationTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(
|
||||
email='test@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.login_url = reverse('token_obtain_pair')
|
||||
self.refresh_url = reverse('token_refresh')
|
||||
self.logout_url = reverse('logout')
|
||||
self.register_url = reverse('register')
|
||||
self.password_reset_url = reverse('password_reset')
|
||||
self.password_reset_confirm_url = reverse('password_reset_confirm')
|
||||
|
||||
def test_user_login(self):
|
||||
data = {
|
||||
'email': 'test@example.com',
|
||||
'password': 'testpass123'
|
||||
}
|
||||
response = self.client.post(self.login_url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('access', response.data)
|
||||
self.assertIn('refresh', response.data)
|
||||
self.assertIn('user', response.data)
|
||||
|
||||
def test_user_login_invalid_credentials(self):
|
||||
data = {
|
||||
'email': 'test@example.com',
|
||||
'password': 'wrongpassword'
|
||||
}
|
||||
response = self.client.post(self.login_url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_token_refresh(self):
|
||||
# First login to get refresh token
|
||||
login_data = {
|
||||
'email': 'test@example.com',
|
||||
'password': 'testpass123'
|
||||
}
|
||||
login_response = self.client.post(self.login_url, login_data, format='json')
|
||||
refresh_token = login_response.data['refresh']
|
||||
|
||||
# Now refresh the token
|
||||
refresh_data = {
|
||||
'refresh': refresh_token
|
||||
}
|
||||
response = self.client.post(self.refresh_url, refresh_data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('access', response.data)
|
||||
|
||||
def test_user_logout(self):
|
||||
# First login to get tokens
|
||||
login_data = {
|
||||
'email': 'test@example.com',
|
||||
'password': 'testpass123'
|
||||
}
|
||||
login_response = self.client.post(self.login_url, login_data, format='json')
|
||||
self.assertEqual(login_response.status_code, status.HTTP_200_OK, login_response.text)
|
||||
|
||||
refresh_token = login_response.data['refresh']
|
||||
|
||||
# Now logout
|
||||
logout_data = {
|
||||
'refresh_token': refresh_token
|
||||
}
|
||||
response = self.client.post(self.logout_url, logout_data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_205_RESET_CONTENT, response.text)
|
||||
|
||||
def test_user_registration(self):
|
||||
data = {
|
||||
'email': 'newuser@example.com',
|
||||
'first_name': 'New',
|
||||
'last_name': 'User',
|
||||
'user_type': 'vendor',
|
||||
'password': 'newpass123',
|
||||
'password2': 'newpass123'
|
||||
}
|
||||
response = self.client.post(self.register_url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertTrue(User.objects.filter(email='newuser@example.com').exists())
|
||||
|
||||
def test_password_reset_request(self):
|
||||
data = {
|
||||
'email': 'test@example.com'
|
||||
}
|
||||
response = self.client.post(self.password_reset_url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(PasswordResetToken.objects.filter(user=self.user).exists())
|
||||
|
||||
def test_password_reset_confirm(self):
|
||||
# First create a reset token
|
||||
expires_at = timezone.now() + timedelta(hours=24)
|
||||
token = PasswordResetToken.objects.create(
|
||||
user=self.user,
|
||||
expires_at=expires_at
|
||||
)
|
||||
|
||||
data = {
|
||||
'token': str(token.token),
|
||||
'new_password': 'newpass123',
|
||||
'new_password2': 'newpass123'
|
||||
}
|
||||
response = self.client.post(self.password_reset_confirm_url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Verify password was changed
|
||||
self.user.refresh_from_db()
|
||||
self.assertTrue(self.user.check_password('newpass123'))
|
||||
|
||||
# Verify token was marked as used
|
||||
token.refresh_from_db()
|
||||
self.assertTrue(token.used)
|
||||
|
||||
class PropertyOwnerViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.user, phone_number='1234567890')
|
||||
self.other_user = User.objects.create_user(
|
||||
email='other@example.com',
|
||||
first_name='Other',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.other_owner = PropertyOwner.objects.create(user=self.other_user)
|
||||
self.url = reverse('property-owner-list')
|
||||
|
||||
# Authenticate
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
def test_get_property_owners(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 2) # Both owners should be visible
|
||||
|
||||
def test_create_property_owner(self):
|
||||
data = {
|
||||
'user': {
|
||||
'email': 'newowner@example.com',
|
||||
'first_name': 'New',
|
||||
'last_name': 'Owner',
|
||||
'user_type': 'property_owner',
|
||||
'password': 'testpass123'
|
||||
},
|
||||
'phone_number': '9876543210'
|
||||
}
|
||||
response = self.client.post(self.url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.text)
|
||||
self.assertTrue(PropertyOwner.objects.filter(user__email='newowner@example.com').exists())
|
||||
|
||||
def test_update_property_owner(self):
|
||||
url = f"{self.url}{self.owner.pk}/"
|
||||
data = {
|
||||
'user': {
|
||||
'first_name': 'Updated',
|
||||
'last_name': 'Owner',
|
||||
'email': 'new_email@email.com',
|
||||
'user_type': 'property_owner'
|
||||
},
|
||||
'phone_number': '9999999999'
|
||||
}
|
||||
response = self.client.put(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK, response.text)
|
||||
self.owner.refresh_from_db()
|
||||
self.assertEqual(self.owner.user.first_name, 'Updated')
|
||||
self.assertEqual(self.owner.phone_number, '9999999999')
|
||||
|
||||
class VendorViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor',
|
||||
phone_number='1234567890',
|
||||
address='123 Test St',
|
||||
city='Testville',
|
||||
state='TS',
|
||||
zip_code='12345'
|
||||
)
|
||||
self.url = reverse('vendor-list')
|
||||
|
||||
# Authenticate
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
def test_get_vendors(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
def test_create_vendor(self):
|
||||
data = {
|
||||
'user': {
|
||||
'email': 'newvendor@example.com',
|
||||
'first_name': 'New',
|
||||
'last_name': 'Vendor',
|
||||
'user_type': 'vendor',
|
||||
'password': 'testpass123'
|
||||
},
|
||||
'business_name': 'New Vendor',
|
||||
'business_type': 'inspector',
|
||||
'phone_number': '9876543210',
|
||||
'address': '456 New St',
|
||||
'city': 'Newtown',
|
||||
'state': 'NS',
|
||||
'zip_code': '54321'
|
||||
}
|
||||
response = self.client.post(self.url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertTrue(Vendor.objects.filter(business_name='New Vendor').exists())
|
||||
|
||||
def test_update_vendor(self):
|
||||
url = f"{self.url}{self.vendor.pk}/"
|
||||
data = {
|
||||
'user': {
|
||||
'first_name': 'Updated',
|
||||
'last_name': 'Vendor',
|
||||
},
|
||||
'business_name': 'Updated Vendor',
|
||||
'phone_number': '9999999999'
|
||||
}
|
||||
response = self.client.patch(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK, response.text)
|
||||
self.vendor.refresh_from_db()
|
||||
self.assertEqual(self.vendor.user.first_name, 'Updated')
|
||||
self.assertEqual(self.vendor.business_name, 'Updated Vendor')
|
||||
self.assertEqual(self.vendor.phone_number, '9999999999')
|
||||
|
||||
class PropertyViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
self.url = reverse('property-list')
|
||||
|
||||
# Authenticate as property owner
|
||||
self.client.force_authenticate(user=self.owner_user)
|
||||
|
||||
def test_get_properties(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
def test_create_property(self):
|
||||
data = {
|
||||
'owner': self.owner.pk,
|
||||
'address': '456 New St',
|
||||
'city': 'Newtown',
|
||||
'state': 'NY',
|
||||
'zip_code': '10001',
|
||||
'market_value': '600000.00'
|
||||
}
|
||||
response = self.client.post(self.url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED,response.text)
|
||||
self.assertTrue(Property.objects.filter(address='456 New St').exists())
|
||||
|
||||
def test_update_property(self):
|
||||
url = f"{self.url}{self.property.pk}/"
|
||||
data = {
|
||||
'address': '789 Updated St',
|
||||
'market_value': '550000.00'
|
||||
}
|
||||
response = self.client.patch(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.property.refresh_from_db()
|
||||
self.assertEqual(self.property.address, '789 Updated St')
|
||||
self.assertEqual(str(self.property.market_value), '550000.00')
|
||||
|
||||
class VideoViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.category = VideoCategory.objects.create(
|
||||
name='Test Category',
|
||||
description='Test Description'
|
||||
)
|
||||
self.video = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video',
|
||||
description='Test Video Description',
|
||||
link='https://example.com/video',
|
||||
duration=300
|
||||
)
|
||||
self.url = reverse('video-list')
|
||||
|
||||
# Authenticate
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
def test_get_videos(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
def test_create_video(self):
|
||||
data = {
|
||||
'category': {
|
||||
"name": "New Category",
|
||||
"description": "a description"
|
||||
},
|
||||
'title': 'New Video',
|
||||
'description': 'New Video Description',
|
||||
'link': 'https://example.com/new-video',
|
||||
'duration': 240
|
||||
}
|
||||
response = self.client.post(self.url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.text)
|
||||
self.assertTrue(Video.objects.filter(title='New Video').exists())
|
||||
|
||||
def test_update_video(self):
|
||||
url = f"{self.url}{self.video.pk}/"
|
||||
data = {
|
||||
'title': 'Updated Video',
|
||||
'duration': 360
|
||||
}
|
||||
response = self.client.patch(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK, response.text)
|
||||
self.video.refresh_from_db()
|
||||
self.assertEqual(self.video.title, 'Updated Video')
|
||||
self.assertEqual(self.video.duration, 360)
|
||||
|
||||
class UserVideoProgressViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(
|
||||
email='user@example.com',
|
||||
first_name='Test',
|
||||
last_name='User',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.category = VideoCategory.objects.create(name='Test Category')
|
||||
self.video = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video',
|
||||
link='https://example.com/video',
|
||||
duration=300
|
||||
)
|
||||
self.video_1 = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video 1',
|
||||
link='https://example.com/video_1',
|
||||
duration=300
|
||||
)
|
||||
self.video_2 = Video.objects.create(
|
||||
category=self.category,
|
||||
title='Test Video 2',
|
||||
link='https://example.com/video_2',
|
||||
duration=300
|
||||
)
|
||||
self.progress = UserVideoProgress.objects.create(
|
||||
user=self.user,
|
||||
video=self.video,
|
||||
progress=150
|
||||
)
|
||||
UserVideoProgress.objects.create(
|
||||
user=self.user,
|
||||
video=self.video_1,
|
||||
progress=150
|
||||
)
|
||||
UserVideoProgress.objects.create(
|
||||
user=self.user,
|
||||
video=self.video_2,
|
||||
progress=150
|
||||
)
|
||||
self.url = reverse('video-progress-list')
|
||||
|
||||
# Authenticate
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
def test_get_video_progress(self):
|
||||
response = self.client.get(f"{self.url}", kwargs={'format','json'})
|
||||
breakpoint()
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK, response.text)
|
||||
breakpoint()
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
def test_update_video_progress(self):
|
||||
url = f"{self.url}{self.progress.pk}/"
|
||||
data = {
|
||||
'progress': 200
|
||||
}
|
||||
response = self.client.patch(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.progress.refresh_from_db()
|
||||
self.assertEqual(self.progress.progress, 200)
|
||||
self.assertEqual(self.progress.status, 'in_progress')
|
||||
|
||||
class ConversationViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
|
||||
# Create owner user
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
|
||||
# Create vendor user
|
||||
self.vendor_user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.vendor_user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor'
|
||||
)
|
||||
|
||||
# Create property
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
# Create conversation
|
||||
self.conversation = Conversation.objects.create(
|
||||
property_owner=self.owner,
|
||||
vendor=self.vendor,
|
||||
property=self.property
|
||||
)
|
||||
|
||||
self.url = reverse('conversation-list')
|
||||
|
||||
# Authenticate as owner
|
||||
self.client.force_authenticate(user=self.owner_user)
|
||||
|
||||
def test_get_conversations_as_owner(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
def test_create_conversation(self):
|
||||
data = {
|
||||
'property_owner': self.owner.pk,
|
||||
'vendor': self.vendor.pk,
|
||||
'property': self.property.pk
|
||||
}
|
||||
response = self.client.post(self.url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.text)
|
||||
self.assertTrue(Conversation.objects.filter(property_owner=self.owner, vendor=self.vendor, property=self.property).exists())
|
||||
|
||||
def test_get_conversations_as_vendor(self):
|
||||
# Switch to vendor user
|
||||
self.client.force_authenticate(user=self.vendor_user)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
class MessageViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
|
||||
# Create owner user
|
||||
self.owner_user = User.objects.create_user(
|
||||
email='owner@example.com',
|
||||
first_name='Property',
|
||||
last_name='Owner',
|
||||
user_type='property_owner',
|
||||
password='testpass123'
|
||||
)
|
||||
self.owner = PropertyOwner.objects.create(user=self.owner_user)
|
||||
|
||||
# Create vendor user
|
||||
self.vendor_user = User.objects.create_user(
|
||||
email='vendor@example.com',
|
||||
first_name='Vendor',
|
||||
last_name='User',
|
||||
user_type='vendor',
|
||||
password='testpass123'
|
||||
)
|
||||
self.vendor = Vendor.objects.create(
|
||||
user=self.vendor_user,
|
||||
business_name='Test Vendor',
|
||||
business_type='contractor'
|
||||
)
|
||||
|
||||
# Create property
|
||||
self.property = Property.objects.create(
|
||||
owner=self.owner,
|
||||
address='123 Main St',
|
||||
city='Anytown',
|
||||
state='CA',
|
||||
zip_code='90210',
|
||||
market_value=500000.00
|
||||
)
|
||||
|
||||
# Create conversation
|
||||
self.conversation = Conversation.objects.create(
|
||||
property_owner=self.owner,
|
||||
vendor=self.vendor,
|
||||
property=self.property
|
||||
)
|
||||
|
||||
# Create message
|
||||
self.message = Message.objects.create(
|
||||
conversation=self.conversation,
|
||||
sender=self.owner_user,
|
||||
text='Test message'
|
||||
)
|
||||
|
||||
self.url = reverse('conversation-messages', kwargs={'conversation_id': self.conversation.pk})
|
||||
|
||||
# Authenticate as owner
|
||||
self.client.force_authenticate(user=self.owner_user)
|
||||
|
||||
def test_get_messages(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
def test_create_message(self):
|
||||
data = {
|
||||
'sender': self.owner.pk,
|
||||
'text': 'New message',
|
||||
'conversation': self.conversation.pk
|
||||
}
|
||||
response = self.client.post(self.url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.text)
|
||||
self.assertTrue(Message.objects.filter(text='New message').exists())
|
||||
|
||||
def test_get_messages_as_vendor(self):
|
||||
# Switch to vendor user
|
||||
self.client.force_authenticate(user=self.vendor_user)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
Reference in New Issue
Block a user