201 lines
6.9 KiB
Python
201 lines
6.9 KiB
Python
"""Domain models for the RisingCompute marketing site."""
|
||
from __future__ import annotations
|
||
|
||
from django.db import models
|
||
from django.utils import timezone
|
||
from django.utils.text import slugify
|
||
|
||
|
||
# --------------------------------------------------------------------------- #
|
||
# Content (curated by the team in the admin)
|
||
# --------------------------------------------------------------------------- #
|
||
class Product(models.Model):
|
||
"""An IP core / product line shown on the marketing site."""
|
||
|
||
CATEGORY_CHOICES = [
|
||
("ai", "AI Inference"),
|
||
("security", "Cybersecurity"),
|
||
("comms", "Communication Protocol"),
|
||
("asic", "Custom ASIC Services"),
|
||
("other", "Other"),
|
||
]
|
||
|
||
slug = models.SlugField(unique=True, max_length=80)
|
||
name = models.CharField(max_length=120)
|
||
category = models.CharField(max_length=20, choices=CATEGORY_CHOICES)
|
||
tagline = models.CharField(max_length=200)
|
||
summary = models.TextField(
|
||
help_text="2–3 sentence overview shown on the products grid."
|
||
)
|
||
description = models.TextField(
|
||
help_text="Long-form description shown on the product detail page (markdown)."
|
||
)
|
||
benefits = models.JSONField(
|
||
default=list,
|
||
blank=True,
|
||
help_text='List of benefit strings. Example: ["High throughput per watt", "INT8/INT4"].',
|
||
)
|
||
features = models.JSONField(default=list, blank=True)
|
||
spec_table = models.JSONField(
|
||
default=list,
|
||
blank=True,
|
||
help_text='List of {"label": "...", "value": "..."} pairs for the spec table.',
|
||
)
|
||
primary_cta_label = models.CharField(max_length=60, default="Request evaluation")
|
||
is_published = models.BooleanField(default=True)
|
||
sort_order = models.PositiveIntegerField(default=0)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
ordering = ["sort_order", "name"]
|
||
|
||
def __str__(self) -> str:
|
||
return self.name
|
||
|
||
|
||
class Founder(models.Model):
|
||
"""Founding-team profile shown on the About page."""
|
||
|
||
name = models.CharField(max_length=120)
|
||
role = models.CharField(max_length=160)
|
||
domain = models.CharField(
|
||
max_length=240,
|
||
help_text="Short description of the technical domain they own.",
|
||
)
|
||
bio = models.TextField(help_text="~80-word bio. Markdown allowed.")
|
||
photo_url = models.URLField(blank=True)
|
||
linkedin_url = models.URLField(blank=True)
|
||
sort_order = models.PositiveIntegerField(default=0)
|
||
is_published = models.BooleanField(default=True)
|
||
|
||
class Meta:
|
||
ordering = ["sort_order", "name"]
|
||
|
||
def __str__(self) -> str:
|
||
return self.name
|
||
|
||
|
||
class BlogPost(models.Model):
|
||
"""Editorial / engineering blog post."""
|
||
|
||
CATEGORY_CHOICES = [
|
||
("ai", "AI"),
|
||
("space", "Space"),
|
||
("robotics", "Robotics"),
|
||
("engineering", "Engineering"),
|
||
("company", "Company"),
|
||
]
|
||
|
||
slug = models.SlugField(unique=True, max_length=200)
|
||
title = models.CharField(max_length=200)
|
||
excerpt = models.CharField(max_length=300)
|
||
body = models.TextField(help_text="Markdown.")
|
||
category = models.CharField(max_length=20, choices=CATEGORY_CHOICES, default="company")
|
||
author_name = models.CharField(max_length=120)
|
||
read_time_minutes = models.PositiveIntegerField(default=5)
|
||
cover_image_url = models.URLField(blank=True)
|
||
is_published = models.BooleanField(default=True)
|
||
published_at = models.DateTimeField(default=timezone.now)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
ordering = ["-published_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs):
|
||
if not self.slug:
|
||
self.slug = slugify(self.title)[:200]
|
||
super().save(*args, **kwargs)
|
||
|
||
|
||
class JobOpening(models.Model):
|
||
"""An open role displayed on the Careers page."""
|
||
|
||
LOCATION_CHOICES = [
|
||
("surat", "Surat, India"),
|
||
("iist", "STIIC / IIST, Thiruvananthapuram"),
|
||
("remote", "Remote (India)"),
|
||
("hybrid", "Hybrid"),
|
||
]
|
||
|
||
slug = models.SlugField(unique=True, max_length=120)
|
||
title = models.CharField(max_length=160)
|
||
location = models.CharField(max_length=20, choices=LOCATION_CHOICES, default="surat")
|
||
employment_type = models.CharField(max_length=40, default="Full-time")
|
||
description = models.TextField(help_text="Markdown.")
|
||
is_open = models.BooleanField(default=True)
|
||
posted_at = models.DateField(default=timezone.now)
|
||
|
||
class Meta:
|
||
ordering = ["-posted_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return self.title
|
||
|
||
|
||
# --------------------------------------------------------------------------- #
|
||
# Submissions (user input via forms — written by the frontend)
|
||
# --------------------------------------------------------------------------- #
|
||
class ContactSubmission(models.Model):
|
||
INTEREST_CHOICES = [
|
||
("ai-ip", "AI Inference IP"),
|
||
("security-ip", "Cybersecurity IP"),
|
||
("comms-ip", "Communication IP"),
|
||
("custom-asic", "Custom ASIC"),
|
||
("careers", "Careers"),
|
||
("press", "Press"),
|
||
("other", "Other"),
|
||
]
|
||
|
||
name = models.CharField(max_length=120)
|
||
email = models.EmailField()
|
||
company = models.CharField(max_length=160, blank=True)
|
||
role = models.CharField(max_length=120, blank=True)
|
||
country = models.CharField(max_length=80, blank=True)
|
||
interest = models.CharField(max_length=20, choices=INTEREST_CHOICES, default="other")
|
||
message = models.TextField()
|
||
referrer = models.CharField(max_length=200, blank=True)
|
||
user_agent = models.CharField(max_length=400, blank=True)
|
||
ip_address = models.GenericIPAddressField(null=True, blank=True)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
ordering = ["-created_at"]
|
||
verbose_name = "Contact submission"
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.name} <{self.email}> · {self.get_interest_display()}"
|
||
|
||
|
||
class NewsletterSignup(models.Model):
|
||
email = models.EmailField(unique=True)
|
||
source = models.CharField(max_length=120, blank=True, help_text="e.g. footer, blog, contact")
|
||
confirmed = models.BooleanField(default=False)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
ordering = ["-created_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return self.email
|
||
|
||
|
||
class JobApplication(models.Model):
|
||
name = models.CharField(max_length=120)
|
||
email = models.EmailField()
|
||
role_applied_for = models.CharField(max_length=160)
|
||
portfolio_url = models.URLField(blank=True)
|
||
message = models.TextField(blank=True)
|
||
cv = models.FileField(upload_to="applications/%Y/%m/", blank=True, null=True)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
ordering = ["-created_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.name} → {self.role_applied_for}"
|