From 6c3327bd3f5076a571c7d5854232408115b7fcfd Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 7 Feb 2026 17:19:22 +0000 Subject: [PATCH] v1 --- core/__pycache__/admin.cpython-311.pyc | Bin 212 -> 2412 bytes core/__pycache__/models.cpython-311.pyc | Bin 209 -> 5558 bytes core/__pycache__/urls.cpython-311.pyc | Bin 347 -> 621 bytes core/__pycache__/views.cpython-311.pyc | Bin 1364 -> 2226 bytes core/admin.py | 25 +- core/migrations/0001_initial.py | 87 +++++++ .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 5222 bytes core/models.py | 60 ++++- core/templates/base.html | 66 ++++-- core/templates/core/dashboard.html | 110 +++++++++ core/templates/core/fanpage_list.html | 42 ++++ core/templates/core/flow_list.html | 46 ++++ core/templates/core/index.html | 214 ++++++------------ core/urls.py | 10 +- core/views.py | 47 ++-- static/css/custom.css | 76 ++++++- staticfiles/css/custom.css | 83 +++++-- 17 files changed, 661 insertions(+), 205 deletions(-) create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 core/templates/core/dashboard.html create mode 100644 core/templates/core/fanpage_list.html create mode 100644 core/templates/core/flow_list.html diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392d6714413db63120e4233d2e96cbadb5de..c77a80823762fd57e2e745bb3886915fe09a53a9 100644 GIT binary patch literal 2412 zcmb7_OK;Ok6vt<5C(g4?Z)quNc}O6xvbfC(78Fs@-j)q?!_FJac&5SNNAB1Ly6Xao zZFYQvBGfNKr7X~_kXW%R>RqwooJriIu7wgiKA9Px`JMlqdH7SaStD=-;)CbugnY+J zc9lnkvl|*A9|rTrh|Q^q^EqOrfH()l`KgI5)_P9b3qNqK+EkVt7I@(goa=U3 zn!8TebGlp_yMFXm8ha6g@(zQR`u0mFdCue5i$Ym@1_khY8gP69YiekvD~oj|5C>vy=nMfoY>5Zd%knsh@}zyx9{A7-SiZ3b%r#)y!0&5a;D>P0B;pS>@q`Uyx_)<3gy0&~7IO zJuaIdGfo_l*w|Jq@+OKzqmp?IYib18G^-+9d_zULtjAF*T&^O^I*91u_Lx`$m~6PI5Ih`7t))Gdt?R-mZbKh| z<_bKQwEjD(6}@KEIzQgJSz66_w5{tg4;dH3iLNGIz+t9?UU5p-Q6?H(mzQKdn3RcL zd+h}|$6h&MH(H0uN`&`9=+G|9u$j3ZixN}>e#3-`2G_T!qQNhYtO(wP&CLazJ?O8r z4>zmY5^Bk*Syt&&;x2BTUzLZ$W8;yy4@5kw;zjsUp6Zm+ujJO3i@&dA_scB5Z*=}} z>HUqqc|unPbmdf|bc>#nV%xtrSiJpHz5HL1U%gf0!}64JI6t;qIE zgVrsiZBwLeQ=~1AyA{#?pe>_qDcaTr8gwh7ZQ?-l=3Le$s@j|swK=BLPw3i!uHguG z)Ch}gKOJ2C8%MaKH0>x&*T>z?HPue&>VU2yZ38vsO`i{z?;>aeHEp0Kh@SUXr`2yY Cefwqr delta 168 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 Ku%RM0pb7xLi8T)Z diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659f6c6e0ae848e54157af197c543a09315f..5ef2e2fd625e814d47bae5164f3d4104d5e59d25 100644 GIT binary patch literal 621 zcmZvYze^)Q6vy9W-^SgnIZ@#dOdGhs;Z`XEN3OZrMr>jsYi9Dp+aFWg?9M_k zg`j_dM!d?uWCL4-ZLhKm*je2hV*(z&oqhA>JD*|RcW#Tt0#F>w-`x@e_^TH4FkXwN z2P&?B17|LHtic%Y9M{~Or!_PNIS`Da&<=5akn4Z)HyXe_{j+#smWa{k3OC+mOk(m2 zrtmIf5wo;lmj7qk*f4l;2Pz*P6;xpv_ME8mNcPl1|IrowFoO&`fhW|i?|5QR;7-^% z2pq}n%v{t1v*q|br!7J|TYfF~-EJ5S@+~*$lWMB@McS^InZ*wsza4DF(ha3@FO?ao zTuarmG*wbhE-gx#MIbd73F(J-@I(?kf3{U)c6<=~QEZDN(Tt-&+WkO&4|`5i*v&xF zHr=q*`}u5q@d6&ZqApkIu<{sQP?~Ctu?dutw_^h9$=fl_gKnOFJ6k*3J#SpM5-g9g zoML%`2C1cCeEDm%mtbv-wG?YJb#o}vkDo>-3D(D0Pq99eH-^>AucOTbt7ELDSe=^s NO77HBpIo7y{s9`XoU;G` delta 244 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 literal 0 HcmV?d00001 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 @@ - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}FlowBot | Facebook Automation{% endblock %} + + {% load static %} + + {% block head %}{% endblock %} - - {% block content %}{% endblock %} - + - + {% block content %}{% endblock %} + +
+
+

© 2026 FlowBot Automation. Built with Django & Love.

+
+
+ + + {% block scripts %}{% endblock %} + + \ No newline at end of file diff --git a/core/templates/core/dashboard.html b/core/templates/core/dashboard.html new file mode 100644 index 0000000..f1402aa --- /dev/null +++ b/core/templates/core/dashboard.html @@ -0,0 +1,110 @@ +{% extends 'base.html' %} + +{% block title %}Dashboard | FlowBot{% endblock %} + +{% block content %} +
+
+
+

Welcome back, {{ user.username }}!

+

Here's what's happening with your bots today.

+
+ +
+ +
+
+
+
Active Pages
+
{{ fanpage_count }}
+
+
+
+
+
Total Flows
+
{{ flow_count }}
+
+
+
+
+
Today's Messages
+
0
+
+
+
+ +
+
+
+
+
Connected Fanpages
+ View All +
+
+ + + + + + + + + + + {% for page in fanpages %} + + + + + + + {% empty %} + + + + {% endfor %} + +
Page NameStatusActive FlowActions
+
{{ page.name }}
+ ID: {{ page.page_id }} +
+ {% if page.is_active %} + Active + {% else %} + Paused + {% endif %} + + {% with page.flows.first as flow %} + {% if flow %}{{ flow.name }}{% else %}None{% endif %} + {% endwith %} + + Manage +
No pages connected yet.
+
+
+
+
+
+
Recent Activity
+
+ {% for log in recent_logs %} +
+
+ + {{ log.sender_type|upper }} + + {{ log.timestamp|timesince }} ago +
+

{{ log.message_text }}

+
+ {% empty %} +

No recent activity found.

+ {% endfor %} +
+
+
+
+
+{% endblock %} diff --git a/core/templates/core/fanpage_list.html b/core/templates/core/fanpage_list.html new file mode 100644 index 0000000..6076464 --- /dev/null +++ b/core/templates/core/fanpage_list.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} + +{% block title %}Fanpages | FlowBot{% endblock %} + +{% block content %} +
+
+

Your Fanpages

+ Add Fanpage +
+ +
+ {% for page in fanpages %} +
+
+
+ + {% if page.is_active %}Active{% else %}Inactive{% endif %} + + Created {{ page.created_at|date:"M d, Y" }} +
+

{{ page.name }}

+

Page ID: {{ page.page_id }}

+
+
+ {{ page.flows.count }} Flow(s) + Edit Settings +
+
+
+ {% empty %} +
+
+

No Fanpages found

+

Connect your first Facebook Page to start automating!

+ Connect Now +
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/core/templates/core/flow_list.html b/core/templates/core/flow_list.html new file mode 100644 index 0000000..5c91e39 --- /dev/null +++ b/core/templates/core/flow_list.html @@ -0,0 +1,46 @@ +{% extends 'base.html' %} + +{% block title %}Flows | FlowBot{% endblock %} + +{% block content %} +
+
+

Conversation Flows

+ Create New Flow +
+ +
+ {% for flow in flows %} +
+
+
+

{{ flow.name }}

+ {% if flow.is_default %} + Default + {% endif %} +
+

{{ flow.description|default:"No description provided." }}

+
+
+ {{ flow.fanpage.name }} + {{ flow.nodes.count }} nodes +
+
+ Edit + +
+
+
+
+ {% empty %} +
+
+

No flows defined

+

Start by creating a conversation flow for one of your pages.

+ Create Flow +
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..407588e 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,75 @@ -{% extends "base.html" %} - -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% extends 'base.html' %} +{% load static %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+
+
+
+

Automate Your Facebook Conversations

+

Build powerful, multi-page chatbots with a simple flow builder. Scale your customer service 24/7 without breaking a sweat.

+ +
+
+
+
+
+ +
+
Smart Auto-Reply
+
+
+ Customer + "What are your opening hours?" +
+
+ FlowBot + "Hi there! We are open from 9 AM to 6 PM daily. Would you like to see our menu?" +
+
+
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
-{% endblock %} \ No newline at end of file + + +
+
+
+

Why Choose FlowBot?

+

The ultimate tool for multi-fanpage management.

+
+
+
+
+
+ +
+

Multi-Page Support

+

Connect and manage unlimited Fanpages from a single dashboard. Each page can have its own unique flow.

+
+
+
+
+
+ +
+

Flow Builder

+

Design complex conversation trees with buttons, quick replies, and images. No coding required.

+
+
+
+
+
+ +
+

Real-time Analytics

+

Track bot performance and view chat history in real-time to optimize your customer experience.

+
+
+
+
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..28de9ee 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,9 @@ from django.urls import path - -from .views import home +from . import views urlpatterns = [ - path("", home, name="home"), -] + path('', views.home, name='home'), + path('dashboard/', views.dashboard, name='dashboard'), + path('fanpages/', views.fanpage_list, name='fanpage_list'), + path('flows/', views.flow_list, name='flow_list'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..65ea9e7 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,32 @@ -import os -import platform - -from django import get_version as django_version -from django.shortcuts import render -from django.utils import timezone - +from django.shortcuts import render, redirect, get_object_or_404 +from django.contrib.auth.decorators import login_required +from .models import Fanpage, Flow, MessageLog, ChatSession def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() + if request.user.is_authenticated: + return redirect('dashboard') + return render(request, 'core/index.html') +@login_required +def dashboard(request): + fanpages = Fanpage.objects.all() + flows = Flow.objects.all() + recent_logs = MessageLog.objects.order_by('-timestamp')[:10] + context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + 'fanpage_count': fanpages.count(), + 'flow_count': flows.count(), + 'fanpages': fanpages, + 'recent_logs': recent_logs, } - return render(request, "core/index.html", context) + return render(request, 'core/dashboard.html', context) + +@login_required +def fanpage_list(request): + fanpages = Fanpage.objects.all() + return render(request, 'core/fanpage_list.html', {'fanpages': fanpages}) + +@login_required +def flow_list(request): + flows = Flow.objects.all() + return render(request, 'core/flow_list.html', {'flows': flows}) diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..811d7ef 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,4 +1,74 @@ -/* Custom styles for the application */ -body { - font-family: system-ui, -apple-system, sans-serif; +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@500;600;700&display=swap'); + +:root { + --fb-indigo: #2D3250; + --fb-slate: #424769; + --fb-grey: #7077A1; + --fb-coral: #F6B17A; + --fb-offwhite: #F0F0F0; } + +body { + font-family: 'Inter', sans-serif; + background-color: var(--fb-offwhite); + color: var(--fb-indigo); +} + +h1, h2, h3, h4, h5, h6 { + font-family: 'Outfit', sans-serif; +} + +.bg-indigo { background-color: var(--fb-indigo) !important; } +.bg-slate { background-color: var(--fb-slate) !important; } +.text-coral { color: var(--fb-coral) !important; } +.btn-coral { + background-color: var(--fb-coral); + color: var(--fb-indigo); + font-weight: 600; + border: none; + transition: all 0.3s ease; +} +.btn-coral:hover { + background-color: #e5a069; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(246, 177, 122, 0.3); +} + +.navbar { + background-color: rgba(45, 50, 80, 0.95); + backdrop-filter: blur(10px); +} + +.card { + border: none; + border-radius: 16px; + box-shadow: 0 4px 24px rgba(0,0,0,0.05); +} + +.hero-section { + background: linear-gradient(135deg, var(--fb-indigo) 0%, var(--fb-slate) 100%); + color: white; + padding: 100px 0; + position: relative; + overflow: hidden; +} + +.hero-section::after { + content: ''; + position: absolute; + top: -10%; + right: -5%; + width: 400px; + height: 400px; + background: radial-gradient(circle, var(--fb-coral) 0%, transparent 70%); + opacity: 0.1; + border-radius: 50%; +} + +.glass-card { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 20px; + padding: 30px; +} \ No newline at end of file diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 108056f..811d7ef 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -1,21 +1,74 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@500;600;700&display=swap'); :root { - --bg-color-start: #6a11cb; - --bg-color-end: #2575fc; - --text-color: #ffffff; - --card-bg-color: rgba(255, 255, 255, 0.01); - --card-border-color: rgba(255, 255, 255, 0.1); + --fb-indigo: #2D3250; + --fb-slate: #424769; + --fb-grey: #7077A1; + --fb-coral: #F6B17A; + --fb-offwhite: #F0F0F0; } + body { - margin: 0; font-family: 'Inter', sans-serif; - background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end)); - color: var(--text-color); - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - text-align: center; - overflow: hidden; - position: relative; + background-color: var(--fb-offwhite); + color: var(--fb-indigo); } + +h1, h2, h3, h4, h5, h6 { + font-family: 'Outfit', sans-serif; +} + +.bg-indigo { background-color: var(--fb-indigo) !important; } +.bg-slate { background-color: var(--fb-slate) !important; } +.text-coral { color: var(--fb-coral) !important; } +.btn-coral { + background-color: var(--fb-coral); + color: var(--fb-indigo); + font-weight: 600; + border: none; + transition: all 0.3s ease; +} +.btn-coral:hover { + background-color: #e5a069; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(246, 177, 122, 0.3); +} + +.navbar { + background-color: rgba(45, 50, 80, 0.95); + backdrop-filter: blur(10px); +} + +.card { + border: none; + border-radius: 16px; + box-shadow: 0 4px 24px rgba(0,0,0,0.05); +} + +.hero-section { + background: linear-gradient(135deg, var(--fb-indigo) 0%, var(--fb-slate) 100%); + color: white; + padding: 100px 0; + position: relative; + overflow: hidden; +} + +.hero-section::after { + content: ''; + position: absolute; + top: -10%; + right: -5%; + width: 400px; + height: 400px; + background: radial-gradient(circle, var(--fb-coral) 0%, transparent 70%); + opacity: 0.1; + border-radius: 50%; +} + +.glass-card { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 20px; + padding: 30px; +} \ No newline at end of file