Skip to content

Commit

Permalink
Merge pull request #804 from kbevers/fire-sag-forbedring
Browse files Browse the repository at this point in the history
Forbedring af sagsopslag med `fire info`
  • Loading branch information
kbevers authored Jan 27, 2025
2 parents 95209a7 + e61571f commit 057bf42
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 16 deletions.
25 changes: 16 additions & 9 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,28 @@ jobs:
cd /opt/oracle
# Download links findes her: https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html
wget -nv https://download.oracle.com/otn_software/linux/instantclient/2340000/instantclient-basic-linux.x64-23.4.0.24.05.zip
wget -nv https://download.oracle.com/otn_software/linux/instantclient/2340000/instantclient-sqlplus-linux.x64-23.4.0.24.05.zip
wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip
wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sqlplus-linuxx64.zip
unzip -o instantclient-basic-linux.x64-23.4.0.24.05.zip
unzip -o instantclient-sqlplus-linux.x64-23.4.0.24.05.zip
unzip -o instantclient-basic-linuxx64.zip
unzip -o instantclient-sqlplus-linuxx64.zip
ls -la /opt/oracle/instantclient_23_4
# Oracle koder versionsnummeret ind i mappenavnet, fx "instantclient_23_6", selv når man henter "latest"-pakken
# Derfor omdøbes den som første skridt herunder.
mv instantclient_* instantclient
ls -la /opt/oracle/instantclient
sudo apt-get install libaio1
sudo apt-get install libaio1t64
# Ubuntu har med version 24.04 ændret navnet på libaio1 pakken og tilhørende .so-fil.
# Det har Oracle selvfølgelig ikke lige taget højde for, så vi hjælper lidt ved at pege
# et symlink i retning af den nye .so-fil.
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1
sudo sh -c "echo /opt/oracle/instantclient_23_4 > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo sh -c "echo /opt/oracle/instantclient > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
export LD_LIBRARY_PATH=/opt/oracle/instantclient_23_4:$LD_LIBRARY_PATH
export PATH=/opt/oracle/instantclient_23_4:$PATH
export LD_LIBRARY_PATH=/opt/oracle/instantclient:$LD_LIBRARY_PATH
export PATH=/opt/oracle/instantclient:$PATH
# Gem miljøvariable til brug i de følgende trin
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> "$GITHUB_ENV"
Expand Down
4 changes: 4 additions & 0 deletions docs/apps/info.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ typer indhold i FIRE databasen.
:prog: fire info sag
:nested: full

.. click:: fire.cli.info:sagsevent
:prog: fire info sagsevent
:nested: full

.. click:: fire.cli.info:srid
:prog: fire info srid
:nested: full
Expand Down
13 changes: 13 additions & 0 deletions fire/api/firedb/hent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from fire.api.firedb.base import FireDbBase
from fire.api.model import (
Sag,
Sagsevent,
Punkt,
PunktSamling,
PunktInformation,
Expand Down Expand Up @@ -213,6 +214,18 @@ def hent_sag(self, sagsid: str) -> Sag:
"""
return self.session.query(Sag).filter(Sag.id.ilike(f"{sagsid}%")).one()

def hent_sagsevent(self, sagseventid: str) -> Sagsevent:
"""
Hent et sagsevent ud fra dens sagseventid.
Sagseventid'er behøver ikke være fuldstændige, funktionen forsøger at matche
partielle sagseventid'er i samme stil som git håndterer commit hashes. I
tilfælde af at søgningen med et partielt sagseventid resulterer i flere
matches udsendes en sqlalchemy.orm.exc.MultipleResultsFound exception.
"""
return self.session.query(Sagsevent).filter(Sagsevent.id.ilike(f"{sagseventid}%")).one()


def hent_alle_sager(self, aktive=True) -> List[Sag]:
"""
Henter alle sager fra databasen.
Expand Down
2 changes: 2 additions & 0 deletions fire/api/model/sagstyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ class Sagsevent(RegisteringFraObjekt):

@property
def beskrivelse(self) -> str:
if not self.sagseventinfos:
return ""
if self.sagseventinfos[-1].beskrivelse is None:
return ""
return self.sagseventinfos[-1].beskrivelse
Expand Down
213 changes: 206 additions & 7 deletions fire/cli/info.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import datetime
import io
import itertools
import re
import textwrap
from typing import List
import zipfile

import click
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
from sqlalchemy import not_, or_
from pyproj import CRS
from pyproj.exceptions import CRSError

import fire.cli
from fire.ident import klargør_ident_til_søgning
from fire.api.model import (
EventType,
Punkt,
PunktInformation,
PunktInformationType,
Expand All @@ -21,6 +25,7 @@
Boolean,
Srid,
Tidsserie,
Grafik,
)


Expand Down Expand Up @@ -271,7 +276,12 @@ def punktsamlingsrapport(punktsamlinger: list[PunktSamling], id: str = None):
"""
Hjælpefunktion for funktionerne punkt_fuld_rapport og punktsamling.
"""
kolonnebredder = (34, 11, 13, 16,)
kolonnebredder = (
34,
11,
13,
16,
)
kolonnenavne = ("Navn", "Jessenpunkt", "Antal punkter", "Antal tidsserier")
header = " ".join([str(n).ljust(w) for n, w in zip(kolonnenavne, kolonnebredder)])
subheader = " ".join(["-" * w for w in kolonnebredder])
Expand All @@ -287,10 +297,18 @@ def punktsamlingsrapport(punktsamlinger: list[PunktSamling], id: str = None):
if ps.jessenpunkt.id == id:
farve = "green"

kolonner = [ps.navn, ps.jessenpunkt.jessennummer, len(ps.punkter), len(ps.tidsserier)]
kolonner = [
ps.navn,
ps.jessenpunkt.jessennummer,
len(ps.punkter),
len(ps.tidsserier),
]

linje = " ".join(
[textwrap.shorten(str(c), width=w, placeholder="...").ljust(w) for c, w in zip(kolonner, kolonnebredder)]
[
textwrap.shorten(str(c), width=w, placeholder="...").ljust(w)
for c, w in zip(kolonner, kolonnebredder)
]
)
fire.cli.print(linje, fg=farve)

Expand All @@ -316,11 +334,16 @@ def tidsserietype(tstype):
return "Højde"

for ts in tidsserier:
navn_ombrudt = textwrap.wrap(str(ts.navn),kolonnebredder[0])
navn_ombrudt = textwrap.wrap(str(ts.navn), kolonnebredder[0])
for navn_del in navn_ombrudt[:-1]:
fire.cli.print(navn_del)

kolonner = [navn_ombrudt[-1], len(ts), tidsserietype(ts.tstype), ts.referenceramme]
kolonner = [
navn_ombrudt[-1],
len(ts),
tidsserietype(ts.tstype),
ts.referenceramme,
]

linje = " ".join([str(c).ljust(w) for c, w in zip(kolonner, kolonnebredder)])
fire.cli.print(linje)
Expand Down Expand Up @@ -734,12 +757,18 @@ def sag(sagsid: str, **kwargs):
for sagsevent in sag.sagsevents:
try:
beskrivelse = sagsevent.beskrivelse
max_beskrivelseslængde = 40
if len(beskrivelse) > max_beskrivelseslængde:
beskrivelse = beskrivelse[0:max_beskrivelseslængde] + "..."

except IndexError:
beskrivelse = ""
eventtype = (
str(sagsevent.eventtype).replace("EventType.", "").replace("OE", "Ø")
)
fire.cli.print(f"[{sagsevent.registreringfra}] {eventtype}: {beskrivelse}")
tid = sagsevent.registreringfra.strftime("%Y-%m-%d")
sagseventid = sagsevent.id[0:8]
fire.cli.print(f"[{tid}|{sagseventid}] {eventtype}: {beskrivelse}")

return

Expand All @@ -751,6 +780,176 @@ def sag(sagsid: str, **kwargs):
fire.cli.print(f"{sag.id[0:8]}: {sag.behandler:20}{beskrivelse}...")


@info.command()
@fire.cli.default_options()
@click.argument("sagseventid", required=True)
def sagsevent(sagseventid: str, **kwargs) -> None:
"""
Information om et sagsevent.
"""

# Hver type FikspunktsregisterObjekt kan tilknyttes to slags Sagsevents,
# oprettelse og nedlukning. De skal præsenteres på omtrent samme måde.
# Nedenstående interne funktioner benyttes til dette.
def _koordinatoversigt(koordinater: list[Koordinat]) -> None:
for koordinat in koordinater:
fire.cli.print(f"{koordinat.punkt.ident:14} {koordinat_linje(koordinat)}")
fire.cli.print("\n")

def _observationsoversigt(observationer: list[Observation]) -> None:
niv_obstyper = (1, 2)
observationstyper = [o.observationstypeid for o in observationer]
ikke_niv_observationer = all(
obstype not in niv_obstyper for obstype in observationstyper
)
if ikke_niv_observationer:
fire.cli.print(
"Sagseventen indeholder observationer, der ikke er målt med nivellement."
)
fire.cli.print("Disse observationer kan på nuværende tidspunkt ikke vises.")
else:
observationsrapport(
observationer_til=observationer,
observationer_fra=[],
options="niv",
opt_detaljeret=False,
)

def _punktoversigt(punkter: list[Punkt]) -> None:
for punkt in punkter:
fire.cli.print(f" PUNKT {punkt.ident} ({punkt.id})", bold=True)
fire.cli.print(f" Lokation {punkt.geometriobjekter[-1].geometri}")
fire.cli.print("\n")

def _punktinfooversigt(
punktinformationer: list[PunktInformation], historik: bool
) -> None:
# PunktInformationer grupperes efter Punkt
punkter = set(punktinfo.punkt for punktinfo in punktinformationer)
punktinfo_oversigt = {punkt: [] for punkt in punkter}

for punktinfo in punktinformationer:
punktinfo_oversigt[punktinfo.punkt].append(punktinfo)

for punkt, punktinformationer in punktinfo_oversigt.items():
fire.cli.print(punkt.ident)
punktinforapport(punktinformationer, historik)
fire.cli.print("\n")

def _grafikoversigt(grafikker: list[Grafik]) -> None:
fire.cli.print(f"{'Filnavn':30} Type")
fire.cli.print(f"{'-'*29:30} --------------")

for grafik in grafikker:
fire.cli.print(f"{grafik.filnavn:30} {grafik.type}")

def _header(tekst: str, bold=False) -> None:
max_bredde = 80
spacer_bredde = (max_bredde - len(tekst) - 2) // 2 + 1
fire.cli.print(
f"{'-'*spacer_bredde} {tekst} {'-'*spacer_bredde}"[0:80], bold=bold
)

try:
event = fire.cli.firedb.hent_sagsevent(sagseventid)
except NoResultFound:
fire.cli.print(f'Fejl! "{sagseventid}" ikke fundet!', fg="red", err=True)
raise SystemExit(1) # pylint: disable=raise-missing-from
except MultipleResultsFound:
fire.cli.print(
f'Fejl! Partielt UUID "{sagseventid}" ikke unikt!', fg="red", err=True
)
raise SystemExit(1) # pylint: disable=raise-missing-from

fire.cli.print("\n")
_header("SAGSEVENT", bold=True)
fire.cli.print(f" Sagseventid : {event.id}")
fire.cli.print(f" Sagseventtype : {event.eventtype.name}")
fire.cli.print(f" Oprettet : {event.registreringfra}")
fire.cli.print(f" Sagsid : {event.sag.id}")
if len(event.beskrivelse) > 45:
fire.cli.print(" Beskrivelse :\n")
fire.cli.print(event.beskrivelse)
else:
fire.cli.print(f" Beskrivelse : {event.beskrivelse}")
fire.cli.print("\n")

if event.eventtype == EventType.KOMMENTAR:
materialer = [m.materiale for si in event.sagseventinfos for m in si.materialer]
htmler = [h.html for si in event.sagseventinfos for h in si.htmler]

if materialer:
_header("Tilknyttet sagsmateriale")
for materiale in materialer:
blob = io.BytesIO(materiale)
with zipfile.ZipFile(blob, "r") as zipped_files:
zipped_files.printdir()
fire.cli.print("\n")

if htmler:
_header("Tilknyttede HTML-filer")
for html in htmler:
match = re.search('<title>(.*?)</title>', html)
title = match.group(1) if match else 'Ingen HTML titel'
fire.cli.print(title)

if event.koordinater:
_header("Tilføjede koordinater")
_koordinatoversigt(event.koordinater)

if event.koordinater_slettede:
_header("Afregistrerede koordinater")
_koordinatoversigt(event.koordinater_slettede)

if event.observationer:
_header("Tilføjede observationer")
_observationsoversigt(event.observationer)

if event.observationer_slettede:
_header("Afregistrerede observationer")
_observationsoversigt(event.observationer_slettede)

if event.punktinformationer:
_header("Tilføjede punktinformationer")
_punktinfooversigt(event.punktinformationer, historik=False)

if event.punktinformationer_slettede:
_header("Afregistrerede punktinformationer")
_punktinfooversigt(event.punktinformationer_slettede, historik=True)

if event.punkter:
_header("Tilføjet punkt")
_punktoversigt(event.punkter)

if event.punkter_slettede:
_header("Afregistreret punkt")
_punktoversigt(event.punkter_slettede)

if event.grafikker:
_header("Tilføjet grafik")
_grafikoversigt(event.grafikker)

if event.grafikker_slettede:
_header("Afregistreret grafik")
_grafikoversigt(event.grafikker_slettede)

if event.punktsamlinger:
_header("Tilføjede punktsamlinger")
punktsamlingsrapport(event.punktsamlinger)

if event.punktsamlinger_slettede:
_header("Afregistrerede punktsamlinger")
punktsamlingsrapport(event.punktsamlinger_slettede)

if event.tidsserier:
_header("Tilføjede tidsserier")
tidsserierapport(event.tidsserier)

if event.tidsserier_slettede:
_header("Afregistrerede tidsserier")
tidsserierapport(event.tidsserier_slettede)


@info.command()
@fire.cli.default_options()
@click.argument("punktsamling", required=False)
Expand Down

0 comments on commit 057bf42

Please sign in to comment.