diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddf..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index e3c8a4b7..00000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,1400 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { - "customColor": "", - "associatedIndex": 4 -} - - - - - - - - - - - true - true - false - false - - - - - - - - 1714731586527 - - - - \ No newline at end of file diff --git a/backend/nba_app/migrations/0003_follow_user_following.py b/backend/nba_app/migrations/0003_follow_user_following.py new file mode 100644 index 00000000..1780907f --- /dev/null +++ b/backend/nba_app/migrations/0003_follow_user_following.py @@ -0,0 +1,32 @@ +# Generated by Django 5.0.4 on 2024-05-09 22:33 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('nba_app', '0002_post'), + ] + + operations = [ + migrations.CreateModel( + name='Follow', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('followed', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='follower_set', to=settings.AUTH_USER_MODEL)), + ('follower', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='following_set', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('follower', 'followed')}, + }, + ), + migrations.AddField( + model_name='user', + name='following', + field=models.ManyToManyField(related_name='followers', through='nba_app.Follow', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/backend/nba_app/models.py b/backend/nba_app/models.py index ff8e71ef..f3a98157 100644 --- a/backend/nba_app/models.py +++ b/backend/nba_app/models.py @@ -35,6 +35,9 @@ class User(AbstractBaseUser, PermissionsMixin): is_staff = models.BooleanField(default=False) is_superuser = models.BooleanField(default=False) + following = models.ManyToManyField('self', symmetrical=False, through='Follow', related_name='followers') + + objects = CustomUserManager() USERNAME_FIELD = 'username' @@ -64,5 +67,11 @@ class Comment(models.Model): def __str__(self): return f'{self.user.username} on {self.post.post_id}: {self.content}' - - \ No newline at end of file + +class Follow(models.Model): + follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following_set') + followed = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower_set') + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + unique_together = ('follower', 'followed') diff --git a/backend/nba_app/urls.py b/backend/nba_app/urls.py index f660bfda..15575f14 100644 --- a/backend/nba_app/urls.py +++ b/backend/nba_app/urls.py @@ -6,6 +6,10 @@ path('signup/', views.sign_up, name='signup'), path('login/', views.log_in, name='login'), path('feed/', views.feed, name='feed'), + path('profile_view_edit/', views.profile_view_edit, name='profile_view_edit'), + path('follow_user/', views.follow_user, name='follow_user'), + path('unfollow_user/', views.unfollow_user, name='unfollow_user'), + path('reset_password/', views.reset_password, name='reset_password'), path('post/', views.post, name='post'), path('search/', views.search, name='search'), path('team/', views.team, name='team'), diff --git a/backend/nba_app/views.py b/backend/nba_app/views.py index 9a615053..ffb0e2d9 100644 --- a/backend/nba_app/views.py +++ b/backend/nba_app/views.py @@ -6,7 +6,7 @@ from django.middleware.csrf import get_token from django.http import JsonResponse, HttpResponse from django.urls import reverse -from .models import User, Post, Comment +from .models import User, Post, Comment, Follow import requests def sign_up(request): @@ -106,11 +106,158 @@ def create_comment(request, post_id): return render(request, 'comment.html', {'post_id': post_id}) + def post_detail(request, post_id): post = Post.objects.get(post_id=post_id) - comments = post.comments.all() + comments = Comment.objects.get(post = post) #post.comments.all() return render(request, 'post_detail.html', {'post': post, 'comments': comments}) + +def profile_view_edit(request): + if request.method == 'POST': + new_username = request.POST.get('username') + new_email = request.POST.get('email') + new_profile_picture = request.FILES.get('profile_picture') + new_bio = request.POST.get('bio') + new_password = request.POST.get('password') + + user = request.user + + # Update username if provided + if new_username: + user.username = new_username + + # Update email if provided + if new_email: + user.email = new_email + + # Update profile picture if provided + if new_profile_picture: + user.profile_picture = new_profile_picture + + # Update bio if provided + if new_bio: + user.bio = new_bio + + # Update password if provided + if new_password: + user.set_password(new_password) + + user.save() + + return JsonResponse({'message': 'Account information updated successfully.'}, status=200) + + # if request.method == 'GET': + user = request.user + following_count = user.following.count() + followers_count = user.followers.count() + posts = Post.objects.filter(user=user) + #post_contents = [post.content for post in posts] + data = { + 'username': user.username, + 'email': user.email, + 'bio': user.bio, + #'profile_picture': user.profile_picture.url if user.profile_picture else None, + # Add any other fields you want to include in the response + 'following_count': following_count, + 'followers_count': followers_count, + 'posts': [{'content': post.content, 'created_at': post.created_at} for post in posts] + } + return JsonResponse(data, status=200) + + + + +def reset_password(request): + if request.method != 'POST': + return JsonResponse({'error': 'Only POST requests are allowed.'}, status=405) + + email = request.POST.get('email') + username = request.POST.get('username') + new_password = request.POST.get('new_password') + + # Check if either email or username is provided + if not email and not username: + return JsonResponse({'error': 'Email address or username is required in the request.'}, status=400) + + # Retrieve the user by email or username + user = None + if email: + try: + user = User.objects.get(email=email) + except User.DoesNotExist: + pass + elif username: + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + pass + + if not user: + return JsonResponse({'error': 'User not found.'}, status=404) + + # Check if new password is provided + if not new_password: + return JsonResponse({'error': 'New password is required.'}, status=400) + + # Set the new password + user.set_password(new_password) + user.save() + + return JsonResponse({'message': 'Password reset successful.'}, status = 200) + + + + +def follow_user(request): + if request.method != 'POST': + return JsonResponse({'error': 'Only POST requests are allowed.'}, status=405) + + user_id = request.POST.get('user_id') + + if request.user.user_id == user_id: + return JsonResponse({'error': 'You cannot follow yourself.'}, status=400) + + # Retrieve the user to follow + try: + followed_user = User.objects.get(pk=user_id) + except User.DoesNotExist: + return JsonResponse({'error': 'User not found.'}, status=404) + + # Check if the user is already following the given user + already_following = Follow.objects.filter(follower=request.user, followed=followed_user).exists() + if already_following: + return JsonResponse({'message': 'You are already following this user.'}, status = 400) + + # Create a new follow instance + Follow.objects.create(follower=request.user, followed=followed_user) + return JsonResponse({'message': 'You have successfully followed the user.'}, status=200) + + + + +def unfollow_user(request): + if request.method != 'POST': + return JsonResponse({'error': 'Only POST requests are allowed.'}, status=405) + + user_id = request.POST.get('user_id') + + # Retrieve the user to unfollow + try: + followed_user = User.objects.get(pk=user_id) + except User.DoesNotExist: + return JsonResponse({'error': 'User not found.'}, status=404) + + # Check if the user is already not following the given user + follow_instance = Follow.objects.filter(follower=request.user, followed=followed_user).first() + if not follow_instance: + return HttpResponse('You are not following this user.', status=400) + + # Delete the follow instance + follow_instance.delete() + return JsonResponse({'message': 'You have successfully unfollowed the user.'}, status=200) + + @login_required def feed(request): # Only authenticated users can access this view diff --git a/backend/nba_project/settings.py b/backend/nba_project/settings.py index b8872103..2ec4b9e2 100644 --- a/backend/nba_project/settings.py +++ b/backend/nba_project/settings.py @@ -16,7 +16,7 @@ import os # Load environment variables from .env file -load_dotenv('././.env') +load_dotenv('./.env') print('DB_HOST:', os.getenv('DB_HOST')) print('DB_USER:', os.getenv('DB_USER')) @@ -100,8 +100,8 @@ 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': os.getenv('DB_NAME'), - 'HOST': os.getenv('DB_HOST'), - 'PORT': os.getenv('DB_PORT'), + 'HOST': '64.226.89.39',#os.getenv('DB_HOST'), + 'PORT': '3307',#os.getenv('DB_PORT'), 'USER': os.getenv('DB_USER'), 'PASSWORD': os.getenv('DB_PASSWORD'), } diff --git a/frontend/.env.example b/frontend/.env.example deleted file mode 100644 index dae007ed..00000000 --- a/frontend/.env.example +++ /dev/null @@ -1 +0,0 @@ -REACT_APP_DEPLOY_MACHINE_IP=127.0.0.1 \ No newline at end of file