From 01092a4c25ae4417aed7266a0250ba2f3ad9b14c Mon Sep 17 00:00:00 2001 From: sudan45 Date: Thu, 22 Feb 2024 11:26:33 +0545 Subject: [PATCH 1/6] update migration of af widget properties --- .../migrations/0041_widget_mapping.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 apps/analysis_framework/migrations/0041_widget_mapping.py diff --git a/apps/analysis_framework/migrations/0041_widget_mapping.py b/apps/analysis_framework/migrations/0041_widget_mapping.py new file mode 100644 index 0000000000..96340c94dc --- /dev/null +++ b/apps/analysis_framework/migrations/0041_widget_mapping.py @@ -0,0 +1,36 @@ +# Generated by Django 3.2.17 on 2024-02-22 05:02 + +from django.db import migrations,transaction + +@transaction.atomic +def analysis_framework_widgets_mapping(apps, schema_editor): + AnalysisFramework = apps.get_model('analysis_framework', 'AnalysisFramework') + analysis_framework_data = AnalysisFramework.objects.filter(properties__isnull=False) + for af in analysis_framework_data: + if af.properties != {}: + widget_properties = af.properties + widget_properties['stats_config']['widget_1d'] = widget_properties['stats_config'].get('widget1d') or widget_properties['stats_config'].get('widget_1d') or [] # noqa + widget_properties['stats_config']['widget_2d'] = widget_properties['stats_config'].get('widget2d') or widget_properties['stats_config'].get('widget_2d') or [] # noqa + widget_properties['stats_config']['organigram_widgets'] = widget_properties['stats_config'].get('affected_groups_widgets') or widget_properties['stats_config'].get('organigram_widgets') or widget_properties['stats_config'].get('organigram_widget') or [] # noqa + widget_properties['stats_config']['multiselect_widgets'] = widget_properties['stats_config'].get('specific_needs_groups_widgets') or widget_properties['stats_config'].get('multiselect_widgets') or widget_properties['stats_config'].get('multiselect_widget') or [] # noqa + if 'old_stats_config' in widget_properties: + widget_properties.pop('old_stats_config') + remove_key = ['widget2d', 'widget1d', 'affected_groups_widgets', 'specific_needs_groups_widgets', 'affected_groups_widget', 'specific_needs_groups_widget'] # noqa + for widget_key in list(widget_properties['stats_config'].keys()): + if widget_key in remove_key: + del widget_properties['stats_config'][widget_key] + af.properties = widget_properties + af.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('analysis_framework', '0040_auto_20231109_1208'), + ] + operations = [ + migrations.RunPython( + analysis_framework_widgets_mapping, + reverse_code=migrations.RunPython.noop + ) + ] From f91d0959219d7c261d9fb67497b3bcc6cd093b6d Mon Sep 17 00:00:00 2001 From: sudan45 Date: Fri, 23 Feb 2024 11:31:11 +0545 Subject: [PATCH 2/6] generate the project viz stats --- .../migrations/0041_widget_mapping.py | 79 ++++++++++++++----- .../commands/generate_projects_viz_stats.py | 20 +++++ 2 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 apps/project/management/commands/generate_projects_viz_stats.py diff --git a/apps/analysis_framework/migrations/0041_widget_mapping.py b/apps/analysis_framework/migrations/0041_widget_mapping.py index 96340c94dc..0cca947473 100644 --- a/apps/analysis_framework/migrations/0041_widget_mapping.py +++ b/apps/analysis_framework/migrations/0041_widget_mapping.py @@ -1,26 +1,69 @@ # Generated by Django 3.2.17 on 2024-02-22 05:02 +from django.db import migrations +import copy -from django.db import migrations,transaction -@transaction.atomic def analysis_framework_widgets_mapping(apps, schema_editor): AnalysisFramework = apps.get_model('analysis_framework', 'AnalysisFramework') - analysis_framework_data = AnalysisFramework.objects.filter(properties__isnull=False) - for af in analysis_framework_data: - if af.properties != {}: - widget_properties = af.properties - widget_properties['stats_config']['widget_1d'] = widget_properties['stats_config'].get('widget1d') or widget_properties['stats_config'].get('widget_1d') or [] # noqa - widget_properties['stats_config']['widget_2d'] = widget_properties['stats_config'].get('widget2d') or widget_properties['stats_config'].get('widget_2d') or [] # noqa - widget_properties['stats_config']['organigram_widgets'] = widget_properties['stats_config'].get('affected_groups_widgets') or widget_properties['stats_config'].get('organigram_widgets') or widget_properties['stats_config'].get('organigram_widget') or [] # noqa - widget_properties['stats_config']['multiselect_widgets'] = widget_properties['stats_config'].get('specific_needs_groups_widgets') or widget_properties['stats_config'].get('multiselect_widgets') or widget_properties['stats_config'].get('multiselect_widget') or [] # noqa - if 'old_stats_config' in widget_properties: - widget_properties.pop('old_stats_config') - remove_key = ['widget2d', 'widget1d', 'affected_groups_widgets', 'specific_needs_groups_widgets', 'affected_groups_widget', 'specific_needs_groups_widget'] # noqa - for widget_key in list(widget_properties['stats_config'].keys()): - if widget_key in remove_key: - del widget_properties['stats_config'][widget_key] - af.properties = widget_properties - af.save() + af_qs = AnalysisFramework.objects.filter(properties__isnull=False) + for af in af_qs: + if af.prop == {}: + continue + af_prop = af.properties + # Remove super legacy config + af_prop.pop('old_stats_config', None) + + # For reassurance + af_prop = { + 'old_stats_config': copy.deepcopy(af_prop), + } + + # Migrate legacy config to latest + # -- Widget1D + af_prop['stats_config']['widget_1d'] = ( + af_prop['stats_config'].get('widget_1d') or + af_prop['stats_config'].get('widget1d') or + [] + ) + + # -- Widget2D + af_prop['stats_config']['widget_2d'] = ( + af_prop['stats_config'].get('widget_2d') or + af_prop['stats_config'].get('widget2d') or + [] + ) + + # -- Organigram + af_prop['stats_config']['organigram_widgets'] = ( + af_prop['stats_config'].get('affected_groups_widgets') or + af_prop['stats_config'].get('organigram_widgets') or + af_prop['stats_config'].get('organigram_widget') or + [] + ) + + # -- Multiselect + af_prop['stats_config']['multiselect_widgets'] = ( + af_prop['stats_config'].get('specific_needs_groups_widgets') or + af_prop['stats_config'].get('multiselect_widgets') or + af_prop['stats_config'].get('multiselect_widget') or + af_prop['stats_config'].get('demographic_group_widget') or + [] + ) + + legacy_widget_keys = [ + 'widget1d', + 'widget2d', + 'affected_groups_widgets', + 'specific_needs_groups_widgets', + 'affected_groups_widget', + 'specific_needs_groups_widget', + 'demographic_group_widget', + ] + for widget_key in legacy_widget_keys: + af_prop['stats_config'].pop(widget_key, None) + + af.properties = af_prop + af.save(update_fields=('properties',)) class Migration(migrations.Migration): diff --git a/apps/project/management/commands/generate_projects_viz_stats.py b/apps/project/management/commands/generate_projects_viz_stats.py new file mode 100644 index 0000000000..7beaccaae3 --- /dev/null +++ b/apps/project/management/commands/generate_projects_viz_stats.py @@ -0,0 +1,20 @@ +from django.core.management.base import BaseCommand + +from project.models import Project + +from project.tasks import generate_viz_stats + + +class Command(BaseCommand): + help = 'Generate the Project Viz Stats' + + def handle(self, *arg, **options): + generate_project_viz_stats() + + +def generate_project_viz_stats(): + project_qs = Project.objects.filter( + is_visualization_enabled=True + ) + for project in project_qs: + generate_viz_stats(project.id, force=True) From d73ad0e1ebfcf6335ac070f4cb392aa58f90d207 Mon Sep 17 00:00:00 2001 From: sudan45 Date: Tue, 23 Jan 2024 15:45:57 +0545 Subject: [PATCH 3/6] Refactor ary/entry stats generator - Fix Null value error issue with viz settings mutation - Update test cases related to AF properties mutation --- apps/analysis_framework/serializers.py | 3 +- .../tests/snapshots/snap_test_mutations.py | 84 +++++++++++++++++-- .../tests/test_mutations.py | 12 ++- apps/entry/stats.py | 32 +------ .../tests/snapshots/snap_test_mutations.py | 30 ------- apps/project/tests/test_apis.py | 4 +- 6 files changed, 95 insertions(+), 70 deletions(-) diff --git a/apps/analysis_framework/serializers.py b/apps/analysis_framework/serializers.py index a29f3545a7..a322bc1c85 100644 --- a/apps/analysis_framework/serializers.py +++ b/apps/analysis_framework/serializers.py @@ -423,7 +423,8 @@ class AnalysisFrameworkPropertiesStatsConfigSerializer(serializers.Serializer): @staticmethod def _validate_widget_with_widget_type(data, widget_type, many=False): if not data: - return + if many: + return [] if many: ids = [item['pk'] for item in data] widgets = list(Widget.objects.filter(pk__in=ids)) diff --git a/apps/analysis_framework/tests/snapshots/snap_test_mutations.py b/apps/analysis_framework/tests/snapshots/snap_test_mutations.py index b199f69a33..8af09fe2f7 100644 --- a/apps/analysis_framework/tests/snapshots/snap_test_mutations.py +++ b/apps/analysis_framework/tests/snapshots/snap_test_mutations.py @@ -715,6 +715,17 @@ 'title': 'Scale', 'version': 1, 'widgetId': 'SCALE' + }, + { + 'clientId': 'organigram-widget-104-client-id', + 'id': '9', + 'key': 'organigram-widget-104-key', + 'order': 5, + 'properties': { + }, + 'title': 'Organigram', + 'version': 1, + 'widgetId': 'ORGANIGRAM' } ], 'title': 'AF (TEST)' @@ -780,6 +791,13 @@ 'messages': "Different widget type was provided. Required: matrix2dWidget Provided: ['multiselectWidget']", 'objectErrors': None }, + { + 'arrayErrors': None, + 'clientId': None, + 'field': 'multiselectWidgets', + 'messages': "Different widget type was provided. Required: multiselectWidget Provided: ['organigramWidget']", + 'objectErrors': None + }, { 'arrayErrors': None, 'clientId': None, @@ -843,7 +861,7 @@ { 'clientId': 'section-2-text-101-client-id', 'conditional': None, - 'id': '9', + 'id': '10', 'key': 'section-2-text-101', 'order': 1, 'properties': { @@ -1018,7 +1036,11 @@ 'pk': '6' } ], - 'organigramWidgets': None, + 'organigramWidgets': [ + { + 'pk': '9' + } + ], 'reliabilityWidget': { 'pk': '8' }, @@ -1041,7 +1063,7 @@ { 'clientId': 'multi-select-widget-102-client-id', 'conditional': None, - 'id': '10', + 'id': '11', 'key': 'multi-select-widget-102-key', 'order': 2, 'properties': { @@ -1073,6 +1095,18 @@ 'title': 'Scale', 'version': 1, 'widgetId': 'SCALE' + }, + { + 'clientId': 'organigram-widget-104-client-id', + 'conditional': None, + 'id': '9', + 'key': 'organigram-widget-104-key', + 'order': 5, + 'properties': { + }, + 'title': 'Organigram', + 'version': 1, + 'widgetId': 'ORGANIGRAM' } ], 'title': 'Updated AF (TEST)' @@ -1143,7 +1177,7 @@ { 'clientId': 'section-2-text-101-client-id', 'conditional': None, - 'id': '12', + 'id': '13', 'key': 'section-2-text-101', 'order': 1, 'properties': { @@ -1320,7 +1354,11 @@ }, 'multiselectWidgets': [ ], - 'organigramWidgets': None, + 'organigramWidgets': [ + { + 'pk': '9' + } + ], 'reliabilityWidget': { 'pk': '8' }, @@ -1348,7 +1386,7 @@ 'parentWidget': '1', 'parentWidgetType': 'MATRIX1D' }, - 'id': '13', + 'id': '14', 'key': 'multi-select-widget-102-key', 'order': 2, 'properties': { @@ -1380,6 +1418,18 @@ 'title': 'Scale', 'version': 1, 'widgetId': 'SCALE' + }, + { + 'clientId': 'organigram-widget-104-client-id', + 'conditional': None, + 'id': '9', + 'key': 'organigram-widget-104-key', + 'order': 5, + 'properties': { + }, + 'title': 'Organigram', + 'version': 1, + 'widgetId': 'ORGANIGRAM' } ], 'title': 'Updated AF (TEST)' @@ -1412,7 +1462,7 @@ { 'clientId': 'section-2-text-101-client-id', 'conditional': None, - 'id': '14', + 'id': '15', 'key': 'section-2-text-101', 'order': 1, 'properties': { @@ -1589,7 +1639,11 @@ }, 'multiselectWidgets': [ ], - 'organigramWidgets': None, + 'organigramWidgets': [ + { + 'pk': '9' + } + ], 'reliabilityWidget': { 'pk': '8' }, @@ -1612,7 +1666,7 @@ { 'clientId': 'multi-select-widget-102-client-id', 'conditional': None, - 'id': '15', + 'id': '16', 'key': 'multi-select-widget-102-key', 'order': 2, 'properties': { @@ -1644,6 +1698,18 @@ 'title': 'Scale', 'version': 1, 'widgetId': 'SCALE' + }, + { + 'clientId': 'organigram-widget-104-client-id', + 'conditional': None, + 'id': '9', + 'key': 'organigram-widget-104-key', + 'order': 5, + 'properties': { + }, + 'title': 'Organigram', + 'version': 1, + 'widgetId': 'ORGANIGRAM' } ], 'title': 'Updated AF (TEST)' diff --git a/apps/analysis_framework/tests/test_mutations.py b/apps/analysis_framework/tests/test_mutations.py index 16ec9602a2..b630820fa6 100644 --- a/apps/analysis_framework/tests/test_mutations.py +++ b/apps/analysis_framework/tests/test_mutations.py @@ -430,7 +430,7 @@ def test_analysis_framework_update(self): widget2d { pk } - multiselectWidgets { + multiselectWidgets { pk } organigramWidgets { @@ -492,6 +492,7 @@ def _query_check(id, minput, **kwargs): variables={'id': id}, **kwargs, ) + # ---------- Without login valid_minput = copy.deepcopy(self.valid_minput) new_widgets = [ @@ -513,6 +514,15 @@ def _query_check(id, minput, **kwargs): order=4, properties=dict(), ), + dict( + clientId='organigram-widget-104-client-id', + title='Organigram', + widgetId=self.genum(Widget.WidgetType.ORGANIGRAM), + version=1, + key='organigram-widget-104-key', + order=5, + properties=dict(), + ), ] valid_minput['secondaryTagging'].extend(new_widgets) _query_check(0, valid_minput, assert_for_error=True) diff --git a/apps/entry/stats.py b/apps/entry/stats.py index 759cf5526d..1aa6dd7201 100644 --- a/apps/entry/stats.py +++ b/apps/entry/stats.py @@ -97,7 +97,7 @@ def _return(properties): return _return(w_filter.properties if w_filter else None) properties = widget.properties - if config.get('is_conditional_widget'): + if config.get('is_conditional_widget'): # TODO: Remove this # TODO: Skipping conditional widget, in new this is not needed return default return _return(properties) @@ -193,21 +193,6 @@ def get_project_entries_stats(project, skip_geo_data=False): af = project.analysis_framework config = af.properties.get('stats_config') - # TODO: REMOVE THIS - if 'multiselect_widgets' not in config: - config['multiselect_widgets'] = [ - {'pk': config[key]['pk']} - for key in [ - 'specific_needs_groups_widget', - 'demographic_groups_widget', - ] - if key in config - ] - if 'organigram_widgets' not in config and 'affected_groups_widget' in config: - config['organigram_widgets'] = [ - config['affected_groups_widget'] - ] - widgets_pk = [ info['pk'] for _info in config.values() @@ -225,15 +210,6 @@ def get_project_entries_stats(project, skip_geo_data=False): for widget in Widget.objects.filter(pk__in=widgets_pk, analysis_framework=af) } - # TODO: Remove this later after all data are updated. - config['widget1d'] = config.get('widget1d') or config['widget_1d'] - config['widget2d'] = config.get('widget2d') or config['widget_2d'] - - # Make sure this are array - for key in ['widget1d', 'widget2d']: - if not isinstance(config[key], list): - config[key] = [config[key]] - w_reliability_default = w_severity_default = w_multiselect_widget_default = w_organigram_widget_default = { 'pk': None, 'properties': { @@ -241,8 +217,8 @@ def get_project_entries_stats(project, skip_geo_data=False): }, } - w1ds = [_get_widget_info(_config, widgets) for _config in config['widget1d']] - w2ds = [_get_widget_info(_config, widgets) for _config in config['widget2d']] + w1ds = [_get_widget_info(_config, widgets) for _config in config['widget_1d'] or []] + w2ds = [_get_widget_info(_config, widgets) for _config in config['widget_2d'] or []] w_multiselect_widgets = [ _get_widget_info( @@ -269,7 +245,7 @@ def get_project_entries_stats(project, skip_geo_data=False): matrix_widgets = [ {'id': w['pk'], 'type': w_type, 'title': w['_widget'].title} - for widgets, w_type in [[w1ds, 'widget1d'], [w2ds, 'widget2d']] + for widgets, w_type in [[w1ds, 'widget_1d'], [w2ds, 'widget_2d']] for w in widgets ] diff --git a/apps/project/tests/snapshots/snap_test_mutations.py b/apps/project/tests/snapshots/snap_test_mutations.py index ba9a301d85..6989984c86 100644 --- a/apps/project/tests/snapshots/snap_test_mutations.py +++ b/apps/project/tests/snapshots/snap_test_mutations.py @@ -208,36 +208,6 @@ } } -snapshots['ProjectMutationSnapshotTest::test_project_update_mutation public-project-0:project-change:diff'] = { - 'details': { - 'description': { - 'new': 'Added some description', - 'old': '' - } - }, - 'organizations': { - 'add': [ - { - 'organization': 1, - 'organization_type': 'lead_organization' - } - ], - 'remove': [ - { - 'organization': 2, - 'organization_type': 'national_partner' - } - ] - } -} - -snapshots['ProjectMutationSnapshotTest::test_project_update_mutation public-project-1:project-change:diff'] = { - 'framework': { - 'new': 4, - 'old': 2 - } -} - snapshots['ProjectMutationSnapshotTest::test_project_update_mutation public-project:is-private-change-error'] = { 'data': { '__typename': 'Mutation', diff --git a/apps/project/tests/test_apis.py b/apps/project/tests/test_apis.py index a806c84c2d..bd74ee47a9 100644 --- a/apps/project/tests/test_apis.py +++ b/apps/project/tests/test_apis.py @@ -1304,9 +1304,11 @@ def test_project_stats(self): **config_kwargs, } invalid_stat_config[widget_identifier] = {'pk': 0} + if data_identifier in ['matrix1dWidget', 'matrix2dWidget', 'multiselectWidget']: + valid_stat_config[widget_identifier] = [valid_stat_config[widget_identifier]] + invalid_stat_config[widget_identifier] = [invalid_stat_config[widget_identifier]] url = f'/api/v1/projects/{project.pk}/project-viz/' - # 404 for non project user self.authenticate(non_project_user) response = self.client.get(url) From 5520e827de3f18244151e8fb965dbf370b1b02cf Mon Sep 17 00:00:00 2001 From: sudan45 Date: Wed, 10 Apr 2024 10:27:02 +0545 Subject: [PATCH 4/6] - fix null value error issue with viz settings mutation - update migration file of af widgets properties --- apps/project/management/commands/generate_projects_viz_stats.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/project/management/commands/generate_projects_viz_stats.py b/apps/project/management/commands/generate_projects_viz_stats.py index 7beaccaae3..6bd86c4d96 100644 --- a/apps/project/management/commands/generate_projects_viz_stats.py +++ b/apps/project/management/commands/generate_projects_viz_stats.py @@ -1,7 +1,6 @@ from django.core.management.base import BaseCommand from project.models import Project - from project.tasks import generate_viz_stats From 42a174bde87c0efb1769139d852148149c5e301a Mon Sep 17 00:00:00 2001 From: sudan45 Date: Fri, 3 May 2024 14:50:22 +0545 Subject: [PATCH 5/6] Minor changes in migrations file --- .../migrations/0041_widget_mapping.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/analysis_framework/migrations/0041_widget_mapping.py b/apps/analysis_framework/migrations/0041_widget_mapping.py index 0cca947473..c4ec21c89c 100644 --- a/apps/analysis_framework/migrations/0041_widget_mapping.py +++ b/apps/analysis_framework/migrations/0041_widget_mapping.py @@ -7,16 +7,14 @@ def analysis_framework_widgets_mapping(apps, schema_editor): AnalysisFramework = apps.get_model('analysis_framework', 'AnalysisFramework') af_qs = AnalysisFramework.objects.filter(properties__isnull=False) for af in af_qs: - if af.prop == {}: + if af.properties == {}: continue af_prop = af.properties # Remove super legacy config af_prop.pop('old_stats_config', None) # For reassurance - af_prop = { - 'old_stats_config': copy.deepcopy(af_prop), - } + old_stats_config = copy.deepcopy(af_prop) # Migrate legacy config to latest # -- Widget1D @@ -35,7 +33,7 @@ def analysis_framework_widgets_mapping(apps, schema_editor): # -- Organigram af_prop['stats_config']['organigram_widgets'] = ( - af_prop['stats_config'].get('affected_groups_widgets') or + af_prop['stats_config'].get('affected_groups_widget') or af_prop['stats_config'].get('organigram_widgets') or af_prop['stats_config'].get('organigram_widget') or [] @@ -43,10 +41,10 @@ def analysis_framework_widgets_mapping(apps, schema_editor): # -- Multiselect af_prop['stats_config']['multiselect_widgets'] = ( - af_prop['stats_config'].get('specific_needs_groups_widgets') or + af_prop['stats_config'].get('specific_needs_groups_widget') or af_prop['stats_config'].get('multiselect_widgets') or af_prop['stats_config'].get('multiselect_widget') or - af_prop['stats_config'].get('demographic_group_widget') or + af_prop['stats_config'].get('demographic_groups_widget') or [] ) @@ -57,12 +55,14 @@ def analysis_framework_widgets_mapping(apps, schema_editor): 'specific_needs_groups_widgets', 'affected_groups_widget', 'specific_needs_groups_widget', - 'demographic_group_widget', + 'demographic_group_widgets', + 'specificNeedsGroupsWidget', ] for widget_key in legacy_widget_keys: af_prop['stats_config'].pop(widget_key, None) af.properties = af_prop + af.properties['old_stats_config'] = old_stats_config af.save(update_fields=('properties',)) From 7669a56263477fa652fd914aed68fcb1219a0d6b Mon Sep 17 00:00:00 2001 From: sudan45 Date: Mon, 13 May 2024 14:51:01 +0545 Subject: [PATCH 6/6] Implement multiselect support for specific needs & demographics --- .../migrations/0041_widget_mapping.py | 78 ++++++++++--------- apps/entry/stats.py | 6 +- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/apps/analysis_framework/migrations/0041_widget_mapping.py b/apps/analysis_framework/migrations/0041_widget_mapping.py index c4ec21c89c..02682b0edc 100644 --- a/apps/analysis_framework/migrations/0041_widget_mapping.py +++ b/apps/analysis_framework/migrations/0041_widget_mapping.py @@ -9,60 +9,64 @@ def analysis_framework_widgets_mapping(apps, schema_editor): for af in af_qs: if af.properties == {}: continue - af_prop = af.properties + new_widget_config = af.properties # Remove super legacy config - af_prop.pop('old_stats_config', None) + new_widget_config.pop('old_stats_config', None) # For reassurance - old_stats_config = copy.deepcopy(af_prop) + new_widget_config = copy.deepcopy(new_widget_config) # Migrate legacy config to latest # -- Widget1D - af_prop['stats_config']['widget_1d'] = ( - af_prop['stats_config'].get('widget_1d') or - af_prop['stats_config'].get('widget1d') or - [] - ) + if 'widget_1d' not in new_widget_config['stats_config']: + new_widget_config['widget_1d'] = [ + {'pk': new_widget_config['stats_config'][key]['pk']} + for key in [ + 'widget1d' + ] + if key in new_widget_config + ] # -- Widget2D - af_prop['stats_config']['widget_2d'] = ( - af_prop['stats_config'].get('widget_2d') or - af_prop['stats_config'].get('widget2d') or - [] - ) - - # -- Organigram - af_prop['stats_config']['organigram_widgets'] = ( - af_prop['stats_config'].get('affected_groups_widget') or - af_prop['stats_config'].get('organigram_widgets') or - af_prop['stats_config'].get('organigram_widget') or - [] - ) + if 'widget_2d' not in new_widget_config['stats_config']: + new_widget_config['widget_2d'] = [ + {'pk': new_widget_config['stats_config'][key]['pk']} + for key in [ + 'widget2d' + ] + if key in new_widget_config + ] # -- Multiselect - af_prop['stats_config']['multiselect_widgets'] = ( - af_prop['stats_config'].get('specific_needs_groups_widget') or - af_prop['stats_config'].get('multiselect_widgets') or - af_prop['stats_config'].get('multiselect_widget') or - af_prop['stats_config'].get('demographic_groups_widget') or - [] - ) + if 'multiselect_widgets' not in new_widget_config['stats_config']: + new_widget_config['multiselect_widgets'] = [ + {'pk': new_widget_config['stats_config'][key]['pk']} + for key in [ + 'specific_needs_groups_widget', + 'demographic_groups_widget' + ] + if key in new_widget_config + ] + + # -- Organigram + if 'organigram_widget' not in new_widget_config['stats_config']: + new_widget_config['organigram_widget'] = [ + {'pk': new_widget_config['stats_config'][key]['pk']} + for key in [ + 'affected_groups_widget' + ] + if key in new_widget_config + ] legacy_widget_keys = [ - 'widget1d', - 'widget2d', - 'affected_groups_widgets', - 'specific_needs_groups_widgets', 'affected_groups_widget', + 'demographic_groups_widget', 'specific_needs_groups_widget', - 'demographic_group_widgets', - 'specificNeedsGroupsWidget', ] for widget_key in legacy_widget_keys: - af_prop['stats_config'].pop(widget_key, None) + new_widget_config['stats_config'].pop(widget_key, None) - af.properties = af_prop - af.properties['old_stats_config'] = old_stats_config + af.properties = new_widget_config af.save(update_fields=('properties',)) diff --git a/apps/entry/stats.py b/apps/entry/stats.py index 1aa6dd7201..8c0ab7e085 100644 --- a/apps/entry/stats.py +++ b/apps/entry/stats.py @@ -180,9 +180,9 @@ def get_project_entries_stats(project, skip_geo_data=False): 'reliability_widget': { 'pk': 2683, }, - 'organigram_widgets': { - 'pk': 2682, - }, + 'organigram_widgets': [ + {'pk': 2682}, + ] 'multiselect_widgets': [ {'pk': 2681}, {'pk': 8703},