This commit is contained in:
Iliyan Angelov
2025-11-24 03:52:08 +02:00
parent dfcaebaf8c
commit 366f28677a
18241 changed files with 865352 additions and 567 deletions

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

39
backEnd/policies/admin.py Normal file
View File

@@ -0,0 +1,39 @@
from django.contrib import admin
from .models import Policy, PolicySection
class PolicySectionInline(admin.TabularInline):
model = PolicySection
extra = 1
fields = ['heading', 'content', 'order', 'is_active']
@admin.register(Policy)
class PolicyAdmin(admin.ModelAdmin):
list_display = ['title', 'type', 'version', 'last_updated', 'effective_date', 'is_active']
list_filter = ['type', 'is_active', 'last_updated']
search_fields = ['title', 'type', 'description']
prepopulated_fields = {'slug': ('type',)}
readonly_fields = ('last_updated',)
inlines = [PolicySectionInline]
fieldsets = (
('Basic Information', {
'fields': ('type', 'title', 'slug', 'description')
}),
('Version & Dates', {
'fields': ('version', 'effective_date', 'last_updated')
}),
('Status', {
'fields': ('is_active',)
}),
)
@admin.register(PolicySection)
class PolicySectionAdmin(admin.ModelAdmin):
list_display = ['policy', 'heading', 'order', 'is_active']
list_filter = ['policy__type', 'is_active']
search_fields = ['heading', 'content']
list_editable = ['order', 'is_active']

8
backEnd/policies/apps.py Normal file
View File

@@ -0,0 +1,8 @@
from django.apps import AppConfig
class PoliciesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'policies'
verbose_name = 'Policies Management'

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,54 @@
# Generated by Django 4.2.7 on 2025-10-08 13:54
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Policy',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', models.CharField(choices=[('privacy', 'Privacy Policy'), ('terms', 'Terms of Use'), ('support', 'Support Policy')], help_text='Type of policy document', max_length=50, unique=True)),
('title', models.CharField(help_text='Title of the policy', max_length=200)),
('slug', models.SlugField(blank=True, max_length=100, unique=True)),
('description', models.TextField(blank=True, help_text='Brief description of the policy')),
('last_updated', models.DateField(auto_now=True, help_text='Last update date')),
('version', models.CharField(default='1.0', help_text='Policy version number', max_length=20)),
('is_active', models.BooleanField(default=True, help_text='Whether this policy is currently active')),
('effective_date', models.DateField(help_text='Date when this policy becomes effective')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'Policy',
'verbose_name_plural': 'Policies',
'ordering': ['type'],
},
),
migrations.CreateModel(
name='PolicySection',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('heading', models.CharField(help_text='Section heading', max_length=300)),
('content', models.TextField(help_text='Section content')),
('order', models.IntegerField(default=0, help_text='Display order of sections')),
('is_active', models.BooleanField(default=True, help_text='Whether this section is currently active')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('policy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sections', to='policies.policy')),
],
options={
'verbose_name': 'Policy Section',
'verbose_name_plural': 'Policy Sections',
'ordering': ['policy', 'order'],
},
),
]

View File

100
backEnd/policies/models.py Normal file
View File

@@ -0,0 +1,100 @@
from django.db import models
from django.utils.text import slugify
class Policy(models.Model):
"""
Model to store various policy documents (Privacy, Terms, Support, etc.)
"""
POLICY_TYPES = [
('privacy', 'Privacy Policy'),
('terms', 'Terms of Use'),
('support', 'Support Policy'),
]
type = models.CharField(
max_length=50,
choices=POLICY_TYPES,
unique=True,
help_text="Type of policy document"
)
title = models.CharField(
max_length=200,
help_text="Title of the policy"
)
slug = models.SlugField(
max_length=100,
unique=True,
blank=True
)
description = models.TextField(
blank=True,
help_text="Brief description of the policy"
)
last_updated = models.DateField(
auto_now=True,
help_text="Last update date"
)
version = models.CharField(
max_length=20,
default="1.0",
help_text="Policy version number"
)
is_active = models.BooleanField(
default=True,
help_text="Whether this policy is currently active"
)
effective_date = models.DateField(
help_text="Date when this policy becomes effective"
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Policy"
verbose_name_plural = "Policies"
ordering = ['type']
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.type)
super().save(*args, **kwargs)
def __str__(self):
return f"{self.get_type_display()} (v{self.version})"
class PolicySection(models.Model):
"""
Individual sections within a policy document
"""
policy = models.ForeignKey(
Policy,
on_delete=models.CASCADE,
related_name='sections'
)
heading = models.CharField(
max_length=300,
help_text="Section heading"
)
content = models.TextField(
help_text="Section content"
)
order = models.IntegerField(
default=0,
help_text="Display order of sections"
)
is_active = models.BooleanField(
default=True,
help_text="Whether this section is currently active"
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Policy Section"
verbose_name_plural = "Policy Sections"
ordering = ['policy', 'order']
def __str__(self):
return f"{self.policy.type} - {self.heading}"

View File

@@ -0,0 +1,47 @@
from rest_framework import serializers
from .models import Policy, PolicySection
class PolicySectionSerializer(serializers.ModelSerializer):
"""Serializer for policy sections"""
class Meta:
model = PolicySection
fields = ['id', 'heading', 'content', 'order']
class PolicySerializer(serializers.ModelSerializer):
"""Serializer for policies with their sections"""
sections = PolicySectionSerializer(many=True, read_only=True)
class Meta:
model = Policy
fields = [
'id',
'type',
'title',
'slug',
'description',
'last_updated',
'version',
'effective_date',
'sections'
]
class PolicyListSerializer(serializers.ModelSerializer):
"""Simplified serializer for policy listing"""
class Meta:
model = Policy
fields = [
'id',
'type',
'title',
'slug',
'description',
'last_updated',
'version'
]

View File

@@ -0,0 +1,4 @@
from django.test import TestCase
# Create your tests here.

11
backEnd/policies/urls.py Normal file
View File

@@ -0,0 +1,11 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import PolicyViewSet
router = DefaultRouter()
router.register(r'', PolicyViewSet, basename='policy')
urlpatterns = [
path('', include(router.urls)),
]

52
backEnd/policies/views.py Normal file
View File

@@ -0,0 +1,52 @@
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from .models import Policy, PolicySection
from .serializers import PolicySerializer, PolicyListSerializer
class PolicyViewSet(viewsets.ReadOnlyModelViewSet):
"""
ViewSet for viewing policies.
Provides list and retrieve actions.
"""
queryset = Policy.objects.filter(is_active=True)
def get_serializer_class(self):
if self.action == 'list':
return PolicyListSerializer
return PolicySerializer
def get_queryset(self):
queryset = Policy.objects.filter(is_active=True)
policy_type = self.request.query_params.get('type', None)
if policy_type:
queryset = queryset.filter(type=policy_type)
return queryset
def retrieve(self, request, pk=None):
"""
Retrieve a policy by ID or type
"""
# Try to get by ID first
if pk.isdigit():
policy = get_object_or_404(Policy, pk=pk, is_active=True)
else:
# Otherwise try by type (slug)
policy = get_object_or_404(Policy, type=pk, is_active=True)
serializer = self.get_serializer(policy)
return Response(serializer.data)
@action(detail=False, methods=['get'], url_path='by-type/(?P<policy_type>[^/.]+)')
def by_type(self, request, policy_type=None):
"""
Get a specific policy by its type
"""
policy = get_object_or_404(Policy, type=policy_type, is_active=True)
serializer = PolicySerializer(policy)
return Response(serializer.data)