diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..c77a808 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..c0990a3 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659..5ef2e2f 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd6..0508c2f 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 8c38f3f..175ab6f 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,26 @@ from django.contrib import admin +from .models import Fanpage, Flow, Node, Edge, ChatSession, MessageLog -# Register your models here. +@admin.register(Fanpage) +class FanpageAdmin(admin.ModelAdmin): + list_display = ('name', 'page_id', 'is_active', 'created_at') + +@admin.register(Flow) +class FlowAdmin(admin.ModelAdmin): + list_display = ('name', 'fanpage', 'is_default', 'created_at') + +@admin.register(Node) +class NodeAdmin(admin.ModelAdmin): + list_display = ('name', 'flow', 'node_type', 'is_start_node') + +@admin.register(Edge) +class EdgeAdmin(admin.ModelAdmin): + list_display = ('source_node', 'target_node', 'condition') + +@admin.register(ChatSession) +class ChatSessionAdmin(admin.ModelAdmin): + list_display = ('psid', 'fanpage', 'current_node', 'updated_at') + +@admin.register(MessageLog) +class MessageLogAdmin(admin.ModelAdmin): + list_display = ('session', 'sender_type', 'timestamp') \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..fc4d89e --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,87 @@ +# Generated by Django 5.2.7 on 2026-02-07 17:11 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Fanpage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('page_id', models.CharField(max_length=255, unique=True)), + ('access_token', models.TextField()), + ('verify_token', models.CharField(help_text='Token for Facebook Webhook verification', max_length=255)), + ('is_active', models.BooleanField(default=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='ChatSession', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('psid', models.CharField(help_text='Facebook Page Scoped ID of the user', max_length=255)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('fanpage', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.fanpage')), + ], + ), + migrations.CreateModel( + name='Flow', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True)), + ('is_default', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('fanpage', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='flows', to='core.fanpage')), + ], + ), + migrations.CreateModel( + name='MessageLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sender_type', models.CharField(choices=[('user', 'User'), ('bot', 'Bot')], max_length=10)), + ('message_text', models.TextField()), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('session', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='core.chatsession')), + ], + ), + migrations.CreateModel( + name='Node', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Internal name for this step', max_length=255)), + ('node_type', models.CharField(choices=[('text', 'Text Message'), ('buttons', 'Buttons/Quick Replies'), ('image', 'Image')], default='text', max_length=20)), + ('content', models.JSONField(help_text='Stores the message text, button labels, etc.')), + ('is_start_node', models.BooleanField(default=False)), + ('flow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='nodes', to='core.flow')), + ], + ), + migrations.CreateModel( + name='Edge', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('condition', models.CharField(help_text='Keyword or button payload that triggers this edge', max_length=255)), + ('flow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='edges', to='core.flow')), + ('source_node', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='outgoing_edges', to='core.node')), + ('target_node', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incoming_edges', to='core.node')), + ], + ), + migrations.AddField( + model_name='chatsession', + name='current_node', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.node'), + ), + migrations.AlterUniqueTogether( + name='chatsession', + unique_together={('psid', 'fanpage')}, + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..3e42eee Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..a511c6b 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,61 @@ from django.db import models -# Create your models here. +class Fanpage(models.Model): + name = models.CharField(max_length=255) + page_id = models.CharField(max_length=255, unique=True) + access_token = models.TextField() + verify_token = models.CharField(max_length=255, help_text="Token for Facebook Webhook verification") + is_active = models.BooleanField(default=True) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name + +class Flow(models.Model): + name = models.CharField(max_length=255) + description = models.TextField(blank=True) + fanpage = models.ForeignKey(Fanpage, on_delete=models.CASCADE, related_name='flows') + is_default = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"{self.name} ({self.fanpage.name})" + +class Node(models.Model): + NODE_TYPES = ( + ('text', 'Text Message'), + ('buttons', 'Buttons/Quick Replies'), + ('image', 'Image'), + ) + flow = models.ForeignKey(Flow, on_delete=models.CASCADE, related_name='nodes') + name = models.CharField(max_length=255, help_text="Internal name for this step") + node_type = models.CharField(max_length=20, choices=NODE_TYPES, default='text') + content = models.JSONField(help_text="Stores the message text, button labels, etc.") + is_start_node = models.BooleanField(default=False) + + def __str__(self): + return f"{self.name} [{self.node_type}]" + +class Edge(models.Model): + flow = models.ForeignKey(Flow, on_delete=models.CASCADE, related_name='edges') + source_node = models.ForeignKey(Node, on_delete=models.CASCADE, related_name='outgoing_edges') + target_node = models.ForeignKey(Node, on_delete=models.CASCADE, related_name='incoming_edges') + condition = models.CharField(max_length=255, help_text="Keyword or button payload that triggers this edge") + + def __str__(self): + return f"{self.source_node.name} -> {self.target_node.name} on '{self.condition}'" + +class ChatSession(models.Model): + psid = models.CharField(max_length=255, help_text="Facebook Page Scoped ID of the user") + fanpage = models.ForeignKey(Fanpage, on_delete=models.CASCADE) + current_node = models.ForeignKey(Node, on_delete=models.SET_NULL, null=True, blank=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + unique_together = ('psid', 'fanpage') + +class MessageLog(models.Model): + session = models.ForeignKey(ChatSession, on_delete=models.CASCADE, related_name='logs') + sender_type = models.CharField(max_length=10, choices=(('user', 'User'), ('bot', 'Bot'))) + message_text = models.TextField() + timestamp = models.DateTimeField(auto_now_add=True) \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..1739522 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,53 @@ -
- -