diff --git a/AKModel/migrations/0050_message_event_reference.py b/AKModel/migrations/0050_message_event_reference.py new file mode 100644 index 0000000000000000000000000000000000000000..704d91a73e4a481b03fa729e77c71495029e3b91 --- /dev/null +++ b/AKModel/migrations/0050_message_event_reference.py @@ -0,0 +1,41 @@ +# Generated by Django 3.1.8 on 2022-05-12 16:57 + +from django.db import migrations, models +import django.db.models.deletion + + +def forwards_func(apps, schema_editor): + # Set event to the corresponding even (from the AK) each + AKOrgaMessage = apps.get_model("AKModel", "AKOrgaMessage") + for message in AKOrgaMessage.objects.all(): + message.event = message.ak.event + message.save() + + +def reverse_func(apps, schema_editor): + # No need to do something here, field will be deleted anyway + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0049_interest_window'), + ] + + operations = [ + migrations.AddField( + model_name='akorgamessage', + name='event', + field=models.ForeignKey(blank=True, help_text='Associated event', null=True, + on_delete=django.db.models.deletion.CASCADE, to='AKModel.event', + verbose_name='Event'), + ), + migrations.RunPython(forwards_func, reverse_func), + migrations.AlterField( + model_name='akorgamessage', + name='event', + field=models.ForeignKey(help_text='Associated event', on_delete=django.db.models.deletion.CASCADE, + to='AKModel.event', verbose_name='Event'), + ), + ] diff --git a/AKModel/models.py b/AKModel/models.py index 2767effb2817e1710ed967119b8dbe306d3fce5b..979f005f70ed48e2bd73daad4d21dbe2160b9aff 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -443,6 +443,8 @@ class AKOrgaMessage(models.Model): text = models.TextField(verbose_name=_("Message text"), help_text=_("Message to the organizers. This is not publicly visible.")) timestamp = models.DateTimeField(auto_now_add=True) + event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'), + help_text=_('Associated event')) class Meta: verbose_name = _('AK Orga Message') diff --git a/AKSubmission/forms.py b/AKSubmission/forms.py index b75f88038880a595581707df1f0c93861bee2ebc..41cebfca9567f82ec7d3537f9d49fd22e2096ac5 100644 --- a/AKSubmission/forms.py +++ b/AKSubmission/forms.py @@ -175,8 +175,9 @@ class AKDurationForm(forms.ModelForm): class AKOrgaMessageForm(forms.ModelForm): class Meta: model = AKOrgaMessage - fields = ['ak', 'text'] + fields = ['ak', 'text', 'event'] widgets = { 'ak': forms.HiddenInput, + 'event': forms.HiddenInput, 'text': forms.Textarea, } diff --git a/AKSubmission/views.py b/AKSubmission/views.py index 077005e2b591daa9230c175367672520064bb540..3f43854608835480385f3236d3bea276b03d67f2 100644 --- a/AKSubmission/views.py +++ b/AKSubmission/views.py @@ -437,6 +437,7 @@ class AKAddOrgaMessageView(EventSlugMixin, CreateView): def get_initial(self): initials = super(AKAddOrgaMessageView, self).get_initial() initials['ak'] = get_object_or_404(AK, pk=self.kwargs['pk']) + initials['event'] = initials['ak'].event return initials def get_context_data(self, *, object_list=None, **kwargs): diff --git a/README.md b/README.md index 7e70a9551c3c07f787200ab95f15ee303cad1986..1bbbfdae91f8b130330849d8774dba74291325f3 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,4 @@ Afterwards, you may check your setup by executing ``Utils/check.sh`` or ``Utils/ ## Developer Notes * to regenerate translations use ````python manage.py makemessages -l de_DE --ignore venv```` * to create a data backup use ````python manage.py dumpdata --indent=2 > db.json --traceback```` +* to export all database items belonging to a certain event use ````.\Utils\json_export.sh <event_id> <export_prefix> [--prod]````. The results will be saved in ````backups/<export_prefix>.json```` diff --git a/Utils/README.md b/Utils/README.md index b601f952c96e4a8a54675da35113d9e7a485844c..d0205298d9d3495c15d8ebd5894542df86f420ff 100644 --- a/Utils/README.md +++ b/Utils/README.md @@ -7,3 +7,4 @@ All scripts should be executed from the project folder (repository root). * **setup** installation script for development setup * **update** update script for development or production (--prod) setup * **check** setup checking script for development and production (--prod) setup +* **json_export** export script for development and production (--prod) -- can be used to export all database items belonging to a given event \ No newline at end of file diff --git a/Utils/json_export.py b/Utils/json_export.py new file mode 100644 index 0000000000000000000000000000000000000000..a3a8af71dce425d7092283d90670d3ef9a316ea6 --- /dev/null +++ b/Utils/json_export.py @@ -0,0 +1,57 @@ +import json +import sys + +event_id = int(sys.argv[1]) +target_name = sys.argv[2] + +print(f"Creating export for event '{event_id}' as '{target_name}'") + +# Load json file just created by django +with open('backups/akplanning_only.json', 'r') as json_file: + exported_entries = json.load(json_file) +print(f"Loaded {len(exported_entries)} entries in total, restricting to event...") + +entries_without_event = 0 +entries_out = [] +virtual_rooms_to_preserve = set() + +# Loop over all dumped entries +for entry in exported_entries: + # Handle all entries with event reference + if "event" in entry['fields']: + event = int(entry['fields']['event']) + + # Does this entry belong to the event we are looking for? + if event == event_id: + # Store for backup + entries_out.append(entry) + + # Remember the primary keys of all rooms of this event + # Required for special handling of virtual rooms, + # since they inherit from normal rooms and have no direct event reference + if entry['model'] == "AKModel.room": + virtual_rooms_to_preserve.add(entry['pk']) + # Handle entries without event reference + else: + # Backup virtual rooms of that event + if entry['model'] == "AKOnline.virtualroom": + if entry['pk'] in virtual_rooms_to_preserve: + entries_out.append(entry) + # Backup the event itself + elif entry['model'] == "AKModel.event": + if int(entry['pk']) == event_id: + entries_out.append(entry) + # Backup tags + elif entry['model'] == "AKModel.aktag": + # No restriction needed, backup all tags + entries_out.append(entry) + else: + # This should normally not happen (all other models should have a reference to the event) + entries_without_event += 1 + print(entry) + +print(f"Ignored entries without event: {entries_without_event}") +print(f"Exporting {len(entries_out)} entries for event") + +with open(f'backups/{target_name}.json', 'w') as json_file: + json.dump(entries_out, json_file, indent=2) diff --git a/Utils/json_export.sh b/Utils/json_export.sh new file mode 100644 index 0000000000000000000000000000000000000000..03ca03ee2a701504f5e474c5226affa39cf732ad --- /dev/null +++ b/Utils/json_export.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Update AKPlanning +# execute as Utils/update.sh id_to_export target_name_to_export_to [--prod] + +# abort on error, print executed commands +set -ex + +# activate virtualenv if necessary +if [ -z ${VIRTUAL_ENV+x} ]; then + source venv/bin/activate +fi + +# set environment variable when we want to update in production +if [ "$3" = "--prod" ]; then + export DJANGO_SETTINGS_MODULE=AKPlanning.settings_production +fi + +mkdir -p ../backups/ +python manage.py dumpdata AKDashboard AKModel AKOnline AKPlan AKScheduling AKSubmission --indent=2 > "backups/akplanning_only.json" --traceback + +python ./Utils/json_export.py $1 $2 + +rm backups/akplanning_only.json