feat: change entire downloads

This commit is contained in:
mohamad
2026-05-16 19:13:32 +03:30
parent eb880e3e8b
commit f0a9d5832b
26 changed files with 1283 additions and 213 deletions
@@ -0,0 +1,34 @@
# Generated by Django 5.0.2 on 2026-05-14 04:53
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SubProductRelease',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('platform', models.CharField(choices=[('windows', 'Windows'), ('macos', 'macOS'), ('linux', 'Linux')], max_length=20)),
('release_type', models.CharField(choices=[('stable', 'Stable'), ('previous', 'Previous')], default='stable', max_length=20)),
('version', models.CharField(help_text='e.g. 2.1.0', max_length=50)),
('download_url', models.URLField()),
('release_notes', models.TextField(blank=True)),
('is_active', models.BooleanField(default=True)),
('order', models.PositiveIntegerField(default=0)),
('sub_product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='releases', to='products.subproduct')),
],
options={
'verbose_name': 'Release',
'verbose_name_plural': 'Releases',
'ordering': ['release_type', 'platform', 'order'],
'unique_together': {('sub_product', 'platform', 'release_type')},
},
),
]
@@ -0,0 +1,33 @@
# Generated by Django 5.0.2 on 2026-05-14 05:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0002_subproductrelease'),
]
operations = [
migrations.AddField(
model_name='article',
name='description_format',
field=models.CharField(choices=[('plain', 'Plain Text'), ('markdown', 'Markdown'), ('html', 'HTML')], default='plain', max_length=20),
),
migrations.AddField(
model_name='articlesection',
name='value_format',
field=models.CharField(choices=[('plain', 'Plain Text'), ('markdown', 'Markdown'), ('html', 'HTML')], default='plain', max_length=20),
),
migrations.AddField(
model_name='mainproduct',
name='description_format',
field=models.CharField(choices=[('plain', 'Plain Text'), ('markdown', 'Markdown'), ('html', 'HTML')], default='plain', max_length=20),
),
migrations.AddField(
model_name='subproduct',
name='description_format',
field=models.CharField(choices=[('plain', 'Plain Text'), ('markdown', 'Markdown'), ('html', 'HTML')], default='plain', max_length=20),
),
]
@@ -0,0 +1,145 @@
from django.db import migrations, models
import django.db.models.deletion
def migrate_legacy_releases_to_versions(apps, schema_editor):
OldRelease = apps.get_model("products", "SubProductRelease")
Version = apps.get_model("products", "SubProductVersion")
PLATFORM_MAP = {
"windows": "windows_download_url",
"macos": "macos_download_url",
"linux": "linux_download_url",
}
sub_ids = (
OldRelease.objects.values_list("sub_product_id", flat=True).distinct().order_by()
)
for sub_id in sub_ids:
used_labels = set()
for release_type in ("stable", "previous"):
slab = OldRelease.objects.filter(
sub_product_id=sub_id, release_type=release_type
).order_by("order", "pk")
if not slab.exists():
continue
urls = {}
labels = []
orders = []
notes = []
any_active = False
for r in slab:
orders.append(r.order)
if r.is_active:
any_active = True
f = PLATFORM_MAP.get(r.platform)
if f and r.download_url:
urls[f] = r.download_url
labels.append(r.version or "")
if (r.release_notes or "").strip():
notes.append((r.release_notes or "").strip())
vn = next((x for x in labels if x), None) or "1.0"
if vn in used_labels:
suffix = "older" if release_type == "previous" else "alternate"
candidate = f"{vn} ({suffix})"
n = 2
while candidate in used_labels:
candidate = f"{vn} ({suffix} {n})"
n += 1
vn = candidate
used_labels.add(vn)
Version.objects.create(
sub_product_id=sub_id,
version=vn,
is_featured_stable=(release_type == "stable"),
windows_download_url=urls.get("windows_download_url", ""),
macos_download_url=urls.get("macos_download_url", ""),
linux_download_url=urls.get("linux_download_url", ""),
source_code_url="",
package_resource_url="",
release_notes="\n\n".join(dict.fromkeys(notes)),
is_active=any_active,
order=min(orders) if orders else 0,
)
def noop_reverse(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
("products", "0003_article_description_format_and_more"),
]
operations = [
migrations.AddField(
model_name="subproduct",
name="distribution",
field=models.CharField(
choices=[
("installable", "Installable application"),
("package", "Package (external / non-installable)"),
],
default="installable",
help_text="Only affects how releases appear on the public site.",
max_length=20,
),
),
migrations.CreateModel(
name="SubProductVersion",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("version", models.CharField(max_length=80)),
(
"is_featured_stable",
models.BooleanField(
default=False,
help_text="Highlighted as the main release on the product page.",
),
),
("windows_download_url", models.URLField(blank=True)),
("macos_download_url", models.URLField(blank=True)),
("linux_download_url", models.URLField(blank=True)),
("source_code_url", models.URLField(blank=True)),
(
"package_resource_url",
models.URLField(
blank=True,
help_text="For package-type modules: external link for this release.",
),
),
("release_notes", models.TextField(blank=True)),
("is_active", models.BooleanField(default=True)),
("order", models.PositiveIntegerField(default=0)),
(
"sub_product",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="versions",
to="products.subproduct",
),
),
],
options={
"verbose_name": "Release version",
"verbose_name_plural": "Release versions",
"ordering": ["order", "version", "pk"],
"unique_together": {("sub_product", "version")},
},
),
migrations.RunPython(migrate_legacy_releases_to_versions, noop_reverse),
migrations.DeleteModel(
name="SubProductRelease",
),
]