285 lines
11 KiB
Python
285 lines
11 KiB
Python
import os
|
|
import platform
|
|
|
|
from django.shortcuts import render, redirect, get_object_or_404
|
|
from django.utils import timezone
|
|
from .models import Profile, Intent, ValueTag, Message, Post, Comment, Reaction, HiddenPost, Follow
|
|
from django.contrib.auth.models import User
|
|
from django.contrib.auth.forms import UserCreationForm
|
|
from django.contrib.auth import login
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.db.models import Q
|
|
|
|
def home(request):
|
|
"""Render the landing screen or member dashboard."""
|
|
|
|
# Simple logic to seed data for the first run
|
|
if not Intent.objects.exists():
|
|
intents_data = [
|
|
('Friendship', 'bi-people'),
|
|
('Networking', 'bi-briefcase'),
|
|
('Activity Partner', 'bi-bicycle'),
|
|
('Accountability', 'bi-check-circle')
|
|
]
|
|
for name, icon in intents_data:
|
|
Intent.objects.create(name=name, icon=icon)
|
|
|
|
if not Profile.objects.exists():
|
|
# Create a demo user/profile
|
|
demo_user, _ = User.objects.get_or_create(username='marcus_v', first_name='Marcus', last_name='V.')
|
|
p = Profile.objects.create(
|
|
user=demo_user,
|
|
professional_headline='Architect & Urban Planner',
|
|
transition_status='new-in-town',
|
|
bio='Passionate about sustainable cities. Recently moved here from Chicago and looking for local communities.',
|
|
location_city='Austin, TX',
|
|
)
|
|
p.intents.add(Intent.objects.get(name='Networking'))
|
|
|
|
demo_user2, _ = User.objects.get_or_create(username='sarah_l', first_name='Sarah', last_name='L.')
|
|
p2 = Profile.objects.create(
|
|
user=demo_user2,
|
|
professional_headline='UX Researcher | Growth Mindset',
|
|
transition_status='post-divorce',
|
|
bio='Rediscovering my love for hiking and photography. Seeking authentic connections and shared growth.',
|
|
location_city='Austin, TX',
|
|
)
|
|
p2.intents.add(Intent.objects.get(name='Friendship'))
|
|
|
|
# Social Feed Logic
|
|
hidden_post_ids = []
|
|
if request.user.is_authenticated:
|
|
hidden_post_ids = HiddenPost.objects.filter(user=request.user).values_list('post_id', flat=True)
|
|
|
|
posts = Post.objects.exclude(id__in=hidden_post_ids).select_related('author', 'author__profile').prefetch_related('comments', 'comments__author', 'reactions')
|
|
|
|
# Filtering by intent (for discovery)
|
|
intent_filter = request.GET.get('intent')
|
|
if intent_filter:
|
|
profiles = Profile.objects.filter(intents__name__iexact=intent_filter)
|
|
else:
|
|
profiles = Profile.objects.all()
|
|
|
|
intents = Intent.objects.all()
|
|
|
|
# Dashboard logic for logged-in users
|
|
stats = {}
|
|
suggested_members = []
|
|
suggested_events = []
|
|
following_ids = []
|
|
if request.user.is_authenticated:
|
|
# Quick Stats
|
|
stats = {
|
|
'unread_messages': Message.objects.filter(recipient=request.user, is_read=False).count(),
|
|
'pending_connections': 0, # Placeholder until connection request system exists
|
|
'upcoming_events_count': request.user.attending_events.filter(start_time__gt=timezone.now()).count(),
|
|
'completion_percentage': request.user.profile.profile_completion_percentage,
|
|
'streak': request.user.profile.accountability_streak,
|
|
'followers_count': request.user.profile.followers_count,
|
|
'following_count': request.user.profile.following_count,
|
|
}
|
|
|
|
following_ids = list(Follow.objects.filter(follower=request.user).values_list('followed_id', flat=True))
|
|
|
|
# Suggestions: Aligned members (shared intents or values)
|
|
user_intents = request.user.profile.intents.all()
|
|
user_values = request.user.profile.value_tags.all()
|
|
suggested_members = Profile.objects.filter(
|
|
Q(intents__in=user_intents) | Q(value_tags__in=user_values)
|
|
).exclude(user=request.user).distinct()[:10]
|
|
|
|
# Suggested Events: Upcoming events
|
|
from .models import Event
|
|
suggested_events = Event.objects.filter(start_time__gt=timezone.now()).order_by('start_time')[:5]
|
|
|
|
context = {
|
|
"project_name": "CommonGround",
|
|
"profiles": profiles,
|
|
"intents": intents,
|
|
"current_intent": intent_filter,
|
|
"current_time": timezone.now(),
|
|
"posts": posts,
|
|
"stats": stats,
|
|
"suggested_members": suggested_members,
|
|
"suggested_events": suggested_events,
|
|
"post_types": Post.POST_TYPE_CHOICES,
|
|
"following_ids": following_ids,
|
|
}
|
|
return render(request, "core/index.html", context)
|
|
|
|
@login_required
|
|
def create_post(request):
|
|
if request.method == 'POST':
|
|
content = request.POST.get('content')
|
|
image = request.FILES.get('image')
|
|
post_type = request.POST.get('post_type', 'reflection')
|
|
if content or image:
|
|
Post.objects.create(author=request.user, content=content, image=image, post_type=post_type)
|
|
return redirect('home')
|
|
|
|
@login_required
|
|
def delete_post(request, post_id):
|
|
post = get_object_or_404(Post, id=post_id, author=request.user)
|
|
post.delete()
|
|
return redirect(request.META.get('HTTP_REFERER', 'home'))
|
|
|
|
@login_required
|
|
def add_comment(request, post_id):
|
|
if request.method == 'POST':
|
|
post = get_object_or_404(Post, id=post_id)
|
|
content = request.POST.get('content')
|
|
if content:
|
|
Comment.objects.create(post=post, author=request.user, content=content)
|
|
return redirect(request.META.get('HTTP_REFERER', 'home'))
|
|
|
|
@login_required
|
|
def toggle_reaction(request, post_id):
|
|
post = get_object_or_404(Post, id=post_id)
|
|
reaction_type = request.GET.get('type', 'heart')
|
|
reaction, created = Reaction.objects.get_or_create(
|
|
post=post, user=request.user, reaction_type=reaction_type
|
|
)
|
|
if not created:
|
|
reaction.delete()
|
|
return redirect(request.META.get('HTTP_REFERER', 'home'))
|
|
|
|
@login_required
|
|
def toggle_follow(request, username):
|
|
target_user = get_object_or_404(User, username=username)
|
|
if target_user == request.user:
|
|
return redirect(request.META.get('HTTP_REFERER', 'home'))
|
|
|
|
follow, created = Follow.objects.get_or_create(follower=request.user, followed=target_user)
|
|
if not created:
|
|
follow.delete()
|
|
|
|
return redirect(request.META.get('HTTP_REFERER', 'home'))
|
|
|
|
@login_required
|
|
def hide_post(request, post_id):
|
|
post = get_object_or_404(Post, id=post_id)
|
|
HiddenPost.objects.get_or_create(user=request.user, post=post)
|
|
return redirect('home')
|
|
|
|
def about(request):
|
|
return render(request, "core/about.html")
|
|
|
|
def signup(request):
|
|
if request.method == 'POST':
|
|
form = UserCreationForm(request.POST)
|
|
if form.is_valid():
|
|
user = form.save()
|
|
# Create profile
|
|
Profile.objects.create(user=user)
|
|
login(request, user)
|
|
return redirect('onboarding')
|
|
else:
|
|
form = UserCreationForm()
|
|
return render(request, 'registration/signup.html', {'form': form})
|
|
|
|
@login_required
|
|
def onboarding(request):
|
|
# Simplified onboarding for MVP
|
|
profile = request.user.profile
|
|
if request.method == 'POST':
|
|
profile.professional_headline = request.POST.get('headline', '')
|
|
profile.bio = request.POST.get('bio', '')
|
|
profile.onboarding_completed = True
|
|
profile.save()
|
|
return redirect('home')
|
|
return render(request, 'core/onboarding.html', {'profile': profile})
|
|
|
|
@login_required
|
|
def settings_view(request):
|
|
profile = request.user.profile
|
|
if request.method == 'POST':
|
|
profile.two_factor_enabled = 'two_factor' in request.POST
|
|
profile.save()
|
|
# In a real app we'd save more settings here
|
|
return redirect('settings')
|
|
return render(request, 'core/settings.html', {'profile': profile})
|
|
|
|
def get_started(request):
|
|
if not request.user.is_authenticated:
|
|
return redirect('signup')
|
|
if not request.user.profile.onboarding_completed:
|
|
return redirect('onboarding')
|
|
return redirect('home')
|
|
|
|
@login_required
|
|
def inbox(request):
|
|
# Get all users the current user has messaged or received messages from
|
|
sent_to = Message.objects.filter(sender=request.user).values_list('recipient', flat=True)
|
|
received_from = Message.objects.filter(recipient=request.user).values_list('sender', flat=True)
|
|
|
|
partner_ids = set(list(sent_to) + list(received_from))
|
|
partners = User.objects.filter(id__in=partner_ids).select_related('profile')
|
|
|
|
# Add last message to each partner for display
|
|
for partner in partners:
|
|
last_message = Message.objects.filter(
|
|
Q(sender=request.user, recipient=partner) |
|
|
Q(sender=partner, recipient=request.user)
|
|
).order_by('-timestamp').first()
|
|
partner.last_message = last_message
|
|
|
|
return render(request, 'core/inbox.html', {'partners': partners})
|
|
|
|
@login_required
|
|
def chat_detail(request, username):
|
|
partner = get_object_or_404(User, username=username)
|
|
if partner == request.user:
|
|
return redirect('inbox')
|
|
|
|
if request.method == 'POST':
|
|
body = request.POST.get('body')
|
|
if body:
|
|
Message.objects.create(sender=request.user, recipient=partner, body=body)
|
|
return redirect('chat_detail', username=username)
|
|
|
|
messages = Message.objects.filter(
|
|
Q(sender=request.user, recipient=partner) |
|
|
Q(sender=partner, recipient=request.user)
|
|
).order_by('timestamp')
|
|
|
|
# Mark as read
|
|
messages.filter(recipient=request.user, is_read=False).update(is_read=True)
|
|
|
|
return render(request, 'core/chat.html', {
|
|
'partner': partner,
|
|
'chat_messages': messages
|
|
})
|
|
|
|
@login_required
|
|
def profile_view(request):
|
|
"""Redirect to the current user's profile detail page."""
|
|
return redirect('profile_detail', username=request.user.username)
|
|
|
|
def profile_detail(request, username):
|
|
"""View a user's profile."""
|
|
target_user = get_object_or_404(User, username=username)
|
|
is_following = False
|
|
if request.user.is_authenticated:
|
|
is_following = Follow.objects.filter(follower=request.user, followed=target_user).exists()
|
|
return render(request, 'core/profile_detail.html', {
|
|
'target_user': target_user,
|
|
'is_following': is_following
|
|
})
|
|
|
|
@login_required
|
|
def edit_profile(request):
|
|
"""Edit the current user's profile."""
|
|
profile = request.user.profile
|
|
if request.method == 'POST':
|
|
profile.professional_headline = request.POST.get('headline', '')
|
|
profile.bio = request.POST.get('bio', '')
|
|
profile.location_city = request.POST.get('location', '')
|
|
|
|
if 'avatar' in request.FILES:
|
|
profile.avatar = request.FILES['avatar']
|
|
|
|
profile.save()
|
|
return redirect('my_profile')
|
|
|
|
return render(request, 'core/edit_profile.html', {'profile': profile})
|