from django.views.generic import TemplateView, View from django.http import HttpResponse, JsonResponse from django.shortcuts import get_object_or_404 from django.template.loader import render_to_string from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import ValidationError from django.db import transaction from django.utils import timezone from .models import VersionBranch, VersionTag, ChangeSet from .managers import BranchManager, ChangeTracker, MergeStrategy class VersionControlPanel(LoginRequiredMixin, TemplateView): """Main version control interface""" template_name = 'history_tracking/version_control_panel.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) branch_manager = BranchManager() context.update({ 'branches': branch_manager.list_branches(), 'current_branch': self.request.GET.get('branch'), }) return context class BranchListView(LoginRequiredMixin, View): """HTMX view for branch list""" def get(self, request): branch_manager = BranchManager() branches = branch_manager.list_branches() content = render_to_string( 'history_tracking/components/branch_list.html', {'branches': branches}, request=request ) return HttpResponse(content) class HistoryView(LoginRequiredMixin, View): """HTMX view for change history""" def get(self, request): branch_name = request.GET.get('branch') if not branch_name: return HttpResponse("No branch selected") branch = get_object_or_404(VersionBranch, name=branch_name) tracker = ChangeTracker() changes = tracker.get_changes(branch) content = render_to_string( 'history_tracking/components/history_view.html', {'changes': changes}, request=request ) return HttpResponse(content) class MergeView(LoginRequiredMixin, View): """HTMX view for merge operations""" def get(self, request): source = request.GET.get('source') target = request.GET.get('target') if not (source and target): return HttpResponse("Source and target branches required") content = render_to_string( 'history_tracking/components/merge_panel.html', { 'source': source, 'target': target }, request=request ) return HttpResponse(content) @transaction.atomic def post(self, request): source_name = request.POST.get('source') target_name = request.POST.get('target') if not (source_name and target_name): return JsonResponse({ 'error': 'Source and target branches required' }, status=400) try: source = get_object_or_404(VersionBranch, name=source_name) target = get_object_or_404(VersionBranch, name=target_name) branch_manager = BranchManager() success, conflicts = branch_manager.merge_branches( source=source, target=target, user=request.user ) if success: content = render_to_string( 'history_tracking/components/merge_success.html', {'source': source, 'target': target}, request=request ) return HttpResponse(content) else: content = render_to_string( 'history_tracking/components/merge_conflicts.html', { 'source': source, 'target': target, 'conflicts': conflicts }, request=request ) return HttpResponse(content) except ValidationError as e: return JsonResponse({'error': str(e)}, status=400) except Exception as e: return JsonResponse( {'error': 'Merge failed. Please try again.'}, status=500 ) class BranchCreateView(LoginRequiredMixin, View): """HTMX view for branch creation""" def get(self, request): content = render_to_string( 'history_tracking/components/branch_create.html', request=request ) return HttpResponse(content) @transaction.atomic def post(self, request): name = request.POST.get('name') parent_name = request.POST.get('parent') if not name: return JsonResponse({'error': 'Branch name required'}, status=400) try: branch_manager = BranchManager() parent = None if parent_name: parent = get_object_or_404(VersionBranch, name=parent_name) branch = branch_manager.create_branch( name=name, parent=parent, user=request.user ) content = render_to_string( 'history_tracking/components/branch_item.html', {'branch': branch}, request=request ) return HttpResponse(content) except ValidationError as e: return JsonResponse({'error': str(e)}, status=400) except Exception as e: return JsonResponse( {'error': 'Branch creation failed. Please try again.'}, status=500 ) class TagCreateView(LoginRequiredMixin, View): """HTMX view for version tagging""" def get(self, request): branch_name = request.GET.get('branch') if not branch_name: return HttpResponse("Branch required") content = render_to_string( 'history_tracking/components/tag_create.html', {'branch_name': branch_name}, request=request ) return HttpResponse(content) @transaction.atomic def post(self, request): name = request.POST.get('name') branch_name = request.POST.get('branch') if not (name and branch_name): return JsonResponse( {'error': 'Tag name and branch required'}, status=400 ) try: branch = get_object_or_404(VersionBranch, name=branch_name) # Get latest historical record for the branch latest_change = ChangeSet.objects.filter( branch=branch, status='applied' ).latest('created_at') if not latest_change: return JsonResponse( {'error': 'No changes to tag'}, status=400 ) tag = VersionTag.objects.create( name=name, branch=branch, historical_record=latest_change.historical_records.latest('history_date'), created_by=request.user, metadata={ 'tagged_at': timezone.now().isoformat(), 'changeset': latest_change.pk } ) content = render_to_string( 'history_tracking/components/tag_item.html', {'tag': tag}, request=request ) return HttpResponse(content) except ValidationError as e: return JsonResponse({'error': str(e)}, status=400) except Exception as e: return JsonResponse( {'error': 'Tag creation failed. Please try again.'}, status=500 )