Dette prosjektet er en Python-basert applikasjon som implementerer et skrivebords-grensesnitt (GUI) forNikita Noark5 Coreved hjelp avGTK4ogLibadwaita. Klienten tilbyr moderne GNOME-design og lar brukeren utføre sentrale arkivfunksjoner mot en Noark 5-kjerne. Funksjonalitet Applikasjonen dekker følgende hovedfunksjoner i Noark5-kjernen:
* Autentisering via OAuth2 (Keycloak):Ved oppstart kan brukeren logge inn gjennom et nettleserbasert Keycloak-vindu. Klienten håndterer deretter OAuth2-tokenet for videre bruk.
* Liste journalposter:Viser en liste over eksisterende journalposter (GET/arkivstruktur/journalpost).
* Opprett journalpost:Lar brukeren registrere en ny journalpost (POST/arkivstruktur/journalpost), med tittel og standard type.
* Laste opp dokument:Gir mulighet til å laste opp dokumentfiler til en valgt journalpost (POST/arkivstruktur/journalpost/{id}/dokumenter). Denne funksjonen korresponderer med dokumenthåndtering i Noark (f.eks. "Last opp dokumenter"). Klienten benytter API-endepunktene i Nikita Noark5 Core og forutsetter at disse er tilgjengelige med gyldige rettigheter for den innloggede brukeren. Teknologier og rammeverk
* GTK4 & Libadwaita:Brukes for å bygge et moderne og responsivt GUI i tråd med GNOMEs Human Interface Guidelines.
* PyGObject:Python-bindingene mot GTK4 benyttes for å lage vinduer, dialoger og komponenter.
* Requests + OAuthlib:For kommunikasjon med Noark5 Core REST-APIet og håndtering av OAuth2-autentisering (Keycloak). Prosjektet brukerrequests-oauthlibtil innlogging via nettleser og token-håndtering. Installasjon og kjøring Kjøring med Flatpak Prosjektet er satt opp for Flatpak-distribusjon. For å bygge og kjøre applikasjonen via Flatpak, gjør følgende:
1. Bygg Flatpak-pakken:Naviger til prosjektmappen og kjør: flatpak-builder --user --install build-dir flatpak-manifest.yml Dette vil bygge applikasjonen og installere den for gjeldende bruker (forutsetter at Flatpak og Flatpak Builder er installert).
2. Start applikasjonen:Kjør applikasjonen via Flatpak: flatpak run org.demo.NoarkClient Applikasjonen starter da opp. Ved første oppstart vil du bli bedt om å logge inn via nettleser. Kjøring utenfor Flatpak (utvikling) For å kjøre programmet direkte med Python (f.eks. under utvikling eller testing), trenger du å ha avhengigheter installert:
* Python 3.10+
* PyGObject (GTK4 og libadwaita bibliotekene) – kan installeres via ditt OS sin pakkehåndtering (f.eks.python3-gi,gir1.2-adw-1).
* requestsogrequests-oauthlib– kan installeres med pip: pip install -r requirements.txt Når avhengighetene er på plass, start programmet med: python3 main.py Brukerveiledning
1. Innlogging:Ved oppstart vil et påloggingsvindu vises. Klikk "Logg inn" for å åpne Keycloak-pålogging i nettleseren. Logg inn med dine brukeropplysninger. Etter vellykket innlogging lukkes nettleservinduet, og applikasjonen mottar et tilgangstoken automatisk.
2. Hente journalposter:Etter innlogging vises hovedvinduet med en liste over journalposter hentet fra Noark5. Klikk på "Oppdater" (🔄) om du ønsker å hente listen på nytt fra serveren.
3. Opprette ny journalpost:Klikk på "Ny journalpost". Skriv inn en tittel for den nye journalposten i dialogen som dukker opp, og bekreft. Den nye posten opprettes i Noark5-kjernen via API-et og vil deretter dukke opp i listen.
4. Laste opp dokument:Velg først en journalpost fra listen. Klikk deretter på "Last opp dokument" og velg en fil fra filsystemet i filvelger-dialogen. Filen lastes opp og knyttes til den valgte journalposten på serveren. (Merk: Avhengig av implementasjon av Noark5-APIet kan det hende at opplastet dokument ikke påvirker listevisningen før man evt. oppdaterer visningen.) Prosjektstruktur Kildekoden er organisert i henhold til MVC-prinsipper for klar separasjon:
* views/****:Inneholder GUI-komponenter (vinduer og dialoger). F.eks. hovedvinduet og dialoger for innlogging og ny journalpost.
* services/****:Inneholder logikk for kommunikasjon med eksterne tjenester. Her ligger f.eks.auth_service.pyfor autentisering mot Keycloak ognoark_service.pyfor kall mot Noark5 Core API (GET/POST forespørsler).
* utils/****:Diverse hjelpefunksjoner og konfigurasjon. Bl.a. konstanter for oppsett (f.eks. endepunkts-URLer og klient-ID for OAuth) iconfig.py.
* Hovedskript (main.py):Starter applikasjonen og binder sammen grensesnittet med tjenestekallene. Prosjektet inkluderer også konfigurasjonsfiler for Flatpak:
* flatpak-manifest.yml****:Oppskrift for å bygge applikasjonen i Flatpak, inkludert nødvendig runtime (org.gnome.Platform) og avhengigheter.
* Desktop-oppføring (org.demo.NoarkClient.desktop):Slik at applikasjonen får en oppføring med ikon og kan lanseres fra skrivebordsmiljøer. Konfigurasjon Vær oppmerksom på at du kan trenge å angi riktige URL-er og innstillinger for Keycloak og Noark5 Core før kjøring:
* Iutils/config.pykan du oppdatere konstanter somKEYCLOAK_SERVER_URL,REALM,CLIENT_IDsamtNOARK_BASE_URLslik at de peker på riktig autentiseringsserver og API-endepunkt for din Noark5 Core-instans. Som standard forventer klienten at Keycloak utsteder et OAuth2-token for enpublic client(uten klienthemmelighet), og at redirect-URI er satt tilhttp://localhost:8000/callbacki Keycloak-oppsettet. Sørg for at disse innstillingene er korrekt konfigurert i Keycloak før bruk. Når alt er konfigurert og applikasjonen kjører, skal den sømløst kunne autentisere mot Nikita Noark5 Core og gi deg et brukervennlig vindu for å registrere og hente ut journalposter, samt laste opp dokumenter knyttet til disse. Nedlasting av prosjektet Du kan laste ned hele prosjektmappen som en ZIP-fil fra https://www.aamot.io/software/gnome-noark5-client/gnome-noark5-client-0.0.0.zip GNOME Noark5 Client – Fullstendig Python-program Struktur Prosjektet er strukturert som følger: gnome-noark5-client/ ├── main.py ├── views/ │ ├── main_window.py │ └── login_window.py ├── services/ │ ├── auth_service.py │ └── noark_service.py ├── utils/ │ └── config.py ├── flatpak-manifest.yml ├── org.demo.NoarkClient.desktop └── requirements.txt main.py import gi import sys
gi.require_version("Gtk", "4.0") from gi.repository import Gtk
from views.main_window import MainWindow
class NoarkApp(Gtk.Application): def __init__(self): super().__init__(application_id="org.demo.NoarkClient")
def do_activate(self): win = MainWindow(self) win.present()
app = NoarkApp() app.run(sys.argv) views/main_window.py import gi from gi.repository import Gtk from services.noark_service import get_journalposter, create_journalpost, upload_document from views.login_window import LoginWindow
class MainWindow(Gtk.ApplicationWindow): def __init__(self, app): super().__init__(application=app) self.set_title("Noark5 Journalposter") self.set_default_size(800, 600)
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(self.box)
self.header = Gtk.HeaderBar() self.set_titlebar(self.header)
self.button_refresh = Gtk.Button(label="🔄") self.button_refresh.connect("clicked", self.load_data) self.header.pack_start(self.button_refresh)
self.button_new = Gtk.Button(label="Ny journalpost") self.button_new.connect("clicked", self.new_journalpost) self.header.pack_end(self.button_new)
self.button_upload = Gtk.Button(label="Last opp dokument") self.button_upload.connect("clicked", self.upload_to_selected) self.header.pack_end(self.button_upload)
self.liststore = Gtk.ListStore(str, str, str) self.treeview = Gtk.TreeView(model=self.liststore)
for i, title in enumerate(["ID", "Tittel", "Dato"]): renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(title, renderer, text=i) self.treeview.append_column(column)
scrolled = Gtk.ScrolledWindow() scrolled.set_child(self.treeview) self.box.append(scrolled)
self.load_data()
def load_data(self, *_): self.liststore.clear() for jp in get_journalposter(): self.liststore.append([jp.get("systemID", ""), jp.get("tittel", ""), jp.get("opprettetDato", "")])
def new_journalpost(self, *_): dialog = Gtk.MessageDialog(modal=True, text="Ny journalpost-tittel:") entry = Gtk.Entry() dialog.get_content_area().append(entry) dialog.add_button("Opprett", Gtk.ResponseType.OK) dialog.add_button("Avbryt", Gtk.ResponseType.CANCEL) response = dialog.run() if response == Gtk.ResponseType.OK: create_journalpost(entry.get_text()) self.load_data() dialog.destroy()
def upload_to_selected(self, *_): selection = self.treeview.get_selection() model, iter = selection.get_selected() if iter: journal_id = model[iter][0] dialog = Gtk.FileChooserDialog("Velg fil", self, Gtk.FileChooserAction.OPEN, ("Avbryt", Gtk.ResponseType.CANCEL, "Åpne", Gtk.ResponseType.OK)) response = dialog.run() if response == Gtk.ResponseType.OK: upload_document(journal_id, dialog.get_file().get_path()) dialog.destroy() views/login_window.py import webbrowser from utils.config import AUTH_URL
class LoginWindow: def __init__(self): webbrowser.open(AUTH_URL) services/auth_service.py from requests_oauthlib import OAuth2Session from utils.config import CLIENT_ID, AUTHORIZATION_BASE_URL, TOKEN_URL, REDIRECT_URI
session = OAuth2Session(CLIENT_ID, redirect_uri=REDIRECT_URI) auth_url, state = session.authorization_url(AUTHORIZATION_BASE_URL) print("Åpne følgende URL i nettleser:", auth_url)
# Forenklet flyt redirect_response = input("Lim inn redirect-URL her: ") token = session.fetch_token(TOKEN_URL, authorization_response=redirect_response) services/noark_service.py import requests from utils.config import NOARK_BASE_URL, ACCESS_TOKEN
def get_journalposter(): response = requests.get(f"{NOARK_BASE_URL}/arkivstruktur/journalpost", headers={"Authorization": f"Bearer {ACCESS_TOKEN}"}) return response.json().get("_entries", [])
def create_journalpost(tittel): payload = {"tittel": tittel, "dokumentType": "generell"} requests.post(f"{NOARK_BASE_URL}/arkivstruktur/journalpost", json=payload, headers={"Authorization": f"Bearer {ACCESS_TOKEN}"})
def upload_document(journal_id, filepath): with open(filepath, "rb") as f: files = {"file": (filepath, f)} requests.post(f"{NOARK_BASE_URL}/arkivstruktur/journalpost/{journal_id}/dokumenter", files=files, headers={"Authorization": f"Bearer {ACCESS_TOKEN}"}) utils/config.py CLIENT_ID = "noark-client" REDIRECT_URI = "http://localhost:8000/callback" AUTHORIZATION_BASE_URL = "http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth" TOKEN_URL = "http://localhost:8080/auth/realms/demo/protocol/openid-connect/token" AUTH_URL = AUTHORIZATION_BASE_URL ACCESS_TOKEN = "sett_din_token_her" # Midlertidig hardkodet NOARK_BASE_URL = "http://localhost:8080/noark5/v1" requirements.txt PyGObject requests requests-oauthlib flatpak-manifest.yml app-id: org.demo.NoarkClient runtime: org.gnome.Platform runtime-version: '48' command: main.py modules: - name: noark-client buildsystem: simple build-commands: - pip3 install --prefix=/app -r requirements.txt sources: - type: dir path: . Mvh, Ole Aamot