469 lines
14 KiB
Python
469 lines
14 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import dataclass, field
|
|
from enum import Enum
|
|
from typing import Any, Optional, Union
|
|
|
|
import regex
|
|
|
|
from src.core.semester import Semester
|
|
|
|
|
|
@dataclass
|
|
class Prof:
|
|
id: int | None = None
|
|
_title: str | None = None
|
|
firstname: str | None = None
|
|
lastname: str | None = None
|
|
fullname: str | None = None
|
|
mail: str | None = None
|
|
telnr: str | None = None
|
|
|
|
# add function that sets the data based on a dict
|
|
def from_dict(self, data: dict[str, Union[str, int]]):
|
|
for key, value in data.items():
|
|
if hasattr(self, key):
|
|
setattr(self, key, value)
|
|
return self
|
|
|
|
@property
|
|
def title(self) -> str:
|
|
if self._title is None or self._title == "None":
|
|
return ""
|
|
return self._title
|
|
|
|
@title.setter
|
|
def title(self, value: str):
|
|
self._title = value
|
|
|
|
# add function that sets the data from a tuple
|
|
def from_tuple(self, data: tuple[Union[str, int], ...]) -> Prof:
|
|
self.id = data[0]
|
|
self._title = data[1]
|
|
self.firstname = data[2]
|
|
self.lastname = data[3]
|
|
self.fullname = data[4]
|
|
self.mail = data[5]
|
|
self.telnr = data[6]
|
|
return self
|
|
|
|
def name(self, comma: bool = False) -> Optional[str]:
|
|
if self.firstname is None and self.lastname is None:
|
|
if "," in self.fullname:
|
|
self.firstname = self.fullname.split(",")[1].strip()
|
|
self.lastname = self.fullname.split(",")[0].strip()
|
|
else:
|
|
return self.fullname
|
|
|
|
if comma:
|
|
return f"{self.lastname}, {self.firstname}"
|
|
return f"{self.lastname} {self.firstname}"
|
|
|
|
|
|
@dataclass
|
|
class BookData:
|
|
ppn: str | None = None
|
|
title: str | None = None
|
|
signature: str | None = None
|
|
edition: str | None = None
|
|
link: str | None = None
|
|
isbn: Union[str, list[str], None] = field(default_factory=list)
|
|
author: str | None = None
|
|
language: Union[str, list[str], None] = field(default_factory=list)
|
|
publisher: str | None = None
|
|
place: str | None = None
|
|
year: int | None = None
|
|
pages: str | None = None
|
|
library_location: str | None = None
|
|
in_apparat: bool | None = False
|
|
adis_idn: str | None = None
|
|
old_book: Any | None = None
|
|
media_type: str | None = None
|
|
in_library: bool | None = None # whether the book is in the library or not
|
|
medianr: int | None = None # Media number in the library system
|
|
|
|
def __post_init__(self):
|
|
self.library_location = (
|
|
str(self.library_location) if self.library_location else None
|
|
)
|
|
if isinstance(self.language, list) and self.language:
|
|
self.language = [lang.strip() for lang in self.language if lang.strip()]
|
|
self.language = ",".join(self.language)
|
|
self.year = regex.sub(r"[^\d]", "", str(self.year)) if self.year else None
|
|
self.in_library = True if self.signature else False
|
|
|
|
def from_dict(self, data: dict) -> BookData:
|
|
for key, value in data.items():
|
|
setattr(self, key, value)
|
|
return self
|
|
|
|
def merge(self, other: BookData) -> BookData:
|
|
for key, value in other.__dict__.items():
|
|
# merge lists, if the attribute is a list, extend it
|
|
if isinstance(value, list):
|
|
current_value = getattr(self, key)
|
|
if current_value is None:
|
|
current_value = []
|
|
elif not isinstance(current_value, list):
|
|
current_value = [current_value]
|
|
# extend the list with the new values, but only if they are not already in the list
|
|
for v in value:
|
|
if v not in current_value:
|
|
current_value.append(v)
|
|
setattr(self, key, current_value)
|
|
if value is not None and (
|
|
getattr(self, key) is None or getattr(self, key) == ""
|
|
):
|
|
setattr(self, key, value)
|
|
# in language, drop all entries that are longer than 3 characters
|
|
if isinstance(self.language, list):
|
|
self.language = [lang for lang in self.language if len(lang) <= 4]
|
|
return self
|
|
|
|
@property
|
|
def to_dict(self) -> str:
|
|
"""Convert the dataclass to a dictionary."""
|
|
data_dict = {
|
|
key: value for key, value in self.__dict__.items() if value is not None
|
|
}
|
|
# remove old_book from data_dict
|
|
if "old_book" in data_dict:
|
|
del data_dict["old_book"]
|
|
return json.dumps(data_dict, ensure_ascii=False)
|
|
|
|
def from_dataclass(self, dataclass: Optional[Any]) -> None:
|
|
if dataclass is None:
|
|
return
|
|
for key, value in dataclass.__dict__.items():
|
|
setattr(self, key, value)
|
|
|
|
def get_book_type(self) -> str:
|
|
if "Online" in self.pages:
|
|
return "eBook"
|
|
return "Druckausgabe"
|
|
|
|
def from_string(self, data: str) -> BookData:
|
|
ndata = json.loads(data)
|
|
|
|
return BookData(**ndata)
|
|
|
|
def from_LehmannsSearchResult(self, result: Any) -> BookData:
|
|
self.title = result.title
|
|
self.author = "; ".join(result.authors) if result.authors else None
|
|
self.edition = str(result.edition) if result.edition else None
|
|
self.link = result.url
|
|
self.isbn = (
|
|
result.isbn13
|
|
if isinstance(result.isbn13, list)
|
|
else [result.isbn13]
|
|
if result.isbn13
|
|
else []
|
|
)
|
|
self.pages = str(result.pages) if result.pages else None
|
|
self.publisher = result.publisher
|
|
self.year = str(result.year) if result.year else None
|
|
# self.pages = str(result.pages) if result.pages else None
|
|
return self
|
|
|
|
@property
|
|
def edition_number(self) -> Optional[int]:
|
|
if self.edition is None:
|
|
return 0
|
|
match = regex.search(r"(\d+)", self.edition)
|
|
if match:
|
|
return int(match.group(1))
|
|
return 0
|
|
|
|
|
|
@dataclass
|
|
class MailData:
|
|
subject: str | None
|
|
body: str | None
|
|
mailto: str | None
|
|
prof: str | None
|
|
|
|
|
|
class Subjects(Enum):
|
|
BIOLOGY = (1, "Biologie")
|
|
CHEMISTRY = (2, "Chemie")
|
|
GERMAN = (3, "Deutsch")
|
|
ENGLISH = (4, "Englisch")
|
|
PEDAGOGY = (5, "Erziehungswissenschaft")
|
|
FRENCH = (6, "Französisch")
|
|
GEOGRAPHY = (7, "Geographie")
|
|
HISTORY = (8, "Geschichte")
|
|
HEALTH_EDUCATION = (9, "Gesundheitspädagogik")
|
|
HTW = (10, "Haushalt / Textil")
|
|
ART = (11, "Kunst")
|
|
MATH_IT = (12, "Mathematik / Informatik")
|
|
MEDIAPEDAGOGY = (13, "Medien in der Bildung")
|
|
MUSIC = (14, "Musik")
|
|
PHILOSOPHY = (15, "Philosophie")
|
|
PHYSICS = (16, "Physik")
|
|
POLITICS = (17, "Politikwissenschaft")
|
|
PRORECTORATE = (18, "Prorektorat Lehre und Studium")
|
|
PSYCHOLOGY = (19, "Psychologie")
|
|
SOCIOLOGY = (20, "Soziologie")
|
|
SPORT = (21, "Sport")
|
|
TECHNIC = (22, "Technik")
|
|
THEOLOGY = (23, "Theologie")
|
|
ECONOMICS = (24, "Wirtschaftslehre")
|
|
|
|
@property
|
|
def id(self) -> int:
|
|
return self.value[0]
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return self.value[1]
|
|
|
|
@classmethod
|
|
def get_index(cls, name: str) -> Optional[int]:
|
|
for i in cls:
|
|
if i.name == name:
|
|
return i.id - 1
|
|
return None
|
|
|
|
|
|
@dataclass
|
|
class Apparat:
|
|
id: int | None = None
|
|
name: str | None = None
|
|
prof_id: int | None = None
|
|
subject: str | None = None
|
|
appnr: int | None = None
|
|
created_semester: str | None = None
|
|
extended_at: str | None = None
|
|
eternal: bool = False
|
|
extend_until: str | None = None
|
|
deleted: int | None = None
|
|
deleted_date: str | None = None
|
|
apparat_id_adis: str | None = None
|
|
prof_id_adis: str | None = None
|
|
konto: int | None = None
|
|
|
|
def from_tuple(self, data: tuple[Any, ...]) -> Apparat:
|
|
self.id = data[0]
|
|
self.name = data[1]
|
|
self.prof_id = data[2]
|
|
self.subject = data[3]
|
|
self.appnr = data[4]
|
|
self.created_semester = data[5]
|
|
self.extended_at = data[6]
|
|
self.eternal = data[7]
|
|
self.extend_until = data[8]
|
|
self.deleted = data[9]
|
|
self.deleted_date = data[10]
|
|
self.apparat_id_adis = data[11]
|
|
self.prof_id_adis = data[12]
|
|
self.konto = data[13]
|
|
return self
|
|
|
|
@property
|
|
def get_semester(self) -> Optional[str]:
|
|
if self.extend_until is not None:
|
|
return self.extend_until
|
|
return self.created_semester
|
|
|
|
|
|
@dataclass
|
|
class ELSA:
|
|
id: int | None = None
|
|
date: str | None = None
|
|
semester: str | None = None
|
|
prof_id: int | None = None
|
|
|
|
def from_tuple(self, data: tuple[Any, ...]) -> ELSA:
|
|
self.id = data[0]
|
|
self.date = data[1]
|
|
self.semester = data[2]
|
|
self.prof_id = data[3]
|
|
return self
|
|
|
|
|
|
@dataclass
|
|
class ApparatData:
|
|
prof: Prof = field(default_factory=Prof)
|
|
apparat: Apparat = field(default_factory=Apparat)
|
|
|
|
|
|
@dataclass
|
|
class XMLMailSubmission:
|
|
name: str | None
|
|
lastname: str | None
|
|
title: str | None
|
|
telno: int | None
|
|
email: str | None
|
|
app_name: str | None
|
|
subject: str | None
|
|
semester: Semester | None
|
|
books: list[BookData] | None
|
|
|
|
|
|
@dataclass
|
|
class Book:
|
|
author: str | None
|
|
year: str | None
|
|
edition: str | None
|
|
title: str | None
|
|
location: str | None
|
|
publisher: str | None
|
|
signature: str | None
|
|
internal_notes: str | None
|
|
|
|
@property
|
|
def has_signature(self) -> bool:
|
|
return self.signature is not None and self.signature != ""
|
|
|
|
@property
|
|
def is_empty(self) -> bool:
|
|
return all(
|
|
[
|
|
self.author == "",
|
|
self.year == "",
|
|
self.edition == "",
|
|
self.title == "",
|
|
self.location == "",
|
|
self.publisher == "",
|
|
self.signature == "",
|
|
self.internal_notes == "",
|
|
],
|
|
)
|
|
|
|
def from_dict(self, data: dict[str, Any]):
|
|
for key, value in data.items():
|
|
value = value.strip()
|
|
if value == "\u2002\u2002\u2002\u2002\u2002":
|
|
value = ""
|
|
|
|
if key == "Autorenname(n):Nachname, Vorname":
|
|
self.author = value
|
|
elif key == "Jahr/Auflage":
|
|
self.year = value.split("/")[0] if "/" in value else value
|
|
self.edition = value.split("/")[1] if "/" in value else ""
|
|
elif key == "Titel":
|
|
self.title = value
|
|
elif key == "Ort und Verlag":
|
|
self.location = value.split(",")[0] if "," in value else value
|
|
self.publisher = value.split(",")[1] if "," in value else ""
|
|
elif key == "Standnummer":
|
|
self.signature = value.strip()
|
|
elif key == "Interne Vermerke":
|
|
self.internal_notes = value
|
|
|
|
|
|
@dataclass
|
|
class SemapDocument:
|
|
subject: str | None
|
|
phoneNumber: int | None
|
|
mail: str | None
|
|
title: str | None
|
|
personName: str | None
|
|
personTitle: str | None
|
|
title_suggestions: list[str] = None
|
|
semester: Union[str, Semester] = None
|
|
books: list[Book] = None
|
|
eternal: bool = False
|
|
title_length: int = 0
|
|
title_max_length: int = 0
|
|
|
|
def __post_init__(self) -> None:
|
|
"""."""
|
|
self.title_suggestions = []
|
|
self.phoneNumber = int(
|
|
regex.sub(r"[^\d]", "", str(self.phoneNumber)),
|
|
)
|
|
|
|
@property
|
|
def nameSetter(self):
|
|
from src.services.openai import name_tester, run_shortener
|
|
|
|
data = name_tester(self.personTitle)
|
|
name = f"{data['last_name']}, {data['first_name']}"
|
|
if data["title"] is not None:
|
|
title = data["title"]
|
|
self.personTitle = title
|
|
self.personName = name
|
|
self.title_length = len(self.title) + 3 + len(self.personName.split(",")[0])
|
|
if self.title_length > 40:
|
|
name_len = len(self.personName.split(",")[0])
|
|
self.title_max_length = 38 - name_len
|
|
suggestions = run_shortener(self.title, self.title_max_length)
|
|
for suggestion in suggestions:
|
|
self.title_suggestions.append(suggestion["shortened_string"])
|
|
else:
|
|
self.title_suggestions = []
|
|
|
|
@property
|
|
def renameSemester(self) -> None:
|
|
from src.services.openai import semester_converter
|
|
|
|
if self.semester:
|
|
if ", Dauer" in self.semester:
|
|
self.semester = self.semester.split(",")[0]
|
|
self.eternal = True
|
|
self.semester = Semester().from_string(self.semester)
|
|
else:
|
|
self.semester = Semester().from_string(
|
|
semester_converter(self.semester),
|
|
)
|
|
|
|
@property
|
|
def signatures(self) -> list[str]:
|
|
if self.books is not None:
|
|
return [book.signature for book in self.books if book.has_signature]
|
|
return []
|
|
|
|
|
|
@dataclass
|
|
class ELSA_Mono:
|
|
authorName: str
|
|
year: int
|
|
signature: str
|
|
page_from: int
|
|
page_to: int
|
|
edition: str | None = None
|
|
|
|
|
|
@dataclass
|
|
class ELSA_Journal:
|
|
authorName: str
|
|
year: int
|
|
issue: str
|
|
page_from: int
|
|
page_to: int
|
|
journal_title: str
|
|
article_title: str
|
|
signature: str
|
|
|
|
|
|
@dataclass
|
|
class Person:
|
|
firstName: str
|
|
lastName: str
|
|
personTitle: str | None = None
|
|
|
|
@property
|
|
def fullName_LNFN(self) -> str:
|
|
return f"{self.lastName}, {self.firstName}"
|
|
|
|
|
|
@dataclass
|
|
class ELSA_Editorial:
|
|
# TODO: add dataclass fields
|
|
pass
|
|
|
|
|
|
@dataclass
|
|
class ELSADocument:
|
|
mail: str = None
|
|
personTitle: str = None
|
|
personName: Optional[str] = None
|
|
|
|
def __post_init__(self) -> None:
|
|
"""."""
|
|
self.mail = self.mail.strip() if self.mail else None
|
|
self.personTitle = self.personTitle.strip() if self.personTitle else None
|
|
self.personName = self.personName.strip() if self.personName else None
|