fix: separate logo and hero icon

This commit is contained in:
mohamad
2026-08-03 16:29:25 +03:30
parent 04b6e9049e
commit 4fc4282f0f
45 changed files with 900 additions and 495 deletions
@@ -4,29 +4,53 @@ from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
DEFAULT_ADMIN_PASSWORD = "cmosV6Tw46Odv7UN"
class Command(BaseCommand):
help = "Create a superuser from environment variables if one does not already exist."
help = "Create the first admin account from environment variables when needed."
def handle(self, *args, **options):
User = get_user_model()
username = os.environ.get("DJANGO_SUPERUSER_USERNAME", "admin")
email = os.environ.get("DJANGO_SUPERUSER_EMAIL", "admin@radiuma.com")
password = os.environ.get("DJANGO_SUPERUSER_PASSWORD")
enabled = os.environ.get("DJANGO_SUPERUSER_ENABLED", "True").lower()
if enabled in {"0", "false", "no", "off"}:
self.stdout.write("Automatic admin creation is disabled.")
return
if not password:
username = os.environ.get("DJANGO_SUPERUSER_USERNAME", "admin")
email = os.environ.get("DJANGO_SUPERUSER_EMAIL", "admin@com2care.com")
password = os.environ.get("DJANGO_SUPERUSER_PASSWORD", DEFAULT_ADMIN_PASSWORD)
sync_password = os.environ.get(
"DJANGO_SUPERUSER_SYNC_PASSWORD", "False"
).lower() in {"1", "true", "yes", "on"}
user = User.objects.filter(username=username).first()
if user:
if sync_password:
user.email = email
user.is_staff = True
user.is_superuser = True
user.set_password(password)
user.save(
update_fields=["email", "is_staff", "is_superuser", "password"]
)
self.stdout.write(
self.style.SUCCESS(
f"Admin '{username}' credentials synchronized from the environment."
)
)
return
self.stdout.write(
self.style.WARNING(
"DJANGO_SUPERUSER_PASSWORD is not set — skipping superuser creation."
self.style.SUCCESS(
f"Admin '{username}' already exists; its password was preserved."
)
)
return
if User.objects.filter(username=username).exists():
self.stdout.write(
self.style.SUCCESS(f"Superuser '{username}' already exists — skipping.")
)
return
User.objects.create_superuser(username=username, email=email, password=password)
self.stdout.write(self.style.SUCCESS(f"Superuser '{username}' created successfully."))
self.stdout.write(
self.style.SUCCESS(
f"Admin '{username}' created. Change the password in Django Admin after first login."
)
)
@@ -0,0 +1,68 @@
import re
from django.apps import apps
from django.core.management.base import BaseCommand
from django.db import models, transaction
LEGACY_NAME = "".join(("Radi", "uma"))
LEGACY_PATTERN = re.compile(re.escape(LEGACY_NAME), re.IGNORECASE)
LEGACY_DOMAIN_PATTERN = re.compile(
rf"{re.escape(LEGACY_NAME)}\.com", re.IGNORECASE
)
PUBLIC_APP_LABELS = frozenset({"core", "pages", "products"})
def branded_value(field, value):
if not isinstance(value, str) or not LEGACY_PATTERN.search(value):
return value
value = LEGACY_DOMAIN_PATTERN.sub("com2care.com", value)
if isinstance(field, (models.EmailField, models.URLField, models.SlugField)):
return LEGACY_PATTERN.sub("com2care", value)
return LEGACY_PATTERN.sub("Communication to Care", value)
class Command(BaseCommand):
help = "Normalize legacy public content to the current com2care identity."
@transaction.atomic
def handle(self, *args, **options):
updated_rows = 0
for model in apps.get_models():
if model._meta.app_label not in PUBLIC_APP_LABELS:
continue
text_fields = [
field
for field in model._meta.concrete_fields
if isinstance(field, (models.CharField, models.TextField))
and not field.primary_key
]
if not text_fields:
continue
field_names = [field.name for field in text_fields]
for instance in model._default_manager.all().only("pk", *field_names).iterator():
changed_fields = []
for field in text_fields:
current = getattr(instance, field.name)
updated = branded_value(field, current)
if updated == current:
continue
if isinstance(field, models.SlugField):
conflict = model._default_manager.exclude(pk=instance.pk).filter(
**{field.name: updated}
).exists()
if conflict:
continue
setattr(instance, field.name, updated)
changed_fields.append(field.name)
if changed_fields:
instance.save(update_fields=changed_fields)
updated_rows += 1
if updated_rows:
self.stdout.write(
self.style.SUCCESS(f"Normalized {updated_rows} public content row(s).")
)
else:
self.stdout.write("Public content already uses the com2care identity.")
+354 -159
View File
@@ -1,24 +1,38 @@
from django.conf import settings
from django.core.files import File
from django.core.management.base import BaseCommand
from django.db import transaction
from apps.core.models import SiteContact
from apps.pages.models import DownloadItem, FAQEntry, HeroSection, HomepageSection, HomepageSectionItem
from apps.products.models import Article, ArticleSection, MainProduct, SubProduct
from apps.core.models import SiteBranding, SiteContact
from apps.pages.models import (
AboutSection,
AboutSectionItem,
DownloadItem,
FAQEntry,
HeroSection,
HomepageSection,
HomepageSectionItem,
PageVideo,
)
from apps.products.models import (
Article,
ArticleSection,
MainProduct,
ProductVideo,
SubProduct,
)
MAIN_PRODUCTS = [
{
"name": "Radiuma",
"slug": "radiuma",
"short_description": "Visualized & Standardized Environment for Radiomics Analysis",
"name": "Communication to Care",
"slug": "com2care",
"short_description": "Collaborative, standardized medical imaging research workflows",
"description": (
"Radiuma is a free, open-source software specialized for visualization, "
"processing, segmentation, registration, fusion and analysis of medical and "
"biomedical images, including radiomics and machine learning analysis. "
"Radiuma is a major, entirely-revamped upgrade to the original SERA "
"(Matlab-based), now built on Python for broader accessibility and community "
"contribution. It enables standardized and reproducible radiomic feature "
"extraction in compliance with the Image Biomarker Standardization Initiative "
"(IBSI 1.0), and implements image filters standardized against IBSI 2.0."
"Communication to Care (com2care) brings medical-image visualization, processing, "
"segmentation, registration, fusion, radiomics, and machine-learning workflows into "
"one research environment. The platform is designed to help multidisciplinary teams "
"discuss findings clearly, build repeatable pipelines, and share analysis context. "
"Its quantitative imaging workflow follows IBSI guidance for reproducible research."
),
"order": 1,
"show_on_homepage": True,
@@ -31,7 +45,7 @@ MAIN_PRODUCTS = [
"description": (
"Advanced image processing capabilities including standardized filtering "
"techniques compliant with IBSI 2.0, image registration, fusion, and "
"Standardized Uptake Value (SUV) conversion. Radiuma employs popular "
"Standardized Uptake Value (SUV) conversion. Communication to Care employs popular "
"image processing algorithms to create end-to-end standardized workflows "
"for consistent, reproducible research outcomes."
),
@@ -40,7 +54,7 @@ MAIN_PRODUCTS = [
{
"title": "Image Filtering Techniques",
"description": (
"Radiuma implements a comprehensive set of image filtering techniques "
"Communication to Care implements a comprehensive set of image filtering techniques "
"fully standardized against the Image Biomarker Standardization "
"Initiative (IBSI) phase 2. These filters enable reproducible "
"preprocessing across institutions and studies."
@@ -53,13 +67,13 @@ MAIN_PRODUCTS = [
"value": "Mean, Gaussian, Laplacian of Gaussian (LoG), Laws kernels, Gabor, Wavelets (PyWavelets), Log-Sigma",
"order": 2,
},
{"title": "Author", "value": "Radiuma R&D Team", "order": 3},
{"title": "Author", "value": "Communication to Care R&D Team", "order": 3},
],
},
{
"title": "Image Registration & Fusion",
"description": (
"Radiuma provides robust image registration and fusion methods, "
"Communication to Care provides robust image registration and fusion methods, "
"enabling multi-modal image alignment for PET/CT, PET/MRI, and "
"other combined modality studies. Standardized Uptake Value (SUV) "
"conversion is also supported."
@@ -78,7 +92,7 @@ MAIN_PRODUCTS = [
"slug": "radiomics-features",
"short_description": "IBSI 1.0 compliant handcrafted radiomic feature extraction",
"description": (
"Radiuma provides comprehensive handcrafted radiomic feature extraction "
"Communication to Care provides comprehensive handcrafted radiomic feature extraction "
"fully standardized by the Image Biomarker Standardization Initiative "
"(IBSI 1.0). Features are computed from segmented regions of interest "
"across multiple image modalities, enabling reproducible quantitative "
@@ -89,7 +103,7 @@ MAIN_PRODUCTS = [
{
"title": "IBSI Compliant Feature Extraction",
"description": (
"Radiuma computes a comprehensive set of radiomic features "
"Communication to Care computes a comprehensive set of radiomic features "
"covering all IBSI 1.0 feature classes. Features are extracted "
"from segmented Regions of Interest (ROIs) and are fully "
"reproducible across different platforms and institutions."
@@ -113,7 +127,7 @@ MAIN_PRODUCTS = [
"slug": "medical-image-visualization",
"short_description": "Professional multi-modality medical image viewer",
"description": (
"Radiuma includes a professional medical image viewer that supports "
"Communication to Care includes a professional medical image viewer that supports "
"multiple imaging modalities and file formats. The viewer provides "
"comfortable, intuitive controls for slice navigation, windowing, "
"zoom, and annotation, suitable for radiation oncologists, radiologists, "
@@ -143,7 +157,7 @@ MAIN_PRODUCTS = [
"slug": "format-conversion",
"short_description": "Professional converter for medical imaging file formats",
"description": (
"Radiuma provides a professional image format converter supporting all "
"Communication to Care provides a professional image format converter supporting all "
"major medical imaging standards. Seamlessly convert between DICOM, "
"NIFTI, NRRD, MHA, and other formats without loss of spatial metadata "
"or patient information integrity."
@@ -172,7 +186,7 @@ MAIN_PRODUCTS = [
"slug": "workflow-management",
"short_description": "Reproducible research workflow creation and sharing",
"description": (
"Radiuma's workflow management system allows researchers to design, save, "
"Communication to Care's workflow management system allows researchers to design, save, "
"share, and reuse analysis pipelines. Workflows connect individual "
"processing steps — from image loading and preprocessing to feature "
"extraction and machine learning — into reproducible, shareable sequences "
@@ -202,34 +216,28 @@ MAIN_PRODUCTS = [
FAQ_ENTRIES = [
{
"question": "What is the Radiuma license?",
"question": "How is Communication to Care licensed?",
"answer": (
"Radiuma is free and open-source for research purposes.\n\n"
"License: CC BY-NC-SA (Creative Commons Attribution-NonCommercial-ShareAlike). "
"This means you may use, share, and adapt the software for non-commercial "
"research purposes, provided you give appropriate credit and distribute "
"derivatives under the same license."
"Licensing and deployment terms are provided with each com2care release. "
"Contact support@com2care.com for research, institutional, or evaluation access."
),
"order": 1,
},
{
"question": "How do I cite Radiuma in my research?",
"question": "How do I acknowledge Communication to Care in my research?",
"answer": (
"Please cite the following reference if you publish results obtained with "
"the help of Radiuma:\n\n"
"M. R. Salmanpour, I. Shiri, M. Hosseinzadeh, H. Zaidi, S. Ashrafinia, "
"M. Oveisi, A. Rahmim. Radiuma: Visualized & Standardized Environment for "
"Radiomics Analysis — A Shareable, Executable, and Reproducible Workflow "
"Generator. Proc. IEEE Medical Imaging Conference, 2023."
"Mention Communication to Care (com2care) and the software version used in your "
"methods section. Release-specific citation guidance can be requested from "
"support@com2care.com."
),
"order": 2,
},
{
"question": "Which operating systems does Radiuma support?",
"question": "Which operating systems does Communication to Care support?",
"answer": (
"Radiuma currently fully supports Windows 10 and above (64-bit). "
"New versions to support macOS and Linux systems are under active development "
"and coming soon. Follow our Discord or check each product module page for updates."
"Communication to Care currently fully supports Windows 10 and above (64-bit). "
"macOS and Linux packages are represented in this demonstration dataset as upcoming "
"channels. Check each product module page for current release information."
),
"order": 3,
},
@@ -244,9 +252,9 @@ FAQ_ENTRIES = [
"order": 4,
},
{
"question": "Is Radiuma suitable for clinical use?",
"question": "Is Communication to Care suitable for clinical use?",
"answer": (
"Radiuma is designed and intended exclusively for research purposes. "
"Communication to Care is designed and intended exclusively for research purposes. "
"It is not certified for clinical diagnostic use. Always consult with "
"qualified medical professionals for clinical decisions."
),
@@ -255,9 +263,8 @@ FAQ_ENTRIES = [
{
"question": "Where can I get support or report issues?",
"answer": (
"Support is available via email and through our community Discord server "
"(see the Contact page for current details). For bug reports and feature "
"requests, please use the Discord forum or contact us directly by email."
"Use the contact form or email support@com2care.com. Include the software version, "
"operating system, a short reproduction description, and non-sensitive logs when relevant."
),
"order": 6,
},
@@ -282,9 +289,42 @@ HOMEPAGE_SECTIONS = [
{
"section_type": HomepageSection.TYPE_SCREENSHOTS,
"badge": "Gallery",
"title": "See Radiuma in Action",
"description": "Explore Radiuma's powerful interface, workflow builder, and multi-modal image viewer.",
"title": "See Communication to Care in Action",
"description": "Explore Communication to Care's powerful interface, workflow builder, and multi-modal image viewer.",
"order": 2,
"items": [
{
"title": "Visual workflow builder",
"content": "Connect image-processing steps into a repeatable analysis pipeline.",
"static_image": "screenshot-3.png",
"order": 1,
},
{
"title": "Multi-planar image review",
"content": "Inspect imaging and segmentation context across synchronized views.",
"static_image": "screenshot-4.png",
"order": 2,
},
{
"title": "Radiomics configuration",
"content": "Review quantitative feature settings before a reproducible run.",
"static_image": "screenshot-5.png",
"order": 3,
},
],
},
{
"section_type": HomepageSection.TYPE_VIDEO,
"badge": "Learning Library",
"title": "Medical image segmentation essentials",
"description": (
"A practical introduction to thresholding, drawing, erasing, and 3D review in a "
"medical-image segmentation workflow."
),
"video_url": "https://www.youtube.com/watch?v=_9J3i883yA4",
"video_styled_background": True,
"video_size": "lg",
"order": 3,
"items": [],
},
{
@@ -292,19 +332,19 @@ HOMEPAGE_SECTIONS = [
"badge": "Our Software",
"title": "Products",
"description": "Explore our suite of medical imaging and radiomics tools.",
"order": 3,
"order": 4,
"items": [],
},
{
"section_type": HomepageSection.TYPE_PROBLEMS,
"badge": "Value Proposition",
"title": "What Problems Does Radiuma Solve?",
"title": "What Problems Does Communication to Care Solve?",
"description": "",
"order": 4,
"order": 5,
"items": [
{"icon": "01", "title": "Accessibility", "content": "Radiuma provides a user-friendly interface and a wide range of tools, allowing researchers to perform complex data analysis without extensive technical knowledge or programming expertise.", "order": 1},
{"icon": "02", "title": "Integrated Tools", "content": "Radiuma integrates a vast collection of tools and resources from various domains of healthcare and medical imaging research in a common, unified environment.", "order": 2},
{"icon": "03", "title": "Flexibility", "content": "Radiuma offers flexibility in terms of tool optimization and workflow customization to match your specific research requirements.", "order": 3},
{"icon": "01", "title": "Accessibility", "content": "Communication to Care provides a user-friendly interface and a wide range of tools, allowing researchers to perform complex data analysis without extensive technical knowledge or programming expertise.", "order": 1},
{"icon": "02", "title": "Integrated Tools", "content": "Communication to Care integrates a vast collection of tools and resources from various domains of healthcare and medical imaging research in a common, unified environment.", "order": 2},
{"icon": "03", "title": "Flexibility", "content": "Communication to Care offers flexibility in terms of tool optimization and workflow customization to match your specific research requirements.", "order": 3},
{"icon": "04", "title": "Reproducibility", "content": "Improve usability, reusability, and reproducibility (URR) through a workflow management system that allows researchers to easily create, share, and reuse analysis pipelines.", "order": 4},
],
},
@@ -313,48 +353,112 @@ HOMEPAGE_SECTIONS = [
"badge": "Our Story",
"title": "More to Know",
"description": (
"Radiuma has been developing since 2021 by the Quantitative Radiomolecular Imaging "
"and Therapy (Qurit) lab & program at the University of British Columbia & "
"BC Cancer Research Institute, Vancouver, BC, Canada."
"Communication to Care is shaped around multidisciplinary research: connect imaging "
"evidence, analysis steps, and team discussion in one understandable workflow."
),
"link_text": "Learn More",
"link_url": "/about/",
"order": 5,
"order": 6,
"items": [],
},
{
"section_type": HomepageSection.TYPE_SUPPORTERS,
"badge": "Acknowledgements",
"title": "Our Supporters",
"description": "Radiuma is made possible by the support of leading research institutions and organizations.",
"order": 6,
"badge": "Who It Serves",
"title": "Built for Collaborative Teams",
"description": "com2care demo workflows are organized around the people who review, analyze, and communicate medical-imaging evidence.",
"order": 7,
"items": [
{
"title": "University of British Columbia",
"content": "Faculty of Medicine and the Department of Integrative Oncology.",
"title": "Imaging Researchers",
"content": "Build standardized pipelines and retain the context behind each processing decision.",
"order": 1,
},
{
"title": "BC Cancer Research Institute",
"content": "Supporting cutting-edge radiomics and medical imaging research in Vancouver, BC.",
"title": "Clinical Research Teams",
"content": "Review images and quantitative results together without presenting research output as diagnosis.",
"order": 2,
},
],
},
]
ABOUT_SECTIONS = [
{
"section_type": AboutSection.TYPE_HERO,
"badge": "Our Mission",
"title": "Better imaging conversations, clearer research decisions",
"subtitle": "Communication to Care",
"content": (
"com2care is built around a simple idea: complex medical-imaging evidence becomes "
"more useful when researchers, clinicians, engineers, and data teams can examine it "
"together in a shared, reproducible workflow."
),
"order": 1,
"items": [
{
"title": "A collaborative care and research team",
"image_alt": "Healthcare and imaging researchers reviewing medical images together",
"static_image": "com2care-care-team.jpg",
"is_featured": True,
"order": 1,
}
],
},
{
"section_type": AboutSection.TYPE_GRID,
"badge": "How We Work",
"title": "Designed for shared understanding",
"content": "Every part of the platform supports transparent, repeatable research communication.",
"order": 2,
"items": [
{
"icon": "01",
"title": "Clinical context",
"content": "Keep imaging evidence and analysis choices visible to the whole team.",
"order": 1,
},
{
"icon": "02",
"title": "Reproducible workflows",
"content": "Save processing steps so collaborators can review and repeat the same pipeline.",
"order": 2,
},
{
"icon": "03",
"title": "Responsible research",
"content": "Separate research exploration from clinical diagnosis and protect patient privacy.",
"order": 3,
},
],
},
{
"section_type": AboutSection.TYPE_VIDEO,
"badge": "Practical Learning",
"title": "Viewing DICOM studies with an open medical-imaging workflow",
"content": (
"This independent tutorial demonstrates how researchers can import and inspect DICOM "
"studies in 3D Slicer—skills that complement the workflows presented on com2care."
),
"video_url": "https://www.youtube.com/watch?v=EV8tAjAHeac",
"video_styled_background": True,
"video_size": "lg",
"order": 3,
"items": [],
},
]
DOWNLOAD_ITEMS = [
{
"name": "Radiuma Desktop",
"name": "com2care Desktop",
"platform": "windows",
"version": "1.0.0",
"download_url": "https://github.com/radiuma/radiuma/releases/latest/download/Radiuma-Setup.exe",
"description": "Windows 10 and above (64-bit). Installer package.",
"download_url": "https://com2care.com/downloads/",
"description": "Demonstration release channel for Windows 10 and above (64-bit).",
"is_active": True,
"order": 1,
},
{
"name": "Radiuma Desktop",
"name": "com2care Desktop",
"platform": "macos",
"version": "Coming Soon",
"download_url": "#",
@@ -363,7 +467,7 @@ DOWNLOAD_ITEMS = [
"order": 2,
},
{
"name": "Radiuma Desktop",
"name": "com2care Desktop",
"platform": "linux",
"version": "Coming Soon",
"download_url": "#",
@@ -375,19 +479,43 @@ DOWNLOAD_ITEMS = [
class Command(BaseCommand):
help = "Seed the database with initial Radiuma / Radiuma content from radiuma.com"
help = "Seed a complete com2care demonstration site."
CONTENT_MODELS = (
MainProduct,
FAQEntry,
DownloadItem,
HeroSection,
HomepageSection,
AboutSection,
PageVideo,
ProductVideo,
)
def add_arguments(self, parser):
parser.add_argument(
"--flush",
action="store_true",
help="Delete all existing seed data before re-seeding",
help="Delete existing public content before re-seeding.",
)
parser.add_argument(
"--if-empty",
action="store_true",
help="Seed only when every public content table is empty.",
)
@transaction.atomic
def handle(self, *args, **options):
if options["if_empty"] and not options["flush"] and self._content_exists():
self.stdout.write("Public content already exists; demo seed skipped.")
return
if options["flush"]:
self.stdout.write("Flushing existing seed data...")
self.stdout.write("Flushing existing public content...")
ProductVideo.objects.all().delete()
PageVideo.objects.all().delete()
AboutSectionItem.objects.all().delete()
AboutSection.objects.all().delete()
ArticleSection.objects.all().delete()
Article.objects.all().delete()
SubProduct.objects.all().delete()
@@ -398,66 +526,96 @@ class Command(BaseCommand):
HomepageSection.objects.all().delete()
HeroSection.objects.all().delete()
self._seed_products()
main_product = self._seed_products()
self._seed_faq()
self._seed_downloads()
self._seed_homepage_sections()
self._seed_about_sections()
self._seed_product_videos(main_product)
self._seed_hero()
self._seed_site_branding()
self._seed_site_contact()
self.stdout.write(self.style.SUCCESS("Content seeded successfully."))
self.stdout.write(self.style.SUCCESS("com2care demonstration content seeded."))
def _content_exists(self):
return any(model.objects.exists() for model in self.CONTENT_MODELS)
@staticmethod
def _update_instance(instance, values):
for field, value in values.items():
setattr(instance, field, value)
instance.save()
@staticmethod
def _attach_static_image(instance, field_name, image_name):
if not image_name or getattr(instance, field_name):
return
source = settings.BASE_DIR / "static" / "images" / image_name
if not source.exists():
return
with source.open("rb") as handle:
getattr(instance, field_name).save(source.name, File(handle), save=True)
def _seed_products(self):
seeded_main_product = None
for product_data in MAIN_PRODUCTS:
sub_products_data = product_data.pop("sub_products")
sub_products_data = product_data["sub_products"]
product_defaults = {
key: value for key, value in product_data.items() if key != "sub_products"
}
main_product, created = MainProduct.objects.get_or_create(
slug=product_data["slug"],
defaults=product_data,
slug=product_defaults["slug"],
defaults=product_defaults,
)
if not created:
for field, value in product_data.items():
setattr(main_product, field, value)
main_product.save()
self._update_instance(main_product, product_defaults)
seeded_main_product = main_product
action = "Created" if created else "Updated"
self.stdout.write(f" {action} main product: {main_product.name}")
for sub_data in sub_products_data:
articles_data = sub_data.pop("articles")
articles_data = sub_data["articles"]
sub_defaults = {
key: value for key, value in sub_data.items() if key != "articles"
}
sub_product, sub_created = SubProduct.objects.get_or_create(
main_product=main_product,
slug=sub_data["slug"],
defaults=sub_data,
slug=sub_defaults["slug"],
defaults=sub_defaults,
)
if not sub_created:
for field, value in sub_data.items():
setattr(sub_product, field, value)
sub_product.save()
self._update_instance(sub_product, sub_defaults)
sub_action = "Created" if sub_created else "Updated"
self.stdout.write(f" {sub_action} sub-product: {sub_product.name}")
for article_data in articles_data:
sections_data = article_data.pop("sections")
sections_data = article_data["sections"]
article_defaults = {
key: value for key, value in article_data.items() if key != "sections"
}
article, art_created = Article.objects.get_or_create(
sub_product=sub_product,
title=article_data["title"],
defaults=article_data,
title=article_defaults["title"],
defaults=article_defaults,
)
if not art_created:
for field, value in article_data.items():
setattr(article, field, value)
article.save()
self._update_instance(article, article_defaults)
art_action = "Created" if art_created else "Updated"
self.stdout.write(f" {art_action} article: {article.title}")
for section_data in sections_data:
section, _ = ArticleSection.objects.get_or_create(
article_section, section_created = ArticleSection.objects.get_or_create(
article=article,
title=section_data["title"],
defaults=section_data,
)
if not section_created:
self._update_instance(article_section, section_data)
return seeded_main_product
def _seed_faq(self):
for entry_data in FAQ_ENTRIES:
@@ -466,34 +624,92 @@ class Command(BaseCommand):
defaults=entry_data,
)
if not created:
for field, value in entry_data.items():
setattr(faq, field, value)
faq.save()
self._update_instance(faq, entry_data)
action = "Created" if created else "Updated"
self.stdout.write(f" {action} FAQ: {faq.question[:60]}...")
def _seed_homepage_sections(self):
for section_data in HOMEPAGE_SECTIONS:
items_data = section_data.pop("items")
items_data = section_data["items"]
section_defaults = {
key: value for key, value in section_data.items() if key != "items"
}
section, created = HomepageSection.objects.get_or_create(
section_type=section_data["section_type"],
defaults=section_data,
section_type=section_defaults["section_type"],
defaults=section_defaults,
)
if not created:
for field, value in section_data.items():
setattr(section, field, value)
section.save()
self._update_instance(section, section_defaults)
action = "Created" if created else "Updated"
self.stdout.write(f" {action} homepage section: {section}")
for item_data in items_data:
item, _ = HomepageSectionItem.objects.get_or_create(
image_name = item_data.get("static_image", "")
item_defaults = {
key: value for key, value in item_data.items() if key != "static_image"
}
item, item_created = HomepageSectionItem.objects.get_or_create(
section=section,
title=item_data["title"],
defaults=item_data,
title=item_defaults["title"],
defaults=item_defaults,
)
if not item_created:
self._update_instance(item, item_defaults)
self._attach_static_image(item, "image", image_name)
def _seed_about_sections(self):
for section_data in ABOUT_SECTIONS:
items_data = section_data["items"]
section_defaults = {
key: value for key, value in section_data.items() if key != "items"
}
section, created = AboutSection.objects.get_or_create(
section_type=section_defaults["section_type"],
title=section_defaults["title"],
defaults=section_defaults,
)
if not created:
self._update_instance(section, section_defaults)
for item_data in items_data:
image_name = item_data.get("static_image", "")
item_defaults = {
key: value for key, value in item_data.items() if key != "static_image"
}
item, item_created = AboutSectionItem.objects.get_or_create(
section=section,
title=item_defaults["title"],
defaults=item_defaults,
)
if not item_created:
self._update_instance(item, item_defaults)
self._attach_static_image(item, "image", image_name)
def _seed_product_videos(self, main_product):
if not main_product:
return
data = {
"badge": "Workflow Tutorial",
"title": "Segmentation workflow from image to 3D review",
"description": (
"An independent demonstration of a guided medical-image segmentation workflow "
"using open research tooling."
),
"video_url": "https://www.youtube.com/watch?v=_7oZygGp2ds",
"video_styled_background": True,
"video_size": "lg",
"order": 1,
"is_active": True,
}
video, created = ProductVideo.objects.get_or_create(
main_product=main_product,
title=data["title"],
defaults=data,
)
if not created:
self._update_instance(video, data)
def _seed_downloads(self):
for item_data in DOWNLOAD_ITEMS:
@@ -503,73 +719,52 @@ class Command(BaseCommand):
defaults=item_data,
)
if not created:
for field, value in item_data.items():
setattr(item, field, value)
item.save()
self._update_instance(item, item_data)
action = "Created" if created else "Updated"
self.stdout.write(f" {action} download: {item}")
def _seed_hero(self):
data = {
"badge": "Developing since 2021",
"title": "Radiuma,",
"title_highlight": "A Powerful Workflow Generator",
"subtitle": "for Standardized Radiomics Analysis and Medical Image Visualization",
"badge": "Communication-first medical imaging",
"title": "Communication to Care,",
"title_highlight": "From Images to Shared Understanding",
"subtitle": "Collaborative medical imaging, radiomics, and reproducible research workflows",
"description": (
"Radiuma is a free, open-source software specialized for visualization, processing, "
"segmentation, registration, fusion and analysis of medical and biomedical images, "
"including radiomics and machine learning analysis."
"com2care helps multidisciplinary teams explore complex imaging evidence, "
"document analysis choices, and communicate results with clearer context."
),
"primary_cta_text": "Get Radiuma",
"primary_cta_text": "Explore com2care",
"primary_cta_url": "/products/",
"secondary_cta_text": "About Radiuma",
"secondary_cta_text": "Our Mission",
"secondary_cta_url": "/about/",
"image_alt": "Radiuma application — main workflow view",
"image_alt": "A multidisciplinary care team collaborating around medical imaging",
}
hero = HeroSection.objects.first()
if hero is None:
HeroSection.objects.create(**data)
self.stdout.write(" Created hero section")
hero = HeroSection.objects.create(**data)
else:
for field, value in data.items():
if field == "image":
continue
setattr(hero, field, value)
hero.save()
self.stdout.write(" Updated hero section")
self._update_instance(hero, data)
self._attach_static_image(hero, "image", "com2care-care-team.jpg")
def _seed_site_branding(self):
branding = SiteBranding.load()
branding.icon_alt = "com2care"
branding.hero_logo_alt = "Communication to Care"
branding.save(update_fields=["icon_alt", "hero_logo_alt"])
def _seed_site_contact(self):
contact, created = SiteContact.objects.get_or_create(
pk=1,
defaults={
"support_email": "support@radiuma.com",
"discord_url": "https://discord.gg/9XxA6pV9hb",
"email_card_description": "For direct software support:",
"discord_card_description": "Join for community support and announcements.",
"office_address": (
"BC Cancer Research Center\n"
"675 West 10th Ave, Office 6-112\n"
"Vancouver, BC, V5Z 1L3\n"
"Canada"
),
},
)
data = {
"support_email": "support@com2care.com",
"discord_url": "",
"discord_label": "",
"email_card_title": "Email com2care Support",
"email_card_description": "For product, evaluation, and research questions:",
"discord_card_title": "",
"discord_card_description": "",
"office_card_title": "",
"office_address": "",
}
contact, created = SiteContact.objects.get_or_create(pk=1, defaults=data)
if not created:
updates = {
"support_email": "support@radiuma.com",
"discord_url": "https://discord.gg/9XxA6pV9hb",
"email_card_description": "For direct software support:",
"discord_card_description": "Join for community support and announcements.",
"office_address": (
"BC Cancer Research Center\n"
"675 West 10th Ave, Office 6-112\n"
"Vancouver, BC, V5Z 1L3\n"
"Canada"
),
}
for field, value in updates.items():
setattr(contact, field, value)
contact.save()
action = "Created" if created else "Updated"
self.stdout.write(f" {action} site contact")
self._update_instance(contact, data)