update
This commit is contained in:
0
backEnd/policies/__init__.py
Normal file
0
backEnd/policies/__init__.py
Normal file
BIN
backEnd/policies/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backEnd/policies/__pycache__/admin.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backEnd/policies/__pycache__/apps.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backEnd/policies/__pycache__/models.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backEnd/policies/__pycache__/serializers.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/serializers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backEnd/policies/__pycache__/urls.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backEnd/policies/__pycache__/views.cpython-312.pyc
Normal file
BIN
backEnd/policies/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
39
backEnd/policies/admin.py
Normal file
39
backEnd/policies/admin.py
Normal 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
8
backEnd/policies/apps.py
Normal 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'
|
||||
|
||||
0
backEnd/policies/management/__init__.py
Normal file
0
backEnd/policies/management/__init__.py
Normal file
BIN
backEnd/policies/management/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
backEnd/policies/management/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
0
backEnd/policies/management/commands/__init__.py
Normal file
0
backEnd/policies/management/commands/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
323
backEnd/policies/management/commands/populate_policies.py
Normal file
323
backEnd/policies/management/commands/populate_policies.py
Normal file
File diff suppressed because one or more lines are too long
54
backEnd/policies/migrations/0001_initial.py
Normal file
54
backEnd/policies/migrations/0001_initial.py
Normal 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'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
backEnd/policies/migrations/__init__.py
Normal file
0
backEnd/policies/migrations/__init__.py
Normal file
Binary file not shown.
BIN
backEnd/policies/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
backEnd/policies/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
100
backEnd/policies/models.py
Normal file
100
backEnd/policies/models.py
Normal 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}"
|
||||
|
||||
47
backEnd/policies/serializers.py
Normal file
47
backEnd/policies/serializers.py
Normal 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'
|
||||
]
|
||||
|
||||
4
backEnd/policies/tests.py
Normal file
4
backEnd/policies/tests.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
11
backEnd/policies/urls.py
Normal file
11
backEnd/policies/urls.py
Normal 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
52
backEnd/policies/views.py
Normal 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)
|
||||
|
||||
Reference in New Issue
Block a user