This commit is contained in:
Flatlogic Bot 2026-03-22 22:50:51 +00:00
parent ebebe4715f
commit b19870501a
7 changed files with 113 additions and 22 deletions

View File

@ -0,0 +1,30 @@
# Generated by Django 5.2.7 on 2026-03-22 22:49
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_relationship'),
]
operations = [
migrations.CreateModel(
name='IdentityProfile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('full_name', models.CharField(max_length=255)),
('description', models.TextField(blank=True)),
('profile_image_url', models.URLField(blank=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
),
migrations.AddField(
model_name='entity',
name='profile',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='entities', to='core.identityprofile'),
),
]

View File

@ -8,6 +8,19 @@ class Source(models.Model):
def __str__(self):
return self.name
class IdentityProfile(models.Model):
"""
Groups various entities (Person, Email, Username, etc.) into a single identity profile.
"""
full_name = models.CharField(max_length=255)
description = models.TextField(blank=True)
profile_image_url = models.URLField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.full_name
class Entity(models.Model):
ENTITY_TYPES = (
('PERSON', 'Person'),
@ -18,6 +31,7 @@ class Entity(models.Model):
entity_type = models.CharField(max_length=20, choices=ENTITY_TYPES)
value = models.CharField(max_length=255, db_index=True)
source = models.ForeignKey(Source, on_delete=models.CASCADE, related_name='entities')
profile = models.ForeignKey(IdentityProfile, on_delete=models.SET_NULL, null=True, blank=True, related_name='entities')
confidence_score = models.FloatField(default=1.0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@ -45,4 +59,4 @@ class Relationship(models.Model):
unique_together = ('source_entity', 'target_entity', 'relationship_type')
def __str__(self):
return f"{self.source_entity} -[{self.relationship_type}]-> {self.target_entity}"
return f"{self.source_entity} -[{self.relationship_type}]-> {self.target_entity}"

View File

@ -1,30 +1,31 @@
from django.db import transaction
from core.models import Source, Entity
from core.models import Source, Entity, IdentityProfile
class IngestionService:
@staticmethod
def ingest_data(source_name, entity_type, raw_data):
def ingest_data(source_name, entity_type, value, profile_data=None):
"""
Aggregates and normalizes raw data into the system.
Aggregates and normalizes data into the system, optionally linking it to an IdentityProfile.
"""
with transaction.atomic():
source, _ = Source.objects.get_or_create(name=source_name)
# Simple normalization logic: assume raw_data is a dict
# In a real scenario, this would be more complex depending on source schema
identifier = raw_data.get('identifier')
if not identifier:
raise ValueError("Missing identifier in raw_data")
profile = None
if profile_data:
profile, _ = IdentityProfile.objects.get_or_create(
full_name=profile_data.get('full_name', 'Unknown'),
defaults={'description': profile_data.get('description', '')}
)
entity, created = Entity.objects.get_or_create(
identifier=identifier,
entity_type=entity_type,
defaults={'source': source, 'metadata': raw_data.get('metadata', {})}
value=value,
source=source,
defaults={'profile': profile}
)
if not created:
# Update existing entity metadata
entity.metadata.update(raw_data.get('metadata', {}))
if not created and profile:
entity.profile = profile
entity.save()
return entity
return entity

View File

@ -2,17 +2,63 @@
{% block content %}
<div class="container mt-5">
<h1 class="mb-4">System Dashboard</h1>
<div class="row">
<div class="col-md-12">
<h1 class="mb-4">System Dashboard</h1>
<div class="card">
<div class="col-md-12 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Welcome to the Management System</h5>
<p class="card-text">You are logged in as <strong>{{ user.username }}</strong>.</p>
<a href="{% url 'core:logout' %}" class="btn btn-danger">Logout</a>
<h5 class="card-title">Quick Search</h5>
<form id="searchForm" class="input-group">
<input type="text" id="searchInput" class="form-control" placeholder="Search for a person, email, or username...">
<button class="btn btn-primary" type="submit">Search</button>
</form>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">People & Identities</h5>
<div id="resultsArea">
<p class="text-muted">Enter a search term to find entities.</p>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-12">
<a href="{% url 'core:logout' %}" class="btn btn-outline-danger">Logout</a>
</div>
</div>
</div>
{% endblock %}
<script>
document.getElementById('searchForm').addEventListener('submit', function(e) {
e.preventDefault();
const query = document.getElementById('searchInput').value;
const resultsArea = document.getElementById('resultsArea');
resultsArea.innerHTML = '<p>Searching...</p>';
// Placeholder: In a real scenario, this would call your Django backend
fetch(`/api/search/?q=${encodeURIComponent(query)}`)
.then(response => response.json())
.then(data => {
resultsArea.innerHTML = data.map(item => `
<div class="d-flex align-items-center mb-3 p-3 border rounded">
<div class="me-3" style="width: 50px; height: 50px; background: #ddd; border-radius: 50%;"></div>
<div>
<strong>${item.name}</strong><br>
<small class="text-muted">${item.type}</small>
</div>
</div>
`).join('');
});
});
</script>
{% endblock %}