aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas "Cakeisalie5" Touhey <thomas@touhey.fr>2018-10-29 01:45:27 +0100
committerThomas "Cakeisalie5" Touhey <thomas@touhey.fr>2018-10-29 01:45:27 +0100
commitbefc89cc89aaff08bb26ee79d175525c4bd0432e (patch)
treef3a391023e786e8847bcfc72ecd95b0f91b36301
parent956a9fd85b03950584ec609d38f98e3ee39a653d (diff)
Starting to add structures search decoding, doesn't work for an unknown reason.
-rw-r--r--docs/intranet/misc.rst9
-rwxr-xr-xsgdfi/_dbs/__init__.py14
-rwxr-xr-xsgdfi/_dbs/_dept.py676
-rwxr-xr-xsgdfi/_dbs/_st.py55
-rwxr-xr-xsgdfi/_dbs/_stspe.py118
-rwxr-xr-xsgdfi/_dbs/_ststatus.py27
-rwxr-xr-xsgdfi/_decode.py61
-rwxr-xr-xsgdfi/_intranet.py48
-rwxr-xr-xsgdfi/_manager.py14
9 files changed, 971 insertions, 51 deletions
diff --git a/docs/intranet/misc.rst b/docs/intranet/misc.rst
index 99be918..2f1234c 100644
--- a/docs/intranet/misc.rst
+++ b/docs/intranet/misc.rst
@@ -44,3 +44,12 @@ Other locations
``/BiensLocauxAssurances/RechercherBien.aspx``
List owned places.
+
+``/WebServices/Statistiques.asmx/RecordUsageStats``
+ Web service for statistics. Takes two JSON POST arguments:
+
+ ``id``
+ ?
+
+ ``duration``
+ ?
diff --git a/sgdfi/_dbs/__init__.py b/sgdfi/_dbs/__init__.py
index 65de2d6..bc9489f 100755
--- a/sgdfi/_dbs/__init__.py
+++ b/sgdfi/_dbs/__init__.py
@@ -5,12 +5,14 @@
#******************************************************************************
""" Databases for SGDFi. """
-from ._ops import OperationType, OperationTypeData
-from ._st import StructureType, StructureTypeData
-from ._ststatus import StructureStatus, StructureStatusData
-from ._funcs import Function, FunctionData, FunctionRawData
-from ._event import EventType, EventTypeData
-from ._code import Code, CodeType
+from ._ops import OperationType, OperationTypeData
+from ._st import StructureType, StructureTypeData
+from ._stspe import StructureSpeciality, StructureSpecialityData
+from ._ststatus import StructureStatus, StructureStatusData
+from ._funcs import Function, FunctionData, FunctionRawData
+from ._event import EventType, EventTypeData
+from ._dept import Department, DepartmentData
+from ._code import Code, CodeType
from ._regime import AllocationsRegime
diff --git a/sgdfi/_dbs/_dept.py b/sgdfi/_dbs/_dept.py
new file mode 100755
index 0000000..b33c212
--- /dev/null
+++ b/sgdfi/_dbs/_dept.py
@@ -0,0 +1,676 @@
+#!/usr/bin/env python3
+#******************************************************************************
+# Copyright (C) 2018 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
+# This file is part of the sgdfi project, which is MIT-licensed.
+#******************************************************************************
+""" Department reference for SGDFi. """
+
+from enum import Enum as _Enum, unique as _unique
+from unicodedata import normalize as _udnormalize
+
+__all__ = ["Department", "DepartmentData"]
+
+@_unique
+class Department(_Enum):
+ """ The default department (unknown). """
+ UNKNOWN = -1
+
+ """ 00 - Not given. """
+ NONE = 0
+
+ '01 - Ain'
+ AIN = 1
+
+ '02 - Aisne'
+ AISNE = 2
+
+ '03 - Allier'
+ ALLIER = 3
+
+ '04 - Alpes-de-Haute-Provence'
+ ALPES_DE_HAUTE_PROVENCE = 4
+
+ '05 - Hautes-Alpes'
+ HAUTES_ALPES = 5
+
+ '06 - Alpes-Maritimes'
+ ALPES_MARITIMES = 6
+
+ '07 - Ardèche'
+ ARDECHE = 7
+
+ '08 - Ardennes'
+ ARDENNES = 8
+
+ '09 - Ariège'
+ ARIEGE = 9
+
+ '10 - Aube'
+ AUBE = 10
+
+ '11 - Aude'
+ AUDE = 11
+
+ '12 - Aveyron'
+ AVEYRON = 12
+
+ '13 - Bouches-du-Rhône'
+ BOUCHES_DU_RHONE = 13
+
+ '14 - Calvados'
+ CALVADOS = 14
+
+ '15 - Cantal'
+ CANTAL = 15
+
+ '16 - Charente'
+ CHARENTE = 16
+
+ '17 - Charente-Maritime'
+ CHARENTE_MARITIME = 17
+
+ '18 - Cher'
+ CHER = 18
+
+ '19 - Corrèze'
+ CORREZE = 19
+
+ "21 - Côte-d'Or"
+ COTE_D_OR = 21
+
+ "22 - Côtes-d'Armor"
+ COTES_D_ARMOR = 22
+
+ '23 - Creuse'
+ CREUSE = 23
+
+ '24 - Dordogne'
+ DORDOGNE = 24
+
+ '25 - Doubs'
+ DOUBS = 25
+
+ '26 - Drôme'
+ DROME = 26
+
+ '27 - Eure'
+ EURE = 27
+
+ '28 - Eure-et-Loir'
+ EURE_ET_LOIR = 28
+
+ '29 - Finistère'
+ FINISTERE = 29
+
+ '2A - Corse-du-Sud'
+ CORSE_DU_SUD = 120
+
+ '2B - Haute-Corse'
+ HAUTE_CORSE = 121
+
+ '30 - Gard'
+ GARD = 30
+
+ '31 - Haute-Garonne'
+ HAUTE_GARONNE = 31
+
+ '32 - Gers'
+ GERS = 32
+
+ '33 - Gironde'
+ GIRONDE = 33
+
+ '34 - Hérault'
+ HERAULT = 34
+
+ '35 - Ille-et-Vilaine'
+ ILLE_ET_VILAINE = 35
+
+ '36 - Indre'
+ INDRE = 36
+
+ '37 - Indre-et-Loire'
+ INDRE_ET_LOIRE = 37
+
+ '38 - Isère'
+ ISERE = 38
+
+ '39 - Jura'
+ JURA = 39
+
+ '40 - Landes'
+ LANDES = 40
+
+ '41 - Loir-et-Cher'
+ LOIR_ET_CHER = 41
+
+ '42 - Loire'
+ LOIRE = 42
+
+ '43 - Haute-Loire'
+ HAUTE_LOIRE = 43
+
+ '44 - Loire-Atlantique'
+ LOIRE_ATLANTIQUE = 44
+
+ '45 - Loiret'
+ LOIRET = 45
+
+ '46 - Lot'
+ LOT = 46
+
+ '47 - Lot-et-Garonne'
+ LOT_ET_GARONNE = 47
+
+ '48 - Lozère'
+ LOZERE = 48
+
+ '49 - Maine-et-Loire'
+ MAINE_ET_LOIRE = 49
+
+ '50 - Manche'
+ MANCHE = 50
+
+ '51 - Marne'
+ MARNE = 51
+
+ '52 - Haute-Marne'
+ HAUTE_MARNE = 52
+
+ '53 - Mayenne'
+ MAYENNE = 53
+
+ '54 - Meurthe-et-Moselle'
+ MEURTHE_ET_MOSELLE = 54
+
+ '55 - Meuse'
+ MEUSE = 55
+
+ '56 - Morbihan'
+ MORBIHAN = 56
+
+ '57 - Moselle'
+ MOSELLE = 57
+
+ '58 - Nièvre'
+ NIEVRE = 58
+
+ '59 - Nord'
+ NORD = 59
+
+ '60 - Oise'
+ OISE = 60
+
+ '61 - Orne'
+ ORNE = 61
+
+ '62 - Pas-de-Calais'
+ PAS_DE_CALAIS = 62
+
+ '63 - Puy-de-Dôme'
+ PUY_DE_DOME = 63
+
+ '64 - Pyrénées-Atlantiques'
+ PYRENEES_ATLANTIQUES = 64
+
+ '65 - Hautes-Pyrénées'
+ HAUTES_PYRENEES = 65
+
+ '66 - Pyrénées-Orientales'
+ PYRENEES_ORIENTALES = 66
+
+ '67 - Bas-Rhin'
+ BAS_RHIN = 67
+
+ '68 - Haut-Rhin'
+ HAUT_RHIN = 68
+
+ '69 - Rhône'
+ RHONE = 69
+
+ '70 - Haute-Saône'
+ HAUTE_SAONE = 70
+
+ '71 - Saône-et-Loire'
+ SAONE_ET_LOIRE = 71
+
+ '72 - Sarthe'
+ SARTHE = 72
+
+ '73 - Savoie'
+ SAVOIE = 73
+
+ '74 - Haute-Savoie'
+ HAUTE_SAVOIE = 74
+
+ '75 - Paris'
+ PARIS = 75
+
+ '76 - Seine-Maritime'
+ SEINE_MARITIME = 76
+
+ '77 - Seine-et-Marne'
+ SEINE_ET_MARNE = 77
+
+ '78 - Yvelines'
+ YVELINES = 78
+
+ '79 - Deux-Sèvres'
+ DEUX_SEVRES = 79
+
+ '80 - Somme'
+ SOMME = 80
+
+ '81 - Tarn'
+ TARN = 81
+
+ '82 - Tarn-et-Garonne'
+ TARN_ET_GARONNE = 82
+
+ '83 - Var'
+ VAR = 83
+
+ '84 - Vaucluse'
+ VAUCLUSE = 84
+
+ '85 - Vendée'
+ VENDEE = 85
+
+ '86 - Vienne'
+ VIENNE = 86
+
+ '87 - Haute-Vienne'
+ HAUTE_VIENNE = 87
+
+ '88 - Vosges'
+ VOSGES = 88
+
+ '89 - Yonne'
+ YONNE = 89
+
+ '90 - Territoire de Belfort'
+ TERRITOIRE_DE_BELFORT = 90
+
+ '91 - Essonne'
+ ESSONNE = 91
+
+ '92 - Hauts-de-Seine'
+ HAUTS_DE_SEINE = 92
+
+ '93 - Seine-Saint-Denis'
+ SEINE_SAINT_DENIS = 93
+
+ '94 - Val-de-Marne'
+ VAL_DE_MARNE = 94
+
+ "95 - Val-d'Oise"
+ VAL_D_OISE = 95
+
+ '971 - Guadeloupe'
+ GUADELOUPE = 971
+
+ '972 - Martinique'
+ MARTINIQUE = 972
+
+ '973 - Guyane'
+ GUYANE = 973
+
+ '974 - Réunion'
+ REUNION = 974
+
+ '975 - Saint-Pierre-et-Miquelon'
+ SAINT_PIERRE_ET_MIQUELON = 975
+
+ '976 - Mayotte'
+ MAYOTTE = 976
+
+ '984 - Terres australes et antarctiques française'
+ TERRES_AUSTRALES_ET_ANTARCTIQUES_FRANCAISE = 984
+
+ '986 - Wallis-et-Futuna'
+ WALLIS_ET_FUTUNA = 986
+
+ '987 - Polynésie française'
+ POLYNESIE_FRANCAISE = 987
+
+ '988 - Nouvelle-Calédonie'
+ NOUVELLE_CALEDONIE = 988
+
+ '998 - Monde - tarifs métropole'
+ MONDE_TARIFS_METROPOLE = 998
+
+ '999 - Monde'
+ MONDE = 999
+
+_DepartmentData = {
+ Department.NONE: \
+ ("00", "Non précisé", 9023),
+ Department.AIN: \
+ ('01', 'Ain', 1),
+ Department.AISNE: \
+ ('02', 'Aisne', 2),
+ Department.ALLIER: \
+ ('03', 'Allier', 3),
+ Department.ALPES_DE_HAUTE_PROVENCE: \
+ ('04', 'Alpes-de-Haute-Provence', 4),
+ Department.HAUTES_ALPES: \
+ ('05', 'Hautes-Alpes', 5),
+ Department.ALPES_MARITIMES: \
+ ('06', 'Alpes-Maritimes', 6),
+ Department.ARDECHE: \
+ ('07', 'Ardèche', 7),
+ Department.ARDENNES: \
+ ('08', 'Ardennes', 8),
+ Department.ARIEGE: \
+ ('09', 'Ariège', 9),
+ Department.AUBE: \
+ ('10', 'Aube', 10),
+ Department.AUDE: \
+ ('11', 'Aude', 11),
+ Department.AVEYRON: \
+ ('12', 'Aveyron', 12),
+ Department.BOUCHES_DU_RHONE: \
+ ('13', 'Bouches-du-Rhône', 13),
+ Department.CALVADOS: \
+ ('14', 'Calvados', 14),
+ Department.CANTAL: \
+ ('15', 'Cantal', 15),
+ Department.CHARENTE: \
+ ('16', 'Charente', 16),
+ Department.CHARENTE_MARITIME: \
+ ('17', 'Charente-Maritime', 17),
+ Department.CHER: \
+ ('18', 'Cher', 18),
+ Department.CORREZE: \
+ ('19', 'Corrèze', 19),
+ Department.COTE_D_OR: \
+ ('21', "Côte-d'Or", 21),
+ Department.COTES_D_ARMOR: \
+ ('22', "Côtes-d'Armor", 22),
+ Department.CREUSE: \
+ ('23', 'Creuse', 23),
+ Department.DORDOGNE: \
+ ('24', 'Dordogne', 24),
+ Department.DOUBS: \
+ ('25', 'Doubs', 25),
+ Department.DROME: \
+ ('26', 'Drôme', 26),
+ Department.EURE: \
+ ('27', 'Eure', 27),
+ Department.EURE_ET_LOIR: \
+ ('28', 'Eure-et-Loir', 28),
+ Department.FINISTERE: \
+ ('29', 'Finistère', 29),
+ Department.CORSE_DU_SUD: \
+ ('2A', 'Corse-du-Sud', 9021),
+ Department.HAUTE_CORSE: \
+ ('2B', 'Haute-Corse', 9022),
+ Department.GARD: \
+ ('30', 'Gard', 30),
+ Department.HAUTE_GARONNE: \
+ ('31', 'Haute-Garonne', 31),
+ Department.GERS: \
+ ('32', 'Gers', 32),
+ Department.GIRONDE: \
+ ('33', 'Gironde', 33),
+ Department.HERAULT: \
+ ('34', 'Hérault', 34),
+ Department.ILLE_ET_VILAINE: \
+ ('35', 'Ille-et-Vilaine', 35),
+ Department.INDRE: \
+ ('36', 'Indre', 36),
+ Department.INDRE_ET_LOIRE: \
+ ('37', 'Indre-et-Loire', 37),
+ Department.ISERE: \
+ ('38', 'Isère', 38),
+ Department.JURA: \
+ ('39', 'Jura', 39),
+ Department.LANDES: \
+ ('40', 'Landes', 40),
+ Department.LOIR_ET_CHER: \
+ ('41', 'Loir-et-Cher', 41),
+ Department.LOIRE: \
+ ('42', 'Loire', 42),
+ Department.HAUTE_LOIRE: \
+ ('43', 'Haute-Loire', 43),
+ Department.LOIRE_ATLANTIQUE: \
+ ('44', 'Loire-Atlantique', 44),
+ Department.LOIRET: \
+ ('45', 'Loiret', 45),
+ Department.LOT: \
+ ('46', 'Lot', 46),
+ Department.LOT_ET_GARONNE: \
+ ('47', 'Lot-et-Garonne', 47),
+ Department.LOZERE: \
+ ('48', 'Lozère', 48),
+ Department.MAINE_ET_LOIRE: \
+ ('49', 'Maine-et-Loire', 49),
+ Department.MANCHE: \
+ ('50', 'Manche', 50),
+ Department.MARNE: \
+ ('51', 'Marne', 51),
+ Department.HAUTE_MARNE: \
+ ('52', 'Haute-Marne', 52),
+ Department.MAYENNE: \
+ ('53', 'Mayenne', 53),
+ Department.MEURTHE_ET_MOSELLE: \
+ ('54', 'Meurthe-et-Moselle', 54),
+ Department.MEUSE: \
+ ('55', 'Meuse', 55),
+ Department.MORBIHAN: \
+ ('56', 'Morbihan', 56),
+ Department.MOSELLE: \
+ ('57', 'Moselle', 57),
+ Department.NIEVRE: \
+ ('58', 'Nièvre', 58),
+ Department.NORD: \
+ ('59', 'Nord', 59),
+ Department.OISE: \
+ ('60', 'Oise', 60),
+ Department.ORNE: \
+ ('61', 'Orne', 61),
+ Department.PAS_DE_CALAIS: \
+ ('62', 'Pas-de-Calais', 62),
+ Department.PUY_DE_DOME: \
+ ('63', 'Puy-de-Dôme', 63),
+ Department.PYRENEES_ATLANTIQUES: \
+ ('64', 'Pyrénées-Atlantiques', 64),
+ Department.HAUTES_PYRENEES: \
+ ('65', 'Hautes-Pyrénées', 65),
+ Department.PYRENEES_ORIENTALES: \
+ ('66', 'Pyrénées-Orientales', 66),
+ Department.BAS_RHIN: \
+ ('67', 'Bas-Rhin', 67),
+ Department.HAUT_RHIN: \
+ ('68', 'Haut-Rhin', 68),
+ Department.RHONE: \
+ ('69', 'Rhône', 69),
+ Department.HAUTE_SAONE: \
+ ('70', 'Haute-Saône', 70),
+ Department.SAONE_ET_LOIRE: \
+ ('71', 'Saône-et-Loire', 71),
+ Department.SARTHE: \
+ ('72', 'Sarthe', 72),
+ Department.SAVOIE: \
+ ('73', 'Savoie', 73),
+ Department.HAUTE_SAVOIE: \
+ ('74', 'Haute-Savoie', 74),
+ Department.PARIS: \
+ ('75', 'Paris', 75),
+ Department.SEINE_MARITIME: \
+ ('76', 'Seine-Maritime', 76),
+ Department.SEINE_ET_MARNE: \
+ ('77', 'Seine-et-Marne', 77),
+ Department.YVELINES: \
+ ('78', 'Yvelines', 78),
+ Department.DEUX_SEVRES: \
+ ('79', 'Deux-Sèvres', 79),
+ Department.SOMME: \
+ ('80', 'Somme', 80),
+ Department.TARN: \
+ ('81', 'Tarn', 81),
+ Department.TARN_ET_GARONNE: \
+ ('82', 'Tarn-et-Garonne', 82),
+ Department.VAR: \
+ ('83', 'Var', 83),
+ Department.VAUCLUSE: \
+ ('84', 'Vaucluse', 84),
+ Department.VENDEE: \
+ ('85', 'Vendée', 85),
+ Department.VIENNE: \
+ ('86', 'Vienne', 86),
+ Department.HAUTE_VIENNE: \
+ ('87', 'Haute-Vienne', 87),
+ Department.VOSGES: \
+ ('88', 'Vosges', 88),
+ Department.YONNE: \
+ ('89', 'Yonne', 89),
+ Department.TERRITOIRE_DE_BELFORT: \
+ ('90', 'Territoire de Belfort', 90),
+ Department.ESSONNE: \
+ ('91', 'Essonne', 91),
+ Department.HAUTS_DE_SEINE: \
+ ('92', 'Hauts-de-Seine', 92),
+ Department.SEINE_SAINT_DENIS: \
+ ('93', 'Seine-Saint-Denis', 93),
+ Department.VAL_DE_MARNE: \
+ ('94', 'Val-de-Marne', 94),
+ Department.VAL_D_OISE: \
+ ('95', "Val-d'Oise", 95),
+ Department.GUADELOUPE: \
+ ('971', 'Guadeloupe', 971),
+ Department.MARTINIQUE: \
+ ('972', 'Martinique', 972),
+ Department.GUYANE: \
+ ('973', 'Guyane', 973),
+ Department.REUNION: \
+ ('974', 'Réunion', 974),
+ Department.SAINT_PIERRE_ET_MIQUELON: \
+ ('975', 'Saint-Pierre-et-Miquelon', 975),
+ Department.MAYOTTE: \
+ ('976', 'Mayotte', 985),
+ Department.TERRES_AUSTRALES_ET_ANTARCTIQUES_FRANCAISE: \
+ ('984', 'Terres australes et antarctiques française', 984),
+ Department.WALLIS_ET_FUTUNA: \
+ ('986', 'Wallis-et-Futuna', 986),
+ Department.POLYNESIE_FRANCAISE: \
+ ('987', 'Polynésie française', 987),
+ Department.NOUVELLE_CALEDONIE: \
+ ('988', 'Nouvelle-Calédonie', 988),
+ Department.MONDE_TARIFS_METROPOLE: \
+ ('998', 'Monde - tarifs métropole', 9024),
+ Department.MONDE: \
+ ('999', 'Monde', 99),
+}
+
+def _normalize(value):
+ """ Normalize a string for comparison. """
+
+ return ''.join(c for c in _udnormalize('NFD', value.casefold()) \
+ if c in 'abcdefghijklmnopqrstuvwxyz')
+
+# Leads are the following:
+# - intranet internal identifier.
+# - same but string version.
+# - normalized name only.
+# - displayed code.
+# - normalized 'dcode - name' (e.g. '01 - AIN').
+
+_DepartmentLeads = {}
+_DepartmentLeads.update({_normalize(name): i for i, (dcode, name, ii) \
+ in _DepartmentData.items()})
+_DepartmentLeads.update({dcode: i for i, (dcode, name, ii) \
+ in _DepartmentData.items()})
+_DepartmentLeads.update({ii: i for i, (dcode, name, ii) \
+ in _DepartmentData.items()})
+_DepartmentLeads.update({str(ii): i for i, (dcode, name, ii) \
+ in _DepartmentData.items()})
+_DepartmentLeads.update({_normalize(f"{dcode} - {name}"): i \
+ for i, (dcode, name, ii) in _DepartmentData.items()})
+
+class DepartmentData:
+ """ Department data (id, name, …). """
+
+ def __init__(self, value):
+ def isid(id):
+ try:
+ Department(value)
+ except ValueError:
+ return False
+ return True
+
+ self.__id = Department.UNKNOWN
+ self.__name = None
+ self.__dcode = None
+ self.__ii = None
+ data = None
+
+ if isinstance(value, StructureTypeData):
+ self.__id = value.id
+ self.__ii = value.iid
+ self.__dcode = value.displayed_code
+ self.__name = value.name
+ elif isid(value):
+ value = StructureType(value)
+ self.__id = value
+
+ data = _StructureTypeData.get(value, None)
+ else:
+ lead = value
+ if type(lead) == str:
+ lead = _normalize(lead)
+
+ try:
+ self.__id = _StructureTypeLeads[lead]
+ data = _StructureTypeData.get(self.__id, None)
+ except KeyError:
+ if type(value) == str:
+ self.__name = value
+ else:
+ raise ValueError("Could not determine a structure type.") \
+ from None
+
+ if data is not None:
+ self.__dcode = data[0]
+ self.__name = data[1]
+ self.__ii = data[2]
+
+ def __repr__(self):
+ p = []
+ if self.__id is not None:
+ p.append(f"id = {repr(self.__id)}")
+ if self.__dcode is not None:
+ p.append(f"displayed_code = {repr(self.__dcode)}")
+ if self.__name is not None:
+ p.append(f"name = {repr(self.__name)}")
+ if self.__ii is not None:
+ p.append(f"iid = {repr(self.__iid)}")
+
+ return f"{self.__class__.__name__}({', '.join(p)})"
+
+ @property
+ def id(self):
+ """ The department identifier, as one of the structure types defined in
+ the Department enumeration. """
+
+ return self.__id
+
+ @property
+ def displayed_code(self):
+ """ The displayed code. """
+
+ return self.__dcode
+
+ @property
+ def name(self):
+ """ The department name. """
+
+ return self.__name
+
+ @property
+ def iid(self):
+ """ The internal identifier on the intranet. """
+
+ return self.__ii
+
+# End of file.
diff --git a/sgdfi/_dbs/_st.py b/sgdfi/_dbs/_st.py
index dcdd7fa..0b9e92c 100755
--- a/sgdfi/_dbs/_st.py
+++ b/sgdfi/_dbs/_st.py
@@ -56,27 +56,35 @@ class StructureType(_Enum):
""" Unité Vent du Large. """
UNITE_VENT_DU_LARGE = 35
+# Structure type data:
+# - name.
+# - internal code.
+
_StructureTypeData = {
- StructureType.AUTRES: "Autres",
-
- StructureType.SOMMET: "Sommet",
- StructureType.TERRITOIRE: "Territoire",
- StructureType.GROUPE: "Groupe",
- StructureType.ASSOCIES_N: "Membres associés National",
- StructureType.ASSOCIES_T: "Membres associés Territorial",
- StructureType.ASSOCIES_L: "Membres associés local",
- StructureType.CENTRE_NATIONAL: "Centre National",
-
- StructureType.UNITE_FARFADET: "Unité Farfadet",
- StructureType.UNITE_8_11_ANS: "Unité 8-11 ans",
- StructureType.UNITE_11_14_ANS: "Unité 11-14 ans",
- StructureType.UNITE_14_17_ANS: "Unité 14-17 ans",
- StructureType.UNITE_17_20_ANS: "Unité 17-20 ans",
- StructureType.UNITE_VENT_DU_LARGE: "Unité Vent du Large",
+ StructureType.AUTRES: ("Autres", 1211),
+
+ StructureType.SOMMET: ("Sommet", 1205),
+ StructureType.TERRITOIRE: ("Territoire", 1203),
+ StructureType.GROUPE: ("Groupe", 1200),
+ StructureType.ASSOCIES_N: ("Membres associés National", 1206),
+ StructureType.ASSOCIES_T: ("Membres associés Territorial", 1204),
+ StructureType.ASSOCIES_L: ("Membres associés local", 1201),
+ StructureType.CENTRE_NATIONAL: ("Centre National", 1205),
+
+ StructureType.UNITE_FARFADET: ("Unité Farfadet", 1208),
+ StructureType.UNITE_8_11_ANS: ("Unité 8-11 ans", 1199),
+ StructureType.UNITE_11_14_ANS: ("Unité 11-14 ans", 1212),
+ StructureType.UNITE_14_17_ANS: ("Unité 14-17 ans", 1210),
+ StructureType.UNITE_17_20_ANS: ("Unité 17-20 ans", 1209),
+ StructureType.UNITE_VENT_DU_LARGE: ("Unité Vent du Large", 1202),
}
_StructureTypeLeads = {}
-_StructureTypeLeads.update({name.strip().casefold(): i for i, name \
+_StructureTypeLeads.update({name.strip().casefold(): i for i, (name, ii) \
+ in _StructureTypeData.items()})
+_StructureTypeLeads.update({ii: i for i, (name, ii) \
+ in _StructureTypeData.items()})
+_StructureTypeLeads.update({str(ii): i for i, (name, ii) \
in _StructureTypeData.items()})
class StructureTypeData:
@@ -92,10 +100,12 @@ class StructureTypeData:
self.__id = StructureType.UNKNOWN
self.__name = None
+ self.__ii = None
data = None
if isinstance(value, StructureTypeData):
self.__id = value.id
+ self.__ii = value.iid
self.__name = value.name
elif isid(value):
value = StructureType(value)
@@ -118,7 +128,8 @@ class StructureTypeData:
from None
if data is not None:
- self.__name = data
+ self.__name = data[0]
+ self.__ii = data[1]
def __repr__(self):
p = []
@@ -126,6 +137,8 @@ class StructureTypeData:
p.append(f"id = {repr(self.__id)}")
if self.__name is not None:
p.append(f"name = {repr(self.__name)}")
+ if self.__ii is not None:
+ p.append(f"iid = {repr(self.__iid)}")
return f"{self.__class__.__name__}({', '.join(p)})"
@@ -142,4 +155,10 @@ class StructureTypeData:
return self.__name
+ @property
+ def iid(self):
+ """ The internal identifier on the intranet. """
+
+ return self.__ii
+
# End of file.
diff --git a/sgdfi/_dbs/_stspe.py b/sgdfi/_dbs/_stspe.py
new file mode 100755
index 0000000..55da554
--- /dev/null
+++ b/sgdfi/_dbs/_stspe.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+#******************************************************************************
+# Copyright (C) 2018 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
+# This file is part of the sgdfi project, which is MIT-licensed.
+#******************************************************************************
+""" Structure speciality reference for SGDFi. """
+
+from enum import Enum as _Enum, unique as _unique
+
+__all__ = ["StructureSpeciality", "StructureSpecialityData"]
+
+@_unique
+class StructureSpeciality(_Enum):
+ """ The default speciality (unknown). """
+ UNKNOWN = 0
+
+ """ Sans specialité. """
+ WITHOUT = 1
+
+ """ Marine. """
+ MARINE = 2
+
+ """ Vent du Large. """
+ VENT_DU_LARGE = 3
+
+# Structure speciality data:
+# - name.
+# - internal code.
+
+_StructureSpecialityData = {
+ StructureSpeciality.WITHOUT: ("sans spécialité", 624),
+ StructureSpeciality.MARINE: ("Marine", 622),
+ StructureSpeciality.VENT_DU_LARGE: ("Vent du Large", 623),
+}
+
+_StructureSpecialityLeads = {}
+_StructureSpecialityLeads.update({name.strip().casefold(): i \
+ for i, (name, ii) in _StructureSpecialityData.items()})
+_StructureSpecialityLeads.update({ii: i \
+ for i, (name, ii) in _StructureSpecialityData.items()})
+_StructureSpecialityLeads.update({str(ii): i \
+ for i, (name, ii) in _StructureSpecialityData.items()})
+
+class StructureSpecialityData:
+ """ Structure speciality data (id, name, …). """
+
+ def __init__(self, value):
+ def isid(id):
+ try:
+ StructureSpeciality(value)
+ except ValueError:
+ return False
+ return True
+
+ self.__id = StructureSpeciality.UNKNOWN
+ self.__name = None
+ self.__ii = None
+ data = None
+
+ if isinstance(value, StructureSpecialityData):
+ self.__id = value.id
+ self.__ii = value.iid
+ self.__name = value.name
+ elif isid(value):
+ value = StructureSpeciality(value)
+ self.__id = value
+
+ data = _StructureSpecialityData.get(value, None)
+ else:
+ lead = value
+ if type(lead) == str:
+ lead = lead.strip().casefold()
+
+ try:
+ self.__id = _StructureSpecialityLeads[lead]
+ data = _StructureSpecialityData.get(self.__id, None)
+ except KeyError:
+ if type(value) == str:
+ self.__name = value
+ else:
+ raise ValueError("Could not determine a structure type.") \
+ from None
+
+ if data is not None:
+ self.__name = data[0]
+ self.__ii = data[1]
+
+ def __repr__(self):
+ p = []
+ if self.__id is not None:
+ p.append(f"id = {repr(self.__id)}")
+ if self.__name is not None:
+ p.append(f"name = {repr(self.__name)}")
+ if self.__ii is not None:
+ p.append(f"iid = {repr(self.__iid)}")
+
+ return f"{self.__class__.__name__}({', '.join(p)})"
+
+ @property
+ def id(self):
+ """ The speciality identifier, as one of the structure types defined in
+ the StructureSpeciality enumeration. """
+
+ return self.__id
+
+ @property
+ def name(self):
+ """ The type name as defined in the structure summary page. """
+
+ return self.__name
+
+ @property
+ def iid(self):
+ """ The internal identifier on the intranet. """
+
+ return self.__ii
+
+# End of file.
diff --git a/sgdfi/_dbs/_ststatus.py b/sgdfi/_dbs/_ststatus.py
index e02cb48..d77df05 100755
--- a/sgdfi/_dbs/_ststatus.py
+++ b/sgdfi/_dbs/_ststatus.py
@@ -23,14 +23,22 @@ class StructureStatus(_Enum):
""" Suspendue. """
SUSPENDED = 3
+# Structure status data.
+# - name.
+# - internal identifier on the intranet.
+
_StructureStatusData = {
- StructureStatus.OPEN: "Ouverte",
- StructureStatus.CLOSED: "Fermée",
- StructureStatus.SUSPENDED: "Suspendue"
+ StructureStatus.OPEN: ("Ouverte", 0),
+ StructureStatus.CLOSED: ("Fermée", 1),
+ StructureStatus.SUSPENDED: ("Suspendue", 2)
}
_StructureStatusLeads = {}
-_StructureStatusLeads.update({name.strip().casefold(): i for i, name \
+_StructureStatusLeads.update({name.strip().casefold(): i for i, (name, ii) \
+ in _StructureStatusData.items()})
+_StructureStatusLeads.update({ii: i for i, (name, ii) \
+ in _StructureStatusData.items()})
+_StructureStatusLeads.update({str(ii): i for i, (name, ii) \
in _StructureStatusData.items()})
class StructureStatusData:
@@ -46,11 +54,13 @@ class StructureStatusData:
self.__id = StructureStatus.UNKNOWN
self.__name = None
+ self.__ii = None
data = None
if isinstance(value, StructureStatusData):
self.__id = value.id
self.__name = value.name
+ self.__ii = value.iid
elif isid(value):
value = StructureStatus(value)
self.__id = value
@@ -72,7 +82,8 @@ class StructureStatusData:
raise ValueError(msg) from None
if data is not None:
- self.__name = data
+ self.__name = data[0]
+ self.__ii = data[1]
def __repr__(self):
p = []
@@ -96,4 +107,10 @@ class StructureStatusData:
return self.__name
+ @property
+ def iid(self):
+ """ The internal identifier on the intranet. """
+
+ return self.__ii
+
# End of file.
diff --git a/sgdfi/_decode.py b/sgdfi/_decode.py
index 09352ed..383e2c3 100755
--- a/sgdfi/_decode.py
+++ b/sgdfi/_decode.py
@@ -198,6 +198,7 @@ class Decoder:
if hint == 'sic':
return tree
+
result = func(tree)
elif type == 'application/x-microsoft-ajax':
# The input might be a stream.
@@ -398,22 +399,8 @@ class Decoder:
# HTML pages decoding.
# ---
- def _decode_html_intranet_operations(self, tree):
- """ Decode the HTML operations from a BeautifulSoup decoded
- content. """
-
- stprefix = '/Specialisation/Sgdf/structures/ResumeStructure.aspx'
- adprefix = '/Specialisation/Sgdf/adherents/ResumeAdherent.aspx'
- irprefix = '/Specialisation/Sgdf/Rassemblements/' \
- 'InscriptionRassemblementV2.aspx'
- cpprefix = '/Specialisation/Sgdf/camps/ConsulterModifierCamp.aspx'
- laprefix = '/Specialisation/Sgdf/Commun/ResumeLieuActivite.aspx'
-
- parent = tree.find(id = 'ctl00_Popup__evenements__gvEvenements')
- if not parent:
- return []
-
- elts = []
+ def __get_html_pagination(self, tree):
+ """ Get the pagination from an HTML page. """
# Récupération de la pagination.
# `numpages` : numéro maximal de page dans la pagination.
@@ -421,7 +408,7 @@ class Decoder:
# en « ... » ?).
# `curpage` : page actuelle selon la pagination.
- p = parent.find('tr', {'class': ['pagination']})
+ p = tree.find('tr', {'class': ['pagination']})
if p != None:
p = p.find('tr')
td = p.find_all('td')[-1]
@@ -448,7 +435,28 @@ class Decoder:
numpages = 1
more = False
- elts.append(_Pagination(curpage, numpages, more))
+ return _Pagination(curpage, numpages, more)
+
+ def _decode_html_intranet_operations(self, tree):
+ """ Decode the HTML operations from a BeautifulSoup decoded
+ content. """
+
+ stprefix = '/Specialisation/Sgdf/structures/ResumeStructure.aspx'
+ adprefix = '/Specialisation/Sgdf/adherents/ResumeAdherent.aspx'
+ irprefix = '/Specialisation/Sgdf/Rassemblements/' \
+ 'InscriptionRassemblementV2.aspx'
+ cpprefix = '/Specialisation/Sgdf/camps/ConsulterModifierCamp.aspx'
+ laprefix = '/Specialisation/Sgdf/Commun/ResumeLieuActivite.aspx'
+
+ parent = tree.find(id = 'ctl00_Popup__evenements__gvEvenements')
+ if not parent:
+ return []
+
+ elts = []
+
+ # Récupération de la pagination.
+
+ elts.append(self.__get_html_pagination(parent))
# Récupération de la liste d'évènements.
@@ -688,6 +696,23 @@ class Decoder:
return place
+ def _decode_html_intranet_structure_search(self, tree):
+ """ Decode the HTML search results for structures from a
+ BeautifulSoup decoded content. """
+
+ print(tree)
+
+ parent = tree.find(id = 'ctl00_Popup__recherche__gvResultats')
+ elts = []
+
+ # Récupération de la pagination.
+
+ #elts.append(self.__get_html_pagination(parent))
+
+ # TODO: récupération des structures.
+
+ return elts
+
def _decode_html_intranet_structure_summary(self, tree):
""" Decode the HTML summary page for a structure from a
BeautifulSoup decoded content. """
diff --git a/sgdfi/_intranet.py b/sgdfi/_intranet.py
index 0e54c36..c37c46c 100755
--- a/sgdfi/_intranet.py
+++ b/sgdfi/_intranet.py
@@ -206,8 +206,8 @@ class AnonymousIntranetSession:
# Définition des headers.
headers = {
- 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) ' \
- 'Gecko/20100101 Firefox/58.0',
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:63.0) ' \
+ 'Gecko/20100101 Firefox/63.0',
'Cache-Control': 'no-cache',
'Upgrade-Insecure-Requests': '1',
'Referer': self.__base + path,
@@ -275,6 +275,14 @@ class AnonymousIntranetSession:
recursive_args(args)
+ # On enlève ensuite ce qui est à supprimer selon l'utilisateur,
+ # à savoir ce qui vaut `None`.
+
+ keys = list(payload.keys())
+ for key in keys:
+ if payload[key] is None:
+ del payload[key]
+
# ---
# Préparation des cookies et exécution de la requête.
# ---
@@ -293,6 +301,7 @@ class AnonymousIntranetSession:
pkw['json'] = payload
else:
pkw['data'] = payload
+ headers['Referer'] = self.__base + path
tm = _monotime()
r = self.__session.post(self.__base + path, headers = headers,
@@ -585,6 +594,41 @@ class IntranetSession(AnonymousIntranetSession):
pl.iid = iid
return pl
+ def _get_structures_page(self, page):
+ """ Get a structures page. """
+
+ # FIXME: this matches the URL, ~headers and POST parameters of the
+ # request on the Firefox DevTools, still, it doesn't get the
+ # freaking results and I don't freaking know why!!!!
+
+ iid = _IID('fCx2YIJV6Qq+qLBWSyMcwA==')
+ path = '/Specialisation/Sgdf/Popups/RechercheStructure.aspx?' \
+ f'dummy=1&operations={iid.urlsafe()}'
+ result = self.get_page(path, {
+ '__EVENTARGUMENT': f"Page${page}",
+ '__EVENTTARGET': 'ctl00$Popup$_recherche$_gvResultats',
+ 'ctl00_Popup__recherche__pnlFormulaire_CurrentState': 'true',
+ 'ctl00$Popup$_recherche': {
+ '_ddDepartement': '-1',
+ '_ddSpecialite': '-1',
+ '_ddStatut': '-1',
+ '_ddTypeStructure': '-1',
+ '_tbCodePostal': '',
+ '_tbCodeStructure': '',
+ '_tbLocalite': '',
+ '_tbMarqueur': '',
+ '_tbNom': '',
+
+ 'Rechercher': None,
+ '_btnAnnuler': None}},
+ method = self.METHOD_FORM,
+ hint = 'intranet_structure_search')
+
+ def get_structures(self):
+ """ Search through structures. """
+
+ return self._get_structures_page(5)
+
def get_structure(self, st_id):
""" Get a structure's data. """
diff --git a/sgdfi/_manager.py b/sgdfi/_manager.py
index d3b60a3..ac8eb11 100755
--- a/sgdfi/_manager.py
+++ b/sgdfi/_manager.py
@@ -8,8 +8,9 @@
import os.path as _path
-from os import makedirs as _makedirs, open as _open, fdopen as _fdopen, \
- O_WRONLY as _O_WRONLY, O_CREAT as _O_CREAT, O_EXCL as _O_EXCL
+from os import listdir as _listdir, makedirs as _makedirs, open as _open, \
+ fdopen as _fdopen, O_WRONLY as _O_WRONLY, O_CREAT as _O_CREAT, \
+ O_EXCL as _O_EXCL
from io import RawIOBase as _RawIOBase, TextIOWrapper as _TextIOWrapper
from sys import stdout as _stdout
from string import ascii_letters as _ascii_letters
@@ -433,6 +434,15 @@ class Manager(_Decoder):
return self.feed(open(path, "rb"), type = type, **kwargs)
+ def load_latest_dump(self):
+ """ Load the latest dump (shortcut for simplifying the reverse
+ engineering process). """
+
+ l = _listdir(self.__folder)
+ l.sort()
+
+ return self.load_dump(l[-1])
+
def load_dump(self, time, id = None):
""" Read from a saved dump (with headers). """