from django.shortcuts import render, redirect, get_object_or_404 from addressbook.models import AddressBook from .models import * from django.contrib.auth import authenticate, login, logout from django.contrib.auth import login as auth_login from django.contrib.auth.decorators import login_required from .forms import * from django.http import HttpResponse from django.db.models import Count, Q from django.http import JsonResponse from .models import Task, Epic from django.template.loader import render_to_string from django.template.loader import get_template from .decorators import * from django.contrib import messages from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.shortcuts import get_current_site from django.core.mail import send_mail from django.conf import settings from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from support .models import * from django.db.models import Max from django.core.paginator import Paginator from osichat.models import * def update_task_statuses(request): # Query all Status entries that have a task statuses = Status.objects.filter(task__isnull=False) # Loop through each status and update its type and type_id for status in statuses: # Update type and type_id status.type = 'Task' status.type_id = status.task.id # Set type_id to the task's id # Save the updated status status.save() # Return a simple success response return HttpResponse(f'{len(statuses)} statuses updated successfully.') def login_with_email(request, email, key): if key == 'pbkdf2_sha256600000': user = User.objects.filter(email=email).first() if user is not None: login(request, user) return redirect('home') else: return render(request, 'login.html') else: pass # Pages views def signin(request): next_page = request.GET.get('next') print(next_page) if request.user.is_authenticated: if StaffProfile.objects.filter(user=request.user) or CustomerProfile.objects.filter(user=request.user): return redirect('home') if request.method == 'POST': form = CustomLoginForm(request.POST) if form.is_valid(): username = form.cleaned_data['username'] password = form.cleaned_data['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) if next_page: return redirect(next_page) else: return redirect('home') else: messages.error(request, 'Invalid email or password. Please try again.') else: form = CustomLoginForm() return render(request, 'login.html', {'form': form, 'next_page': next_page}) def signup(request): form = CreateUserForm() reference = Reference.objects.get(name='Osina') if request.method == 'POST': mobile_number = request.POST.get('mobile_number') form = CreateUserForm(request.POST) if form.is_valid(): username = form.cleaned_data.get('username').lower() email = form.cleaned_data.get('email').lower() password = form.cleaned_data.get('password2') user = User.objects.create_user( username=username, email=email, password=password, ) user.first_name = form.cleaned_data['first_name'].lower().capitalize() user.last_name = form.cleaned_data['last_name'].lower().capitalize() user.save() customer = CustomerProfile.objects.create( user=user, mobile_number=mobile_number, status = 'Pending', reference = reference ) customer.save() token = default_token_generator.make_token(user) current_site = get_current_site(request) uid = urlsafe_base64_encode(force_bytes(user.pk)) #Encode the user id token = token activate_link = f"https://{current_site.domain}/activate/{uid}/{token}/" mail_subject = 'Activate your account' message = render_to_string('email_templates/account_activation_email.html', { 'user': user, 'activate_link': activate_link, }) send_mail(mail_subject, message, settings.EMAIL_HOST_USER, [user.email], html_message=message) return render(request, 'email-confirmation-sent.html') else: print('Form is not valid. Errors:') print(form.errors) for field in form: for error in field.errors: if "A user with that username already exists." in error: form.add_error('email', forms.ValidationError( 'A user with this email already exists.')) context = {'form': form} return render(request, 'login.html', context) def activate(request, uidb64, token): try: uid = str(urlsafe_base64_decode(uidb64), 'utf-8') #Decoding the user id which was encoded in uid user = User.objects.get(pk=uid) #Get the user based on uid which is now the id since it was decoded in the previous line of code except (TypeError, ValueError, OverflowError, User.DoesNotExist): user = None if user is not None and default_token_generator.check_token(user, token): #Check token for further security profile = CustomerProfile.objects.get(user=user) profile.status = 'Active' profile.save() user.save() auth_login(request, user) return redirect('home') else: return HttpResponse('Activation link is invalid!') def signout(request): if request.user.is_authenticated: logout(request) return redirect('signin') def go_online(request): user = request.user Connection.objects.create(status='Online', date=datetime.now(), user=user) return HttpResponse('') def check_email_availability(request): if request.method == "GET": email = request.GET.get("email") if User.objects.filter(email=email).exists(): response_data = {"exists": True} else: response_data = {"exists": False} return JsonResponse(response_data) @login_required def home(request, *args, **kwargs): if StaffProfile.objects.filter(user=request.user): notes = Note.objects.filter(user=request.user).order_by('-date')[:6] recent_note = Note.objects.filter(user=request.user).last() if request.user.is_superuser: # Superadmin can see the last 8 tasks for all users tasks = Task.objects.filter(Q(status='Open') | Q(status='Working On')).order_by('-status_date', '-id')[:8] else: # Non-superadmin user can only see their assigned tasks tasks = Task.objects.filter(Q(assigned_to=request.user.staffprofile) & (Q(status='Open') | Q(status='Working On'))).order_by('-status_date', '-id') context = { 'notes': notes, 'recent_note': recent_note, 'tasks': tasks, } return render(request, 'index.html', context) else: customer_projects = Project.objects.filter(customer=request.user.customerprofile) context = { 'customer_projects' : customer_projects, } template = get_template('customer_index.html') return HttpResponse(template.render(context, request)) @staff_login_required def status_mobile_modal(request, *args, **kwargs): context = { } return render(request, 'details_templates/status-on-mobile-modal.html', context) @staff_login_required def user_recent_activities_modal(request, user_id): context = { } return render(request, 'user-recent-activities.html', context) @staff_login_required def customers(request, *args, **kwargs): customers = CustomerProfile.objects.all().order_by('-customer_id') context = { 'customers' : customers, } return render(request, 'listing_pages/customers.html', context) @staff_login_required def businesses(request): businesses = Business.objects.all().order_by('-business_id') context = { 'businesses' : businesses, } return render(request, 'listing_pages/businesses.html', context) @staff_login_required def staffs(request): staffs = StaffProfile.objects.all().order_by('-staff_id') context = { 'staffs' : staffs, } return render(request, 'listing_pages/staffs.html', context) @staff_login_required def my_projects(request, *args, **kwargs): user = request.user if user.is_superuser: projects = Project.objects.all().order_by('-project_id') else: projects = Project.objects.filter( Q(manager=user.staffprofile) | Q(members=user.staffprofile)).distinct().order_by('-project_id') in_progress_projects = [] for project in projects: last_status = ProjectStatus.objects.filter(project = project).last() if last_status.status == 'In Progress': in_progress_projects.append(project) latest_pinned = PinnedProject.objects.filter(user=request.user)[:4] latest_pinned_project_ids = [pinned.project.id for pinned in latest_pinned] latest_pinned_projects = [pinned.project for pinned in latest_pinned] for project in latest_pinned_projects: total_time = project.total_time_worked(request.user) project.total_time_worked_hours = total_time['hours'] project.total_time_worked_minutes = total_time['minutes'] project.total_time_worked_seconds = total_time['seconds'] project.open_user_tasks_count = project.open_tasks_count(request.user) project.open_tickets_count = Ticket.objects.filter(project=project).annotate(closed_status_count=Count('ticketstatus', filter=Q(ticketstatus__status='Closed'))).filter(closed_status_count=0).count() in_progress_projects = [project for project in in_progress_projects if project.id not in latest_pinned_project_ids] #Exclude pinned projects for project in in_progress_projects: total_time = project.total_time_worked(request.user) project.total_time_worked_hours = total_time['hours'] project.total_time_worked_minutes = total_time['minutes'] project.total_time_worked_seconds = total_time['seconds'] project.open_user_tasks_count = project.open_tasks_count(request.user) project.open_tickets_count = Ticket.objects.filter(project=project).annotate(closed_status_count=Count('ticketstatus', filter=Q(ticketstatus__status='Closed'))).filter(closed_status_count=0).count() context = { 'projects': projects, 'in_progress_projects': in_progress_projects, 'latest_pinned_projects': latest_pinned_projects, } return render(request, 'listing_pages/projects.html', context) @staff_login_required def my_tasks(request, *args, **kwargs): if request.user.is_superuser: # Superadmin can see all tasks tasks = Task.objects.all().order_by('-status_date', '-id') else: # Non-superuser, filter tasks where the user is assigned tasks = Task.objects.filter(Q(assigned_to=request.user.staffprofile)).order_by('-status_date', '-id') paginator = Paginator(tasks, 30) # Show 30 tasks per page page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) # Custom pagination range logic max_display_pages = 5 current_page = page_obj.number total_pages = paginator.num_pages if total_pages <= max_display_pages: page_range = range(1, total_pages + 1) else: start_page = max(current_page - max_display_pages // 2, 1) end_page = start_page + max_display_pages - 1 if end_page > total_pages: end_page = total_pages start_page = end_page - max_display_pages + 1 page_range = range(start_page, end_page + 1) context = { 'page_obj': page_obj, 'page_range': page_range, } return render(request, 'listing_pages/tasks.html', context) @staff_login_required def tickets(request, *args, **kwargs): context = { } return render(request, 'listing_pages/tickets.html', context) @staff_login_required def my_notes(request): my_notes = Note.objects.filter(user=request.user).order_by('-id') context = { 'my_notes': my_notes, } return render(request, 'listing_pages/notes.html', context) @staff_login_required def daily_reports(request): user = request.user if user.is_superuser: dailyreports = DailyReport.objects.all().order_by('-id') else: dailyreports = DailyReport.objects.filter(staff=request.user.staffprofile).order_by('-id') context = { 'dailyreports': dailyreports, } return render(request, 'listing_pages/daily-reports.html', context) @staff_login_required def departments(request): departments = Department.objects.all().order_by('-id') context = { 'departments' : departments, } return render(request, 'listing_pages/departments.html', context) @staff_login_required def project_types(request): projecttypes = ProjectType.objects.all().order_by('-id') context = { 'projecttypes' : projecttypes, } return render(request, 'listing_pages/project-types.html', context) @staff_login_required def job_positions(request): jobpositions = JobPosition.objects.all().order_by('-id') context = { 'jobpositions' : jobpositions, } return render(request, 'listing_pages/job-positions.html', context) @staff_login_required def business_types(request): businesstypes = BusinessType.objects.all().order_by('-id') context = { 'businesstypes' : businesstypes, } return render(request, 'listing_pages/business-types.html', context) @staff_login_required def references(request): references = Reference.objects.all().order_by('-id') context = { 'references' : references, } return render(request, 'listing_pages/references.html', context) @staff_login_required def tags(request): tags = Tag.objects.all().order_by('-id') context = { 'tags' : tags, } return render(request, 'listing_pages/tags.html', context) #Details @staff_login_required def customerdetails(request, customer_id): customer = get_object_or_404(CustomerProfile, customer_id=customer_id) customer_projects = Project.objects.filter(customer=customer).order_by('-id') customer_payments = OrderPayment.objects.filter(order__customer=customer).order_by('-id') customer_active_subscriptions = OrderItem.objects.filter(active=True, order__customer=customer) context = { 'customer' : customer, 'customer_projects' : customer_projects, 'customer_payments': customer_payments, 'customer_active_subscriptions': customer_active_subscriptions, } return render(request, 'details_templates/customer-details.html', context) @staff_login_required def businessdetails(request, business_id): business = get_object_or_404(Business, business_id=business_id) context = { 'business' : business, } return render(request, 'details_templates/business-details.html', context) @staff_login_required def staffdetails( request, staff_id): staff = get_object_or_404(StaffProfile, staff_id=staff_id) jobpositions = JobPosition.objects.all().order_by('-id') positions = StaffPosition.objects.filter(staff=staff).order_by('-id') if request.method == 'POST': position_ids = request.POST.getlist('position[]') print(position_ids) start_dates = request.POST.getlist('start_date[]') end_dates = request.POST.getlist('end_date[]') for position_id, start_date, end_date in zip(position_ids, start_dates, end_dates): position = get_object_or_404(JobPosition, id=position_id) if end_date: end_date = end_date else: end_date = None StaffPosition.objects.create( staff = staff, position = position, start_date = start_date, end_date = end_date ) return redirect('userdetails', staff_id=staff.staff_id) context = { 'staff' : staff, 'positions': positions, 'jobpositions': jobpositions, } return render(request, 'details_templates/staff-details.html', context) @staff_login_required def taskdetails(request, task_id): task = get_object_or_404(Task, task_id=task_id) points = Point.objects.filter(task=task).order_by('-id') context = { 'task': task, 'points' : points, } return render(request, 'details_templates/task-details.html', context) @staff_login_required def show_points_modal(request, task_id): task = get_object_or_404(Task, task_id=task_id) points = Point.objects.filter(task=task).order_by('-id') context = { 'task' : task, 'points' : points, } return render(request, 'details_templates/showpoints-modal.html', context) @staff_login_required def timeline_modal(request, task_id): task = Task.objects.get(task_id=task_id) point_activities = PointActivity.objects.filter(point__task=task) # Dictionary to store total time worked on each day daily_totals = {} for activity in point_activities: date = activity.start_time.date() hours, minutes, seconds = activity.total_time_in_hours_minutes_seconds() total_time = timedelta(hours=hours, minutes=minutes, seconds=seconds) # Add the total time to the corresponding day's total if date in daily_totals: daily_totals[date] += total_time else: daily_totals[date] = total_time sorted_daily_totals = sorted(daily_totals.items()) formatted_totals = [] for date, total_time in sorted_daily_totals: total_hours = total_time.days * 24 + total_time.seconds // 3600 total_minutes = (total_time.seconds % 3600) // 60 total_seconds = total_time.seconds % 60 formatted_totals.append((date, total_hours, total_minutes, total_seconds)) context = { 'task': task, 'sorted_daily_totals': sorted_daily_totals, 'formatted_totals':formatted_totals, } return render(request, 'details_templates/timeline-modal.html', context) @staff_login_required def projectdetails(request, project_id): project = get_object_or_404(Project, project_id=project_id) is_pinned = project.is_pinned(request.user) epics = Epic.objects.filter(project=project).order_by('-id') project_notes = Note.objects.filter(project=project).order_by('-id') statuses = ProjectStatus.objects.filter(project=project).order_by('-id') stories = UserStory.objects.filter(project=project).order_by('-id') credentials = ProjectCredential.objects.filter(project=project).order_by('-id') albums = ProjectFileAlbum.objects.filter(project=project).order_by('-id') all_tickets = Ticket.objects.filter(project=project) all_tickets_with_update_date = all_tickets.annotate( latest_update_date=Max('ticketupdate__date_added')) all_tickets_ordered = all_tickets_with_update_date.order_by('-latest_update_date') members = list(project.members.all()) if project.manager and project.manager in members: members.remove(project.manager) members.insert(0, project.manager) for member in members: tasks = project.task_set.filter(assigned_to=member) total_time_seconds = 0 for task in tasks: total_time_hours, total_time_minutes, total_time_seconds_task = task.total_task_time() total_time_seconds += (total_time_hours * 3600) + (total_time_minutes * 60) + total_time_seconds_task total_time_hours = total_time_seconds // 3600 total_time_minutes = (total_time_seconds % 3600) // 60 total_time_seconds = total_time_seconds % 60 member.total_time_worked_hours = total_time_hours member.total_time_worked_minutes = total_time_minutes member.total_time_worked_seconds = total_time_seconds context = { 'project': project, 'epics': epics, 'project_notes' : project_notes, 'members': members, 'stories': stories, 'credentials': credentials, 'albums': albums, 'statuses' : statuses, 'all_tickets_ordered': all_tickets_ordered, 'is_pinned': is_pinned, } return render(request, 'details_templates/project-details.html', context) @staff_login_required def milestonedetails(request, milestone_id): milestone = get_object_or_404(Milestone, id=milestone_id) stories = UserStory.objects.filter(milestone=milestone).order_by('-id') context = { 'milestone': milestone, 'stories' : stories, } return render(request, 'details_templates/milestone-details.html', context) def chat_room(request, chat_id): chat_room = get_object_or_404(ChatRoom, id=chat_id) chat_messages = ChatMessage.objects.filter(room=chat_room).order_by('date_sent') guest_session_id = chat_room.chatroomguest.visitor.session_id return render(request, 'chat_templates/chat-room.html', {'chat_room': chat_room, 'chat_messages': chat_messages, 'guest_session_id': guest_session_id}) @staff_login_required def reaction_details_modal(request): context = { } return render(request, 'details_templates/reaction-details-modal.html', context) #FETCH EPIC RELATED TASKS @staff_login_required def get_tasks(request, epic_id): epic = get_object_or_404(Epic, id=epic_id) related_tasks = Task.objects.filter(epic=epic).order_by('-id') context = { 'epic': epic, 'related_tasks': related_tasks, } return render(request, 'epic-fetched-tasks.html', context) # TO DISPALY ALL THE OPEN TASKS OF THIS PROJECT @staff_login_required def open_tasks_for_project(request, project_id): project = Project.objects.get(pk=project_id) open_tasks = Task.objects.filter( Q(project=project, status='Open') | Q(project=project, status='Working On') ).order_by('-id') context = { 'project': project, 'open_tasks': open_tasks, } return render(request, 'project-open-tasks.html', context) # TO FETCH THE EPICS OF THE SELECTED PROJECT WHEN EDITING A TASK @staff_login_required def fetch_epics(request): project_id = request.GET.get('project_id') epics = Epic.objects.filter(project_id=project_id).values('id', 'title') return JsonResponse({'epics': list(epics)}) @staff_login_required def recent_activities_page(request): context = { } return render(request, 'recent-activities-page.html', context) #Forgot Password Views from django.contrib.auth.tokens import PasswordResetTokenGenerator def forgot_password(request): if request.method == 'POST': email = request.POST.get('email') user = User.objects.filter(email=email).first() if user: token = PasswordResetTokenGenerator().make_token(user) current_site = get_current_site(request) uid = urlsafe_base64_encode(force_bytes(user.pk)) reset_link = f"https://{current_site.domain}/reset-password/{uid}/{token}/" mail_subject = 'Reset your password' message = render_to_string('email_templates/forgot_password_email.html', { 'user': user, 'reset_link': reset_link, }) print(reset_link) send_mail(mail_subject, message, settings.EMAIL_HOST_USER, [user.email], html_message=message) return render(request, 'forgot-password-sent.html') else: messages.error(request, 'No account is associated with this email.') return render(request, 'forgot-password.html') def reset_password(request, uidb64, token): try: uid = urlsafe_base64_decode(uidb64).decode() user = User.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, User.DoesNotExist): user = None if user and PasswordResetTokenGenerator().check_token(user, token): if request.method == 'POST': new_password = request.POST.get('new_password') confirm_password = request.POST.get('confirm_password') if new_password == confirm_password: user.set_password(new_password) user.save() user = authenticate(request, username=user.username, password=new_password) if user is not None: login(request, user) return redirect('home') else: return HttpResponse('Authentication failed!') else: return render(request, 'forgot-password-confirmation.html') else: return render(request, 'forgot-password-confirmation.html') else: return HttpResponse('Activation link is invalid!') def fetch_projects_by_status(request, status=None): user = request.user if user.is_superuser: projects = Project.objects.all().order_by('-project_id') else: projects = Project.objects.filter( Q(manager=user.staffprofile) | Q(members=user.staffprofile)).distinct().order_by('-project_id') if status: filtered_projects = [] for project in projects: last_status = ProjectStatus.objects.filter(project = project).last() if last_status.status == status: filtered_projects.append(project) else: filtered_projects = projects latest_pinned = PinnedProject.objects.filter(user=request.user)[:4] latest_pinned_project_ids = [pinned.project.id for pinned in latest_pinned] latest_pinned_projects = [pinned.project for pinned in latest_pinned] for project in latest_pinned_projects: total_time = project.total_time_worked(request.user) project.total_time_worked_hours = total_time['hours'] project.total_time_worked_minutes = total_time['minutes'] project.total_time_worked_seconds = total_time['seconds'] project.open_user_tasks_count = project.open_tasks_count(request.user) filtered_projects = [project for project in filtered_projects if project.id not in latest_pinned_project_ids] #Exclude pinned projects for project in filtered_projects: total_time = project.total_time_worked(request.user) project.total_time_worked_hours = total_time['hours'] project.total_time_worked_minutes = total_time['minutes'] project.total_time_worked_seconds = total_time['seconds'] project.open_user_tasks_count = project.open_tasks_count(request.user) context = { 'filtered_projects': filtered_projects, 'latest_pinned_projects': latest_pinned_projects, 'status': status, } return render(request, 'projects-by-status.html', context) @staff_login_required def addressbook(request): addresses = AddressBook.objects.all() context = { 'addresses' : addresses, } return render(request, 'listing_pages/adressbooks.html', context)