Resolve "Napraviti dummy payment page" #59

Merged
amirsabani303 merged 4 commits from 10-napraviti-dummy-payment-page into master 2025-02-21 07:23:53 +01:00
11 changed files with 214 additions and 55 deletions

View File

@@ -34,7 +34,7 @@ def create_document_for_organization(confirmation_email):
for risk in top_risks:
controls_content += f"Risk: {risk.risk_id} - {risk.risk_name}\n"
selected_controls = get_controls_for_risk(risk)
selected_controls = get_controls_for_risk(risk ,organization=organization)
for control_id, weight in selected_controls:
control = Control.objects.filter(id=control_id).first()

View File

@@ -1,8 +1,10 @@
{% extends "base_login.html" %}
{% extends "base.html" %}
{%block content%}
<h2>Link has expired! </h2>
<form method="POST">
{% csrf_token %}
<button type="submit">Resend link</button>
</form>
</form>
{% endblock %}

View File

@@ -1,5 +1,11 @@
{% extends "base_login.html" %}
{% extends "base.html" %}
{%block content%}
<div class="out-risk-management">
<div class="risk-management">
<h1>Email Confirmed!</h1>
<p>Your email {{ email }} has been successfully verified.</p>
</div>
</div>
<h1>Email Confirmed!</h1>
<p>Your email {{ email }} has been successfully verified.</p>
{%endblock%}

View File

@@ -4,7 +4,7 @@ from .models import EmailConfirmation
import uuid
from django.conf import settings
from django.utils.timezone import now
from backend.core.models import Document, Organization
def send_confirmation_email(email):
confirmation, created = EmailConfirmation.objects.get_or_create(email=email)
@@ -21,4 +21,28 @@ def send_confirmation_email(email):
message=f"Please click on the link to confirm your e-mail address: {confirmation_link}",
from_email= settings.EMAIL_HOST_USER,
recipient_list=[email]
)
)
def send_payment_email(email):
organization = Organization.objects.get(email=email)
document = Document.objects.get(organization=organization)
payment_link = f"http://127.0.0.1:8000{reverse('core:payment_page')}?email={email}"
send_mail(
subject="Complete your payment",
message=f"Click the link to proceed with payment: {payment_link}",
from_email=settings.EMAIL_HOST_USER,
recipient_list=[email],
fail_silently=False,
)
def send_document_email(email, document_link):
send_mail(
subject="Your Document is Ready",
message=f"You can access your document at any time here: {document_link}",
from_email=settings.EMAIL_HOST_USER,
recipient_list=[email],
fail_silently=False,
)

View File

@@ -17,13 +17,10 @@ def confirm_email(request, uuid):
confirmation = get_object_or_404(EmailConfirmation, uuid=uuid)
if confirmation.is_expired():
return render(request, 'confirmation_expired.html', {'email': confirmation.email})
return render(request, 'accounts/confirmation_expired.html', {'email': confirmation.email})
task = create_document_for_organization.delay(confirmation.email)
print(f"Task ID: {task.id}")
return HttpResponse("Email is confirmed")
return render(request, 'accounts/confirmation_success.html', {'email': confirmation.email})
def resend_confirmation(request,email):
if request.method == 'POST':

View File

@@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% block content %}
<div class="out-risk-management">
<div class="risk-management">
<h2>Payment</h2>
<p>Click the button below to pay and access your document.</p>
<form method="post">
{% csrf_token %}
<button class="btn-bl" type="submit">Pay</button>
</form>
</div>
</div>
{% endblock %}

View File

@@ -11,4 +11,5 @@ urlpatterns = [
# url document/ recieves a parameter named 'uuid' and passes it to the view
path('document/<uuid:document_id>/', v.document, name='document'),
path('preview/<str:name>/', v.template_preview, name='template_preview'),
path("payment/", v.payment_page, name="payment_page"),
]

View File

@@ -1,17 +1,19 @@
from openai import OpenAI
from django.conf import settings
from .models import Risk, Control, Document, DocumentRiskControl
from django.shortcuts import get_object_or_404
from .models import Risk, Control
import time
def extract_risk_factors(organization):
excluded_fields={"name","email"}
def extract_organization_details(organization):
excluded_fields = {"name", "email"}
risk_data = {}
for field in organization._meta.get_fields():
if field.name not in excluded_fields and hasattr(organization, field.name):
value = getattr(organization, field.name)
if value:
risk_data[field.name] = value
help_text = getattr(field, 'help_text', '').strip()
key = help_text if help_text else field.name
risk_data[key] = value
return risk_data
def get_top_risk(organization):
@@ -26,16 +28,21 @@ def get_top_risk(organization):
Category: {risk.category}
Name: {risk.risk_name}
Primary Impact: {risk.primary_impact}
Secondary Impact: {risk.secondary_impact}
Tertiary Impact: {risk.tretiary_impact}
Detection Difficulty: {risk.detection_difficulty}
Recovery Complexity: {risk.recovery_complexity}
Business Impact Severity: {risk.businnes_impact_severity}
""")
risk_factors = extract_risk_factors(organization)
organization_details = extract_organization_details(organization)
prompt = f"""
You are an AI risk assessor. Based on the following company details and list of known risks,
identify the 10 most critical risks for this company. Respond only with risk IDs.
Company Details:
{risk_factors}
{organization_details}
List of Risks:
{risk_list}
@@ -44,59 +51,134 @@ def get_top_risk(organization):
"""
response = client.chat.completions.create(
model="gpt-4",
model="gpt-4o-mini",
messages=[{"role": "system", "content": prompt}]
)
risk_ids = response.choices[0].message.content.strip().split(",")
print(f"Risks: {risk_ids}")
return [int(risk_id) for risk_id in risk_ids if risk_id.isdigit()]
def get_controls_for_risk(risk):
def get_controls_for_risk(risk, organization):
client = OpenAI(api_key=settings.OPENAI_API_KEY)
all_controls = Control.objects.all()
control_list = []
organization_details = extract_organization_details(organization)
control_list = [f"Control ID: {control.id}, Control Name: {control.name}" for control in all_controls]
valid_control_ids = {control.id for control in all_controls}
control_map = {control.id: control.name for control in all_controls}
for control in all_controls:
control_list.append(f"Control ID: {control.id}, Control Name: {control.name}")
def fetch_controls(prompt):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": prompt}]
)
return response.choices[0].message.content.strip()
prompt = f"""
You are a cyber security expert. For the risk '{risk.risk_name}', select 10 relevant controls
from the following list and assign a weight (1-10) based on how much they reduce risks.
Available Controls (only respond with control IDs and weights):
You are an expert in cybersecurity risk management. Given the risk "{risk.risk_name}" and its associated organization details "{organization_details}",
your task is to select **exactly 10 unique controls** from the provided list that best mitigate this risk. Each control should be assigned a weight between **1 and 10** based on its effectiveness in reducing the risk.
### Rules:
1. **Each control ID must be unique** (no duplicates).
2. **Only return control IDs and weights** in the exact format below.
3. **Weights must be between 1 and 10** (1 = low impact, 10 = high impact).
4. **Do NOT add explanations, descriptions, or extra text.**
5. **Ensure that control IDs are randomly distributed and diverse across different categories.**
### Available Controls:
{control_list}
Respond only with control IDs (numbers) and their corresponding weights (1-10).
Format:
ID: <control_id> Weight: <weight>
Example:
1: 9
2: 6
3: 4
### Expected Response Format (STRICTLY FOLLOW THIS FORMAT):
<control_id> : <weight>
<control_id> : <weight>
### Example Correct Response (NO DUPLICATES):
12 : 8
45 : 7
⚠️ **If you provide duplicate control IDs, your response will be rejected. Ensure all control IDs are unique.**
⚠️ **Follow the response format exactly. Any deviation will be considered invalid.**
"""
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "system", "content": prompt}]
)
result = response.choices[0].message.content.strip()
selected_controls = []
control_ids_seen = set()
result = fetch_controls(prompt)
for line in result.split("\n"):
line = line.strip()
parts = line.split("Weight:")
parts = line.split(":")
if len(parts) == 2:
control_id_str = parts[0].replace("ID:", "").replace("id:", "").replace("Id:", "").strip()
weight_str = parts[1].strip().replace("Weight:", "").replace("weight:","").strip()
control_id_str = parts[0].replace("ID:", "").replace("id:", "").replace("Id:", "").strip()
weight_str = parts[1].strip().replace("Weight:", "").replace("weight:", "").strip()
print(f"Control:{control_id_str} Weight:{weight_str}")
print(f"ControlType: {type(control_id_str)} WeightType: {type(weight_str)}")
control_id_str = ''.join(filter(str.isdigit, control_id_str))
weight_str = ''.join(filter(str.isdigit, weight_str))
control_id = int(control_id_str)
weight = int(weight_str)
print(f"ID: {control_id}, Weight: {weight}")
if control_id_str and weight_str:
try:
control_id = int(control_id_str)
weight = int(weight_str)
if control_id in valid_control_ids and 1 <= weight <= 10 and control_id not in control_ids_seen:
selected_controls.append((control_id, weight))
control_ids_seen.add(control_id)
except ValueError:
continue
if len(selected_controls) == 10:
return selected_controls
while len(selected_controls) < 10:
missing_count = 10 - len(selected_controls)
remaining_controls = valid_control_ids - control_ids_seen
remaining_controls_list = [f"Control ID: {cid}, Control Name: {control_map[cid]}" for cid in remaining_controls]
control = Control.objects.filter(id=control_id).first()
if control:
selected_controls.append((control_id, weight))
return selected_controls[:10]
retry_prompt = f"""
You are an expert in cybersecurity risk management. Given the risk "{risk.risk_name}" and its associated organization details "{organization_details}",
your task is to select **exactly {missing_count} unique controls** from the provided list that best mitigate this risk. Each control should be assigned a weight between **1 and 10** based on its effectiveness in reducing the risk.
### Rules:
1. **Each control ID must be unique** (no duplicates).
2. **Only return control IDs and weights** in the exact format below.
3. **Weights must be between 1 and 10** (1 = low impact, 10 = high impact).
4. **Do NOT add explanations, descriptions, or extra text.**
5. **Ensure that control IDs are randomly distributed and diverse across different categories.**
### Available Controls:
{remaining_controls_list}
### Expected Response Format (STRICTLY FOLLOW THIS FORMAT):
<control_id> : <weight>
<control_id> : <weight>
### Example Correct Response (NO DUPLICATES):
12 : 8
45 : 7
⚠️ **If you provide duplicate control IDs, your response will be rejected. Ensure all control IDs are unique.**
⚠️ **Follow the response format exactly. Any deviation will be considered invalid.**
"""
result = fetch_controls(retry_prompt)
for line in result.split("\n"):
line = line.strip()
parts = line.split(":")
if len(parts) == 2:
control_id_str = parts[0].replace("ID:", "").replace("id:", "").replace("Id:", "").strip()
weight_str = parts[1].strip().replace("Weight:", "").replace("weight:", "").strip()
print(f"Control:{control_id} Weight:{weight_str}")
print(f"ControlType: {type(control_id)} WeightType: {type(weight_str)}")
control_id_str = ''.join(filter(str.isdigit, control_id_str))
weight_str = ''.join(filter(str.isdigit, weight_str))
if control_id_str and weight_str:
try:
control_id = int(control_id_str)
weight = int(weight_str)
if control_id in valid_control_ids and 1 <= weight <= 10 and control_id not in control_ids_seen:
selected_controls.append((control_id, weight))
control_ids_seen.add(control_id)
except ValueError:
continue
if not remaining_controls:
break
return selected_controls if len(selected_controls) == 10 else []

View File

@@ -5,7 +5,7 @@ from .forms import OrganizationForm
from .models import Organization,Document,Risk, DocumentTemplate
from backend.core.utils import get_top_risk
from django.urls import reverse
from backend.accounts.utils import send_confirmation_email
from backend.accounts.utils import send_confirmation_email, send_document_email
from django.contrib.admin.views.decorators import staff_member_required
# @login_required
@@ -56,4 +56,17 @@ def document(request, document_id):
def template_preview(request, name):
template = get_object_or_404(DocumentTemplate, name=name)
parsed_template = template.to_dict()
return render(request, 'template_preview.html', {'template': parsed_template})
return render(request, 'template_preview.html', {'template': parsed_template})
def payment_page(request):
email = request.GET.get("email")
organization = Organization.objects.get(email=email)
document = Document.objects.get(organization=organization)
document_link = f"http://127.0.0.1:8000/document/{document.id}/"
if request.method == "POST":
send_document_email(email, document_link)
return redirect(document_link)
return render(request, "payment.html", {"email": email})

View File

@@ -9,3 +9,11 @@ Faker==33.0.0
isort==5.13.2
python-decouple==3.8
psycopg2-binary==2.9.10
openai==1.63.0
python-dotenv==1.0.1
PyYAML==6.0.2
celery==5.4.0
django-celery-results==2.5.1
redis==5.2.1

12
start_services.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
echo "Starting Django server..."
python3 manage.py runserver &
echo "Starting Celery worker..."
celery -A backend worker --loglevel=info &
echo "Starting Redis server on port 6380..."
redis-server --port 6380 &
wait