#132 WIP Migrate Users

* improves auto-recording of eco accounts
* adds migration of users and adding to auto-created teams
This commit is contained in:
mpeltriaux 2022-04-29 13:33:44 +02:00
parent 6ce2dd8509
commit 9cd73aefe1
7 changed files with 163 additions and 10 deletions

View File

@ -51,7 +51,7 @@
<td class="align-middle">{{ deadline.date|default_if_none:"---" }}</td> <td class="align-middle">{{ deadline.date|default_if_none:"---" }}</td>
<td class="align-middle"> <td class="align-middle">
<div class="scroll-150"> <div class="scroll-150">
{{ deadline.comment }} {{ deadline.comment|linebreaks }}
</div> </div>
</td> </td>
<td class="align-middle float-right"> <td class="align-middle float-right">

View File

@ -49,7 +49,7 @@
<td class="align-middle">{{ deadline.date|default_if_none:"---" }}</td> <td class="align-middle">{{ deadline.date|default_if_none:"---" }}</td>
<td class="align-middle"> <td class="align-middle">
<div class="scroll-150"> <div class="scroll-150">
{{ deadline.comment }} {{ deadline.comment|linebreaks }}
</div> </div>
</td> </td>
<td class="align-middle float-right"> <td class="align-middle float-right">

View File

@ -24,12 +24,12 @@ class BaseMigrater:
if self.db_connection is not None: if self.db_connection is not None:
self.db_connection.close() self.db_connection.close()
def connect_db(self): def connect_db(self, db_name: str="ksp"):
if self.options is None: if self.options is None:
return return
conn = psycopg2.connect( conn = psycopg2.connect(
host=self.options["host"], host=self.options["host"],
database="ksp", database=db_name,
user=self.options["db_user"], user=self.options["db_user"],
password=self.options["db_pw"], password=self.options["db_pw"],
) )
@ -182,7 +182,23 @@ class BaseMigrater:
tmp_cursor.close() tmp_cursor.close()
return instance return instance
def _migrate_responsible_code_to_team(self, instance, responsible_code, prefix: str = "Team"): def _get_team(self, team_name: str):
""" Returns a team from given name
"""
name = f"Team {team_name}"
description = f"Automatisch erzeugtes Team für {team_name}"
team = Team.objects.get_or_create(
name=name,
description=description
)[0]
return team
def _get_team_from_responsible_code(self, responsible_code, prefix: str = "Team"):
""" Returns a team from given responsible code
"""
name = f"{prefix} {responsible_code.long_name}" name = f"{prefix} {responsible_code.long_name}"
if responsible_code.parent is not None: if responsible_code.parent is not None:
name += f", {responsible_code.parent.long_name}" name += f", {responsible_code.parent.long_name}"
@ -192,6 +208,10 @@ class BaseMigrater:
name=name, name=name,
description=description description=description
)[0] )[0]
return team
def _migrate_responsible_code_to_team(self, instance, responsible_code, prefix: str = "Team"):
team = self._get_team_from_responsible_code(responsible_code, prefix)
instance.share_with_team(team) instance.share_with_team(team)
return instance return instance

View File

@ -4,7 +4,7 @@ from django.contrib.auth.models import Group
from django.contrib.gis.geos import MultiPolygon, Polygon from django.contrib.gis.geos import MultiPolygon, Polygon
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction from django.db import transaction
from django.utils import timezone from django.utils import timezone, formats
from codelist.models import KonovaCode from codelist.models import KonovaCode
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_COMPENSATION_HANDLER_ID from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_COMPENSATION_HANDLER_ID
@ -13,7 +13,6 @@ from compensation.utils.quality import EcoAccountQualityChecker
from intervention.models import Responsibility, Handler, Intervention, Legal from intervention.models import Responsibility, Handler, Intervention, Legal
from konova.management.commands.kspMigrater.compensation_migrater import CompensationMigrater from konova.management.commands.kspMigrater.compensation_migrater import CompensationMigrater
from konova.models import Geometry from konova.models import Geometry
from konova.settings import DEFAULT_GROUP
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP, DEFAULT_SRID from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP, DEFAULT_SRID
from user.models import User, UserActionLogEntry from user.models import User, UserActionLogEntry
@ -21,6 +20,7 @@ from user.models import User, UserActionLogEntry
class EcoAccountMigrater(CompensationMigrater): class EcoAccountMigrater(CompensationMigrater):
def migrate(self): def migrate(self):
el = "'OEK-1488450234228'"
self.connect_db() self.connect_db()
cursor = self.db_connection.cursor() cursor = self.db_connection.cursor()
cursor.execute( cursor.execute(
@ -61,11 +61,12 @@ class EcoAccountMigrater(CompensationMigrater):
)[0] )[0]
eco_account.title = oek_title eco_account.title = oek_title
eco_account.prevent_recording = False
eco_account.comment = oek_comment eco_account.comment = oek_comment
eco_account = self._migrate_legal(eco_account, oek) eco_account = self._migrate_legal(eco_account, oek)
eco_account = self._migrate_states(eco_account, oek)
eco_account = self._migrate_geometry(eco_account, oek) eco_account = self._migrate_geometry(eco_account, oek)
eco_account = self._migrate_responsibility(eco_account, oek) eco_account = self._migrate_responsibility(eco_account, oek)
eco_account = self._migrate_states(eco_account, oek)
eco_account = self._migrate_deadlines(eco_account, oek) eco_account = self._migrate_deadlines(eco_account, oek)
eco_account = self._migrate_action_control_deadlines(eco_account, oek) eco_account = self._migrate_action_control_deadlines(eco_account, oek)
eco_account = self._migrate_actions(eco_account, oek) eco_account = self._migrate_actions(eco_account, oek)
@ -126,6 +127,20 @@ class EcoAccountMigrater(CompensationMigrater):
# Calculate area by transforming # Calculate area by transforming
rlp_geom = db_result_geom.transform(ct=DEFAULT_SRID_RLP, clone=True) rlp_geom = db_result_geom.transform(ct=DEFAULT_SRID_RLP, clone=True)
area = round(rlp_geom.area) area = round(rlp_geom.area)
max_state_after_area = instance.get_state_after_surface_sum()
# Check whether the geometric area is at least
diff = abs(area - max_state_after_area)
diff_perc = diff / max(area, max_state_after_area)
is_diff_too_high = diff_perc > 0.1
if is_diff_too_high:
print(f" !!! {identifier} has diff of {diff_perc*100} % between geometry and after_states. Should not be recorded!")
instance.comment += f"\n\nÖkokonto konnte nicht automatisch verzeichnet übernommen werden: Zu große Differenz zwischen Geometriefläche ({formats.localize(area, use_l10n=True)} m²) und angegebener Zielzustandsfläche. Bitte prüfen und korrigieren bzw. eigenständig verzeichnen."
instance.prevent_recording = True
area = min(area, max_state_after_area)
else:
area = max_state_after_area
instance.deductable_surface = area instance.deductable_surface = area
instance.geometry.geom = db_result_geom if not db_result_geom.empty else None instance.geometry.geom = db_result_geom if not db_result_geom.empty else None
instance.geometry.save() instance.geometry.save()
@ -341,7 +356,7 @@ class EcoAccountMigrater(CompensationMigrater):
quality_checker = EcoAccountQualityChecker(instance) quality_checker = EcoAccountQualityChecker(instance)
quality_checker.run_check() quality_checker.run_check()
if quality_checker.valid: if quality_checker.valid and not instance.prevent_recording:
identifier = f"'{db_result[0]}'" identifier = f"'{db_result[0]}'"
tmp_cursor = self.db_connection.cursor() tmp_cursor = self.db_connection.cursor()
tmp_cursor.execute( tmp_cursor.execute(
@ -358,7 +373,25 @@ class EcoAccountMigrater(CompensationMigrater):
'limit 1' 'limit 1'
) )
fetch_result = tmp_cursor.fetchone() fetch_result = tmp_cursor.fetchone()
if fetch_result is None:
# Can happen on very old eco accounts: This data might only be found on table 'protokoll'
tmp_cursor.execute(
'select '
'p.bemerkung1, '
'p.geaendertvon, '
'p.geaendertam '
'from "OBJ_MASTER" om '
'join protokoll p on om."GISPADID"=p."FKEY" '
'where '
f'om."KENNUNG"={identifier} '
'order by '
'p.geaendertam '
'limit 1'
)
fetch_result = tmp_cursor.fetchone()
if fetch_result is not None: if fetch_result is not None:
# Something has been found on one of these two tables
recorded_by = fetch_result[1] recorded_by = fetch_result[1]
recorded_ts = timezone.make_aware(fetch_result[2]) recorded_ts = timezone.make_aware(fetch_result[2])
user = self._get_migrate_user(recorded_by) user = self._get_migrate_user(recorded_by)
@ -369,4 +402,7 @@ class EcoAccountMigrater(CompensationMigrater):
) )
instance.recorded.timestamp = recorded_ts instance.recorded.timestamp = recorded_ts
instance.recorded.save() instance.recorded.save()
tmp_cursor.close()
else:
instance.recorded = None
return instance return instance

View File

@ -0,0 +1,92 @@
from django.core.exceptions import ObjectDoesNotExist
from codelist.models import KonovaCode
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
from konova.management.commands.kspMigrater.base_migrater import BaseMigrater
from user.models import User
class UserMigrater(BaseMigrater):
def migrate(self):
self.connect_db(db_name="natportal")
cursor = self.db_connection.cursor()
el = "'%§§15§§%'"
cursor.execute(
'select '
'kennung, '
'name, '
'vorname, '
'email, '
'anwendungsnutzer, '
'firmenname '
'from berechtigung.nutzer where '
'aktiv=true and '
f'anwendungsnutzer like {el}'
)
fetch_results = cursor.fetchall()
len_all_users = len(fetch_results)
print(f"Migrate users...")
print(f"--Found {len_all_users} entries. Process now...")
num_processed = 0
for result in fetch_results:
if num_processed % 500 == 0:
print(f"----{num_processed}/{len_all_users} processed")
user = User.objects.get_or_create(
username=result[0]
)[0]
user.last_name = result[2]
user.first_name = result[2]
user.email = result[3]
appusers = result[4].split(";;;")
user_teams = []
company_team = None
for tmp in appusers:
if "§§15§§" not in tmp:
continue
contents = tmp.split("§§")
_type = contents[2]
_org = contents[3]
ets_id = "20"
zb_id = "26"
is_type_ets = _type == ets_id
is_type_zb = _type == zb_id
if not _type or not _org:
# broken - unusable
continue
try:
if is_type_zb:
_org = KonovaCode.objects.get(
atom_id=_org,
code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID]
)
team = self._get_team_from_responsible_code(responsible_code=_org, prefix="ZB")
user_teams.append(team)
elif is_type_ets:
_org = KonovaCode.objects.get(
atom_id=_org,
code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID]
)
team = self._get_team_from_responsible_code(responsible_code=_org, prefix="ETS")
user_teams.append(team)
else:
_org = result[5]
if company_team is None:
company_team = self._get_team(_org)
except ObjectDoesNotExist:
# organisation code might not be valid anymore
continue
if company_team is not None and len(user_teams) == 0:
# Only team is the company team
company_team.users.add(user)
else:
if company_team is not None:
company_team.delete()
for team in user_teams:
team.users.add(user)
num_processed += 1
cursor.close()

View File

@ -2,6 +2,7 @@ from konova.management.commands.kspMigrater.compensation_migrater import Compens
from konova.management.commands.kspMigrater.eco_account_migrater import EcoAccountMigrater from konova.management.commands.kspMigrater.eco_account_migrater import EcoAccountMigrater
from konova.management.commands.kspMigrater.ema_migrater import EmaMigrater from konova.management.commands.kspMigrater.ema_migrater import EmaMigrater
from konova.management.commands.kspMigrater.intervention_migrater import InterventionMigrater from konova.management.commands.kspMigrater.intervention_migrater import InterventionMigrater
from konova.management.commands.kspMigrater.user_migrater import UserMigrater
from konova.management.commands.setup import BaseKonovaCommand from konova.management.commands.setup import BaseKonovaCommand
@ -20,7 +21,8 @@ class Command(BaseKonovaCommand):
#InterventionMigrater(options), #InterventionMigrater(options),
#CompensationMigrater(options), #CompensationMigrater(options),
#EmaMigrater(options), #EmaMigrater(options),
EcoAccountMigrater(options), #EcoAccountMigrater(options),
UserMigrater(options),
] ]
for migrater in migraters: for migrater in migraters:
migrater.migrate() migrater.migrate()

View File

@ -74,6 +74,9 @@ class TeamAdmin(admin.ModelAdmin):
"name", "name",
"description", "description",
] ]
filter_horizontal = [
"users"
]
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)