diff --git a/compendium_v2/publishers/survey_publisher_v2.py b/compendium_v2/publishers/survey_publisher_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..09570b376dd81976e6259bfea5666fffb2eb9c15 --- /dev/null +++ b/compendium_v2/publishers/survey_publisher_v2.py @@ -0,0 +1,112 @@ +from decimal import Decimal + +from sqlalchemy import delete, select + +from compendium_v2.db import db +from compendium_v2.db.model import BudgetEntry, ChargingStructure, ECProject, FeeType, FundingSource, InstitutionURLs,\ + NrenStaff, ParentOrganization, Policy, SubOrganization, TrafficVolume +from compendium_v2.db.survey_model import ResponseStatus, SurveyResponse + + +def map_2023(year, nren, answers): + for table_class in [BudgetEntry, ChargingStructure, ECProject, FundingSource, InstitutionURLs, + NrenStaff, ParentOrganization, Policy, SubOrganization, TrafficVolume]: + db.session.execute(delete(table_class).where(table_class.year == 2023)) + + answers = answers["data"] + budget = answers.get("budget") + if budget: + db.session.add(BudgetEntry(nren_id=nren.id, nren=nren, year=year, budget=Decimal(budget))) + + funding_source = answers.get("income_sources") + if funding_source: + db.session.add(FundingSource( + nren_id=nren.id, nren=nren, year=year, + client_institutions=Decimal(funding_source.get("client_institutions", 0)), + european_funding=Decimal(funding_source.get("european_funding", 0)), + gov_public_bodies=Decimal(funding_source.get("gov_public_bodies", 0)), + commercial=Decimal(funding_source.get("commercial", 0)), + other=Decimal(funding_source.get("other", 0)) + )) + + charging = answers.get("charging_mechanism") + if charging: + db.session.add(ChargingStructure(nren_id=nren.id, nren=nren, year=year, fee_type=FeeType[charging])) + + staff_roles = answers.get("staff_roles", {}) + staff_employment_type = answers.get("staff_employment_type", {}) + if staff_roles or staff_employment_type: + db.session.add(NrenStaff( + nren_id=nren.id, nren=nren, year=year, + permanent_fte=Decimal(staff_employment_type.get("permanent_fte", 0)), + subcontracted_fte=Decimal(staff_employment_type.get("subcontracted_fte", 0)), + technical_fte=Decimal(staff_roles.get("technical_fte", 0)), + non_technical_fte=Decimal(staff_roles.get("nontechnical_fte", 0)) + )) + + parent = answers.get("parent_organization_name") + if parent: + db.session.add(ParentOrganization(nren_id=nren.id, nren=nren, year=year, organization=parent)) + + subs = answers.get("suborganization_details") + if subs: + for sub in subs: + db.session.add(SubOrganization( + nren_id=nren.id, nren=nren, year=year, + organization=sub.get("suborganization_name"), + role=sub.get("suborganization_role") # TODO handle 'other' option properly + )) + + ec_projects = answers.get("ec_project_names") + if ec_projects: + for ec_project in ec_projects: + db.session.add(ECProject(nren_id=nren.id, nren=nren, year=year, project=ec_project.get("ec_project_name"))) + + strategy = answers.get("corporate_strategy_url", "") + policies = answers.get("policies", {}) + if strategy or policies: + db.session.add(Policy( + nren_id=nren.id, nren=nren, year=year, + strategic_plan=strategy, + environmental=policies.get("environmental_policy", {}).get("url", ""), + equal_opportunity=policies.get("equal_opportunity_policy", {}).get("url", ""), + connectivity=policies.get("connectivity_policy", {}).get("url", ""), + acceptable_use=policies.get("acceptable_use_policy", {}).get("url", ""), + privacy_notice=policies.get("privacy_notice", {}).get("url", ""), + data_protection=policies.get("data_protection_contact", {}).get("url", "") + # TODO gender_equality_policy missing? + )) + + traffic_estimate = answers.get("traffic_estimate") + if traffic_estimate: + db.session.add(TrafficVolume( + nren_id=nren.id, nren=nren, year=year, + strategic_plan=strategy, + to_customers=Decimal(traffic_estimate.get("to_customers")), + from_customers=Decimal(traffic_estimate.get("from_customers")), + to_external=Decimal(traffic_estimate.get("to_external")), + from_external=Decimal(traffic_estimate.get("from_external")), + )) + + institution_urls = answers.get("connected_sites_lists") + if institution_urls: + db.session.add(InstitutionURLs( + nren_id=nren.id, nren=nren, year=year, + urls=institution_urls, + )) + + +def publish(year): + responses = db.session.scalars( + select(SurveyResponse).where(SurveyResponse.survey_year == year) + .where(SurveyResponse.status == ResponseStatus.completed) + ).unique() + + question_mapping = { + 2023: map_2023 + } + + mapping_function = question_mapping[year] + + for response in responses: + mapping_function(year, response.nren, response.answers) diff --git a/compendium_v2/routes/survey.py b/compendium_v2/routes/survey.py index 041e60f9c91ffc992da03a3e5e3bf3ce2ffffa60..6b4a2c5a47e51a7821be08b17e23f0f5007e77d5 100644 --- a/compendium_v2/routes/survey.py +++ b/compendium_v2/routes/survey.py @@ -8,6 +8,7 @@ from sqlalchemy.orm import joinedload, load_only from compendium_v2.db import db from compendium_v2.db.model import NREN, PreviewYear from compendium_v2.db.survey_model import Survey, SurveyResponse, SurveyStatus, RESPONSE_NOT_STARTED +from compendium_v2.publishers.survey_publisher_v2 import publish from compendium_v2.routes import common from compendium_v2.auth.session_management import admin_required @@ -195,7 +196,10 @@ def preview_survey(year) -> Any: if survey.status not in [SurveyStatus.closed, SurveyStatus.preview]: return {'message': 'Survey is not closed or in preview and can therefore not be published for preview'}, 400 - # TODO call new survey_publisher with all completed responses and the year + if year < 2023: + return {'message': 'The 2023 survey is the first that can be published from this application'}, 400 + + publish(year) preview = db.session.scalar(select(PreviewYear).where(PreviewYear.year == year)) if not preview: @@ -223,7 +227,10 @@ def publish_survey(year) -> Any: if survey.status not in [SurveyStatus.preview, SurveyStatus.published]: return {'message': 'Survey is not in preview or published and can therefore not be published'}, 400 - # TODO call new survey_publisher with all completed responses and the year + if year < 2023: + return {'message': 'The 2023 survey is the first that can be published from this application'}, 400 + + publish(year) db.session.execute(delete(PreviewYear).where(PreviewYear.year == year))