From c094c536b0b5d56292cdec75e537ad867d183c10 Mon Sep 17 00:00:00 2001
From: Mohammad Torkashvand <mohammad.torkashvand@geant.org>
Date: Thu, 14 Sep 2023 16:23:39 +0200
Subject: [PATCH] refacgtor modules name and structures

---
 compendium_v2/background_task/__init__.py     |   0
 compendium_v2/conversion/conversion.py        |   6 +--
 compendium_v2/db/auth_model.py                |   2 +-
 .../db/{model.py => presentation_models.py}   |   0
 .../db/{survey_model.py => survey_models.py}  |   2 +-
 compendium_v2/migrations/dump_survey_model.py |   2 +-
 .../excel_parser.py}                          |   6 +--
 compendium_v2/publishers/helpers.py           |   4 +-
 ...ey_publisher_v2.py => survey_publisher.py} |  19 ++++++--
 ...v1.py => survey_publisher_legacy_excel.py} |  43 +++++++++---------
 ...022.py => survey_publisher_old_db_2022.py} |  43 ++++++++++--------
 .../2021_Organisation_DataSeries.xlsx         | Bin
 .../2022_Connected_Users_DataSeries.xlsx      | Bin
 .../2022_Networks_DataSeries.xlsx             | Bin
 ...NREN-Services-prefills_2023_Recovered.xlsx | Bin
 compendium_v2/routes/budget.py                |   2 +-
 compendium_v2/routes/charging.py              |   2 +-
 compendium_v2/routes/common.py                |   2 +-
 compendium_v2/routes/ec_projects.py           |   2 +-
 compendium_v2/routes/funding.py               |   2 +-
 compendium_v2/routes/institutions_urls.py     |   2 +-
 compendium_v2/routes/organization.py          |   2 +-
 compendium_v2/routes/policy.py                |   2 +-
 compendium_v2/routes/response.py              |   4 +-
 compendium_v2/routes/staff.py                 |   2 +-
 compendium_v2/routes/survey.py                |   6 +--
 compendium_v2/routes/traffic.py               |   2 +-
 compendium_v2/routes/user.py                  |   2 +-
 ...22.py => test_db_survey_publisher_2022.py} |  27 +++++------
 ...blisher_v2.py => test_survey_publisher.py} |  40 ++++++++--------
 ... => test_survey_publisher_legacy_excel.py} |  22 +++++----
 31 files changed, 134 insertions(+), 114 deletions(-)
 delete mode 100644 compendium_v2/background_task/__init__.py
 rename compendium_v2/db/{model.py => presentation_models.py} (100%)
 rename compendium_v2/db/{survey_model.py => survey_models.py} (97%)
 rename compendium_v2/{background_task/parse_excel_data.py => publishers/excel_parser.py} (98%)
 rename compendium_v2/publishers/{survey_publisher_v2.py => survey_publisher.py} (88%)
 rename compendium_v2/publishers/{survey_publisher_v1.py => survey_publisher_legacy_excel.py} (84%)
 rename compendium_v2/publishers/{survey_publisher_2022.py => survey_publisher_old_db_2022.py} (93%)
 rename compendium_v2/{background_task/xlsx => resources}/2021_Organisation_DataSeries.xlsx (100%)
 rename compendium_v2/{background_task/xlsx => resources}/2022_Connected_Users_DataSeries.xlsx (100%)
 rename compendium_v2/{background_task/xlsx => resources}/2022_Networks_DataSeries.xlsx (100%)
 rename compendium_v2/{conversion => resources}/NREN-Services-prefills_2023_Recovered.xlsx (100%)
 rename test/{test_survey_publisher_2022.py => test_db_survey_publisher_2022.py} (88%)
 rename test/{test_survey_publisher_v2.py => test_survey_publisher.py} (65%)
 rename test/{test_survey_publisher_v1.py => test_survey_publisher_legacy_excel.py} (80%)

diff --git a/compendium_v2/background_task/__init__.py b/compendium_v2/background_task/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/compendium_v2/conversion/conversion.py b/compendium_v2/conversion/conversion.py
index a963b446..0da96978 100644
--- a/compendium_v2/conversion/conversion.py
+++ b/compendium_v2/conversion/conversion.py
@@ -21,8 +21,8 @@ from compendium_v2.environment import setup_logging
 from compendium_v2.db import db
 from compendium_v2.config import load
 from compendium_v2.survey_db import model as survey_model
-from compendium_v2.db.model import NREN
-from compendium_v2.db.survey_model import Survey, SurveyResponse, ResponseStatus
+from compendium_v2.db.presentation_models import NREN
+from compendium_v2.db.survey_models import Survey, SurveyResponse, ResponseStatus
 
 from compendium_v2.conversion import mapping
 
@@ -30,7 +30,7 @@ setup_logging()
 
 logger = logging.getLogger('conversion')
 
-EXCEL_FILE = os.path.join(os.path.dirname(__file__), "NREN-Services-prefills_2023_Recovered.xlsx")
+EXCEL_FILE = os.path.join(os.path.dirname(__file__), "../resources/NREN-Services-prefills_2023_Recovered.xlsx")
 
 
 def query_nren(nren_id: int):
diff --git a/compendium_v2/db/auth_model.py b/compendium_v2/db/auth_model.py
index 50be7e3e..8605ab39 100644
--- a/compendium_v2/db/auth_model.py
+++ b/compendium_v2/db/auth_model.py
@@ -15,7 +15,7 @@ from sqlalchemy.schema import ForeignKey
 from flask_login import UserMixin  # type: ignore
 
 from compendium_v2.db import db
-from compendium_v2.db.model import NREN
+from compendium_v2.db.presentation_models import NREN
 
 logger = logging.getLogger(__name__)
 
diff --git a/compendium_v2/db/model.py b/compendium_v2/db/presentation_models.py
similarity index 100%
rename from compendium_v2/db/model.py
rename to compendium_v2/db/presentation_models.py
diff --git a/compendium_v2/db/survey_model.py b/compendium_v2/db/survey_models.py
similarity index 97%
rename from compendium_v2/db/survey_model.py
rename to compendium_v2/db/survey_models.py
index 866df323..fd688d38 100644
--- a/compendium_v2/db/survey_model.py
+++ b/compendium_v2/db/survey_models.py
@@ -15,7 +15,7 @@ from sqlalchemy.types import JSON
 
 from compendium_v2.db import db
 from compendium_v2.db.auth_model import User
-from compendium_v2.db.model import NREN
+from compendium_v2.db.presentation_models import NREN
 
 
 logger = logging.getLogger(__name__)
diff --git a/compendium_v2/migrations/dump_survey_model.py b/compendium_v2/migrations/dump_survey_model.py
index 314fda6d..3869a4a6 100644
--- a/compendium_v2/migrations/dump_survey_model.py
+++ b/compendium_v2/migrations/dump_survey_model.py
@@ -24,7 +24,7 @@ import compendium_v2
 from compendium_v2.environment import setup_logging
 from compendium_v2.db import db
 from compendium_v2.config import load
-from compendium_v2.db.survey_model import Survey
+from compendium_v2.db.survey_models import Survey
 
 setup_logging()
 
diff --git a/compendium_v2/background_task/parse_excel_data.py b/compendium_v2/publishers/excel_parser.py
similarity index 98%
rename from compendium_v2/background_task/parse_excel_data.py
rename to compendium_v2/publishers/excel_parser.py
index aba3ef6f..594031b9 100644
--- a/compendium_v2/background_task/parse_excel_data.py
+++ b/compendium_v2/publishers/excel_parser.py
@@ -2,15 +2,15 @@ import logging
 import openpyxl
 import os
 
-from compendium_v2.db.model import FeeType
+from compendium_v2.db.presentation_models import FeeType
 from compendium_v2.environment import setup_logging
 
 setup_logging()
 
 logger = logging.getLogger(__name__)
 
-EXCEL_FILE = os.path.join(os.path.dirname(__file__), "xlsx", "2021_Organisation_DataSeries.xlsx")
-NETWORK_EXCEL_FILE = os.path.join(os.path.dirname(__file__), "xlsx", "2022_Networks_DataSeries.xlsx")
+EXCEL_FILE = os.path.join(os.path.dirname(__file__), "../resources", "2021_Organisation_DataSeries.xlsx")
+NETWORK_EXCEL_FILE = os.path.join(os.path.dirname(__file__), "../resources", "2022_Networks_DataSeries.xlsx")
 
 
 def fetch_budget_excel_data():
diff --git a/compendium_v2/publishers/helpers.py b/compendium_v2/publishers/helpers.py
index f6492d2d..aeb4ecd9 100644
--- a/compendium_v2/publishers/helpers.py
+++ b/compendium_v2/publishers/helpers.py
@@ -3,7 +3,7 @@ from typing import List
 
 from sqlalchemy import select
 
-from compendium_v2.db import db, model
+from compendium_v2.db import db, presentation_models
 
 URL_PATTERN = re.compile(
     (r'\b(https?://[^\s<>";,(){}\[\]!\\]+'
@@ -17,7 +17,7 @@ def get_uppercase_nren_dict():
     """
     :return: a dictionary of all known NRENs db entities keyed on the uppercased name
     """
-    current_nrens = db.session.scalars(select(model.NREN))
+    current_nrens = db.session.scalars(select(presentation_models.NREN))
     nren_dict = {nren.name.upper(): nren for nren in current_nrens}
     # add aliases that are used in the source data:
     nren_dict['ASNET'] = nren_dict['ASNET-AM']
diff --git a/compendium_v2/publishers/survey_publisher_v2.py b/compendium_v2/publishers/survey_publisher.py
similarity index 88%
rename from compendium_v2/publishers/survey_publisher_v2.py
rename to compendium_v2/publishers/survey_publisher.py
index ebede055..3b88d5b9 100644
--- a/compendium_v2/publishers/survey_publisher_v2.py
+++ b/compendium_v2/publishers/survey_publisher.py
@@ -1,14 +1,25 @@
+"""
+This module handles adding responses from the latest 2023 survey into the 2023 presentation_models.
+The process is straightforward as the data is new and can be directly inserted into the presentation_models.
+
+For subsequent years like 2024, handling should be almost the same as 2023, only changes in questions
+will need to be addressed.
+
+Usage:
+    Used in publish_survey API in compendium_v2/routes/survey.py
+"""
+
 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, \
+from compendium_v2.db.presentation_models import BudgetEntry, ChargingStructure, ECProject, FeeType, FundingSource, \
     InstitutionURLs, NrenStaff, ParentOrganization, Policy, SubOrganization, TrafficVolume
-from compendium_v2.db.survey_model import ResponseStatus, SurveyResponse
+from compendium_v2.db.survey_models import ResponseStatus, SurveyResponse
 
 
-def map_2023(nren, answers):
+def _map_2023(nren, answers):
     year = 2023
 
     for table_class in [BudgetEntry, ChargingStructure, ECProject, FundingSource, InstitutionURLs,
@@ -112,7 +123,7 @@ def publish(year):
     ).unique()
 
     question_mapping = {
-        2023: map_2023
+        2023: _map_2023
     }
 
     mapping_function = question_mapping[year]
diff --git a/compendium_v2/publishers/survey_publisher_v1.py b/compendium_v2/publishers/survey_publisher_legacy_excel.py
similarity index 84%
rename from compendium_v2/publishers/survey_publisher_v1.py
rename to compendium_v2/publishers/survey_publisher_legacy_excel.py
index a6e2376f..f265231a 100644
--- a/compendium_v2/publishers/survey_publisher_v1.py
+++ b/compendium_v2/publishers/survey_publisher_legacy_excel.py
@@ -2,7 +2,7 @@
 survey_publisher_v1
 =========================
 
-This module loads the survey data from before 2022 from an excel file.
+This module loads the survey data from before 2022 from a legacy Excel files.
 Missing info is filled in from the survey db for some questions.
 Registered as click cli command when installing compendium-v2.
 
@@ -16,15 +16,14 @@ from sqlalchemy import select
 
 import compendium_v2
 from compendium_v2.environment import setup_logging
-from compendium_v2.background_task import parse_excel_data
 from compendium_v2.config import load
-from compendium_v2.db import db, model
+from compendium_v2.db import db, presentation_models
 from compendium_v2.survey_db import model as survey_model
-from compendium_v2.publishers import helpers
+from compendium_v2.publishers import helpers, excel_parser
 
 setup_logging()
 
-logger = logging.getLogger('survey-publisher-v1')
+logger = logging.getLogger(__file__)
 
 
 def db_budget_migration(nren_dict):
@@ -46,7 +45,7 @@ def db_budget_migration(nren_dict):
                 logger.warning(f'{abbrev} unknown. Skipping.')
                 continue
 
-            budget_entry = model.BudgetEntry(
+            budget_entry = presentation_models.BudgetEntry(
                 nren=nren_dict[abbrev],
                 nren_id=nren_dict[abbrev].id,
                 budget=float(budget.budget),
@@ -55,7 +54,7 @@ def db_budget_migration(nren_dict):
             db.session.merge(budget_entry)
 
     # Import the data from excel sheet to database
-    exceldata = parse_excel_data.fetch_budget_excel_data()
+    exceldata = excel_parser.fetch_budget_excel_data()
 
     for abbrev, budget, year in exceldata:
         if abbrev not in nren_dict:
@@ -65,7 +64,7 @@ def db_budget_migration(nren_dict):
         if budget > 200:
             logger.warning(f'{nren} has budget set to >200M EUR for {year}. ({budget})')
 
-        budget_entry = model.BudgetEntry(
+        budget_entry = presentation_models.BudgetEntry(
             nren=nren_dict[abbrev],
             nren_id=nren_dict[abbrev].id,
             budget=budget,
@@ -77,7 +76,7 @@ def db_budget_migration(nren_dict):
 
 def db_funding_migration(nren_dict):
     # Import the data to database
-    data = parse_excel_data.fetch_funding_excel_data()
+    data = excel_parser.fetch_funding_excel_data()
 
     for (abbrev, year, client_institution,
             european_funding,
@@ -93,7 +92,7 @@ def db_funding_migration(nren_dict):
             logger.warning(f'{abbrev} unknown. Skipping.')
             continue
 
-        budget_entry = model.FundingSource(
+        budget_entry = presentation_models.FundingSource(
             nren=nren_dict[abbrev],
             nren_id=nren_dict[abbrev].id,
             year=year,
@@ -108,14 +107,14 @@ def db_funding_migration(nren_dict):
 
 def db_charging_structure_migration(nren_dict):
     # Import the data to database
-    data = parse_excel_data.fetch_charging_structure_excel_data()
+    data = excel_parser.fetch_charging_structure_excel_data()
 
     for (abbrev, year, charging_structure) in data:
         if abbrev not in nren_dict:
             logger.warning(f'{abbrev} unknown. Skipping.')
             continue
 
-        charging_structure_entry = model.ChargingStructure(
+        charging_structure_entry = presentation_models.ChargingStructure(
             nren=nren_dict[abbrev],
             nren_id=nren_dict[abbrev].id,
             year=year,
@@ -126,7 +125,7 @@ def db_charging_structure_migration(nren_dict):
 
 
 def db_staffing_migration(nren_dict):
-    staff_data = parse_excel_data.fetch_staffing_excel_data()
+    staff_data = excel_parser.fetch_staffing_excel_data()
 
     nren_staff_map = {}
     for (abbrev, year, permanent_fte, subcontracted_fte) in staff_data:
@@ -135,7 +134,7 @@ def db_staffing_migration(nren_dict):
             continue
 
         nren = nren_dict[abbrev]
-        nren_staff_map[(nren.id, year)] = model.NrenStaff(
+        nren_staff_map[(nren.id, year)] = presentation_models.NrenStaff(
             nren=nren,
             nren_id=nren.id,
             year=year,
@@ -145,7 +144,7 @@ def db_staffing_migration(nren_dict):
             non_technical_fte=0
         )
 
-    function_data = parse_excel_data.fetch_staff_function_excel_data()
+    function_data = excel_parser.fetch_staff_function_excel_data()
     for (abbrev, year, technical_fte, non_technical_fte) in function_data:
         if abbrev not in nren_dict:
             logger.warning(f'{abbrev} unknown. Skipping staff function data.')
@@ -156,7 +155,7 @@ def db_staffing_migration(nren_dict):
             nren_staff_map[(nren.id, year)].technical_fte = technical_fte
             nren_staff_map[(nren.id, year)].non_technical_fte = non_technical_fte
         else:
-            nren_staff_map[(nren.id, year)] = model.NrenStaff(
+            nren_staff_map[(nren.id, year)] = presentation_models.NrenStaff(
                 nren=nren,
                 nren_id=nren.id,
                 year=year,
@@ -179,40 +178,40 @@ def db_staffing_migration(nren_dict):
 
 
 def db_ecprojects_migration(nren_dict):
-    ecproject_data = parse_excel_data.fetch_ecproject_excel_data()
+    ecproject_data = excel_parser.fetch_ecproject_excel_data()
     for (abbrev, year, project) in ecproject_data:
         if abbrev not in nren_dict:
             logger.warning(f'{abbrev} unknown. Skipping.')
             continue
 
         nren = nren_dict[abbrev]
-        ecproject_entry = model.ECProject(nren=nren, nren_id=nren.id, year=year, project=project)
+        ecproject_entry = presentation_models.ECProject(nren=nren, nren_id=nren.id, year=year, project=project)
         db.session.merge(ecproject_entry)
     db.session.commit()
 
 
 def db_organizations_migration(nren_dict):
-    organization_data = parse_excel_data.fetch_organization_excel_data()
+    organization_data = excel_parser.fetch_organization_excel_data()
     for (abbrev, year, org) in organization_data:
         if abbrev not in nren_dict:
             logger.warning(f'{abbrev} unknown. Skipping.')
             continue
 
         nren = nren_dict[abbrev]
-        org_entry = model.ParentOrganization(nren=nren, nren_id=nren.id, year=year, organization=org)
+        org_entry = presentation_models.ParentOrganization(nren=nren, nren_id=nren.id, year=year, organization=org)
         db.session.merge(org_entry)
     db.session.commit()
 
 
 def db_traffic_volume_migration(nren_dict):
-    traffic_data = parse_excel_data.fetch_traffic_excel_data()
+    traffic_data = excel_parser.fetch_traffic_excel_data()
     for (abbrev, year, from_external, to_external, from_customers, to_customers) in traffic_data:
         if abbrev not in nren_dict:
             logger.warning(f'{abbrev} unknown. Skipping.')
             continue
 
         nren = nren_dict[abbrev]
-        traffic_entry = model.TrafficVolume(
+        traffic_entry = presentation_models.TrafficVolume(
             nren=nren,
             nren_id=nren.id,
             year=year,
diff --git a/compendium_v2/publishers/survey_publisher_2022.py b/compendium_v2/publishers/survey_publisher_old_db_2022.py
similarity index 93%
rename from compendium_v2/publishers/survey_publisher_2022.py
rename to compendium_v2/publishers/survey_publisher_old_db_2022.py
index 39038d1e..fc028fc6 100644
--- a/compendium_v2/publishers/survey_publisher_2022.py
+++ b/compendium_v2/publishers/survey_publisher_old_db_2022.py
@@ -2,7 +2,7 @@
 survey_publisher_2022
 =========================
 
-This module loads the survey data from 2022 from the survey database.
+This module loads the survey data from 2022 from the old survey database into presentation_models.
 Registered as click cli command when installing compendium-v2.
 
 """
@@ -17,17 +17,17 @@ from sqlalchemy import delete, text
 from collections import defaultdict
 
 import compendium_v2
-from compendium_v2.db.model import FeeType
+from compendium_v2.db.presentation_models import FeeType
 from compendium_v2.environment import setup_logging
 from compendium_v2.config import load
 from compendium_v2.publishers.helpers import extract_urls
 from compendium_v2.survey_db import model as survey_model
-from compendium_v2.db import db, model
+from compendium_v2.db import db, presentation_models
 from compendium_v2.publishers import helpers
 
 setup_logging()
 
-logger = logging.getLogger('survey-publisher-2022')
+logger = logging.getLogger(__name__)
 
 BUDGET_QUERY = """
 SELECT DISTINCT ON (n.id, a.question_id)
@@ -189,7 +189,7 @@ def transfer_budget(nren_dict):
             logger.info(f'{nren_name} unknown. Skipping.')
             continue
 
-        budget_entry = model.BudgetEntry(
+        budget_entry = presentation_models.BudgetEntry(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             budget=budget,
@@ -227,7 +227,7 @@ def transfer_institutions_urls(nren_dict):
             logger.info(f'{nren_name} has no urls for {year}. Skipping.')
             continue
 
-        institution_urls = model.InstitutionURLs(
+        institution_urls = presentation_models.InstitutionURLs(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             urls=urls,
@@ -267,7 +267,7 @@ def transfer_funding_sources(nren_dict):
             logger.info(f'{nren_name} unknown. Skipping.')
             continue
 
-        funding_source = model.FundingSource(
+        funding_source = presentation_models.FundingSource(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             year=2022,
@@ -303,9 +303,9 @@ def transfer_staff_data(nren_dict):
     for nren_name, nren_info in data.items():
         if sum([nren_info[question] for question in StaffQuestion]) == 0:
             logger.info(f'{nren_name} has no staff data. Deleting if exists.')
-            db.session.execute(delete(model.NrenStaff).where(
-                model.NrenStaff.nren_id == nren_dict[nren_name].id,
-                model.NrenStaff.year == 2022
+            db.session.execute(delete(presentation_models.NrenStaff).where(
+                presentation_models.NrenStaff.nren_id == nren_dict[nren_name].id,
+                presentation_models.NrenStaff.year == 2022
             ))
             continue
 
@@ -316,7 +316,7 @@ def transfer_staff_data(nren_dict):
             logger.info(f'{nren_name} FTE do not equal across employed/technical categories.'
                         f' ({employed} != {technical})')
 
-        staff_data = model.NrenStaff(
+        staff_data = presentation_models.NrenStaff(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             year=2022,
@@ -335,7 +335,9 @@ def transfer_nren_parent_org(nren_dict):
         'We are affiliated to '
     ]
 
-    db.session.execute(delete(model.ParentOrganization).where(model.ParentOrganization.year == 2022))
+    db.session.execute(delete(presentation_models.ParentOrganization).where(
+        presentation_models.ParentOrganization.year == 2022)
+    )
 
     rows = query_question(OrgQuestion.PARENT_ORG_NAME)
     for row in rows:
@@ -352,7 +354,7 @@ def transfer_nren_parent_org(nren_dict):
             logger.info(f'{nren_name} unknown. Skipping.')
             continue
 
-        parent_org = model.ParentOrganization(
+        parent_org = presentation_models.ParentOrganization(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             year=2022,
@@ -370,10 +372,11 @@ def transfer_nren_sub_org(nren_dict):
         (OrgQuestion.SUB_ORGS_4_NAME, OrgQuestion.SUB_ORGS_4_CHOICE, OrgQuestion.SUB_ORGS_4_ROLE),
         (OrgQuestion.SUB_ORGS_5_NAME, OrgQuestion.SUB_ORGS_5_CHOICE, OrgQuestion.SUB_ORGS_5_ROLE)
     ]
-
     lookup = defaultdict(list)
 
-    db.session.execute(delete(model.SubOrganization).where(model.SubOrganization.year == 2022))
+    db.session.execute(delete(presentation_models.SubOrganization).where(
+        presentation_models.SubOrganization.year == 2022)
+    )
 
     for name, choice, role in suborg_questions:
         _name_rows = query_question(name)
@@ -403,7 +406,7 @@ def transfer_nren_sub_org(nren_dict):
 
     for nren_name, suborgs in lookup.items():
         for suborg_name, role in suborgs:
-            suborg = model.SubOrganization(
+            suborg = presentation_models.SubOrganization(
                 nren=nren_dict[nren_name],
                 nren_id=nren_dict[nren_name].id,
                 year=2022,
@@ -437,7 +440,7 @@ def transfer_charging_structure(nren_dict):
         else:
             charging_structure = None
 
-        charging_structure = model.ChargingStructure(
+        charging_structure = presentation_models.ChargingStructure(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             year=2022,
@@ -450,7 +453,7 @@ def transfer_charging_structure(nren_dict):
 def transfer_ec_projects(nren_dict):
     # delete all existing EC projects, in case something changed
     db.session.execute(
-        delete(model.ECProject).where(model.ECProject.year == 2022)
+        delete(presentation_models.ECProject).where(presentation_models.ECProject.year == 2022)
     )
 
     rows = query_question(ECQuestion.EC_PROJECT)
@@ -478,7 +481,7 @@ def transfer_ec_projects(nren_dict):
             # some answers include contract numbers, which we don't want here
             val = val.split('(contract n')[0]
 
-            ec_project = model.ECProject(
+            ec_project = presentation_models.ECProject(
                 nren=nren_dict[nren_name],
                 nren_id=nren_dict[nren_name].id,
                 year=2022,
@@ -536,7 +539,7 @@ def transfer_policies(nren_dict):
                 data[(nren_name, year)][question_key] = value
 
     for (nren_name, year), nren_info in data.items():
-        policy_data = model.Policy(
+        policy_data = presentation_models.Policy(
             nren=nren_dict[nren_name],
             nren_id=nren_dict[nren_name].id,
             year=year,
diff --git a/compendium_v2/background_task/xlsx/2021_Organisation_DataSeries.xlsx b/compendium_v2/resources/2021_Organisation_DataSeries.xlsx
similarity index 100%
rename from compendium_v2/background_task/xlsx/2021_Organisation_DataSeries.xlsx
rename to compendium_v2/resources/2021_Organisation_DataSeries.xlsx
diff --git a/compendium_v2/background_task/xlsx/2022_Connected_Users_DataSeries.xlsx b/compendium_v2/resources/2022_Connected_Users_DataSeries.xlsx
similarity index 100%
rename from compendium_v2/background_task/xlsx/2022_Connected_Users_DataSeries.xlsx
rename to compendium_v2/resources/2022_Connected_Users_DataSeries.xlsx
diff --git a/compendium_v2/background_task/xlsx/2022_Networks_DataSeries.xlsx b/compendium_v2/resources/2022_Networks_DataSeries.xlsx
similarity index 100%
rename from compendium_v2/background_task/xlsx/2022_Networks_DataSeries.xlsx
rename to compendium_v2/resources/2022_Networks_DataSeries.xlsx
diff --git a/compendium_v2/conversion/NREN-Services-prefills_2023_Recovered.xlsx b/compendium_v2/resources/NREN-Services-prefills_2023_Recovered.xlsx
similarity index 100%
rename from compendium_v2/conversion/NREN-Services-prefills_2023_Recovered.xlsx
rename to compendium_v2/resources/NREN-Services-prefills_2023_Recovered.xlsx
diff --git a/compendium_v2/routes/budget.py b/compendium_v2/routes/budget.py
index 2f11be47..b0cff93d 100644
--- a/compendium_v2/routes/budget.py
+++ b/compendium_v2/routes/budget.py
@@ -3,7 +3,7 @@ from typing import Any
 
 from flask import Blueprint, jsonify
 
-from compendium_v2.db.model import BudgetEntry
+from compendium_v2.db.presentation_models import BudgetEntry
 from compendium_v2.routes import common
 
 
diff --git a/compendium_v2/routes/charging.py b/compendium_v2/routes/charging.py
index d61df556..8c40679b 100644
--- a/compendium_v2/routes/charging.py
+++ b/compendium_v2/routes/charging.py
@@ -3,7 +3,7 @@ from typing import Any
 
 from flask import Blueprint, jsonify
 
-from compendium_v2.db.model import ChargingStructure
+from compendium_v2.db.presentation_models import ChargingStructure
 from compendium_v2.routes import common
 
 
diff --git a/compendium_v2/routes/common.py b/compendium_v2/routes/common.py
index cc7b9fd1..be84fbfd 100644
--- a/compendium_v2/routes/common.py
+++ b/compendium_v2/routes/common.py
@@ -4,7 +4,7 @@ Utilities used by multiple route blueprints.
 import functools
 import logging
 from compendium_v2 import db
-from compendium_v2.db.model import NREN, PreviewYear
+from compendium_v2.db.presentation_models import NREN, PreviewYear
 
 from flask import Response, request
 from sqlalchemy import select
diff --git a/compendium_v2/routes/ec_projects.py b/compendium_v2/routes/ec_projects.py
index aaf1c74f..501d2206 100644
--- a/compendium_v2/routes/ec_projects.py
+++ b/compendium_v2/routes/ec_projects.py
@@ -3,7 +3,7 @@ from typing import Any
 
 from flask import Blueprint, jsonify
 
-from compendium_v2.db.model import ECProject
+from compendium_v2.db.presentation_models import ECProject
 from compendium_v2.routes import common
 
 
diff --git a/compendium_v2/routes/funding.py b/compendium_v2/routes/funding.py
index 2ca91eb3..0c110190 100644
--- a/compendium_v2/routes/funding.py
+++ b/compendium_v2/routes/funding.py
@@ -3,7 +3,7 @@ import logging
 from flask import Blueprint, jsonify
 
 from compendium_v2.routes import common
-from compendium_v2.db.model import FundingSource
+from compendium_v2.db.presentation_models import FundingSource
 from typing import Any
 
 
diff --git a/compendium_v2/routes/institutions_urls.py b/compendium_v2/routes/institutions_urls.py
index 7153a8fc..8af1bbb6 100644
--- a/compendium_v2/routes/institutions_urls.py
+++ b/compendium_v2/routes/institutions_urls.py
@@ -4,7 +4,7 @@ from flask import Blueprint, jsonify
 from sqlalchemy import select
 
 from compendium_v2.db import db
-from compendium_v2.db.model import NREN, InstitutionURLs
+from compendium_v2.db.presentation_models import NREN, InstitutionURLs
 from compendium_v2.routes import common
 
 routes = Blueprint('institutions-urls', __name__)
diff --git a/compendium_v2/routes/organization.py b/compendium_v2/routes/organization.py
index 473994b9..b39f7fd8 100644
--- a/compendium_v2/routes/organization.py
+++ b/compendium_v2/routes/organization.py
@@ -3,7 +3,7 @@ from typing import Any
 
 from flask import Blueprint, jsonify
 
-from compendium_v2.db.model import ParentOrganization, SubOrganization
+from compendium_v2.db.presentation_models import ParentOrganization, SubOrganization
 from compendium_v2.routes import common
 
 
diff --git a/compendium_v2/routes/policy.py b/compendium_v2/routes/policy.py
index 68c6add0..a97dcf22 100644
--- a/compendium_v2/routes/policy.py
+++ b/compendium_v2/routes/policy.py
@@ -2,7 +2,7 @@ import logging
 from typing import Any
 
 from flask import Blueprint, jsonify
-from compendium_v2.db.model import Policy
+from compendium_v2.db.presentation_models import Policy
 from compendium_v2.routes import common
 
 routes = Blueprint('policy', __name__)
diff --git a/compendium_v2/routes/response.py b/compendium_v2/routes/response.py
index 9ba078e5..1c691431 100644
--- a/compendium_v2/routes/response.py
+++ b/compendium_v2/routes/response.py
@@ -9,8 +9,8 @@ from sqlalchemy import select
 from sqlalchemy.orm import lazyload
 
 from compendium_v2.db import db
-from compendium_v2.db.model import NREN
-from compendium_v2.db.survey_model import Survey, SurveyResponse, SurveyStatus, ResponseStatus, RESPONSE_NOT_STARTED
+from compendium_v2.db.presentation_models import NREN
+from compendium_v2.db.survey_models import Survey, SurveyResponse, SurveyStatus, ResponseStatus, RESPONSE_NOT_STARTED
 from compendium_v2.routes import common
 from compendium_v2.auth.session_management import admin_required, User
 
diff --git a/compendium_v2/routes/staff.py b/compendium_v2/routes/staff.py
index 3c049385..3a23cd65 100644
--- a/compendium_v2/routes/staff.py
+++ b/compendium_v2/routes/staff.py
@@ -2,7 +2,7 @@ import logging
 
 from flask import Blueprint, jsonify
 
-from compendium_v2.db.model import NrenStaff
+from compendium_v2.db.presentation_models import NrenStaff
 from compendium_v2.routes import common
 from typing import Any
 
diff --git a/compendium_v2/routes/survey.py b/compendium_v2/routes/survey.py
index 5d685e7f..35766d19 100644
--- a/compendium_v2/routes/survey.py
+++ b/compendium_v2/routes/survey.py
@@ -7,9 +7,9 @@ from sqlalchemy import delete, select
 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.db.presentation_models import NREN, PreviewYear
+from compendium_v2.db.survey_models import Survey, SurveyResponse, SurveyStatus, RESPONSE_NOT_STARTED
+from compendium_v2.publishers.survey_publisher import publish
 from compendium_v2.routes import common
 from compendium_v2.auth.session_management import admin_required
 
diff --git a/compendium_v2/routes/traffic.py b/compendium_v2/routes/traffic.py
index 70255d0f..56668fc4 100644
--- a/compendium_v2/routes/traffic.py
+++ b/compendium_v2/routes/traffic.py
@@ -3,7 +3,7 @@ import logging
 from flask import Blueprint, jsonify
 
 from compendium_v2.routes import common
-from compendium_v2.db.model import TrafficVolume
+from compendium_v2.db.presentation_models import TrafficVolume
 from typing import Any
 
 
diff --git a/compendium_v2/routes/user.py b/compendium_v2/routes/user.py
index f526e33a..ab9cce2e 100644
--- a/compendium_v2/routes/user.py
+++ b/compendium_v2/routes/user.py
@@ -8,7 +8,7 @@ from sqlalchemy import select
 from compendium_v2.auth.session_management import admin_required
 from compendium_v2.db import db
 from compendium_v2.db.auth_model import User, ROLES
-from compendium_v2.db.model import NREN
+from compendium_v2.db.presentation_models import NREN
 from compendium_v2.routes import common
 
 routes = Blueprint('user', __name__)
diff --git a/test/test_survey_publisher_2022.py b/test/test_db_survey_publisher_2022.py
similarity index 88%
rename from test/test_survey_publisher_2022.py
rename to test/test_db_survey_publisher_2022.py
index e8eaa8b4..6e9c9096 100644
--- a/test/test_survey_publisher_2022.py
+++ b/test/test_db_survey_publisher_2022.py
@@ -1,6 +1,6 @@
 from sqlalchemy import select
 
-from compendium_v2.db import db, model
+from compendium_v2.db import db, presentation_models
 from compendium_v2.publishers.survey_publisher_2022 import _cli, FundingSource, \
     StaffQuestion, OrgQuestion, ChargingStructure, ECQuestion
 
@@ -209,21 +209,21 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
     nren_names = ['Nren1', 'Nren2', 'Nren3', 'Nren4', 'SURF', 'KIFU', 'University of Malta', 'ASNET-AM',
                   'SIKT', 'LAT', 'RASH', 'ANAS', 'GRNET', 'CSC']
     with app_with_survey_db.app_context():
-        db.session.add_all([model.NREN(name=nren_name, country='country') for nren_name in nren_names])
+        db.session.add_all([presentation_models.NREN(name=nren_name, country='country') for nren_name in nren_names])
         db.session.commit()
 
     _cli(dummy_config, app_with_survey_db)
 
     with app_with_survey_db.app_context():
         budgets = db.session.scalars(
-            select(model.BudgetEntry).order_by(model.BudgetEntry.nren_id.asc())
+            select(presentation_models.BudgetEntry).order_by(presentation_models.BudgetEntry.nren_id.asc())
         ).all()
         assert len(budgets) == 3
         assert budgets[0].nren.name.lower() == 'nren1'
         assert budgets[0].budget == 100
 
         funding_sources = db.session.scalars(
-            select(model.FundingSource).order_by(model.FundingSource.nren_id.asc())
+            select(presentation_models.FundingSource).order_by(presentation_models.FundingSource.nren_id.asc())
         ).all()
         assert len(funding_sources) == 3
         assert funding_sources[0].nren.name.lower() == 'nren1'
@@ -242,7 +242,7 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert funding_sources[2].other == 30
 
         staff_data = db.session.scalars(
-            select(model.NrenStaff).order_by(model.NrenStaff.nren_id.asc())
+            select(presentation_models.NrenStaff).order_by(presentation_models.NrenStaff.nren_id.asc())
         ).all()
 
         assert len(staff_data) == 3
@@ -265,7 +265,8 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert staff_data[2].subcontracted_fte == 0
 
         _org_data = db.session.scalars(
-            select(model.ParentOrganization).order_by(model.ParentOrganization.nren_id.asc())
+            select(presentation_models.ParentOrganization).order_by(
+                presentation_models.ParentOrganization.nren_id.asc())
         ).all()
 
         assert len(_org_data) == 2
@@ -276,18 +277,18 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert _org_data[1].organization == 'Org3'
 
         charging_structures = db.session.scalars(
-            select(model.ChargingStructure).order_by(model.ChargingStructure.nren_id.asc())
+            select(presentation_models.ChargingStructure).order_by(presentation_models.ChargingStructure.nren_id.asc())
         ).all()
         assert len(charging_structures) == 3
         assert charging_structures[0].nren.name.lower() == 'nren1'
-        assert charging_structures[0].fee_type == model.FeeType.no_charge
+        assert charging_structures[0].fee_type == presentation_models.FeeType.no_charge
         assert charging_structures[1].nren.name.lower() == 'nren2'
-        assert charging_structures[1].fee_type == model.FeeType.usage_based_fee
+        assert charging_structures[1].fee_type == presentation_models.FeeType.usage_based_fee
         assert charging_structures[2].nren.name.lower() == 'nren3'
-        assert charging_structures[2].fee_type == model.FeeType.other
+        assert charging_structures[2].fee_type == presentation_models.FeeType.other
 
         _ec_data = db.session.scalars(
-            select(model.ECProject).order_by(model.ECProject.nren_id.asc())
+            select(presentation_models.ECProject).order_by(presentation_models.ECProject.nren_id.asc())
         ).all()
 
         assert len(_ec_data) == 3
@@ -301,7 +302,7 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert _ec_data[2].project == 'project3'
 
         policy_data = db.session.scalars(
-            select(model.Policy).order_by(model.Policy.nren_id.asc())
+            select(presentation_models.Policy).order_by(presentation_models.Policy.nren_id.asc())
         ).all()
         policy_data_2020 = [p for p in policy_data if p.year == 2020]
         policy_data_2022 = [p for p in policy_data if p.year == 2022]
@@ -311,7 +312,7 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert policy_data_2020[1].strategic_plan == 'policyemail@nren.com'
 
         _institution_urls_data = db.session.scalars(
-            select(model.InstitutionURLs).order_by(model.InstitutionURLs.nren_id.asc())
+            select(presentation_models.InstitutionURLs).order_by(presentation_models.InstitutionURLs.nren_id.asc())
         ).all()
         assert len(_institution_urls_data) == 2
         assert _institution_urls_data[0].nren.name.lower() == 'rash'
diff --git a/test/test_survey_publisher_v2.py b/test/test_survey_publisher.py
similarity index 65%
rename from test/test_survey_publisher_v2.py
rename to test/test_survey_publisher.py
index 68b4b2d0..91f3d70d 100644
--- a/test/test_survey_publisher_v2.py
+++ b/test/test_survey_publisher.py
@@ -5,8 +5,8 @@ import os
 from sqlalchemy import func, select
 
 from compendium_v2 import db
-from compendium_v2.db import model
-from compendium_v2.publishers.survey_publisher_v2 import map_2023
+from compendium_v2.db import presentation_models
+from compendium_v2.publishers.survey_publisher import _map_2023
 
 
 JSON_FILE = os.path.join(os.path.dirname(__file__), "data", "2023_all_questions_answered.json")
@@ -16,15 +16,15 @@ def test_v2_publisher_empty(app):
     data = {}
 
     with app.app_context():
-        nren = model.NREN(name='name', country='country')
+        nren = presentation_models.NREN(name='name', country='country')
         db.session.commit()
 
     with app.app_context():
-        map_2023(nren, {"data": data})
+        _map_2023(nren, {"data": data})
         db.session.commit()
 
     with app.app_context():
-        budget_count = db.session.scalar(select(func.count(model.BudgetEntry.year)))
+        budget_count = db.session.scalar(select(func.count(presentation_models.BudgetEntry.year)))
         assert budget_count == 0
         # the main thing is actually that it doesnt crash
 
@@ -34,37 +34,39 @@ def test_v2_publisher_full(app):
         data = json.load(json_data)
 
     with app.app_context():
-        nren = model.NREN(name='name', country='country')
+        nren = presentation_models.NREN(name='name', country='country')
         db.session.commit()
 
     with app.app_context():
-        map_2023(nren, {"data": data})
+        _map_2023(nren, {"data": data})
         db.session.commit()
 
     with app.app_context():
-        budget = db.session.scalar(select(model.BudgetEntry.budget))
+        budget = db.session.scalar(select(presentation_models.BudgetEntry.budget))
         assert budget == Decimal("124.76")
 
-        funding_source = db.session.scalar(select(model.FundingSource))
+        funding_source = db.session.scalar(select(presentation_models.FundingSource))
         assert funding_source.client_institutions == Decimal("0")
         assert funding_source.european_funding == Decimal("20")
         assert funding_source.gov_public_bodies == Decimal("70")
         assert funding_source.commercial == Decimal("0")
         assert funding_source.other == Decimal("10")
 
-        charging_structure = db.session.scalar(select(model.ChargingStructure.fee_type))
-        assert charging_structure == model.FeeType.usage_based_fee
+        charging_structure = db.session.scalar(select(presentation_models.ChargingStructure.fee_type))
+        assert charging_structure == presentation_models.FeeType.usage_based_fee
 
-        staff = db.session.scalar(select(model.NrenStaff))
+        staff = db.session.scalar(select(presentation_models.NrenStaff))
         assert staff.permanent_fte == Decimal("5.6")
         assert staff.subcontracted_fte == Decimal("56")
         assert staff.technical_fte == Decimal("2")
         assert staff.non_technical_fte == Decimal("1")
 
-        parent = db.session.scalar(select(model.ParentOrganization.organization))
+        parent = db.session.scalar(select(presentation_models.ParentOrganization.organization))
         assert parent == "sdtfgd"
 
-        subs = db.session.scalars(select(model.SubOrganization).order_by(model.SubOrganization.organization))
+        subs = db.session.scalars(select(presentation_models.SubOrganization).order_by(
+            presentation_models.SubOrganization.organization)
+        )
         subs = [s for s in subs]
         assert subs[0].organization == "Aaerer"
         assert subs[0].role == "Treer"
@@ -73,13 +75,15 @@ def test_v2_publisher_full(app):
         assert subs[2].organization == "werser"
         assert subs[2].role == ""
 
-        projects = db.session.scalars(select(model.ECProject.project).order_by(model.ECProject.project))
+        projects = db.session.scalars(select(presentation_models.ECProject.project).order_by(
+            presentation_models.ECProject.project)
+        )
         projects = [p for p in projects]
         assert projects[0] == "dgdg"
         assert projects[1] == "rrrrr"
         assert projects[2] == "st"
 
-        policy = db.session.scalar(select(model.Policy))
+        policy = db.session.scalar(select(presentation_models.Policy))
         assert policy.strategic_plan == "https://serere.com"
         assert policy.environmental == "http://mren.ac.me/documents/Environmental%20policy%20for%20MREN.pdf"
         assert policy.equal_opportunity == ""
@@ -89,11 +93,11 @@ def test_v2_publisher_full(app):
         assert policy.data_protection == ""
         assert policy.gender_equality == "https://www.ucg.ac.me/objava/blog/616808/objava/148423-plan-rodne-ravnopravnosti-univerziteta-crne-gore"  # noqa: E501
 
-        traffic = db.session.scalar(select(model.TrafficVolume))
+        traffic = db.session.scalar(select(presentation_models.TrafficVolume))
         assert traffic.to_customers == Decimal("3")
         assert traffic.from_customers == Decimal("34")
         assert traffic.to_external == Decimal("22")
         assert traffic.from_external == Decimal("3")
 
-        client_urls = db.session.scalar(select(model.InstitutionURLs))
+        client_urls = db.session.scalar(select(presentation_models.InstitutionURLs))
         assert client_urls.urls == ["http://erse.com", "https://wwe.com"]
diff --git a/test/test_survey_publisher_v1.py b/test/test_survey_publisher_legacy_excel.py
similarity index 80%
rename from test/test_survey_publisher_v1.py
rename to test/test_survey_publisher_legacy_excel.py
index d3bd42b6..5a20fc06 100644
--- a/test/test_survey_publisher_v1.py
+++ b/test/test_survey_publisher_legacy_excel.py
@@ -3,30 +3,32 @@ import os
 from sqlalchemy import select, func
 
 from compendium_v2 import db
-from compendium_v2.db import model
-from compendium_v2.publishers.survey_publisher_v1 import _cli
+from compendium_v2.db import presentation_models
+from compendium_v2.publishers.survey_publisher_legacy_excel import _cli
 
 EXCEL_FILE = os.path.join(os.path.dirname(__file__), "data", "2021_Organisation_DataSeries.xlsx")
 
 
 def test_publisher(app_with_survey_db, mocker, dummy_config):
-    mocker.patch('compendium_v2.background_task.parse_excel_data.EXCEL_FILE', EXCEL_FILE)
+    mocker.patch('compendium_v2.publishers.excel_parser.EXCEL_FILE', EXCEL_FILE)
 
     with app_with_survey_db.app_context():
         nren_names = ['SURF', 'KIFU', 'University of Malta', 'ASNET-AM', 'SIKT', 'LAT', 'RASH', 'ANAS', 'GRNET', 'CSC']
-        db.session.add_all([model.NREN(name=nren_name, country='country') for nren_name in nren_names])
+        db.session.add_all([presentation_models.NREN(name=nren_name, country='country') for nren_name in nren_names])
         db.session.commit()
 
     _cli(dummy_config, app_with_survey_db)
 
     with app_with_survey_db.app_context():
-        budget_count = db.session.scalar(select(func.count(model.BudgetEntry.year)))
+        budget_count = db.session.scalar(select(func.count(presentation_models.BudgetEntry.year)))
         assert budget_count
-        funding_source_count = db.session.scalar(select(func.count(model.FundingSource.year)))
+        funding_source_count = db.session.scalar(select(func.count(presentation_models.FundingSource.year)))
         assert funding_source_count
-        charging_structure_count = db.session.scalar(select(func.count(model.ChargingStructure.year)))
+        charging_structure_count = db.session.scalar(select(func.count(presentation_models.ChargingStructure.year)))
         assert charging_structure_count
-        staff_data = db.session.scalars(select(model.NrenStaff).order_by(model.NrenStaff.year.asc())).all()
+        staff_data = db.session.scalars(select(presentation_models.NrenStaff).order_by(
+            presentation_models.NrenStaff.year.asc())
+        ).all()
 
         # data should only be saved for the NRENs we have saved in the database
         staff_data_nrens = set([staff.nren.name for staff in staff_data])
@@ -72,7 +74,7 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert kifu_data[5].technical_fte == 133
         assert kifu_data[5].non_technical_fte == 45
 
-        ecproject_data = db.session.scalars(select(model.ECProject)).all()
+        ecproject_data = db.session.scalars(select(presentation_models.ECProject)).all()
         # test a couple of random entries
         surf2017 = [x for x in ecproject_data if x.nren.name == 'SURF' and x.year == 2017]
         assert len(surf2017) == 1
@@ -86,7 +88,7 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
         assert len(kifu2019) == 4
         assert kifu2019[3].project == 'SuperHeroes for Science'
 
-        parent_data = db.session.scalars(select(model.ParentOrganization)).all()
+        parent_data = db.session.scalars(select(presentation_models.ParentOrganization)).all()
         # test a random entry
         asnet2021 = [x for x in parent_data if x.nren.name == 'ASNET-AM' and x.year == 2021]
         assert len(asnet2021) == 1
-- 
GitLab