feat: change entire downloads
This commit is contained in:
@@ -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",
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user