from rest_framework import serializers from django.contrib.auth import get_user_model from ..models import ( Postmortem, KnowledgeBaseArticle, IncidentRecommendation, LearningPattern, KnowledgeBaseUsage, AutomatedPostmortemGeneration ) User = get_user_model() class PostmortemSerializer(serializers.ModelSerializer): """Serializer for Postmortem model""" owner_username = serializers.CharField(source='owner.username', read_only=True) approver_username = serializers.CharField(source='approver.username', read_only=True) reviewer_usernames = serializers.StringRelatedField(source='reviewers', many=True, read_only=True) incident_title = serializers.CharField(source='incident.title', read_only=True) completion_percentage = serializers.ReadOnlyField() is_overdue = serializers.ReadOnlyField() class Meta: model = Postmortem fields = [ 'id', 'title', 'incident', 'incident_title', 'executive_summary', 'timeline', 'root_cause_analysis', 'impact_assessment', 'lessons_learned', 'action_items', 'is_automated', 'generation_confidence', 'auto_generated_sections', 'status', 'severity', 'owner', 'owner_username', 'reviewers', 'reviewer_usernames', 'approver', 'approver_username', 'created_at', 'updated_at', 'published_at', 'due_date', 'related_incidents', 'affected_services', 'affected_teams', 'completion_percentage', 'is_overdue' ] read_only_fields = ['id', 'created_at', 'updated_at'] def validate(self, data): """Validate postmortem data""" if data.get('due_date') and data['due_date'] < timezone.now(): raise serializers.ValidationError("Due date cannot be in the past") return data class PostmortemListSerializer(serializers.ModelSerializer): """Simplified serializer for postmortem lists""" owner_username = serializers.CharField(source='owner.username', read_only=True) incident_title = serializers.CharField(source='incident.title', read_only=True) completion_percentage = serializers.ReadOnlyField() is_overdue = serializers.ReadOnlyField() class Meta: model = Postmortem fields = [ 'id', 'title', 'incident', 'incident_title', 'status', 'severity', 'owner_username', 'created_at', 'due_date', 'completion_percentage', 'is_overdue' ] class KnowledgeBaseArticleSerializer(serializers.ModelSerializer): """Serializer for KnowledgeBaseArticle model""" author_username = serializers.CharField(source='author.username', read_only=True) last_updated_by_username = serializers.CharField(source='last_updated_by.username', read_only=True) maintainer_username = serializers.CharField(source='maintainer.username', read_only=True) is_due_for_review = serializers.ReadOnlyField() class Meta: model = KnowledgeBaseArticle fields = [ 'id', 'title', 'slug', 'content', 'summary', 'tags', 'article_type', 'category', 'subcategory', 'related_services', 'related_components', 'status', 'is_featured', 'view_count', 'author', 'author_username', 'last_updated_by', 'last_updated_by_username', 'maintainer', 'maintainer_username', 'created_at', 'updated_at', 'last_reviewed', 'next_review_due', 'related_incidents', 'source_postmortems', 'confluence_url', 'wiki_url', 'external_references', 'search_keywords', 'difficulty_level', 'is_due_for_review' ] read_only_fields = ['id', 'created_at', 'updated_at', 'view_count'] def create(self, validated_data): """Create a new knowledge base article""" if not validated_data.get('slug'): validated_data['slug'] = self.generate_slug(validated_data['title']) return super().create(validated_data) def generate_slug(self, title): """Generate a URL-friendly slug from title""" import re slug = re.sub(r'[^\w\s-]', '', title.lower()) slug = re.sub(r'[-\s]+', '-', slug) return slug[:50] # Limit slug length class KnowledgeBaseArticleListSerializer(serializers.ModelSerializer): """Simplified serializer for knowledge base article lists""" author_username = serializers.CharField(source='author.username', read_only=True) is_due_for_review = serializers.ReadOnlyField() class Meta: model = KnowledgeBaseArticle fields = [ 'id', 'title', 'slug', 'summary', 'article_type', 'category', 'subcategory', 'status', 'is_featured', 'view_count', 'author_username', 'created_at', 'updated_at', 'difficulty_level', 'is_due_for_review' ] class IncidentRecommendationSerializer(serializers.ModelSerializer): """Serializer for IncidentRecommendation model""" incident_title = serializers.CharField(source='incident.title', read_only=True) related_incident_title = serializers.CharField(source='related_incident.title', read_only=True) knowledge_article_title = serializers.CharField(source='knowledge_article.title', read_only=True) suggested_expert_username = serializers.CharField(source='suggested_expert.username', read_only=True) applied_by_username = serializers.CharField(source='applied_by.username', read_only=True) class Meta: model = IncidentRecommendation fields = [ 'id', 'incident', 'incident_title', 'recommendation_type', 'title', 'description', 'similarity_score', 'confidence_level', 'confidence_score', 'related_incident', 'related_incident_title', 'knowledge_article', 'knowledge_article_title', 'suggested_expert', 'suggested_expert_username', 'suggested_actions', 'expected_outcome', 'time_to_implement', 'is_applied', 'applied_at', 'applied_by', 'applied_by_username', 'effectiveness_rating', 'reasoning', 'matching_factors', 'model_version', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def validate_effectiveness_rating(self, value): """Validate effectiveness rating""" if value is not None and (value < 1 or value > 5): raise serializers.ValidationError("Effectiveness rating must be between 1 and 5") return value class IncidentRecommendationListSerializer(serializers.ModelSerializer): """Simplified serializer for incident recommendation lists""" incident_title = serializers.CharField(source='incident.title', read_only=True) related_incident_title = serializers.CharField(source='related_incident.title', read_only=True) knowledge_article_title = serializers.CharField(source='knowledge_article.title', read_only=True) class Meta: model = IncidentRecommendation fields = [ 'id', 'incident', 'incident_title', 'recommendation_type', 'title', 'similarity_score', 'confidence_level', 'confidence_score', 'related_incident_title', 'knowledge_article_title', 'is_applied', 'created_at' ] class LearningPatternSerializer(serializers.ModelSerializer): """Serializer for LearningPattern model""" validated_by_username = serializers.CharField(source='validated_by.username', read_only=True) source_incident_count = serializers.SerializerMethodField() source_postmortem_count = serializers.SerializerMethodField() class Meta: model = LearningPattern fields = [ 'id', 'name', 'pattern_type', 'description', 'frequency', 'success_rate', 'confidence_score', 'triggers', 'actions', 'outcomes', 'source_incidents', 'source_postmortems', 'source_incident_count', 'source_postmortem_count', 'is_validated', 'validated_by', 'validated_by_username', 'validation_notes', 'times_applied', 'last_applied', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_source_incident_count(self, obj): """Get count of source incidents""" return obj.source_incidents.count() def get_source_postmortem_count(self, obj): """Get count of source postmortems""" return obj.source_postmortems.count() class LearningPatternListSerializer(serializers.ModelSerializer): """Simplified serializer for learning pattern lists""" validated_by_username = serializers.CharField(source='validated_by.username', read_only=True) class Meta: model = LearningPattern fields = [ 'id', 'name', 'pattern_type', 'frequency', 'success_rate', 'confidence_score', 'is_validated', 'validated_by_username', 'times_applied', 'created_at' ] class KnowledgeBaseUsageSerializer(serializers.ModelSerializer): """Serializer for KnowledgeBaseUsage model""" user_username = serializers.CharField(source='user.username', read_only=True) knowledge_article_title = serializers.CharField(source='knowledge_article.title', read_only=True) recommendation_title = serializers.CharField(source='recommendation.title', read_only=True) incident_title = serializers.CharField(source='incident.title', read_only=True) class Meta: model = KnowledgeBaseUsage fields = [ 'id', 'user', 'user_username', 'usage_type', 'knowledge_article', 'knowledge_article_title', 'recommendation', 'recommendation_title', 'incident', 'incident_title', 'context', 'session_id', 'created_at' ] read_only_fields = ['id', 'created_at'] class AutomatedPostmortemGenerationSerializer(serializers.ModelSerializer): """Serializer for AutomatedPostmortemGeneration model""" incident_title = serializers.CharField(source='incident.title', read_only=True) generated_postmortem_title = serializers.CharField(source='generated_postmortem.title', read_only=True) class Meta: model = AutomatedPostmortemGeneration fields = [ 'id', 'incident', 'incident_title', 'status', 'generation_trigger', 'incident_data', 'timeline_data', 'log_data', 'generated_content', 'confidence_scores', 'quality_metrics', 'generated_postmortem', 'generated_postmortem_title', 'processing_time', 'model_version', 'error_message', 'started_at', 'completed_at' ] read_only_fields = ['id', 'started_at', 'completed_at'] class PostmortemGenerationRequestSerializer(serializers.Serializer): """Serializer for requesting postmortem generation""" incident_id = serializers.UUIDField() include_timeline = serializers.BooleanField(default=True) include_logs = serializers.BooleanField(default=True) generation_trigger = serializers.CharField(max_length=50, default='manual') def validate_incident_id(self, value): """Validate that incident exists and is resolved""" from incident_intelligence.models import Incident try: incident = Incident.objects.get(id=value) if not incident.is_resolved: raise serializers.ValidationError("Postmortem can only be generated for resolved incidents") return value except Incident.DoesNotExist: raise serializers.ValidationError("Incident not found") class RecommendationRequestSerializer(serializers.Serializer): """Serializer for requesting incident recommendations""" incident_id = serializers.UUIDField() recommendation_types = serializers.ListField( child=serializers.ChoiceField(choices=IncidentRecommendation.RECOMMENDATION_TYPE_CHOICES), required=False ) max_recommendations = serializers.IntegerField(min_value=1, max_value=20, default=5) min_confidence = serializers.FloatField(min_value=0.0, max_value=1.0, default=0.5) def validate_incident_id(self, value): """Validate that incident exists""" from incident_intelligence.models import Incident try: Incident.objects.get(id=value) return value except Incident.DoesNotExist: raise serializers.ValidationError("Incident not found") class KnowledgeBaseSearchSerializer(serializers.Serializer): """Serializer for knowledge base search""" query = serializers.CharField(max_length=200) article_types = serializers.ListField( child=serializers.ChoiceField(choices=KnowledgeBaseArticle.ARTICLE_TYPE_CHOICES), required=False ) categories = serializers.ListField(child=serializers.CharField(), required=False) difficulty_levels = serializers.ListField( child=serializers.ChoiceField(choices=KnowledgeBaseArticle._meta.get_field('difficulty_level').choices), required=False ) limit = serializers.IntegerField(min_value=1, max_value=100, default=20) offset = serializers.IntegerField(min_value=0, default=0) class KnowledgeBaseArticleRatingSerializer(serializers.Serializer): """Serializer for rating knowledge base articles""" article_id = serializers.UUIDField() rating = serializers.IntegerField(min_value=1, max_value=5) feedback = serializers.CharField(max_length=500, required=False) def validate_article_id(self, value): """Validate that article exists""" try: KnowledgeBaseArticle.objects.get(id=value) return value except KnowledgeBaseArticle.DoesNotExist: raise serializers.ValidationError("Knowledge base article not found")