Skip to content
Snippets Groups Projects
Commit d2981688 authored by Remco Tukker's avatar Remco Tukker
Browse files

added datamodels for policy, connected users, and network questions

parent 6ecf0324
No related branches found
No related tags found
1 merge request!79COMP-283 datamodels
......@@ -2,7 +2,7 @@ import logging
import openpyxl
import os
from compendium_v2.db.model import FeeType
from compendium_v2.db.model_enums import FeeType
from compendium_v2.environment import setup_logging
setup_logging()
......
......
......@@ -3,24 +3,44 @@ from __future__ import annotations
import logging
from decimal import Decimal
from enum import Enum
from typing import List, Optional
from typing_extensions import Annotated
from typing_extensions import Annotated, TypedDict
from sqlalchemy import String, JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.schema import ForeignKey
from compendium_v2.db import db
from compendium_v2.db.model_enums import CarryMechanism, CommarcialChargingLevel, UserCategory, ServiceCategory, \
ConnectivityCoverage, ConnectionMethod, YesNoPlanned, MonitoringMethod, CommercialConnectivityCoverage, FeeType
logger = logging.getLogger(__name__)
str128 = Annotated[str, 128]
str128_pk = Annotated[str, mapped_column(String(128), primary_key=True)]
str256_pk = Annotated[str, mapped_column(String(256), primary_key=True)]
int_pk = Annotated[int, mapped_column(primary_key=True)]
int_pk_fkNREN = Annotated[int, mapped_column(ForeignKey("nren.id"), primary_key=True)]
user_category_pk = Annotated[UserCategory, mapped_column(primary_key=True)]
json_str_list = Annotated[List[str], mapped_column(JSON)]
ExternalConnection = TypedDict(
'ExternalConnection',
{
'link_name': str,
'capacity': Optional[Decimal],
'from_organization': str,
'to_organization': str,
'interconnection_method': Optional[ConnectionMethod]
}
)
RemoteCampus = TypedDict(
'RemoteCampus',
{'country': str, 'local_r_and_e_connection': Optional[bool]}
)
# Unfortunately flask-sqlalchemy doesnt fully support DeclarativeBase yet.
......@@ -60,14 +80,6 @@ class FundingSource(db.Model):
other: Mapped[Decimal]
class FeeType(Enum):
flat_fee = "flat_fee"
usage_based_fee = "usage_based_fee"
combination = "combination"
no_charge = "no_charge"
other = "other"
class ChargingStructure(db.Model):
__tablename__ = 'charging_structure'
nren_id: Mapped[int_pk_fkNREN]
......@@ -140,8 +152,321 @@ class TrafficVolume(db.Model):
class InstitutionURLs(db.Model):
__tablename__ = 'institution_urls'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
urls: Mapped[json_str_list]
class CentralProcurement(db.Model):
__tablename__ = 'central_procurement'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
central_procurement: Mapped[bool]
amount: Mapped[Optional[Decimal]]
class ServiceManagement(db.Model):
__tablename__ = 'service_management'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
service_management_framework: Mapped[Optional[bool]]
service_level_targets: Mapped[Optional[bool]]
class ServiceUserTypes(db.Model):
__tablename__ = 'service_user_types'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
user_category: Mapped[user_category_pk]
service_category: Mapped[ServiceCategory]
class EOSCListings(db.Model):
__tablename__ = 'eosc_listings'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
service_names: Mapped[json_str_list]
class Standards(db.Model):
__tablename__ = 'standards'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
audits: Mapped[Optional[bool]]
audit_specifics: Mapped[str]
business_continuity_plans: Mapped[Optional[bool]]
business_continuity_plans_specifics: Mapped[str]
crisis_management_procedure: Mapped[Optional[bool]]
class CrisisExcercises(db.Model):
__tablename__ = 'crisis_excercises'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
exercise_descriptions: Mapped[json_str_list]
class SecurityControls(db.Model):
__tablename__ = 'security_controls'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
security_control_descriptions: Mapped[json_str_list]
class ConnectedProportion(db.Model):
__tablename__ = 'connected_proportion'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
user_category: Mapped[user_category_pk]
coverage: Mapped[Optional[ConnectivityCoverage]]
number_connected: Mapped[Optional[int]]
market_share: Mapped[Optional[Decimal]]
users_served: Mapped[Optional[int]]
class ConnectivityLevel(db.Model):
__tablename__ = 'connectivity_level'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
user_category: Mapped[user_category_pk]
typical_speed: Mapped[Optional[int]]
highest_speed: Mapped[Optional[int]]
highest_speed_proportion: Mapped[Optional[Decimal]]
class ConnectionCarrier(db.Model):
__tablename__ = 'connection_carrier'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
user_category: Mapped[user_category_pk]
carry_mechanism: Mapped[CarryMechanism]
class ConnectivityLoad(db.Model):
__tablename__ = 'connectivity_load'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
user_category: Mapped[user_category_pk]
average_load_from_institutions: Mapped[Optional[int]]
average_load_to_institutions: Mapped[Optional[int]]
peak_load_from_institutions: Mapped[Optional[int]]
peak_load_to_institutions: Mapped[Optional[int]]
class ConnectivityGrowth(db.Model):
__tablename__ = 'connectivity_growth'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
user_category: Mapped[user_category_pk]
growth: Mapped[Decimal]
class CommercialConnectivity(db.Model):
__tablename__ = 'commercial_connectivity'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
commercial_r_and_e: Mapped[Optional[CommercialConnectivityCoverage]]
commercial_general: Mapped[Optional[CommercialConnectivityCoverage]]
commercial_collaboration: Mapped[Optional[CommercialConnectivityCoverage]]
commercial_service_provider: Mapped[Optional[CommercialConnectivityCoverage]]
university_spin_off: Mapped[Optional[CommercialConnectivityCoverage]]
class CommercialChargingLevel(db.Model):
__tablename__ = 'commercial_charging_level'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
collaboration: Mapped[Optional[CommarcialChargingLevel]]
service_supplier: Mapped[Optional[CommarcialChargingLevel]]
direct_peering: Mapped[Optional[CommarcialChargingLevel]]
class RemoteCampuses(db.Model):
__tablename__ = 'remote_campuses'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
remote_campus_connectivity: Mapped[bool]
connections: Mapped[List[RemoteCampus]] = mapped_column(JSON)
class DarkFibreLease(db.Model):
__tablename__ = 'dark_fibre_lease'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
iru_or_lease: Mapped[bool]
fibre_length_in_country: Mapped[Optional[int]]
fibre_length_outside_country: Mapped[Optional[int]]
iru_duration: Mapped[Optional[Decimal]]
class DarkFibreInstalled(db.Model):
__tablename__ = 'dark_fibre_installed'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
installed: Mapped[bool]
fibre_length_in_country: Mapped[Optional[int]]
class FibreLight(db.Model):
__tablename__ = 'fibre_light'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
light_description: Mapped[str]
class NetworkMapUrls(db.Model):
__tablename__ = 'network_map_urls'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
urls: Mapped[json_str_list]
class MonitoringTools(db.Model):
__tablename__ = 'monitoring_tools'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
tool_descriptions: Mapped[json_str_list]
netflow_processing_description: Mapped[str]
class PassiveMonitoring(db.Model):
__tablename__ = 'passive_monitoring'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
monitoring: Mapped[bool]
method: Mapped[Optional[MonitoringMethod]]
class TrafficStatistics(db.Model):
__tablename__ = 'traffic_statistics'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
traffic_statistics: Mapped[bool]
urls: Mapped[json_str_list]
class SiemVendors(db.Model):
__tablename__ = 'siem_vendors'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
vendor_names: Mapped[json_str_list]
class CertificateProviders(db.Model):
__tablename__ = 'certificate_providers'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
provider_names: Mapped[json_str_list]
class WeatherMap(db.Model):
__tablename__ = 'weather_map'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
weather_map: Mapped[bool]
url: Mapped[str]
class PertTeam(db.Model):
__tablename__ = 'pert_team'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
pert_team: Mapped[YesNoPlanned]
class AlienWave(db.Model):
__tablename__ = 'alien_wave'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
alien_wave_third_pary: Mapped[Optional[YesNoPlanned]]
nr_of_alien_wave_third_party_services: Mapped[Optional[int]]
alien_wave_internal: Mapped[Optional[bool]]
class Capacity(db.Model):
__tablename__ = 'capacity'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
largest_link_capacity: Mapped[Optional[Decimal]]
typical_backbone_capacity: Mapped[Optional[Decimal]]
class ExternalConnections(db.Model):
__tablename__ = 'external_connections'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
connections: Mapped[List[ExternalConnection]] = mapped_column(JSON)
class NonREPeers(db.Model):
__tablename__ = 'non_r_and_e_peers'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
nr_of_non_r_and_e_peers: Mapped[int]
class TrafficRatio(db.Model):
__tablename__ = 'traffic_ratio'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
r_and_e_percentage: Mapped[int]
commodity_percentage: Mapped[int]
class OpsAutomation(db.Model):
__tablename__ = 'ops_automation'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
ops_automation: Mapped[YesNoPlanned]
ops_automation_specifics: Mapped[str]
class NetworkFunctionVirtualisation(db.Model):
__tablename__ = 'network_function_virtualisation'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
nfv: Mapped[YesNoPlanned]
nfv_specifics: Mapped[json_str_list]
class NetworkAutomation(db.Model):
__tablename__ = 'network_automation'
nren_id: Mapped[int_pk_fkNREN]
nren: Mapped[NREN] = relationship(lazy='joined')
year: Mapped[int_pk]
urls: Mapped[List[str]] = mapped_column(JSON)
network_automation: Mapped[YesNoPlanned]
network_automation_specifics: Mapped[json_str_list]
from enum import Enum
class FeeType(Enum):
flat_fee = "flat_fee"
usage_based_fee = "usage_based_fee"
combination = "combination"
no_charge = "no_charge"
other = "other"
class UserCategory(Enum):
universities = "universities"
further_education = "further_education"
secondary_schools = "secondary_schools"
primary_schools = "primary_schools"
institutes = "institutes"
cultural = "cultural"
hospitals = "hospitals"
government = "government"
iros = "iros"
for_profit_orgs = "for_profit_orgs"
class ServiceCategory(Enum):
network_services = "network_services"
isp_support = "isp_support"
security = "security"
identity = "identity"
collaboration = "collaboration"
multimedia = "multimedia"
storage_and_hosting = "storage_and_hosting"
professional_services = "professional_services"
class ConnectivityCoverage(Enum):
yes_incl_other = "yes_incl_other"
yes_national_nren = "yes_national_nren"
sometimes = "sometimes"
no_policy = "no_policy"
no_financial = "no_financial"
no_other = "no_other"
unsure = "unsure"
class CarryMechanism(Enum):
nren_local_loops = "nren_local_loops"
regional_nren_backbone = "regional_nren_backbone"
commercial_provider_backbone = "commercial_provider_backbone"
man = "man"
other = "other"
class CommercialConnectivityCoverage(Enum):
yes_incl_other = "yes_incl_other"
yes_national_nren = "yes_national_nren"
yes_if_sponsored = "yes_if_sponsored"
no_but_direct_peering = "no_but_direct_peering"
no_policy = "no_policy"
no_financial = "no_financial"
no_other = "no_other"
class CommarcialChargingLevel(Enum):
higher_than_r_e_charges = "higher_than_r_e_charges"
same_as_r_e_charges = "same_as_r_e_charges"
no_charges_if_r_e_requested = "no_charges_if_r_e_requested"
lower_than_r_e_charges = "lower_than_r_e_charges"
class ConnectionMethod(Enum):
internet_exchange = "internet_exchange"
open_exchange = "open_exchange"
direct = "direct"
geant = "geant"
other = "other"
class YesNoPlanned(Enum):
yes = "yes"
no = "no"
planned = "planned"
class MonitoringMethod(Enum):
span_ports = "span_ports"
taps = "taps"
both = "both"
This diff is collapsed.
......@@ -17,7 +17,7 @@ from sqlalchemy import delete, text
from collections import defaultdict
import compendium_v2
from compendium_v2.db.model import FeeType
from compendium_v2.db.model_enums import FeeType
from compendium_v2.environment import setup_logging
from compendium_v2.config import load
from compendium_v2.publishers.helpers import extract_urls
......
......
from decimal import Decimal
from typing import List
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.model import BudgetEntry, ChargingStructure, ECProject, ExternalConnections, FundingSource, \
InstitutionURLs, NrenStaff, ParentOrganization, Policy, SubOrganization, TrafficVolume, ExternalConnection
from compendium_v2.db.model_enums import FeeType
from compendium_v2.db.survey_model import ResponseStatus, SurveyResponse
def map_2023(nren, answers):
def map_2023(nren, answers) -> None:
year = 2023
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))
db.session.execute(delete(table_class).where(table_class.year == 2023)) # type: ignore
answers = answers["data"]
budget = answers.get("budget")
......@@ -104,6 +106,22 @@ def map_2023(nren, answers):
urls=urls
))
external_connections = answers.get("external_connections")
if external_connections:
connections: List[ExternalConnection] = []
for connection in external_connections:
connections.append({
'link_name': connection.get('link_name', ''),
'capacity': connection.get('capacity'),
'from_organization': connection.get('from_organization', ''),
'to_organization': connection.get('to_organization', ''),
'interconnection_method': connection.get('interconnection_method')
})
db.session.add(ExternalConnections(
nren_id=nren.id, nren=nren, year=year,
connections=connections
))
def publish(year):
responses = db.session.scalars(
......
......
from sqlalchemy import select
from compendium_v2.db import db, model
from compendium_v2.db import db, model, model_enums
from compendium_v2.publishers.survey_publisher_2022 import _cli, FundingSource, \
StaffQuestion, OrgQuestion, ChargingStructure, ECQuestion
......@@ -280,11 +280,11 @@ def test_publisher(app_with_survey_db, mocker, dummy_config):
).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 == model_enums.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 == model_enums.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 == model_enums.FeeType.other
_ec_data = db.session.scalars(
select(model.ECProject).order_by(model.ECProject.nren_id.asc())
......
......
......@@ -5,7 +5,7 @@ import os
from sqlalchemy import func, select
from compendium_v2 import db
from compendium_v2.db import model
from compendium_v2.db import model, model_enums
from compendium_v2.publishers.survey_publisher_v2 import map_2023
......@@ -53,7 +53,7 @@ def test_v2_publisher_full(app):
assert funding_source.other == Decimal("10")
charging_structure = db.session.scalar(select(model.ChargingStructure.fee_type))
assert charging_structure == model.FeeType.usage_based_fee
assert charging_structure == model_enums.FeeType.usage_based_fee
staff = db.session.scalar(select(model.NrenStaff))
assert staff.permanent_fte == Decimal("5.6")
......@@ -97,3 +97,28 @@ def test_v2_publisher_full(app):
client_urls = db.session.scalar(select(model.InstitutionURLs))
assert client_urls.urls == ["http://erse.com", "https://wwe.com"]
external_connections = db.session.scalar(select(model.ExternalConnections))
external_connection_list = external_connections.connections
assert len(external_connection_list) == 6
assert external_connection_list[0] == {
"capacity": "1",
"from_organization": "GEANT",
"interconnection_method": "geant",
"link_name": "GEANT",
"to_organization": "MREN"
}
assert external_connection_list[3] == {
"capacity": None,
"from_organization": "",
"interconnection_method": "other",
"link_name": "",
"to_organization": ""
}
assert external_connection_list[4] == {
"capacity": "1.1",
"from_organization": "",
"interconnection_method": None,
"link_name": "",
"to_organization": "",
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment