Merge branch 'dev'
This commit is contained in:
@@ -1,22 +0,0 @@
|
|||||||
[tool.bumpversion]
|
|
||||||
current_version = "0.2.1"
|
|
||||||
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
||||||
serialize = ["{major}.{minor}.{patch}"]
|
|
||||||
search = "{current_version}"
|
|
||||||
replace = "{new_version}"
|
|
||||||
regex = false
|
|
||||||
ignore_missing_version = false
|
|
||||||
ignore_missing_files = false
|
|
||||||
tag = true
|
|
||||||
sign_tags = false
|
|
||||||
tag_name = "v{new_version}"
|
|
||||||
tag_message = "Bump version: {current_version} → {new_version}"
|
|
||||||
allow_dirty = false
|
|
||||||
commit = true
|
|
||||||
message = "Bump version: {current_version} → {new_version}"
|
|
||||||
commit_args = ""
|
|
||||||
setup_hooks = []
|
|
||||||
pre_commit_hooks = []
|
|
||||||
post_commit_hooks = []
|
|
||||||
[[tool.bumpversion.files]]
|
|
||||||
filename = "src/__init__.py"
|
|
||||||
@@ -42,16 +42,6 @@ jobs:
|
|||||||
id: bump_version
|
id: bump_version
|
||||||
run: |
|
run: |
|
||||||
uv tool run bump-my-version bump ${{ github.event.inputs.bump }} --tag --allow-dirty
|
uv tool run bump-my-version bump ${{ github.event.inputs.bump }} --tag --allow-dirty
|
||||||
- name: Add release notes
|
|
||||||
id: add_release_notes
|
|
||||||
run: |
|
|
||||||
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
|
|
||||||
echo "${{ github.event.inputs.release_notes }}" >> $GITHUB_ENV
|
|
||||||
echo "EOF" >> $GITHUB_ENV
|
|
||||||
- name: Create Gitea Release
|
|
||||||
if: ${{ github.event.inputs.github_release == 'true' }}
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
|
|
||||||
- name: Add release notes
|
- name: Add release notes
|
||||||
id: add_release_notes
|
id: add_release_notes
|
||||||
run: |
|
run: |
|
||||||
@@ -62,14 +52,7 @@ jobs:
|
|||||||
if: ${{ github.event.inputs.github_release == 'true' }}
|
if: ${{ github.event.inputs.github_release == 'true' }}
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.sha }}
|
tag_name:
|
||||||
release_name: Release ${{ github.sha }}
|
|
||||||
body: ${{ env.RELEASE_NOTES }}
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
||||||
release_name: Release ${{ github.sha }}
|
release_name: Release ${{ github.sha }}
|
||||||
body: ${{ env.RELEASE_NOTES }}
|
body: ${{ env.RELEASE_NOTES }}
|
||||||
draft: false
|
draft: false
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -230,3 +230,4 @@ config.yaml
|
|||||||
logs/
|
logs/
|
||||||
*.pdf
|
*.pdf
|
||||||
*.docx
|
*.docx
|
||||||
|
test.py
|
||||||
|
|||||||
31
build.py
Normal file
31
build.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
with open(".version", "r") as version_file:
|
||||||
|
version = version_file.read().strip()
|
||||||
|
|
||||||
|
print("Building the project...")
|
||||||
|
print("Cleaning build dir...")
|
||||||
|
# clear dist directory
|
||||||
|
if os.path.exists("dist"):
|
||||||
|
shutil.rmtree("dist")
|
||||||
|
os.makedirs("dist")
|
||||||
|
print("Build directory cleaned.")
|
||||||
|
build = input("Include console in build? (y/n): ").strip().lower()
|
||||||
|
|
||||||
|
|
||||||
|
command = f"uv run python -m nuitka --standalone --output-dir=dist --include-data-dir=./config=config --include-data-dir=./site=site --include-data-dir=./icons=icons --include-data-dir=./mail_vorlagen=mail_vorlagen --enable-plugin=pyside6 --product-name=SemesterApparatsManager --product-version={version} --output-filename=SAM.exe --windows-icon-from-ico=icons/logo.ico"
|
||||||
|
executable = "main.py"
|
||||||
|
|
||||||
|
|
||||||
|
if build == 'y':
|
||||||
|
|
||||||
|
os.system(f"{command} {executable}")
|
||||||
|
else:
|
||||||
|
command += " --windows-console-mode=disable"
|
||||||
|
os.system(f"{command} {executable}")
|
||||||
|
|
||||||
|
# rename main.dist in dist dir to SemesterApparatsManager
|
||||||
|
os.rename("dist/main.dist", "dist/SemesterApparatsManager")
|
||||||
|
|
||||||
|
print("Build complete.")
|
||||||
57
config/base_config.yaml
Normal file
57
config/base_config.yaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
default_apps: true
|
||||||
|
save_path: .
|
||||||
|
icon_path: icons/
|
||||||
|
openAI:
|
||||||
|
api_key:
|
||||||
|
model:
|
||||||
|
zotero:
|
||||||
|
api_key:
|
||||||
|
library_id:
|
||||||
|
library_type: user
|
||||||
|
database:
|
||||||
|
name: semesterapparate.db
|
||||||
|
path: .
|
||||||
|
temp: ~/AppData/Local/SAM/SemesterApparatsManager/Cache
|
||||||
|
mail:
|
||||||
|
smtp_server:
|
||||||
|
port:
|
||||||
|
sender:
|
||||||
|
printer_mail:
|
||||||
|
user_name:
|
||||||
|
use_user_name: true
|
||||||
|
password:
|
||||||
|
signature:
|
||||||
|
colors:
|
||||||
|
dark: '#6b6160'
|
||||||
|
light: '#000000'
|
||||||
|
warning: '#ff0000'
|
||||||
|
success: '#00ff00'
|
||||||
|
icons:
|
||||||
|
locked: locked.svg
|
||||||
|
logo: logo.ico
|
||||||
|
show_password: visibility_off.svg
|
||||||
|
hide_password: visibility_on.svg
|
||||||
|
settings: settings.svg
|
||||||
|
today: calendar_today.svg
|
||||||
|
save: save.svg
|
||||||
|
edit_note: edit_note.svg
|
||||||
|
warning: warning.svg
|
||||||
|
error: error.svg
|
||||||
|
mail: mail.svg
|
||||||
|
semester: semester.svg
|
||||||
|
template_fail: test_fail.svg
|
||||||
|
offAction: shutdown.svg
|
||||||
|
info: info.svg
|
||||||
|
help: help.svg
|
||||||
|
close: close.svg
|
||||||
|
notification: notification.svg
|
||||||
|
valid_true: check_success.svg
|
||||||
|
valid_false: check_fail.svg
|
||||||
|
edit: edit.svg
|
||||||
|
important_warn: red_warn.svg
|
||||||
|
person: person_add.svg
|
||||||
|
database: database.svg
|
||||||
|
icons: icons.svg
|
||||||
|
api: api.svg
|
||||||
|
print: print.svg
|
||||||
|
db_search: db_search.svg
|
||||||
@@ -1,8 +1,19 @@
|
|||||||
from typing import Optional
|
from typing import Optional, Any, Union
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from omegaconf import OmegaConf, DictConfig
|
from omegaconf import OmegaConf, DictConfig
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class OpenAI:
|
||||||
|
api_key: str
|
||||||
|
model: str
|
||||||
|
|
||||||
|
def getattr(self, name: str):
|
||||||
|
return getattr(self, name)
|
||||||
|
|
||||||
|
def _setattr(self, name: str, value: Any):
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Zotero:
|
class Zotero:
|
||||||
@@ -10,25 +21,29 @@ class Zotero:
|
|||||||
library_id: str
|
library_id: str
|
||||||
library_type: str
|
library_type: str
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name: str):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
|
|
||||||
def _setattr(self, name, value):
|
def _setattr(self, name: str, value: Any):
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Database:
|
class Database:
|
||||||
name: str
|
name: str
|
||||||
path: str
|
path: Union[str, Path, None]
|
||||||
temp: str
|
temp: Union[str, Path, None]
|
||||||
|
def getattr(self, name: str):
|
||||||
def getattr(self, name):
|
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
|
|
||||||
def _setattr(self, name, value):
|
def _setattr(self, name: str, value: Any):
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if isinstance(self.path, str):
|
||||||
|
self.path = Path(self.path).expanduser()
|
||||||
|
if isinstance(self.temp, str):
|
||||||
|
self.temp = Path(self.temp).expanduser()
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Mail:
|
class Mail:
|
||||||
@@ -59,13 +74,13 @@ class Mail:
|
|||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
|
||||||
margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""
|
margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name: str):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
|
|
||||||
def _setattr(self, name, value):
|
def _setattr(self, name: str, value: Any):
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
def setValue(self, **kwargs):
|
def setValue(self, **kwargs: Any):
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
if hasattr(self, key):
|
if hasattr(self, key):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
@@ -79,7 +94,7 @@ class Icons:
|
|||||||
self._colors = None
|
self._colors = None
|
||||||
self._icons = None
|
self._icons = None
|
||||||
|
|
||||||
def assign(self, key, value):
|
def assign(self, key: str, value: Any):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -87,7 +102,7 @@ class Icons:
|
|||||||
return self._path
|
return self._path
|
||||||
|
|
||||||
@path.setter
|
@path.setter
|
||||||
def path(self, value):
|
def path(self, value: Any):
|
||||||
self._path = value
|
self._path = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -95,7 +110,7 @@ class Icons:
|
|||||||
return self._colors
|
return self._colors
|
||||||
|
|
||||||
@colors.setter
|
@colors.setter
|
||||||
def colors(self, value):
|
def colors(self, value: Any):
|
||||||
self._colors = value
|
self._colors = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -103,10 +118,10 @@ class Icons:
|
|||||||
return self._icons
|
return self._icons
|
||||||
|
|
||||||
@icons.setter
|
@icons.setter
|
||||||
def icons(self, value):
|
def icons(self, value: Any):
|
||||||
self._icons = value
|
self._icons = value
|
||||||
|
|
||||||
def get(self, name):
|
def get(self, name: str):
|
||||||
return self.icons.get(name)
|
return self.icons.get(name)
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +136,7 @@ class Config:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
_config: Optional[DictConfig] = None
|
_config: Optional[DictConfig] = None
|
||||||
|
config_exists: bool = True
|
||||||
def __init__(self, config_path: str):
|
def __init__(self, config_path: str):
|
||||||
"""
|
"""
|
||||||
Loads the configuration file and stores it for future access.
|
Loads the configuration file and stores it for future access.
|
||||||
@@ -133,10 +148,22 @@ class Config:
|
|||||||
FileNotFoundError: Configuration file not found
|
FileNotFoundError: Configuration file not found
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(config_path):
|
if not os.path.exists(config_path):
|
||||||
raise FileNotFoundError(f"Configuration file not found: {config_path}")
|
# copy base config file to the given path
|
||||||
|
base = "config/base_config.yaml"
|
||||||
|
if not os.path.exists(base):
|
||||||
|
raise FileNotFoundError(f"Base configuration file not found: {base}")
|
||||||
|
with open(base, "r") as base_file:
|
||||||
|
base_config = base_file.read()
|
||||||
|
with open(config_path, "w") as config_file:
|
||||||
|
config_file.write(base_config)
|
||||||
|
self.config_exists = False
|
||||||
self._config = OmegaConf.load(config_path)
|
self._config = OmegaConf.load(config_path)
|
||||||
self.config_path = config_path
|
self.config_path = config_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exists(self) -> bool:
|
||||||
|
return self.config_exists
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
Saves the current configuration to the file.
|
Saves the current configuration to the file.
|
||||||
@@ -146,16 +173,22 @@ class Config:
|
|||||||
"""
|
"""
|
||||||
OmegaConf.save(self._config, self.config_path)
|
OmegaConf.save(self._config, self.config_path)
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
"""
|
||||||
|
Reloads the configuration from the file.
|
||||||
|
"""
|
||||||
|
self._config = OmegaConf.load(self.config_path)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def zotero(self):
|
def zotero(self):
|
||||||
return Zotero(**self._config.zotero)
|
return Zotero(**self._config.zotero)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def zotero_attr(self, name):
|
def zotero_attr(self, name: str):
|
||||||
return getattr(self.zotero, name)
|
return getattr(self.zotero, name)
|
||||||
|
|
||||||
@zotero_attr.setter
|
@zotero_attr.setter
|
||||||
def zotero_attr(self, name, value):
|
def zotero_attr(self, name: str, value: Any):
|
||||||
self.zotero._setattr(name, value)
|
self.zotero._setattr(name, value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -163,30 +196,37 @@ class Config:
|
|||||||
return Database(**self._config.database)
|
return Database(**self._config.database)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def database_attr(self, name):
|
def database_attr(self, name: str):
|
||||||
return getattr(self.database, name)
|
return getattr(self.database, name)
|
||||||
|
|
||||||
@database_attr.setter
|
@database_attr.setter
|
||||||
def database_attr(self, name, value):
|
def database_attr(self, name: str, value: Any):
|
||||||
self.database._setattr(name, value)
|
self.database._setattr(name, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def openAI(self):
|
||||||
|
return OpenAI(**self._config.openAI)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mail(self):
|
def mail(self):
|
||||||
return Mail(**self._config.mail)
|
return Mail(**self._config.mail)
|
||||||
|
|
||||||
def mail_attr(self, name):
|
def mail_attr(self, name: str):
|
||||||
return getattr(self.mail, name)
|
return getattr(self.mail, name)
|
||||||
|
|
||||||
def set_mail_attr(self, name, value):
|
def set_mail_attr(self, name: str, value: Any):
|
||||||
OmegaConf.update(self._config, f"mail.{name}", value)
|
OmegaConf.update(self._config, f"mail.{name}", value)
|
||||||
|
|
||||||
def set_database_attr(self, name, value):
|
def set_database_attr(self, name: str, value: Any):
|
||||||
OmegaConf.update(self._config, f"database.{name}", value)
|
OmegaConf.update(self._config, f"database.{name}", value)
|
||||||
|
|
||||||
def set_zotero_attr(self, name, value):
|
def set_zotero_attr(self, name: str, value: Any):
|
||||||
OmegaConf.update(self._config, f"zotero.{name}", value)
|
OmegaConf.update(self._config, f"zotero.{name}", value)
|
||||||
|
|
||||||
def set_icon_attr(self, name, value):
|
def set_openai_attr(self, name: str, value: Any):
|
||||||
|
OmegaConf.update(self._config, f"openAI.{name}", value)
|
||||||
|
|
||||||
|
def set_icon_attr(self, name: str, value: Any):
|
||||||
OmegaConf.update(self._config, f"icons.{name}", value)
|
OmegaConf.update(self._config, f"icons.{name}", value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
BIN
icons/logo.ico
BIN
icons/logo.ico
Binary file not shown.
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 264 KiB |
33
mail.py
33
mail.py
@@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
from PyQt6 import QtWidgets
|
|
||||||
|
|
||||||
from src.ui.dialogs.mail import Mail_Dialog
|
|
||||||
|
|
||||||
|
|
||||||
def launch_gui(app_id="", app_name="", app_subject="", prof_name="", prof_mail=""):
|
|
||||||
QtWidgets.QApplication([""])
|
|
||||||
|
|
||||||
dialog = Mail_Dialog(
|
|
||||||
app_id=app_id,
|
|
||||||
app_name=app_name,
|
|
||||||
app_subject=app_subject,
|
|
||||||
prof_name=prof_name,
|
|
||||||
prof_mail=prof_mail,
|
|
||||||
# default_mail="Information bezüglich der Auflösung des Semesterapparates",
|
|
||||||
)
|
|
||||||
dialog.exec()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app_id = "123"
|
|
||||||
app_name = "Test"
|
|
||||||
app_subject = "TestFach"
|
|
||||||
prof_name = "Test"
|
|
||||||
prof_mail = "kirchneralexander020@gmail.com"
|
|
||||||
launch_gui(
|
|
||||||
app_id=app_id,
|
|
||||||
app_name=app_name,
|
|
||||||
app_subject=app_subject,
|
|
||||||
prof_name=prof_name,
|
|
||||||
prof_mail=prof_mail,
|
|
||||||
)
|
|
||||||
17
main.py
17
main.py
@@ -1,4 +1,19 @@
|
|||||||
|
from src import first_launch, settings
|
||||||
|
from src.ui.widgets.welcome_wizard import launch_wizard as startup
|
||||||
|
from PySide6 import QtWidgets
|
||||||
|
import sys
|
||||||
from src.ui.userInterface import launch_gui as UI
|
from src.ui.userInterface import launch_gui as UI
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
UI()
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
if not first_launch:
|
||||||
|
setup = startup()
|
||||||
|
if setup == 1:
|
||||||
|
settings.reload()
|
||||||
|
# kill qApplication singleton
|
||||||
|
UI()
|
||||||
|
else:
|
||||||
|
sys.exit()
|
||||||
|
else:
|
||||||
|
UI()
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "semesterapparatsmanager"
|
name = "semesterapparatsmanager"
|
||||||
version = "0.1.0"
|
version = "0.2.1"
|
||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"appdirs>=1.4.4",
|
||||||
"beautifulsoup4>=4.12.3",
|
"beautifulsoup4>=4.12.3",
|
||||||
"bump-my-version>=0.29.0",
|
"bump-my-version>=0.29.0",
|
||||||
"chardet>=5.2.0",
|
"chardet>=5.2.0",
|
||||||
@@ -17,10 +18,11 @@ dependencies = [
|
|||||||
"mkdocs-material-extensions>=1.3.1",
|
"mkdocs-material-extensions>=1.3.1",
|
||||||
"natsort>=8.4.0",
|
"natsort>=8.4.0",
|
||||||
"omegaconf>=2.3.0",
|
"omegaconf>=2.3.0",
|
||||||
|
"openai>=1.79.0",
|
||||||
"pandas>=2.2.3",
|
"pandas>=2.2.3",
|
||||||
"playwright>=1.49.1",
|
"playwright>=1.49.1",
|
||||||
"pyqt6>=6.8.0",
|
"pyramid>=2.0.2",
|
||||||
"pyqtgraph>=0.13.7",
|
"pyside6>=6.9.1",
|
||||||
"python-docx>=1.1.2",
|
"python-docx>=1.1.2",
|
||||||
"pyzotero>=1.6.4",
|
"pyzotero>=1.6.4",
|
||||||
"ratelimit>=2.2.1",
|
"ratelimit>=2.2.1",
|
||||||
@@ -33,3 +35,29 @@ dev = [
|
|||||||
"icecream>=2.1.4",
|
"icecream>=2.1.4",
|
||||||
"nuitka>=2.5.9",
|
"nuitka>=2.5.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.bumpversion]
|
||||||
|
current_version = "0.2.1"
|
||||||
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
||||||
|
serialize = ["{major}.{minor}.{patch}"]
|
||||||
|
search = "{current_version}"
|
||||||
|
replace = "{new_version}"
|
||||||
|
regex = false
|
||||||
|
ignore_missing_version = false
|
||||||
|
ignore_missing_files = false
|
||||||
|
tag = true
|
||||||
|
sign_tags = false
|
||||||
|
tag_name = "v{new_version}"
|
||||||
|
tag_message = "Bump version: {current_version} → {new_version}"
|
||||||
|
allow_dirty = true
|
||||||
|
commit = true
|
||||||
|
message = "Bump version: {current_version} → {new_version}"
|
||||||
|
moveable_tags = []
|
||||||
|
commit_args = ""
|
||||||
|
setup_hooks = []
|
||||||
|
pre_commit_hooks = []
|
||||||
|
post_commit_hooks = []
|
||||||
|
[[tool.bumpversion.files]]
|
||||||
|
filename = "src/__init__.py"
|
||||||
|
[[tool.bumpversion.files]]
|
||||||
|
filename = ".version"
|
||||||
|
|||||||
@@ -1,16 +1,33 @@
|
|||||||
__all__ = ["__version__", "__author__", "Icon", "settings"]
|
|
||||||
from config import Config
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
settings = Config("config/config.yaml")
|
|
||||||
if not os.path.exists(settings.database.temp):
|
|
||||||
os.mkdir(settings.database.temp)
|
|
||||||
from .utils.icon import Icon
|
|
||||||
|
|
||||||
__version__ = "0.2.1"
|
__version__ = "0.2.1"
|
||||||
__author__ = "Alexander Kirchner"
|
__author__ = "Alexander Kirchner"
|
||||||
|
__all__ = ["__version__", "__author__", "Icon", "settings"]
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from appdirs import AppDirs
|
||||||
|
|
||||||
|
from config import Config
|
||||||
|
|
||||||
|
|
||||||
|
app = AppDirs("SemesterApparatsManager", "SAM")
|
||||||
|
LOG_DIR = app.user_log_dir
|
||||||
|
CONFIG_DIR = app.user_config_dir
|
||||||
|
if not os.path.exists(LOG_DIR):
|
||||||
|
os.makedirs(LOG_DIR)
|
||||||
|
if not os.path.exists(CONFIG_DIR):
|
||||||
|
os.makedirs(CONFIG_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
settings = Config(f"{CONFIG_DIR}/config.yaml")
|
||||||
|
DATABASE_DIR = (
|
||||||
|
app.user_config_dir if settings.database.path is None else settings.database.path
|
||||||
|
)
|
||||||
|
if not os.path.exists(DATABASE_DIR):
|
||||||
|
os.makedirs(DATABASE_DIR)
|
||||||
|
first_launch = settings.exists
|
||||||
|
if not os.path.exists(settings.database.temp.expanduser()):
|
||||||
|
settings.database.temp.expanduser().mkdir(parents=True, exist_ok=True)
|
||||||
|
from .utils.icon import Icon
|
||||||
|
|
||||||
if not os.path.exists("logs"):
|
if not os.path.exists("logs"):
|
||||||
os.mkdir("logs")
|
os.mkdir("logs")
|
||||||
|
|||||||
@@ -2,6 +2,14 @@ import hashlib
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from .database import Database
|
from .database import Database
|
||||||
|
import loguru
|
||||||
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
|
|
||||||
|
log = loguru.logger
|
||||||
|
log.remove()
|
||||||
|
log.add(sys.stdout, level="INFO")
|
||||||
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
# change passwords for apparats, change passwords for users, list users, create and delete users etc
|
# change passwords for apparats, change passwords for users, list users, create and delete users etc
|
||||||
@@ -9,9 +17,14 @@ from .database import Database
|
|||||||
class AdminCommands:
|
class AdminCommands:
|
||||||
"""Basic Admin commands for the admin console. This class is used to create, delete, and list users. It also has the ability to change passwords for users."""
|
"""Basic Admin commands for the admin console. This class is used to create, delete, and list users. It also has the ability to change passwords for users."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, db_path=None):
|
||||||
"""Defaulf Constructor for the AdminCommands class."""
|
"""Default Constructor for the AdminCommands class."""
|
||||||
self.db = Database()
|
if db_path is None:
|
||||||
|
self.db = Database()
|
||||||
|
else:
|
||||||
|
self.db = Database(db_path=db_path)
|
||||||
|
log.info("AdminCommands initialized with database connection.")
|
||||||
|
log.debug("location: {}", self.db.db_path)
|
||||||
|
|
||||||
def create_password(self, password: str) -> tuple[str, str]:
|
def create_password(self, password: str) -> tuple[str, str]:
|
||||||
"""Create a hashed password and a salt for the password.
|
"""Create a hashed password and a salt for the password.
|
||||||
@@ -44,6 +57,20 @@ class AdminCommands:
|
|||||||
hashed_password = self.hash_password("admin")
|
hashed_password = self.hash_password("admin")
|
||||||
self.db.createUser("admin", salt + hashed_password, "admin", salt)
|
self.db.createUser("admin", salt + hashed_password, "admin", salt)
|
||||||
|
|
||||||
|
def create_user(self, username: str, password: str, role: str = "user") -> bool:
|
||||||
|
"""Create a new user in the database.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
username (str): the username of the user to be created.
|
||||||
|
password (str): the password of the user to be created.
|
||||||
|
role (str, optional): the role of the user to be created. Defaults to "user".
|
||||||
|
"""
|
||||||
|
hashed_password, salt = self.create_password(password)
|
||||||
|
status = self.db.createUser(
|
||||||
|
user=username, password=salt + hashed_password, role=role, salt=salt
|
||||||
|
)
|
||||||
|
return status
|
||||||
|
|
||||||
def hash_password(self, password: str) -> str:
|
def hash_password(self, password: str) -> str:
|
||||||
"""Hash a password using SHA256.
|
"""Hash a password using SHA256.
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ from src.backend.database import Database
|
|||||||
|
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
db = Database()
|
db = Database()
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import os
|
|
||||||
import sqlite3 as sql
|
|
||||||
import tempfile
|
|
||||||
from pathlib import Path
|
|
||||||
from src import settings
|
|
||||||
from typing import Any, List, Optional, Tuple, Union
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
import sqlite3 as sql
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
|
from pathlib import Path
|
||||||
|
from string import ascii_lowercase as lower
|
||||||
|
from string import digits, punctuation
|
||||||
|
from typing import Any, List, Optional, Tuple, Union
|
||||||
|
|
||||||
|
import loguru
|
||||||
|
|
||||||
|
from src import LOG_DIR, settings, DATABASE_DIR
|
||||||
from src.backend.db import (
|
from src.backend.db import (
|
||||||
CREATE_ELSA_FILES_TABLE,
|
CREATE_ELSA_FILES_TABLE,
|
||||||
CREATE_ELSA_MEDIA_TABLE,
|
CREATE_ELSA_MEDIA_TABLE,
|
||||||
@@ -20,17 +26,16 @@ from src.backend.db import (
|
|||||||
CREATE_TABLE_USER,
|
CREATE_TABLE_USER,
|
||||||
)
|
)
|
||||||
from src.errors import AppPresentError, NoResultError
|
from src.errors import AppPresentError, NoResultError
|
||||||
from src.logic import ApparatData, BookData, Prof, Apparat, ELSA
|
from src.logic import ELSA, Apparat, ApparatData, BookData, Prof
|
||||||
from src.logic.constants import SEMAP_MEDIA_ACCOUNTS
|
from src.logic.constants import SEMAP_MEDIA_ACCOUNTS
|
||||||
|
from src.utils.blob import create_blob
|
||||||
|
|
||||||
from .semester import Semester
|
from .semester import Semester
|
||||||
from string import ascii_lowercase as lower, digits, punctuation
|
|
||||||
import loguru
|
|
||||||
import sys
|
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -39,12 +44,11 @@ ascii_lowercase = lower + digits + punctuation
|
|||||||
|
|
||||||
# get the line that called the function
|
# get the line that called the function
|
||||||
class Database:
|
class Database:
|
||||||
database = settings.database
|
|
||||||
"""
|
"""
|
||||||
Initialize the database and create the tables if they do not exist.
|
Initialize the database and create the tables if they do not exist.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, db_path: str = None):
|
def __init__(self, db_path: Union[Path, None] = None):
|
||||||
"""
|
"""
|
||||||
Default constructor for the database class
|
Default constructor for the database class
|
||||||
|
|
||||||
@@ -52,23 +56,41 @@ class Database:
|
|||||||
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
|
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
|
||||||
"""
|
"""
|
||||||
if db_path is None:
|
if db_path is None:
|
||||||
self.db_path = self.database.path + self.database.name
|
if settings.database.path is not None:
|
||||||
self.db_path = self.db_path.replace("~", str(Path.home()))
|
self.db_path = Path(
|
||||||
log.debug(self.db_path)
|
settings.database.path.expanduser(), settings.database.name
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.db_path = None
|
||||||
|
|
||||||
|
# self.db_path = self.db_path.replace("~", str(Path.home()))
|
||||||
else:
|
else:
|
||||||
self.db_path = db_path
|
self.db_path = db_path
|
||||||
self.checkDatabaseStatus()
|
log.debug(f"Database path: {self.db_path}")
|
||||||
|
self.db_initialized = False
|
||||||
|
|
||||||
|
def initializeDatabase(self):
|
||||||
|
if not self.db_initialized:
|
||||||
|
self.checkDatabaseStatus()
|
||||||
|
self.db_initialized = True
|
||||||
|
|
||||||
|
def overwritePath(self, new_db_path: str):
|
||||||
|
log.debug("got new path, overwriting")
|
||||||
|
self.db_path = Path(new_db_path)
|
||||||
|
|
||||||
def checkDatabaseStatus(self):
|
def checkDatabaseStatus(self):
|
||||||
path = self.database.path
|
path = settings.database.path
|
||||||
path = path.replace("~", str(Path.home()))
|
if path is None:
|
||||||
path = os.path.abspath(path)
|
path = Path(DATABASE_DIR)
|
||||||
|
# path = path.replace("~", str(Path.home()))
|
||||||
|
# path = os.path.abspath(path)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
# create path
|
# create path
|
||||||
# log.debug(path)
|
# log.debug(path)
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
if self.get_db_contents() == []:
|
if self.get_db_contents() == []:
|
||||||
log.critical("Database does not exist, creating tables")
|
log.critical("Database does not exist, creating tables")
|
||||||
|
log.critical(f"Path: {path}")
|
||||||
self.create_tables()
|
self.create_tables()
|
||||||
self.insertSubjects()
|
self.insertSubjects()
|
||||||
|
|
||||||
@@ -503,11 +525,9 @@ class Database:
|
|||||||
str: The filename of the recreated file
|
str: The filename of the recreated file
|
||||||
"""
|
"""
|
||||||
blob = self.getBlob(filename, app_id)
|
blob = self.getBlob(filename, app_id)
|
||||||
tempdir = self.database.temp
|
tempdir = settings.database.temp.expanduser()
|
||||||
tempdir = tempdir.replace("~", str(Path.home()))
|
if not tempdir.exists():
|
||||||
tempdir_path = Path(tempdir)
|
tempdir.mkdir(parents=True, exist_ok=True)
|
||||||
if not os.path.exists(tempdir_path):
|
|
||||||
os.mkdir(tempdir_path)
|
|
||||||
file = tempfile.NamedTemporaryFile(
|
file = tempfile.NamedTemporaryFile(
|
||||||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||||||
)
|
)
|
||||||
@@ -1197,10 +1217,13 @@ class Database:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if the login was successful, False if not
|
bool: True if the login was successful, False if not
|
||||||
"""
|
"""
|
||||||
salt = self.query_db(
|
try:
|
||||||
"SELECT salt FROM user WHERE username=?", (user,), one=True
|
salt = self.query_db(
|
||||||
)[0]
|
"SELECT salt FROM user WHERE username=?", (user,), one=True
|
||||||
if salt is None:
|
)[0]
|
||||||
|
if salt is None:
|
||||||
|
return False
|
||||||
|
except TypeError:
|
||||||
return False
|
return False
|
||||||
hashed_password = salt + hashed_password
|
hashed_password = salt + hashed_password
|
||||||
password = self.query_db(
|
password = self.query_db(
|
||||||
@@ -1276,6 +1299,13 @@ class Database:
|
|||||||
"INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)",
|
"INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)",
|
||||||
(user, password, role, salt),
|
(user, password, role, salt),
|
||||||
)
|
)
|
||||||
|
# check if user was created
|
||||||
|
return (
|
||||||
|
self.query_db(
|
||||||
|
"SELECT username FROM user WHERE username=?", (user,), one=True
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
|
||||||
def deleteUser(self, user):
|
def deleteUser(self, user):
|
||||||
"""delete an unser
|
"""delete an unser
|
||||||
@@ -1463,11 +1493,10 @@ class Database:
|
|||||||
"SELECT fileblob FROM elsa_files WHERE filename=?", (filename,), one=True
|
"SELECT fileblob FROM elsa_files WHERE filename=?", (filename,), one=True
|
||||||
)[0]
|
)[0]
|
||||||
# log.debug(blob)
|
# log.debug(blob)
|
||||||
tempdir = self.database.temp
|
tempdir = settings.database.temp.expanduser()
|
||||||
tempdir = tempdir.replace("~", str(Path.home()))
|
if not tempdir.exists():
|
||||||
tempdir_path = Path(tempdir)
|
tempdir.mkdir(parents=True, exist_ok=True)
|
||||||
if not os.path.exists(tempdir_path):
|
|
||||||
os.mkdir(tempdir_path)
|
|
||||||
file = tempfile.NamedTemporaryFile(
|
file = tempfile.NamedTemporaryFile(
|
||||||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ def delete_temp_contents():
|
|||||||
"""
|
"""
|
||||||
delete_temp_contents deletes the contents of the temp directory.
|
delete_temp_contents deletes the contents of the temp directory.
|
||||||
"""
|
"""
|
||||||
path = database.temp
|
path = database.temp.expanduser()
|
||||||
path = path.replace("~", str(Path.home()))
|
|
||||||
path = Path(path)
|
|
||||||
path = path.resolve()
|
|
||||||
for root, dirs, files in os.walk(path):
|
for root, dirs, files in os.walk(path):
|
||||||
for file in files:
|
for file in files:
|
||||||
os.remove(os.path.join(root, file))
|
os.remove(os.path.join(root, file))
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
from PyQt6.QtCore import QThread
|
from PySide6.QtCore import QThread, Slot
|
||||||
from src.utils.documentation import run_mkdocs
|
from src.utils.documentation import website, QuietHandler
|
||||||
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
|
|
||||||
class DocumentationThread(QThread):
|
class DocumentationThread(QThread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self._server = None # store server so we can shut it down
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# launch_documentation()
|
# launch_documentation()
|
||||||
run_mkdocs()
|
self._server = make_server(
|
||||||
|
"localhost", 8000, website(), handler_class=QuietHandler
|
||||||
|
)
|
||||||
|
while not self.isInterruptionRequested():
|
||||||
|
self._server.handle_request()
|
||||||
|
|
||||||
|
@Slot() # slot you can connect to aboutToQuit
|
||||||
|
def stop(self):
|
||||||
|
self.requestInterruption() # ask the loop above to exit
|
||||||
|
if self._server:
|
||||||
|
self._server.shutdown() # unblock handle_request()
|
||||||
@@ -1,146 +1,242 @@
|
|||||||
import datetime
|
"""Semester helper class
|
||||||
|
|
||||||
|
A small utility around the *German* academic calendar that distinguishes
|
||||||
|
between *Wintersemester* (WiSe) and *Sommersemester* (SoSe).
|
||||||
|
|
||||||
|
Key points
|
||||||
|
----------
|
||||||
|
* A **`Semester`** is identified by a *term* ("SoSe" or "WiSe") and the last two
|
||||||
|
digits of the calendar year in which the term *starts*.
|
||||||
|
* Formatting **never** pads the year with a leading zero – so ``6`` stays ``6``.
|
||||||
|
* ``offset(n)`` and the static ``generate_missing`` reliably walk the timeline
|
||||||
|
one semester at a time with correct year transitions:
|
||||||
|
|
||||||
|
SoSe 6 → **WiSe 6/7** → SoSe 7 → WiSe 7/8 → …
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
# @dataclass
|
||||||
class Semester:
|
class Semester:
|
||||||
log.debug("Semester class loaded")
|
"""Represents a German university semester (WiSe or SoSe)."""
|
||||||
|
|
||||||
_year: int | None = str(datetime.datetime.now().year)[2:]
|
# ------------------------------------------------------------------
|
||||||
_semester: str | None = None
|
# Class‑level defaults – will be *copied* to each instance and then
|
||||||
|
# potentially overwritten in ``__init__``.
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
_year: int | None = int(str(datetime.datetime.now().year)[2:]) # 24 → 24
|
||||||
|
_semester: str | None = None # "WiSe" or "SoSe" – set later
|
||||||
_month: int | None = datetime.datetime.now().month
|
_month: int | None = datetime.datetime.now().month
|
||||||
value: str = None
|
value: str | None = None # Human‑readable label, e.g. "WiSe 23/24"
|
||||||
log.debug(
|
|
||||||
f"Initialized Semester class with values: month: {_month}, semester: {_semester}, year {_year}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __post_init__(self):
|
# ------------------------------------------------------------------
|
||||||
if isinstance(self._year, str):
|
# Construction helpers
|
||||||
self._year = int(self._year)
|
# ------------------------------------------------------------------
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
year: int | None = None,
|
||||||
|
semester: str | None = None,
|
||||||
|
month: int | None = None,
|
||||||
|
) -> None:
|
||||||
|
if year is not None:
|
||||||
|
self._year = int(year)
|
||||||
|
if semester is not None:
|
||||||
|
if semester not in ("WiSe", "SoSe"):
|
||||||
|
raise ValueError("semester must be 'WiSe' or 'SoSe'")
|
||||||
|
self._semester = semester
|
||||||
|
if month is not None:
|
||||||
|
self._month = month
|
||||||
|
|
||||||
|
self.__post_init__()
|
||||||
|
|
||||||
|
def __post_init__(self) -> None: # noqa: D401 – keep original name
|
||||||
if self._year is None:
|
if self._year is None:
|
||||||
self._year = datetime.datetime.now().year[2:]
|
self._year = int(str(datetime.datetime.now().year)[2:])
|
||||||
if self._month is None:
|
if self._month is None:
|
||||||
self._month = datetime.datetime.now().month
|
self._month = datetime.datetime.now().month
|
||||||
if self._semester is None:
|
if self._semester is None:
|
||||||
self.generateSemester()
|
self._generate_semester_from_month()
|
||||||
self.computeValue()
|
self._compute_value()
|
||||||
|
|
||||||
def __str__(self):
|
# ------------------------------------------------------------------
|
||||||
return self.value
|
# Dunder helpers
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
def __str__(self) -> str: # noqa: D401 – keep original name
|
||||||
|
return self.value or "<invalid Semester>"
|
||||||
|
|
||||||
def generateSemester(self):
|
def __repr__(self) -> str: # Helpful for debugging lists
|
||||||
if self._month <= 3 or self._month > 9:
|
return f"Semester({self._year!r}, {self._semester!r})"
|
||||||
self._semester = "WiSe"
|
|
||||||
else:
|
|
||||||
self._semester = "SoSe"
|
|
||||||
|
|
||||||
@log.catch
|
# ------------------------------------------------------------------
|
||||||
def computeValue(self):
|
# Internal helpers
|
||||||
# year is only last two digits
|
# ------------------------------------------------------------------
|
||||||
|
def _generate_semester_from_month(self) -> None:
|
||||||
|
"""Infer *WiSe* / *SoSe* from the month attribute."""
|
||||||
|
self._semester = "WiSe" if (self._month <= 3 or self._month > 9) else "SoSe"
|
||||||
|
|
||||||
|
def _compute_value(self) -> None:
|
||||||
|
"""Human‑readable semester label – e.g. ``WiSe 23/24`` or ``SoSe 24``."""
|
||||||
year = self._year
|
year = self._year
|
||||||
valueyear = str(year)
|
|
||||||
if self._semester == "WiSe":
|
if self._semester == "WiSe":
|
||||||
if self._month < 4:
|
next_year = (year + 1) % 100 # wrap 99 → 0
|
||||||
valueyear = str(year - 1) + "/" + str(year)
|
self.value = f"WiSe {year}/{next_year}"
|
||||||
else:
|
else: # SoSe
|
||||||
valueyear = str(year) + "/" + str(year + 1)
|
self.value = f"SoSe {year}"
|
||||||
self.value = f"{self._semester} {valueyear}"
|
|
||||||
|
|
||||||
@log.catch
|
# ------------------------------------------------------------------
|
||||||
def offset(self, value: int) -> str:
|
# Public API
|
||||||
"""Generate a new Semester object by offsetting the current semester by a given value
|
# ------------------------------------------------------------------
|
||||||
|
def offset(self, value: int) -> "Semester":
|
||||||
|
"""Return a new :class:`Semester` *value* steps away.
|
||||||
|
|
||||||
Args:
|
The algorithm maps every semester to a monotonically increasing
|
||||||
value (int): The value by which the semester should be offset
|
*linear index* so that simple addition suffices:
|
||||||
|
|
||||||
Returns:
|
``index = year * 2 + (0 if SoSe else 1)``.
|
||||||
str: the new semester value
|
|
||||||
"""
|
"""
|
||||||
assert isinstance(value, int), "Value must be an integer"
|
if not isinstance(value, int):
|
||||||
|
raise TypeError("value must be an int (number of semesters to jump)")
|
||||||
if value == 0:
|
if value == 0:
|
||||||
return self
|
return Semester(self._year, self._semester)
|
||||||
if value > 0:
|
|
||||||
if value % 2 == 0:
|
|
||||||
return Semester(
|
|
||||||
self._year - value // 2, self._semester - value // 2 + 1
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
semester = self._semester
|
|
||||||
semester = "SoSe" if semester == "WiSe" else "WiSe"
|
|
||||||
return Semester(self._year + value // 2, semester)
|
|
||||||
else:
|
|
||||||
if value % 2 == 0:
|
|
||||||
return Semester(self.year + value // 2, self._semester)
|
|
||||||
else:
|
|
||||||
semester = self._semester
|
|
||||||
semester = "SoSe" if semester == "WiSe" else "WiSe"
|
|
||||||
return Semester(self._year + value // 2, semester)
|
|
||||||
|
|
||||||
def isPastSemester(self, semester) -> bool:
|
current_idx = self._year * 2 + (0 if self._semester == "SoSe" else 1)
|
||||||
"""Checks if the current Semester is a past Semester compared to the given Semester
|
target_idx = current_idx + value
|
||||||
|
if target_idx < 0:
|
||||||
|
raise ValueError("offset would result in a negative year – not supported")
|
||||||
|
|
||||||
Args:
|
new_year, semester_bit = divmod(target_idx, 2)
|
||||||
semester (str): The semester to compare to
|
new_semester = "SoSe" if semester_bit == 0 else "WiSe"
|
||||||
|
return Semester(new_year, new_semester)
|
||||||
|
|
||||||
Returns:
|
# ------------------------------------------------------------------
|
||||||
bool: True if the current semester is in the past, False otherwise
|
# Comparison helpers
|
||||||
"""
|
# ------------------------------------------------------------------
|
||||||
if self.year < semester.year:
|
def isPastSemester(self, other: "Semester") -> bool:
|
||||||
|
if self.year < other.year:
|
||||||
return True
|
return True
|
||||||
if self.year == semester.year:
|
if self.year == other.year:
|
||||||
if self.semester == "WiSe" and semester.semester == "SoSe":
|
return (
|
||||||
return True
|
self.semester == "WiSe" and other.semester == "SoSe"
|
||||||
|
) # WiSe before next SoSe
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isFutureSemester(self, semester: "Semester") -> bool:
|
def isFutureSemester(self, other: "Semester") -> bool:
|
||||||
"""Checks if the current Semester is a future Semester compared to the given Semester
|
if self.year > other.year:
|
||||||
|
|
||||||
Args:
|
|
||||||
semester (str): The semester to compare to
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if the current semester is in the future, False otherwise
|
|
||||||
"""
|
|
||||||
if self.year > semester.year:
|
|
||||||
return True
|
return True
|
||||||
if self.year == semester.year:
|
if self.year == other.year:
|
||||||
if self.semester == "SoSe" and semester.semester == "WiSe":
|
return (
|
||||||
return True
|
self.semester == "SoSe" and other.semester == "WiSe"
|
||||||
|
) # SoSe after WiSe of same year
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def from_string(self, val: str):
|
def isMatch(self, other: "Semester") -> bool:
|
||||||
if " " in val:
|
return self.year == other.year and self.semester == other.semester
|
||||||
values = val.split(" ")
|
|
||||||
if len(values) != 2:
|
|
||||||
raise ValueError("Invalid semester format")
|
|
||||||
self._semester = values[0]
|
|
||||||
if len(values[1]) == 4:
|
|
||||||
self._year = int(values[1][2:])
|
|
||||||
# self._year = int(values[1])
|
|
||||||
self.computeValue()
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Convenience properties
|
||||||
|
# ------------------------------------------------------------------
|
||||||
@property
|
@property
|
||||||
def next(self):
|
def next(self) -> "Semester":
|
||||||
return self.offset(1)
|
return self.offset(1)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def previous(self):
|
def previous(self) -> "Semester":
|
||||||
return self.offset(-1)
|
return self.offset(-1)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def year(self):
|
def year(self) -> int:
|
||||||
return self._year
|
return self._year
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def semester(self):
|
def semester(self) -> str:
|
||||||
return self._semester
|
return self._semester
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Static helpers
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def generate_missing(start: "Semester", end: "Semester") -> list[str]:
|
||||||
|
"""Return all consecutive semesters from *start* to *end* (inclusive)."""
|
||||||
|
if not isinstance(start, Semester) or not isinstance(end, Semester):
|
||||||
|
raise TypeError("start and end must be Semester instances")
|
||||||
|
if start.isFutureSemester(end) and not start.isMatch(end):
|
||||||
|
raise ValueError("'start' must not be after 'end'")
|
||||||
|
|
||||||
|
chain: list[Semester] = [start.value]
|
||||||
|
current = start
|
||||||
|
while not current.isMatch(end):
|
||||||
|
current = current.next
|
||||||
|
chain.append(current.value)
|
||||||
|
if len(chain) > 1000: # sanity guard
|
||||||
|
raise RuntimeError("generate_missing exceeded sane iteration limit")
|
||||||
|
return chain
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Parsing helper
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@classmethod
|
||||||
|
def from_string(cls, s: str) -> "Semester":
|
||||||
|
"""Parse a human‑readable semester label and return a :class:`Semester`.
|
||||||
|
|
||||||
|
Accepted formats (case‑insensitive)::
|
||||||
|
|
||||||
|
"SoSe <YY>" → SoSe of year YY
|
||||||
|
"WiSe <YY>/<YY+1>" → Winter term starting in YY
|
||||||
|
"WiSe <YY>" → Shorthand for the above (next year implied)
|
||||||
|
|
||||||
|
``YY`` may contain a leading zero ("06" → 6).
|
||||||
|
"""
|
||||||
|
if not isinstance(s, str):
|
||||||
|
raise TypeError("s must be a string")
|
||||||
|
|
||||||
|
pattern = r"\s*(WiSe|SoSe)\s+(\d{1,2})(?:\s*/\s*(\d{1,2}))?\s*"
|
||||||
|
m = re.fullmatch(pattern, s, flags=re.IGNORECASE)
|
||||||
|
if not m:
|
||||||
|
raise ValueError(
|
||||||
|
"invalid semester string format – expected 'SoSe YY' or 'WiSe YY/YY' (spacing flexible)"
|
||||||
|
)
|
||||||
|
|
||||||
|
term_raw, y1_str, y2_str = m.groups()
|
||||||
|
term = term_raw.capitalize() # normalize case → "WiSe" or "SoSe"
|
||||||
|
year = int(y1_str.lstrip("0") or "0") # "06" → 6, "0" stays 0
|
||||||
|
|
||||||
|
if term == "SoSe":
|
||||||
|
if y2_str is not None:
|
||||||
|
raise ValueError(
|
||||||
|
"SoSe string should not contain '/' followed by a second year"
|
||||||
|
)
|
||||||
|
return cls(year, "SoSe")
|
||||||
|
|
||||||
|
# term == "WiSe"
|
||||||
|
if y2_str is not None:
|
||||||
|
next_year = int(y2_str.lstrip("0") or "0")
|
||||||
|
expected_next = (year + 1) % 100
|
||||||
|
if next_year != expected_next:
|
||||||
|
raise ValueError("WiSe second year must equal first year + 1 (mod 100)")
|
||||||
|
# Accept both explicit "WiSe 6/7" and shorthand "WiSe 6"
|
||||||
|
return cls(year, "WiSe")
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------- quick self‑test -------------------------
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Chain generation demo ------------------------------------------------
|
||||||
|
s_start = Semester(6, "SoSe") # SoSe 6
|
||||||
|
s_end = Semester(25, "WiSe") # WiSe 25/26
|
||||||
|
chain = Semester.generate_missing(s_start, s_end)
|
||||||
|
print("generate_missing:", [str(s) for s in chain])
|
||||||
|
|
||||||
|
# Parsing demo ---------------------------------------------------------
|
||||||
|
for label in ["SoSe 6", "WiSe 6/7", "wise 23/24", "WiSe 9"]:
|
||||||
|
print("from_string:", label, "→", Semester.from_string(label))
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
from PyQt6.QtCore import QThread
|
from PySide6.QtCore import QThread
|
||||||
from PyQt6.QtCore import pyqtSignal as Signal
|
from PySide6.QtCore import Signal
|
||||||
from src.backend import Database
|
from src.backend import Database
|
||||||
|
|
||||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
|
|
||||||
|
|
||||||
class BookGrabber(QThread):
|
class BookGrabber(QThread):
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
# from icecream import ic
|
# from icecream import ic
|
||||||
from PyQt6.QtCore import QThread
|
from PySide6.QtCore import QThread
|
||||||
from PyQt6.QtCore import pyqtSignal as Signal
|
from PySide6.QtCore import Signal as Signal
|
||||||
|
|
||||||
from src.backend import Database
|
from src.backend import Database
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
# from src.transformers import RDS_AVAIL_DATA
|
# from src.transformers import RDS_AVAIL_DATA
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
# from icecream import ic
|
# from icecream import ic
|
||||||
from PyQt6.QtCore import QThread
|
from PySide6.QtCore import QThread
|
||||||
from PyQt6.QtCore import pyqtSignal as Signal
|
from PySide6.QtCore import Signal as Signal
|
||||||
|
|
||||||
from src.backend.database import Database
|
from src.backend.database import Database
|
||||||
|
from src import LOG_DIR
|
||||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||||
|
|
||||||
# from src.transformers import RDS_AVAIL_DATA
|
# from src.transformers import RDS_AVAIL_DATA
|
||||||
@@ -14,8 +14,8 @@ import sys
|
|||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
from docx import Document
|
|
||||||
|
|
||||||
data = {}
|
|
||||||
wordDoc = Document("files/Semesterapparat - Anmeldung.docx")
|
|
||||||
paragraphs = wordDoc.tables
|
|
||||||
for table in paragraphs:
|
|
||||||
for column in table.columns:
|
|
||||||
cellcount = 0
|
|
||||||
for _cell in column.cells:
|
|
||||||
if cellcount < 12:
|
|
||||||
cellcount += 1
|
|
||||||
# print(f"cell:{cell.text}")
|
|
||||||
|
|
||||||
# # print(f'paragraphs[{i}]: {paragraphs[i]}')
|
|
||||||
# data[i] = paragraphs[i]
|
|
||||||
|
|
||||||
# for i in range(0, len(paragraphs)):
|
|
||||||
# for i in range(2, len(paragraphs)):
|
|
||||||
# data[i] = paragraphs[i]
|
|
||||||
|
|
||||||
# print(data)
|
|
||||||
|
|
||||||
# for table in wordDoc.tables:
|
|
||||||
# for row in table.rows:
|
|
||||||
# # print('---')
|
|
||||||
# for cell in row.cells:
|
|
||||||
# # print(f'cell:{cell.text}')
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import tabula
|
|
||||||
|
|
||||||
file = "files/Semesterapparat - Anmeldung.pdf"
|
|
||||||
|
|
||||||
|
|
||||||
def extract_book_data(file):
|
|
||||||
tabula.read_pdf(file, pages="all", encoding="utf-8", multiple_tables=True)
|
|
||||||
tabula.convert_into(file, file.replace(".pdf"), output_format="csv", pages="all")
|
|
||||||
with open("files/Semesterapparat - Anmeldung.csv", "r") as f:
|
|
||||||
f.read()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
53
src/logic/openai.py
Normal file
53
src/logic/openai.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
from openai import OpenAI
|
||||||
|
from src import settings
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def init_client():
|
||||||
|
"""Initialize the OpenAI client with the API key and model from settings."""
|
||||||
|
global client, model, api_key
|
||||||
|
if not settings.openAI.api_key:
|
||||||
|
raise ValueError("OpenAI API key is not set in the configuration.")
|
||||||
|
if not settings.openAI.model:
|
||||||
|
raise ValueError("OpenAI model is not set in the configuration.")
|
||||||
|
|
||||||
|
model = settings.openAI.model
|
||||||
|
api_key = settings.openAI.api_key
|
||||||
|
client = OpenAI(api_key=api_key)
|
||||||
|
return client
|
||||||
|
def run_shortener(title:str, length:int):
|
||||||
|
client = init_client()
|
||||||
|
response = client.responses.create(
|
||||||
|
model=model,
|
||||||
|
instructions="""you are a sentence shortener. The next message will contain the string to shorten and the length limit.
|
||||||
|
You need to shorten the string to be under the length limit, while keeping as much detail as possible. The result may NOT be longer than the length limit.
|
||||||
|
based on that, please reply only the shortened string. Give me 5 choices. if the length is too long, discard the string and try another one.Return the data as a python list containing the result as {"shortened_string": shortened_string, "length": lengthasInt}. Do not return the answer in a codeblock, use a pure string. Before answering, check the results and if ANY is longer than the needed_length, discard all and try again""",
|
||||||
|
input=f'{{"string":"{title}", "needed_length":{length}}}',
|
||||||
|
)
|
||||||
|
answers = response.output_text
|
||||||
|
return eval(answers) # type: ignore
|
||||||
|
#answers are strings in json format, so we need to convert them to a list of dicts
|
||||||
|
|
||||||
|
|
||||||
|
def name_tester(name: str):
|
||||||
|
client = init_client()
|
||||||
|
response = client.responses.create(
|
||||||
|
model = model,
|
||||||
|
instructions="""you are a name tester, You are given a name and will have to split the name into first name, last name, and if present the title. Return the name in a json format with the keys "title", "first_name", "last_name". If no title is present, set title to none. Do NOt return the answer in a codeblock, use a pure json string. Assume the names are in the usual german naming scheme""",
|
||||||
|
input = f'{{"name":"{name}"}}'
|
||||||
|
)
|
||||||
|
answers = response.output_text
|
||||||
|
|
||||||
|
return json.loads(answers)
|
||||||
|
|
||||||
|
def semester_converter(semester:str):
|
||||||
|
client = init_client()
|
||||||
|
response = client.responses.create(
|
||||||
|
model = model,
|
||||||
|
instructions="""you are a semester converter. You will be given a string. Convert this into a string like this: SoSe YY or WiSe YY/YY+1. Do not return the answer in a codeblock, use a pure string.""",
|
||||||
|
input = semester
|
||||||
|
)
|
||||||
|
answers = response.output_text
|
||||||
|
|
||||||
|
return answers
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
# from icecream import ic
|
|
||||||
from omegaconf import OmegaConf
|
|
||||||
from PyQt6 import QtWidgets
|
|
||||||
from PyQt6.QtCore import QThread
|
|
||||||
from PyQt6.QtCore import pyqtSignal as Signal
|
|
||||||
|
|
||||||
from src.backend.database import Database
|
|
||||||
from src.logic.log import MyLogger
|
|
||||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
|
||||||
|
|
||||||
# from src.transformers import RDS_AVAIL_DATA
|
|
||||||
from src.ui.dialogs.Ui_mail_preview import Ui_eMailPreview
|
|
||||||
|
|
||||||
config = OmegaConf.load("config.yaml")
|
|
||||||
|
|
||||||
|
|
||||||
class BackgroundChecker(QThread):
|
|
||||||
"""Check all apparats for available Books"""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MockAvailCheck:
|
|
||||||
def __init__(
|
|
||||||
self, links: list = None, appnumber: int = None, parent=None, books=list[dict]
|
|
||||||
):
|
|
||||||
if links is None:
|
|
||||||
links = []
|
|
||||||
super().__init__(parent)
|
|
||||||
self.logger = MyLogger("MockAvailChecker")
|
|
||||||
self.logger.log_info("Starting worker thread")
|
|
||||||
self.logger.log_info(
|
|
||||||
"Checking availability for "
|
|
||||||
+ str(links)
|
|
||||||
+ " with appnumber "
|
|
||||||
+ str(appnumber)
|
|
||||||
+ "..."
|
|
||||||
)
|
|
||||||
self.links = links
|
|
||||||
self.appnumber = appnumber
|
|
||||||
self.books = books
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.db = Database()
|
|
||||||
state = 0
|
|
||||||
count = 0
|
|
||||||
result = []
|
|
||||||
for link in self.links:
|
|
||||||
self.logger.log_info("Processing entry: " + str(link))
|
|
||||||
data = WebRequest().get_ppn(link).get_data()
|
|
||||||
transformer = BibTextTransformer("RDS")
|
|
||||||
rds = transformer.get_data(data).return_data("rds_availability")
|
|
||||||
|
|
||||||
for item in rds.items:
|
|
||||||
sign = item.superlocation
|
|
||||||
loc = item.location
|
|
||||||
# ic(item.location, item.superlocation)
|
|
||||||
if self.appnumber in sign or self.appnumber in loc:
|
|
||||||
state = 1
|
|
||||||
book_id = None
|
|
||||||
for book in self.books:
|
|
||||||
if book["bookdata"].signature == link:
|
|
||||||
book_id = book["id"]
|
|
||||||
break
|
|
||||||
self.logger.log_info(f"State of {link}: " + str(state))
|
|
||||||
print(
|
|
||||||
"lock acquired, updating availability of "
|
|
||||||
+ str(book_id)
|
|
||||||
+ " to "
|
|
||||||
+ str(state)
|
|
||||||
)
|
|
||||||
result.append((item.callnumber, state))
|
|
||||||
count += 1
|
|
||||||
return result
|
|
||||||
|
|
||||||
self.logger.log_info("Worker thread finished")
|
|
||||||
# teminate thread
|
|
||||||
|
|
||||||
|
|
||||||
class Mailer(Ui_eMailPreview):
|
|
||||||
updateSignal = Signal(int)
|
|
||||||
|
|
||||||
def __init__(self, data=None, parent=None):
|
|
||||||
super(QThread).__init__()
|
|
||||||
super(Ui_eMailPreview).__init__()
|
|
||||||
|
|
||||||
self.logger = MyLogger("Mailer")
|
|
||||||
self.data = data
|
|
||||||
self.appid = data["app_id"]
|
|
||||||
self.appname = data["app_name"]
|
|
||||||
self.subject = data["app_subject"]
|
|
||||||
self.profname = data["prof_name"]
|
|
||||||
self.mail_data = ""
|
|
||||||
self.prof_mail = data["prof_mail"]
|
|
||||||
self.dialog = QtWidgets.QDialog()
|
|
||||||
self.comboBox.currentIndexChanged.connect(self.set_mail)
|
|
||||||
self.prof_name.setText(self.prof_name)
|
|
||||||
self.mail_name.setText(self.prof_mail)
|
|
||||||
self.load_mail_templates()
|
|
||||||
self.gender_female.clicked.connect(self.set_mail)
|
|
||||||
self.gender_male.clicked.connect(self.set_mail)
|
|
||||||
self.gender_non.clicked.connect(self.set_mail)
|
|
||||||
self.buttonBox.accepted.connect(self.createAndSendMail)
|
|
||||||
|
|
||||||
def load_mail_templates(self):
|
|
||||||
# print("loading mail templates")
|
|
||||||
mail_templates = os.listdir("mail_vorlagen")
|
|
||||||
for template in mail_templates:
|
|
||||||
self.comboBox.addItem(template)
|
|
||||||
|
|
||||||
def get_greeting(self):
|
|
||||||
if self.gender_male.isChecked():
|
|
||||||
return "Sehr geehrter Herr"
|
|
||||||
elif self.gender_female.isChecked():
|
|
||||||
return "Sehr geehrte Frau"
|
|
||||||
elif self.gender_non.isChecked():
|
|
||||||
return "Guten Tag"
|
|
||||||
|
|
||||||
def set_mail(self):
|
|
||||||
email_template = self.comboBox.currentText()
|
|
||||||
if email_template == "":
|
|
||||||
return
|
|
||||||
with open(f"mail_vorlagen/{email_template}", "r", encoding="utf-8") as f:
|
|
||||||
mail_template = f.read()
|
|
||||||
email_header = email_template.split(".eml")[0]
|
|
||||||
if "{AppNr}" in email_template:
|
|
||||||
email_header = email_template.split(".eml")[0]
|
|
||||||
email_header = email_header.format(AppNr=self.appid, AppName=self.appname)
|
|
||||||
self.mail_header.setText(email_header)
|
|
||||||
self.mail_data = mail_template.split("<html>")[0]
|
|
||||||
mail_html = mail_template.split("<html>")[1]
|
|
||||||
mail_html = "<html>" + mail_html
|
|
||||||
Appname = self.appname
|
|
||||||
mail_html = mail_html.format(
|
|
||||||
Profname=self.prof_name.text().split(" ")[-1],
|
|
||||||
Appname=Appname,
|
|
||||||
AppNr=self.appid,
|
|
||||||
AppSubject=self.subject,
|
|
||||||
greeting=self.get_greeting(),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mail_body.setHtml(mail_html)
|
|
||||||
|
|
||||||
def createAndSendMail(self):
|
|
||||||
import smtplib
|
|
||||||
from email.mime.multipart import MIMEMultipart
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
|
|
||||||
smtp_server = config["mail"]["smtp_server"]
|
|
||||||
port: int = config["mail"]["port"]
|
|
||||||
sender_email = config["mail"]["sender"]
|
|
||||||
password = config["mail"]["password"]
|
|
||||||
message = MIMEMultipart()
|
|
||||||
message["From"] = sender_email
|
|
||||||
message["To"] = self.prof_mail
|
|
||||||
message["Subject"] = self.mail_header.text()
|
|
||||||
mail_body = self.mail_body.toHtml()
|
|
||||||
message.attach(MIMEText(mail_body, "html"))
|
|
||||||
mail = message.as_string()
|
|
||||||
|
|
||||||
server = smtplib.SMTP_SSL(smtp_server, port)
|
|
||||||
# server.starttls()
|
|
||||||
# server.auth(mechanism="PLAIN")
|
|
||||||
if config["mail"]["use_user_name"] == 1:
|
|
||||||
# print(config["mail"]["user_name"])
|
|
||||||
server.login(config["mail"]["user_name"], password)
|
|
||||||
else:
|
|
||||||
server.login(sender_email, password)
|
|
||||||
server.sendmail(sender_email, self.prof_mail, mail)
|
|
||||||
# print("Mail sent")
|
|
||||||
# end active process
|
|
||||||
server.quit()
|
|
||||||
|
|
||||||
|
|
||||||
class MailThread(QThread):
|
|
||||||
updateSignal = Signal(int)
|
|
||||||
|
|
||||||
def __init__(self, data=None, parent=None):
|
|
||||||
super(QThread).__init__()
|
|
||||||
super(MailThread).__init__()
|
|
||||||
self.logger = MyLogger("MailThread")
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def show_ui(self):
|
|
||||||
self.mailer = Mailer()
|
|
||||||
self.mailer.__init__()
|
|
||||||
self.mailer.dialog.exec_()
|
|
||||||
self.mailer.dialog.show()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.show_ui()
|
|
||||||
self.updateSignal.emit(1)
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import time
|
|
||||||
|
|
||||||
from PyQt6.QtCore import QThread, pyqtSignal
|
|
||||||
|
|
||||||
from src.backend.database import Database
|
|
||||||
from src.logic.log import MyLogger
|
|
||||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
|
||||||
|
|
||||||
# from icecream import ic
|
|
||||||
|
|
||||||
|
|
||||||
class BookGrabber(QThread):
|
|
||||||
updateSignal = pyqtSignal(int, int)
|
|
||||||
|
|
||||||
def __init__(self, filename):
|
|
||||||
super(BookGrabber, self).__init__(parent=None)
|
|
||||||
self.is_Running = True
|
|
||||||
self.logger = MyLogger("Worker")
|
|
||||||
self.logger.log_info("Starting worker thread")
|
|
||||||
self.data, self.app_id, self.prof_id, self.mode = self.readFile(filename)
|
|
||||||
|
|
||||||
self.book_id = None
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
def readFile(self, filename):
|
|
||||||
with open(filename, "r") as file:
|
|
||||||
data = file.readlines()
|
|
||||||
app_id = data[0].strip()
|
|
||||||
prof_id = data[1].strip()
|
|
||||||
mode = data[2].strip()
|
|
||||||
data = data[3:]
|
|
||||||
return data, app_id, prof_id, mode
|
|
||||||
|
|
||||||
# def resetValues(self):
|
|
||||||
# self.app_id = None
|
|
||||||
# self.prof_id = None
|
|
||||||
# self.mode = None
|
|
||||||
# self.data = None
|
|
||||||
# self.book_id = None
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
while self.is_Running:
|
|
||||||
self.db = Database()
|
|
||||||
item = 0
|
|
||||||
iterdata = self.data
|
|
||||||
print(iterdata)
|
|
||||||
for entry in iterdata:
|
|
||||||
signature = str(entry)
|
|
||||||
self.logger.log_info("Processing entry: " + signature)
|
|
||||||
|
|
||||||
webdata = WebRequest().get_ppn(entry).get_data()
|
|
||||||
if webdata == "error":
|
|
||||||
continue
|
|
||||||
bd = BibTextTransformer(self.mode).get_data(webdata).return_data()
|
|
||||||
transformer = BibTextTransformer("RDS")
|
|
||||||
rds = transformer.get_data(webdata).return_data("rds_availability")
|
|
||||||
bd.signature = entry
|
|
||||||
# confirm lock is acquired
|
|
||||||
print("lock acquired, adding book to database")
|
|
||||||
self.db.addBookToDatabase(bd, self.app_id, self.prof_id)
|
|
||||||
# get latest book id
|
|
||||||
self.book_id = self.db.getLastBookId()
|
|
||||||
self.logger.log_info("Added book to database")
|
|
||||||
state = 0
|
|
||||||
print(len(rds.items))
|
|
||||||
for rds_item in rds.items:
|
|
||||||
sign = rds_item.superlocation
|
|
||||||
loc = rds_item.location
|
|
||||||
# ic(sign, loc)
|
|
||||||
# ic(rds_item)
|
|
||||||
if self.app_id in sign or self.app_id in loc:
|
|
||||||
state = 1
|
|
||||||
break
|
|
||||||
|
|
||||||
# for book in self.books:
|
|
||||||
# if book["bookdata"].signature == entry:
|
|
||||||
# book_id = book["id"]
|
|
||||||
# break
|
|
||||||
self.logger.log_info(f"State of {signature}: {state}")
|
|
||||||
print(
|
|
||||||
"updating availability of "
|
|
||||||
+ str(self.book_id)
|
|
||||||
+ " to "
|
|
||||||
+ str(state)
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
self.db.setAvailability(self.book_id, state)
|
|
||||||
except sqlite3.OperationalError as e:
|
|
||||||
self.logger.log_error(f"Failed to update availability: {e}")
|
|
||||||
|
|
||||||
# time.sleep(5)
|
|
||||||
item += 1
|
|
||||||
self.updateSignal.emit(item, len(self.data))
|
|
||||||
self.logger.log_info("Worker thread finished")
|
|
||||||
self.stop()
|
|
||||||
if not self.is_Running:
|
|
||||||
break
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.is_Running = False
|
|
||||||
|
|
||||||
|
|
||||||
class AvailChecker(QThread):
|
|
||||||
updateSignal = pyqtSignal(str, int)
|
|
||||||
updateProgress = pyqtSignal(int, int)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, links: list = None, appnumber: int = None, parent=None, books=list[dict]
|
|
||||||
):
|
|
||||||
if links is None:
|
|
||||||
links = []
|
|
||||||
super().__init__(parent)
|
|
||||||
self.logger = MyLogger("AvailChecker")
|
|
||||||
self.logger.log_info("Starting worker thread")
|
|
||||||
self.logger.log_info(
|
|
||||||
"Checking availability for "
|
|
||||||
+ str(links)
|
|
||||||
+ " with appnumber "
|
|
||||||
+ str(appnumber)
|
|
||||||
+ "..."
|
|
||||||
)
|
|
||||||
self.links = links
|
|
||||||
self.appnumber = appnumber
|
|
||||||
self.books = books
|
|
||||||
self.logger.log_info(
|
|
||||||
f"Started worker with appnumber: {self.appnumber} and links: {self.links} and {len(self.books)} books..."
|
|
||||||
)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.db = Database()
|
|
||||||
state = 0
|
|
||||||
count = 0
|
|
||||||
for link in self.links:
|
|
||||||
self.logger.log_info("Processing entry: " + str(link))
|
|
||||||
data = WebRequest().get_ppn(link).get_data()
|
|
||||||
transformer = BibTextTransformer("RDS")
|
|
||||||
rds = transformer.get_data(data).return_data("rds_availability")
|
|
||||||
|
|
||||||
book_id = None
|
|
||||||
for item in rds.items:
|
|
||||||
sign = item.superlocation
|
|
||||||
loc = item.location
|
|
||||||
# print(item.location)
|
|
||||||
if self.appnumber in sign or self.appnumber in loc:
|
|
||||||
state = 1
|
|
||||||
break
|
|
||||||
for book in self.books:
|
|
||||||
if book["bookdata"].signature == link:
|
|
||||||
book_id = book["id"]
|
|
||||||
break
|
|
||||||
self.logger.log_info(f"State of {link}: " + str(state))
|
|
||||||
print("Updating availability of " + str(book_id) + " to " + str(state))
|
|
||||||
self.db.setAvailability(book_id, state)
|
|
||||||
count += 1
|
|
||||||
self.updateProgress.emit(count, len(self.links))
|
|
||||||
self.updateSignal.emit(item.callnumber, state)
|
|
||||||
|
|
||||||
self.logger.log_info("Worker thread finished")
|
|
||||||
# teminate thread
|
|
||||||
|
|
||||||
self.quit()
|
|
||||||
|
|
||||||
|
|
||||||
class AutoAdder(QThread):
|
|
||||||
updateSignal = pyqtSignal(int)
|
|
||||||
|
|
||||||
setTextSignal = pyqtSignal(int)
|
|
||||||
progress = pyqtSignal(int)
|
|
||||||
|
|
||||||
def __init__(self, data=None, app_id=None, prof_id=None, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.logger = MyLogger("AutoAdder")
|
|
||||||
self.data = data
|
|
||||||
self.app_id = app_id
|
|
||||||
self.prof_id = prof_id
|
|
||||||
|
|
||||||
print("Launched AutoAdder")
|
|
||||||
print(self.data, self.app_id, self.prof_id)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.db = Database()
|
|
||||||
# show the dialog, start the thread to gather data and dynamically update progressbar and listwidget
|
|
||||||
self.logger.log_info("Starting worker thread")
|
|
||||||
item = 0
|
|
||||||
for entry in self.data:
|
|
||||||
try:
|
|
||||||
# webdata = WebRequest().get_ppn(entry).get_data()
|
|
||||||
# bd = BibTextTransformer("ARRAY").get_data(webdata).return_data()
|
|
||||||
# bd.signature = entry
|
|
||||||
self.updateSignal.emit(item)
|
|
||||||
self.setTextSignal.emit(entry)
|
|
||||||
# qsleep
|
|
||||||
item += 1
|
|
||||||
self.progress.emit(item)
|
|
||||||
print(item, len(self.data))
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
self.logger.log_exception(
|
|
||||||
f"The query failed with message {e} for signature {entry}"
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
if item == len(self.data):
|
|
||||||
self.logger.log_info("Worker thread finished")
|
|
||||||
# teminate thread
|
|
||||||
self.finished.emit()
|
|
||||||
|
|
||||||
|
|
||||||
class MockAvailCheck:
|
|
||||||
def __init__(
|
|
||||||
self, links: list = None, appnumber: int = None, parent=None, books=list[dict]
|
|
||||||
):
|
|
||||||
if links is None:
|
|
||||||
links = []
|
|
||||||
super().__init__(parent)
|
|
||||||
self.logger = MyLogger("MockAvailChecker")
|
|
||||||
self.logger.log_info("Starting worker thread")
|
|
||||||
self.logger.log_info(
|
|
||||||
"Checking availability for "
|
|
||||||
+ str(links)
|
|
||||||
+ " with appnumber "
|
|
||||||
+ str(appnumber)
|
|
||||||
+ "..."
|
|
||||||
)
|
|
||||||
self.links = links
|
|
||||||
self.appnumber = appnumber
|
|
||||||
self.books = books
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.db = Database()
|
|
||||||
state = 0
|
|
||||||
count = 0
|
|
||||||
result = []
|
|
||||||
for link in self.links:
|
|
||||||
self.logger.log_info("Processing entry: " + str(link))
|
|
||||||
data = WebRequest().get_ppn(link).get_data()
|
|
||||||
transformer = BibTextTransformer("RDS")
|
|
||||||
rds = transformer.get_data(data).return_data("rds_availability")
|
|
||||||
|
|
||||||
for item in rds.items:
|
|
||||||
sign = item.superlocation
|
|
||||||
loc = item.location
|
|
||||||
# ic(item.location, item.superlocation)
|
|
||||||
if self.appnumber in sign or self.appnumber in loc:
|
|
||||||
state = 1
|
|
||||||
book_id = None
|
|
||||||
for book in self.books:
|
|
||||||
if book["bookdata"].signature == link:
|
|
||||||
book_id = book["id"]
|
|
||||||
break
|
|
||||||
self.logger.log_info(f"State of {link}: " + str(state))
|
|
||||||
print(
|
|
||||||
"lock acquired, updating availability of "
|
|
||||||
+ str(book_id)
|
|
||||||
+ " to "
|
|
||||||
+ str(state)
|
|
||||||
)
|
|
||||||
result.append((item.callnumber, state))
|
|
||||||
count += 1
|
|
||||||
return result
|
|
||||||
|
|
||||||
self.logger.log_info("Worker thread finished")
|
|
||||||
# teminate thread
|
|
||||||
@@ -11,10 +11,11 @@ from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData
|
|||||||
from src.transformers.transformers import RDS_AVAIL_DATA, RDS_GENERIC_DATA
|
from src.transformers.transformers import RDS_AVAIL_DATA, RDS_GENERIC_DATA
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import pandas as pd
|
import sys
|
||||||
from docx import Document
|
import zipfile
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from src.backend import Semester
|
from typing import Any, Union
|
||||||
from typing import Union, Any
|
|
||||||
|
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import pandas as pd
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from docx import Document
|
||||||
|
|
||||||
|
from src import LOG_DIR
|
||||||
|
from src.backend import Semester
|
||||||
|
from src.logic.openai import name_tester, run_shortener, semester_converter
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -75,12 +80,37 @@ class SemapDocument:
|
|||||||
phoneNumber: int = None
|
phoneNumber: int = None
|
||||||
mail: str = None
|
mail: str = None
|
||||||
title: str = None
|
title: str = None
|
||||||
|
title_suggestions: list[str] = None
|
||||||
semester: Union[str, Semester] = None
|
semester: Union[str, Semester] = None
|
||||||
books: list[Book] = None
|
books: list[Book] = None
|
||||||
eternal: bool = False
|
eternal: bool = False
|
||||||
personName: str = None
|
personName: str = None
|
||||||
personTitle: str = None
|
personTitle: str = None
|
||||||
|
title_length = 0
|
||||||
|
title_max_length = 0
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
self.title_suggestions = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nameSetter(self):
|
||||||
|
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:
|
||||||
|
log.warning("Title is too long")
|
||||||
|
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 = []
|
||||||
|
pass
|
||||||
@property
|
@property
|
||||||
def renameSemester(self) -> None:
|
def renameSemester(self) -> None:
|
||||||
if ", Dauer" in self.semester:
|
if ", Dauer" in self.semester:
|
||||||
@@ -88,8 +118,8 @@ class SemapDocument:
|
|||||||
self.eternal = True
|
self.eternal = True
|
||||||
self.semester = Semester().from_string(self.semester)
|
self.semester = Semester().from_string(self.semester)
|
||||||
else:
|
else:
|
||||||
logger.warning("Semester {} is not valid", self.semester)
|
log.warning("Semester {} is not valid", self.semester)
|
||||||
self.semester = None
|
self.semester = Semester().from_string(semester_converter(self.semester))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def signatures(self) -> list[str]:
|
def signatures(self) -> list[str]:
|
||||||
@@ -105,11 +135,14 @@ def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
|
|||||||
for table in tables:
|
for table in tables:
|
||||||
data = []
|
data = []
|
||||||
for row in table.rows:
|
for row in table.rows:
|
||||||
row_data = []
|
row_data: list[Any] = []
|
||||||
for cell in row.cells:
|
for cell in row.cells:
|
||||||
text = cell.text
|
text = cell.text
|
||||||
|
|
||||||
text = text.replace("\n", "")
|
text = text.replace("\n", "")
|
||||||
row_data.append(text)
|
row_data.append(text)
|
||||||
|
if text == "Ihr Fach:":
|
||||||
|
row_data.append(get_fach(path))
|
||||||
data.append(row_data)
|
data.append(row_data)
|
||||||
df = pd.DataFrame(data)
|
df = pd.DataFrame(data)
|
||||||
df.columns = df.iloc[0]
|
df.columns = df.iloc[0]
|
||||||
@@ -117,11 +150,27 @@ def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
|
|||||||
|
|
||||||
m_data.append(df)
|
m_data.append(df)
|
||||||
|
|
||||||
# for df[0, 1]: merge i and i+1 as key, value
|
|
||||||
|
|
||||||
return m_data
|
return m_data
|
||||||
|
|
||||||
|
|
||||||
|
def get_fach(path: str) -> str:
|
||||||
|
document = zipfile.ZipFile(path)
|
||||||
|
xml_data = document.read("word/document.xml")
|
||||||
|
document.close()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(xml_data, "xml")
|
||||||
|
# text we need is in <w:p w14:paraId="12456A32" ... > -> w:r -> w:t
|
||||||
|
paragraphs = soup.find_all("w:p")
|
||||||
|
names = []
|
||||||
|
for para in paragraphs:
|
||||||
|
para_id = para.get("w14:paraId")
|
||||||
|
if para_id == "12456A32":
|
||||||
|
# get the data in the w:t
|
||||||
|
for run in para.find_all("w:r"):
|
||||||
|
data = run.find("w:t")
|
||||||
|
return data.contents[0]
|
||||||
|
|
||||||
|
|
||||||
def makeDict():
|
def makeDict():
|
||||||
return {
|
return {
|
||||||
"work_author": None,
|
"work_author": None,
|
||||||
@@ -222,10 +271,10 @@ def word_to_semap(word_path: str) -> SemapDocument:
|
|||||||
df = word_docx_to_csv(word_path)
|
df = word_docx_to_csv(word_path)
|
||||||
apparatdata = df[0]
|
apparatdata = df[0]
|
||||||
apparatdata = apparatdata.to_dict()
|
apparatdata = apparatdata.to_dict()
|
||||||
|
|
||||||
keys = list(apparatdata.keys())
|
keys = list(apparatdata.keys())
|
||||||
|
print(apparatdata, keys)
|
||||||
|
|
||||||
appdata = {keys[i]: keys[i + 1] for i in range(0, len(keys), 2)}
|
appdata = {keys[i]: keys[i + 1] for i in range(0, len(keys) - 1, 2)}
|
||||||
semap.phoneNumber = appdata["Telefon:"]
|
semap.phoneNumber = appdata["Telefon:"]
|
||||||
semap.subject = appdata["Ihr Fach:"]
|
semap.subject = appdata["Ihr Fach:"]
|
||||||
semap.mail = appdata["Mailadresse:"]
|
semap.mail = appdata["Mailadresse:"]
|
||||||
@@ -238,6 +287,8 @@ def word_to_semap(word_path: str) -> SemapDocument:
|
|||||||
semap.title = appdata["Veranstaltung:"]
|
semap.title = appdata["Veranstaltung:"]
|
||||||
semap.semester = appdata["Semester:"]
|
semap.semester = appdata["Semester:"]
|
||||||
semap.renameSemester
|
semap.renameSemester
|
||||||
|
semap.nameSetter
|
||||||
|
|
||||||
books = df[2]
|
books = df[2]
|
||||||
booklist = []
|
booklist = []
|
||||||
for i in range(len(books)):
|
for i in range(len(books)):
|
||||||
@@ -254,7 +305,6 @@ def word_to_semap(word_path: str) -> SemapDocument:
|
|||||||
booklist.append(book)
|
booklist.append(book)
|
||||||
log.info("Found {} books", len(booklist))
|
log.info("Found {} books", len(booklist))
|
||||||
semap.books = booklist
|
semap.books = booklist
|
||||||
|
|
||||||
return semap
|
return semap
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,8 @@ class ZoteroController:
|
|||||||
zoterocfg = settings.zotero
|
zoterocfg = settings.zotero
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
if self.zoterocfg.library_id is None:
|
||||||
|
return
|
||||||
self.zot = zotero.Zotero(
|
self.zot = zotero.Zotero(
|
||||||
self.zoterocfg.library_id,
|
self.zoterocfg.library_id,
|
||||||
self.zoterocfg.library_type,
|
self.zoterocfg.library_type,
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ from dataclasses import dataclass
|
|||||||
from dataclasses import field as dataclass_field
|
from dataclasses import field as dataclass_field
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
|
|
||||||
|
from src import LOG_DIR
|
||||||
from src.logic.dataclass import BookData
|
from src.logic.dataclass import BookData
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
###Pydatnic models
|
###Pydatnic models
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\edit_bookdata.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\edit_bookdata.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from src.logic.dataclass import BookData
|
from src.logic.dataclass import BookData
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\fileparser.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\fileparser.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ class Ui_Dialog(object):
|
|||||||
self.listWidget.setObjectName("listWidget")
|
self.listWidget.setObjectName("listWidget")
|
||||||
self.signatures = []
|
self.signatures = []
|
||||||
self.returned = []
|
self.returned = []
|
||||||
# self.data_gathering_complete = QtCore.pyqtSignal()
|
# self.data_gathering_complete = QtCore.Signal()
|
||||||
self.retranslateUi(Dialog)
|
self.retranslateUi(Dialog)
|
||||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Form implementation generated from reading ui file '/home/alexander/GitHub/Semesterapparate/ui/dialogs/login.ui'
|
# Form implementation generated from reading ui file '/home/alexander/GitHub/Semesterapparate/ui/dialogs/login.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.5.3
|
# Created by: PySide6 UI code generator 6.5.3
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
from src.backend.database import Database
|
from src.backend.database import Database
|
||||||
from src.backend.admin_console import AdminCommands
|
from src.backend.admin_console import AdminCommands
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\mail_preview.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\mail_preview.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\medianadder.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\medianadder.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\new_subject.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\new_subject.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\parsed_titles.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\parsed_titles.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from src.logic.log import MyLogger
|
from src.logic.log import MyLogger
|
||||||
from src.logic.threads import AutoAdder
|
from src.logic.threads import AutoAdder
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\reminder.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\reminder.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\settings.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\Semesterapparate\ui\dialogs\settings.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from omegaconf import OmegaConf
|
from omegaconf import OmegaConf
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
config = OmegaConf.load("config.yaml")
|
config = OmegaConf.load("config.yaml")
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from .dialog_sources.Ui_about import Ui_about
|
from .dialog_sources.Ui_about import Ui_about
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
from PyQt6.QtCore import PYQT_VERSION_STR
|
import PySide6
|
||||||
from src import Icon, __version__, __author__
|
from src import Icon, __version__, __author__
|
||||||
|
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ class About(QtWidgets.QDialog, Ui_about):
|
|||||||
data = {
|
data = {
|
||||||
"Version": __version__,
|
"Version": __version__,
|
||||||
"Author": __author__,
|
"Author": __author__,
|
||||||
"PyQt6 Version": PYQT_VERSION_STR,
|
"PySide6 Version": PySide6.__version__,
|
||||||
"License": "MIT License",
|
"License": "MIT License",
|
||||||
"Icons": """Google Material Design Icons (https://fonts.google.com/icons)
|
"Icons": """Google Material Design Icons (https://fonts.google.com/icons)
|
||||||
StableDiffusion (logo)
|
StableDiffusion (logo)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
from .dialog_sources.Ui_apparat_extend import Ui_Dialog
|
from .dialog_sources.Ui_apparat_extend import Ui_Dialog
|
||||||
from src import Icon
|
from src import Icon
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
from src.logic.dataclass import BookData
|
from src.logic.dataclass import BookData
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from .dialog_sources.Ui_confirm_extend import Ui_extend_confirm
|
from .dialog_sources.Ui_confirm_extend import Ui_extend_confirm
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class ConfirmExtend(QtWidgets.QDialog, Ui_extend_confirm):
|
class ConfirmExtend(QtWidgets.QDialog, Ui_extend_confirm):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\confirm_extend.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\confirm_extend.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_extend_confirm(object):
|
class Ui_extend_confirm(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\about.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\about.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_about(object):
|
class Ui_about(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\app_status.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\app_status.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore
|
from PySide6 import QtCore
|
||||||
|
|
||||||
|
|
||||||
class Ui_Form(object):
|
class Ui_Form(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\apparat_extend.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\apparat_extend.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.7.1
|
# Created by: PySide6 UI code generator 6.7.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\confirm_extend.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\confirm_extend.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.7.1
|
# Created by: PySide6 UI code generator 6.7.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_extend_confirm(object):
|
class Ui_extend_confirm(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\edit_bookdata.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\edit_bookdata.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_add_table_entry.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_add_table_entry.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.7.1
|
# Created by: PySide6 UI code generator 6.7.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generate_citation.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generate_citation.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generator_confirm.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generator_confirm.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\login.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\login.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.7.1
|
# Created by: PySide6 UI code generator 6.7.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_eMailPreview(object):
|
class Ui_eMailPreview(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\medianadder.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\medianadder.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.7.1
|
# Created by: PySide6 UI code generator 6.7.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\parsed_titles.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\parsed_titles.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Form(object):
|
class Ui_Form(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\reminder.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\reminder.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.6.1
|
# Created by: PySide6 UI code generator 6.6.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Erinnerung(object):
|
class Ui_Erinnerung(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\settings.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\settings.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.7.1
|
# Created by: PySide6 UI code generator 6.7.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\about.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\about.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_about(object):
|
class Ui_about(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\app_status.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\app_status.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Form(object):
|
class Ui_Form(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\apparat_extend.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\apparat_extend.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\confirm_extend.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\confirm_extend.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_extend_confirm(object):
|
class Ui_extend_confirm(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\documentprint.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\documentprint.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.9.0
|
# Created by: PySide6 UI code generator 6.9.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\edit_bookdata.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\edit_bookdata.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_add_table_entry.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_add_table_entry.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generate_citation.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generate_citation.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generator_confirm.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generator_confirm.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\login.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\login.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_eMailPreview(object):
|
class Ui_eMailPreview(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\medianadder.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\medianadder.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\parsed_titles.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\parsed_titles.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Form(object):
|
class Ui_Form(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\reminder.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\reminder.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Erinnerung(object):
|
class Ui_Erinnerung(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\settings.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\settings.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.9.0
|
# Created by: PySide6 UI code generator 6.9.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from .dialog_sources.documentprint_ui import Ui_Dialog
|
from .dialog_sources.documentprint_ui import Ui_Dialog
|
||||||
from PyQt6 import QtWidgets, QtCore
|
from PySide6 import QtWidgets, QtCore
|
||||||
from src import Icon
|
from src import Icon
|
||||||
|
|
||||||
from src.utils.richtext import SemapSchilder, SemesterDocument
|
from src.utils.richtext import SemapSchilder, SemesterDocument
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from .dialog_sources.Ui_elsa_add_table_entry import Ui_Dialog
|
from .dialog_sources.Ui_elsa_add_table_entry import Ui_Dialog
|
||||||
from src.logic.webrequest import WebRequest, BibTextTransformer
|
from src.logic.webrequest import WebRequest, BibTextTransformer
|
||||||
from src import Icon
|
from src import Icon
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
from src.transformers.transformers import DictToTable
|
from src.transformers.transformers import DictToTable
|
||||||
from src.logic.zotero import ZoteroController
|
from src.logic.zotero import ZoteroController
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from .dialog_sources.Ui_elsa_generate_citation import Ui_Dialog
|
from .dialog_sources.Ui_elsa_generate_citation import Ui_Dialog
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class ElsaCitation(QtWidgets.QDialog, Ui_Dialog):
|
class ElsaCitation(QtWidgets.QDialog, Ui_Dialog):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from .dialog_sources.Ui_elsa_generator_confirm import Ui_Dialog
|
from .dialog_sources.Ui_elsa_generator_confirm import Ui_Dialog
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class ElsaGenConfirm(QtWidgets.QDialog, Ui_Dialog):
|
class ElsaGenConfirm(QtWidgets.QDialog, Ui_Dialog):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'ui/dialogs/extend_apparat.ui'
|
# Form implementation generated from reading ui file 'ui/dialogs/extend_apparat.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Frame(object):
|
class Ui_Frame(object):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
import sys
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
import loguru
|
||||||
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
from src import LOG_DIR, Icon
|
||||||
from src.backend.admin_console import AdminCommands
|
|
||||||
from src.backend.database import Database
|
from src.backend.database import Database
|
||||||
|
|
||||||
from .dialog_sources.login_ui import Ui_Dialog
|
from .dialog_sources.login_ui import Ui_Dialog
|
||||||
import sys
|
|
||||||
import loguru
|
|
||||||
from src import Icon
|
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
class LoginDialog(Ui_Dialog):
|
class LoginDialog(Ui_Dialog):
|
||||||
@@ -52,6 +50,7 @@ class LoginDialog(Ui_Dialog):
|
|||||||
self.lineEdit_2.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
|
self.lineEdit_2.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
|
||||||
self.lineEdit_2.setClearButtonEnabled(True)
|
self.lineEdit_2.setClearButtonEnabled(True)
|
||||||
self.lineEdit_2.setObjectName("lineEdit_2")
|
self.lineEdit_2.setObjectName("lineEdit_2")
|
||||||
|
log.info("Calling database")
|
||||||
self.db = Database()
|
self.db = Database()
|
||||||
|
|
||||||
self.retranslateUi(Dialog)
|
self.retranslateUi(Dialog)
|
||||||
@@ -76,6 +75,8 @@ class LoginDialog(Ui_Dialog):
|
|||||||
|
|
||||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
||||||
if len(self.db.getUsers()) == 0:
|
if len(self.db.getUsers()) == 0:
|
||||||
|
from src.backend.admin_console import AdminCommands
|
||||||
|
|
||||||
AdminCommands().create_admin()
|
AdminCommands().create_admin()
|
||||||
self.lresult = 1 # Indicate successful login
|
self.lresult = 1 # Indicate successful login
|
||||||
self.lusername = username
|
self.lusername = username
|
||||||
@@ -89,14 +90,14 @@ class LoginDialog(Ui_Dialog):
|
|||||||
else:
|
else:
|
||||||
# Credentials are invalid, display a warning
|
# Credentials are invalid, display a warning
|
||||||
if username == "" or password == "":
|
if username == "" or password == "":
|
||||||
logger.warning("Invalid username or password. Login failed.")
|
log.warning("Invalid username or password. Login failed.")
|
||||||
warning_dialog = QtWidgets.QMessageBox()
|
warning_dialog = QtWidgets.QMessageBox()
|
||||||
warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||||
warning_dialog.setText("Please enter a username and password.")
|
warning_dialog.setText("Please enter a username and password.")
|
||||||
warning_dialog.setWindowTitle("Login Failed")
|
warning_dialog.setWindowTitle("Login Failed")
|
||||||
warning_dialog.exec()
|
warning_dialog.exec()
|
||||||
else:
|
else:
|
||||||
logger.warning("Invalid username or password. Login failed.")
|
log.warning("Invalid username or password. Login failed.")
|
||||||
warning_dialog = QtWidgets.QMessageBox()
|
warning_dialog = QtWidgets.QMessageBox()
|
||||||
warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||||
warning_dialog.setText(
|
warning_dialog.setText(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
from src import Icon, settings as config
|
from src import Icon, settings as config
|
||||||
|
|
||||||
@@ -10,11 +10,11 @@ from .dialog_sources.Ui_mail_preview import Ui_eMailPreview as MailPreviewDialog
|
|||||||
from .mailTemplate import MailTemplateDialog
|
from .mailTemplate import MailTemplateDialog
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt6 import QtGui, QtWidgets, QtCore
|
from PySide6 import QtGui, QtWidgets, QtCore
|
||||||
|
|
||||||
from src import Icon
|
from src import Icon
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ logger.add(sys.stdout)
|
|||||||
|
|
||||||
|
|
||||||
class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||||
updateSignal = QtCore.pyqtSignal()
|
updateSignal = QtCore.Signal()
|
||||||
|
|
||||||
def __init__(self, parent=None) -> None:
|
def __init__(self, parent=None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'ui\dialogs\mail_preview.ui'
|
# Form implementation generated from reading ui file 'ui\dialogs\mail_preview.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\mail_preview.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\mail_preview.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PySide6 UI code generator 6.8.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_eMailPreview(object):
|
class Ui_eMailPreview(object):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from .dialog_sources.medianadder_ui import Ui_Dialog
|
from .dialog_sources.medianadder_ui import Ui_Dialog
|
||||||
from src import Icon
|
from src import Icon
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
from src.backend import AutoAdder
|
from src.backend import AutoAdder
|
||||||
|
|
||||||
@@ -6,11 +6,11 @@ from src.backend import AutoAdder
|
|||||||
from .dialog_sources.parsed_titles_ui import Ui_Form
|
from .dialog_sources.parsed_titles_ui import Ui_Form
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\parsed_titles.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\parsed_titles.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.9.0
|
# Created by: PySide6 UI code generator 6.9.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Form(object):
|
class Ui_Form(object):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'ui\dialogs\confirm_extend.ui'
|
# Form implementation generated from reading ui file 'ui\dialogs\confirm_extend.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.3.1
|
# Created by: PySide6 UI code generator 6.3.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
from src import Icon
|
from src import Icon
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
from .dialog_sources.reminder_ui import Ui_Erinnerung as Ui_Dialog
|
from .dialog_sources.reminder_ui import Ui_Erinnerung as Ui_Dialog
|
||||||
from src import Icon
|
from src import Icon
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
from src import Icon, settings
|
from src import Icon, settings
|
||||||
from .dialog_sources.settings_ui import Ui_Dialog as _settings
|
from .dialog_sources.settings_ui import Ui_Dialog as _settings
|
||||||
from src.ui.widgets.iconLine import IconWidget
|
from src.ui.widgets.iconLine import IconWidget
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
import sys
|
||||||
|
from src import LOG_DIR
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -80,8 +81,8 @@ class Settings(QtWidgets.QDialog, _settings):
|
|||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
self.db_name.setText(settings.database.name)
|
self.db_name.setText(settings.database.name)
|
||||||
self.db_path.setText(settings.database.path)
|
self.db_path.setText(str(settings.database.path.expanduser()))
|
||||||
self.save_path.setText(settings.database.temp)
|
self.save_path.setText(str(settings.database.temp.expanduser()))
|
||||||
self.smtp_address.setText(settings.mail.smtp_server)
|
self.smtp_address.setText(settings.mail.smtp_server)
|
||||||
self.smtp_port.setText(str(settings.mail.port))
|
self.smtp_port.setText(str(settings.mail.port))
|
||||||
self.sender_email.setText(settings.mail.sender)
|
self.sender_email.setText(settings.mail.sender)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt6 import QtWidgets
|
from PySide6 import QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class ValidatorButton(QtWidgets.QToolButton):
|
class ValidatorButton(QtWidgets.QToolButton):
|
||||||
|
|||||||
@@ -1923,8 +1923,8 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Help</string>
|
<string>Help</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionDokumentation_lokal"/>
|
|
||||||
<addaction name="actionAbout"/>
|
<addaction name="actionAbout"/>
|
||||||
|
<addaction name="actionDokumentation"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuDatei"/>
|
<addaction name="menuDatei"/>
|
||||||
<addaction name="menuEinstellungen"/>
|
<addaction name="menuEinstellungen"/>
|
||||||
@@ -1956,17 +1956,6 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDokumentation">
|
|
||||||
<property name="text">
|
|
||||||
<string>Dokumentation (online)</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F1</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcutContext">
|
|
||||||
<enum>Qt::ApplicationShortcut</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionAbout">
|
<action name="actionAbout">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>About</string>
|
<string>About</string>
|
||||||
@@ -1975,9 +1964,9 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
<enum>QAction::AboutRole</enum>
|
<enum>QAction::AboutRole</enum>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDokumentation_lokal">
|
<action name="actionDokumentation">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Dokumentation (lokal)</string>
|
<string>Dokumentation</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>F1</string>
|
<string>F1</string>
|
||||||
@@ -2009,8 +1998,6 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
<tabstop>automation_add_selected_books</tabstop>
|
<tabstop>automation_add_selected_books</tabstop>
|
||||||
<tabstop>saveandcreate</tabstop>
|
<tabstop>saveandcreate</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources/>
|
||||||
<include location="../../resources.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
|||||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\sounds\semesterapparat_ui.ui'
|
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\sounds\semesterapparat_ui.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.9.0
|
# Created by: PySide6 UI code generator 6.9.0
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_MainWindow(object):
|
class Ui_MainWindow(object):
|
||||||
|
|||||||
@@ -1,74 +1,71 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
import atexit
|
import atexit
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import time
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
|
import loguru
|
||||||
from natsort import natsorted
|
from natsort import natsorted
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
from PyQt6.QtCore import QThread
|
from PySide6.QtCore import QThread, Qt
|
||||||
from PyQt6.QtGui import QRegularExpressionValidator
|
from PySide6.QtGui import QRegularExpressionValidator
|
||||||
|
|
||||||
from src import Icon
|
from src import LOG_DIR, Icon
|
||||||
from src.backend import Database, BookGrabber, AvailChecker, DocumentationThread
|
from src.backend import AvailChecker, BookGrabber, Database, DocumentationThread
|
||||||
from src.backend.semester import Semester
|
|
||||||
from src.backend.create_file import recreateFile
|
from src.backend.create_file import recreateFile
|
||||||
from src.backend.delete_temp_contents import delete_temp_contents as tempdelete
|
from src.backend.delete_temp_contents import delete_temp_contents as tempdelete
|
||||||
from src.ui import Ui_Semesterapparat
|
from src.backend.semester import Semester
|
||||||
from src.logic import (
|
from src.logic import (
|
||||||
APP_NRS,
|
APP_NRS,
|
||||||
# PROF_TITLES,
|
Apparat,
|
||||||
ApparatData,
|
ApparatData,
|
||||||
BookData,
|
BookData,
|
||||||
|
Prof,
|
||||||
|
SemapDocument,
|
||||||
csv_to_list,
|
csv_to_list,
|
||||||
word_to_semap,
|
word_to_semap,
|
||||||
SemapDocument,
|
|
||||||
Prof,
|
|
||||||
Apparat,
|
|
||||||
)
|
)
|
||||||
|
from src.ui import Ui_Semesterapparat
|
||||||
from src.ui.dialogs import (
|
from src.ui.dialogs import (
|
||||||
popus_confirm,
|
|
||||||
MedienAdder,
|
|
||||||
About,
|
About,
|
||||||
ApparatExtendDialog,
|
ApparatExtendDialog,
|
||||||
Mail_Dialog,
|
|
||||||
Settings,
|
|
||||||
BookDataUI,
|
BookDataUI,
|
||||||
|
DocumentPrintDialog,
|
||||||
LoginDialog,
|
LoginDialog,
|
||||||
|
Mail_Dialog,
|
||||||
|
MedienAdder,
|
||||||
ParsedTitles,
|
ParsedTitles,
|
||||||
ReminderDialog,
|
ReminderDialog,
|
||||||
DocumentPrintDialog,
|
Settings,
|
||||||
|
popus_confirm,
|
||||||
)
|
)
|
||||||
from src.ui.widgets import (
|
from src.ui.widgets import (
|
||||||
ElsaDialog,
|
|
||||||
MessageCalendar,
|
|
||||||
FilePicker,
|
|
||||||
CalendarEntry,
|
CalendarEntry,
|
||||||
UserCreate,
|
|
||||||
SearchStatisticPage,
|
|
||||||
EditUser,
|
|
||||||
EditProf,
|
EditProf,
|
||||||
|
EditUser,
|
||||||
|
ElsaDialog,
|
||||||
|
FilePicker,
|
||||||
|
MessageCalendar,
|
||||||
|
SearchStatisticPage,
|
||||||
|
UserCreate,
|
||||||
)
|
)
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
import loguru
|
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
log.add(
|
log.add(
|
||||||
f"logs/{datetime.now().strftime('%Y-%m-%d')}.log",
|
f"{LOG_DIR}/{datetime.now().strftime('%Y-%m-%d')}.log",
|
||||||
rotation="1 day",
|
rotation="1 day",
|
||||||
retention="1 month",
|
retention="1 month",
|
||||||
)
|
)
|
||||||
|
log.critical("UI started")
|
||||||
valid_input = (0, 0, 0, 0, 0, 0)
|
valid_input = (0, 0, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
@@ -120,7 +117,7 @@ class Ui(Ui_Semesterapparat):
|
|||||||
# Actions
|
# Actions
|
||||||
self.actionEinstellungen.triggered.connect(self.open_settings) # type:ignore
|
self.actionEinstellungen.triggered.connect(self.open_settings) # type:ignore
|
||||||
Icon("settings", self.actionEinstellungen)
|
Icon("settings", self.actionEinstellungen)
|
||||||
self.actionDokumentation_lokal.triggered.connect(self.open_documentation) # type:ignore
|
self.documentation_open = False
|
||||||
Icon("offAction", self.actionBeenden)
|
Icon("offAction", self.actionBeenden)
|
||||||
self.actionBeenden.triggered.connect(self.quit) # type:ignore
|
self.actionBeenden.triggered.connect(self.quit) # type:ignore
|
||||||
self.actionAbout.triggered.connect(self.open_about) # type:ignore
|
self.actionAbout.triggered.connect(self.open_about) # type:ignore
|
||||||
@@ -206,7 +203,7 @@ class Ui(Ui_Semesterapparat):
|
|||||||
self.add_medium.setEnabled(False)
|
self.add_medium.setEnabled(False)
|
||||||
self.docu = DocumentationThread()
|
self.docu = DocumentationThread()
|
||||||
|
|
||||||
self.actionDokumentation_lokal.triggered.connect(self.open_documentation) # type:ignore
|
self.actionDokumentation.triggered.connect(self.open_documentation) # type:ignore
|
||||||
|
|
||||||
# get all current apparats and cache them in a list
|
# get all current apparats and cache them in a list
|
||||||
self.apparats = self.get_apparats()
|
self.apparats = self.get_apparats()
|
||||||
@@ -331,10 +328,16 @@ class Ui(Ui_Semesterapparat):
|
|||||||
|
|
||||||
def open_documentation(self):
|
def open_documentation(self):
|
||||||
log.info("Opening Documentation")
|
log.info("Opening Documentation")
|
||||||
if not self.docu.isRunning():
|
self.statusBar.showMessage("Dokumentation wird geöffnet", 5000)
|
||||||
|
|
||||||
|
if not self.documentation_open:
|
||||||
|
# write "opening documentation in 5s into status bar"
|
||||||
|
self.documentation_open = True
|
||||||
self.docu.start()
|
self.docu.start()
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
webbrowser.open("http://localhost:8000")
|
webbrowser.open("http://localhost:8000")
|
||||||
|
self.statusBar.showMessage("")
|
||||||
|
|
||||||
def update_calendar(self, data: list[dict[str, Any]]):
|
def update_calendar(self, data: list[dict[str, Any]]):
|
||||||
self.calendarWidget.setMessages([data])
|
self.calendarWidget.setMessages([data])
|
||||||
@@ -556,6 +559,7 @@ class Ui(Ui_Semesterapparat):
|
|||||||
else:
|
else:
|
||||||
self.__setValidState(self.valid_check_semester, 0, self._mand, 5)
|
self.__setValidState(self.valid_check_semester, 0, self._mand, 5)
|
||||||
self.check_eternal_app.setEnabled(False)
|
self.check_eternal_app.setEnabled(False)
|
||||||
|
return valid
|
||||||
|
|
||||||
def display_valid_semester(self):
|
def display_valid_semester(self):
|
||||||
print(f"""
|
print(f"""
|
||||||
@@ -563,6 +567,7 @@ class Ui(Ui_Semesterapparat):
|
|||||||
Sommer: {self.sem_sommer.isChecked()}
|
Sommer: {self.sem_sommer.isChecked()}
|
||||||
Winter: {self.sem_winter.isChecked()}
|
Winter: {self.sem_winter.isChecked()}
|
||||||
Eternal: {self.check_eternal_app.isChecked()}
|
Eternal: {self.check_eternal_app.isChecked()}
|
||||||
|
Valid: {self.validate_semester()}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def change_state(self, index, state):
|
def change_state(self, index, state):
|
||||||
@@ -985,7 +990,7 @@ class Ui(Ui_Semesterapparat):
|
|||||||
self.confirm_popup("Bitte erst ein document auswählen!", title="Fehler")
|
self.confirm_popup("Bitte erst ein document auswählen!", title="Fehler")
|
||||||
return
|
return
|
||||||
if not _selected_doc_location == "Database":
|
if not _selected_doc_location == "Database":
|
||||||
path = Path(_selected_doc_location + "/" + _selected_doc_name)
|
path = Path(_selected_doc_location)
|
||||||
# path: Path = path.resolve()
|
# path: Path = path.resolve()
|
||||||
# path.
|
# path.
|
||||||
# path = path + "/" + _selected_doc_name
|
# path = path + "/" + _selected_doc_name
|
||||||
@@ -1119,12 +1124,53 @@ class Ui(Ui_Semesterapparat):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.prof_mail.setText(data.mail)
|
self.prof_mail.setText(data.mail)
|
||||||
self.prof_tel_nr.setText(str(data.phoneNumber))
|
self.prof_tel_nr.setText(str(data.phoneNumber).replace("-", ""))
|
||||||
self.app_name.setText(data.title)
|
if len(data.title_suggestions) > 0:
|
||||||
self.app_fach.setCurrentText(data.subject)
|
# create a dialog that has a dropdown with the suggestions, and oc and cancel button. on ok return the selected text and set it as title
|
||||||
|
dialog = QtWidgets.QDialog()
|
||||||
|
dialog.setWindowTitle("Titelvorschläge")
|
||||||
|
dialog.setModal(True)
|
||||||
|
layout = QtWidgets.QVBoxLayout()
|
||||||
|
label = QtWidgets.QLabel(
|
||||||
|
f"Bitte wählen Sie einen Titel aus:/nDer Titel darf max. {data.title_max_length} Zeichen lang sein."
|
||||||
|
)
|
||||||
|
layout.addWidget(label)
|
||||||
|
dropdown = QtWidgets.QComboBox()
|
||||||
|
titles = [f"{title} [{len(title)}]" for title in data.title_suggestions]
|
||||||
|
dropdown.addItems(titles)
|
||||||
|
layout.addWidget(dropdown)
|
||||||
|
button_box = QtWidgets.QDialogButtonBox()
|
||||||
|
button_box.setStandardButtons(
|
||||||
|
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||||
|
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||||
|
)
|
||||||
|
button_box.accepted.connect(dialog.accept)
|
||||||
|
button_box.rejected.connect(dialog.reject)
|
||||||
|
layout.addWidget(button_box)
|
||||||
|
dialog.setLayout(layout)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
if dialog.result() == QtWidgets.QDialog.DialogCode.Accepted:
|
||||||
|
print("Selected title:", dropdown.currentText())
|
||||||
|
self.app_name.setText(dropdown.currentText().split(" [")[0].strip())
|
||||||
|
else:
|
||||||
|
self.app_name.setText("CHANGEME")
|
||||||
|
# self.app_name.setText(data.title)
|
||||||
|
subjects = self.db.getSubjects()
|
||||||
|
subjects = [subject[1] for subject in subjects]
|
||||||
|
self.app_fach.setCurrentText(data.subject if data.subject in subjects else "")
|
||||||
self.prof_title.setText(data.personTitle)
|
self.prof_title.setText(data.personTitle)
|
||||||
self.drpdwn_prof_name.setCurrentText(data.personName)
|
self.drpdwn_prof_name.setCurrentText(data.personName)
|
||||||
self.sem_year.setText("20" + data.semester.year)
|
self.sem_year.setText("20" + str(data.semester.year))
|
||||||
|
if data.semester.semester == "SoSe":
|
||||||
|
self.sem_sommer.setChecked(True)
|
||||||
|
self.sem_winter.setChecked(False)
|
||||||
|
else:
|
||||||
|
self.sem_winter.setChecked(True)
|
||||||
|
self.sem_sommer.setChecked(False)
|
||||||
|
if data.eternal:
|
||||||
|
self.check_eternal_app.setChecked(True)
|
||||||
|
self.validate_semester()
|
||||||
|
|
||||||
def btn_check_file_threaded(self):
|
def btn_check_file_threaded(self):
|
||||||
for runner in self.bookGrabber:
|
for runner in self.bookGrabber:
|
||||||
@@ -1771,7 +1817,11 @@ def launch_gui():
|
|||||||
# #log.debug("checking if database available")
|
# #log.debug("checking if database available")
|
||||||
|
|
||||||
log.info("Starting login dialog")
|
log.info("Starting login dialog")
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication.instance()
|
||||||
|
if app is None:
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
else:
|
||||||
|
log.info("Using existing QApplication instance")
|
||||||
login_dialog = QtWidgets.QDialog()
|
login_dialog = QtWidgets.QDialog()
|
||||||
ui = LoginDialog()
|
ui = LoginDialog()
|
||||||
ui.setupUi(login_dialog)
|
ui.setupUi(login_dialog)
|
||||||
@@ -1787,8 +1837,14 @@ def launch_gui():
|
|||||||
# #log.debug(aui.active_user)
|
# #log.debug(aui.active_user)
|
||||||
MainWindow.show()
|
MainWindow.show()
|
||||||
# atexit.register()
|
# atexit.register()
|
||||||
|
app.aboutToQuit.connect(
|
||||||
|
aui.validate_thread.quit
|
||||||
|
) # if that thread uses an event loop
|
||||||
|
app.aboutToQuit.connect(aui.docu.terminate) # our new slot
|
||||||
|
app.aboutToQuit.connect(aui.docu.wait)
|
||||||
atexit.register(tempdelete)
|
atexit.register(tempdelete)
|
||||||
atexit.register(aui.validate_thread.quit)
|
# atexit.register(aui.validate_thread.quit)
|
||||||
|
# atexit.register(aui.docu.quit)
|
||||||
sys.exit(app.exec())
|
sys.exit(app.exec())
|
||||||
|
|
||||||
elif ui.lresult == 0:
|
elif ui.lresult == 0:
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
from PyQt6 import QtWidgets, QtCore
|
import sys
|
||||||
from PyQt6.QtCore import QDate
|
|
||||||
from PyQt6.QtGui import QColor, QPen
|
|
||||||
from src.backend import Database
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import darkdetect
|
import darkdetect
|
||||||
import loguru
|
import loguru
|
||||||
import sys
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
from PySide6.QtCore import QDate
|
||||||
|
from PySide6.QtGui import QColor, QPen
|
||||||
|
|
||||||
|
from src import LOG_DIR
|
||||||
|
from src.backend import Database
|
||||||
|
|
||||||
log = loguru.logger
|
log = loguru.logger
|
||||||
log.remove()
|
log.remove()
|
||||||
log.add(sys.stdout)
|
log.add(sys.stdout, level="INFO")
|
||||||
log.add("logs/application.log", rotation="1 MB", retention="10 days")
|
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||||
|
|
||||||
|
|
||||||
color = "#ddfb00" if darkdetect.isDark() else "#2204ff"
|
color = "#ddfb00" if darkdetect.isDark() else "#2204ff"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ __all__ = [
|
|||||||
|
|
||||||
from .collapse import StatusWidget
|
from .collapse import StatusWidget
|
||||||
from .filepicker import FilePicker
|
from .filepicker import FilePicker
|
||||||
from .graph import DataGraph
|
from .graph import DataQtGraph
|
||||||
from .calendar_entry import CalendarEntry
|
from .calendar_entry import CalendarEntry
|
||||||
from .MessageCalendar import MessageCalendar
|
from .MessageCalendar import MessageCalendar
|
||||||
from .searchPage import SearchStatisticPage
|
from .searchPage import SearchStatisticPage
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user