87 Commits

Author SHA1 Message Date
79f51852e5 initial commit 2025-04-03 19:57:34 +02:00
c0db86dfcc update code 2025-02-05 12:47:38 +01:00
057117521c feat: set focus to book ident on change 2025-02-05 09:15:50 +01:00
18be111dc1 adding build file, updating gititgnore, adding check in backup to create archive if source is present 2025-02-05 08:18:37 +01:00
7140032109 Bump version: 0.3.1 → 0.3.2 2025-02-03 14:43:39 +01:00
50534d46b1 updating readme for new run and build process 2025-02-03 14:43:18 +01:00
776346748e set window icon 2025-02-03 13:56:41 +01:00
d01cafcbb7 add archive to keep databases permanently stored in an archive folder 2025-02-03 13:56:13 +01:00
8b8c115091 update version, change help text 2025-01-30 11:10:20 +01:00
df2f9af726 Bump version: 0.3.0 → 0.3.1 2025-01-30 10:58:25 +01:00
348e944c73 update documentation to reflect latest changes 2025-01-30 10:54:36 +01:00
7171d2a4da add option to add books manually, fix multiple user selection bug 2025-01-30 10:42:52 +01:00
5501cbf97c Bump version: 0.2.19 → 0.3.0 2025-01-29 11:13:57 +01:00
0f71f82a3f update project, launch files 2025-01-29 11:13:11 +01:00
b5015b11d9 enable the addition of the signature in the report in the UI, update docs 2025-01-29 11:09:34 +01:00
21e09d1dc0 fix typo 2025-01-29 09:52:04 +01:00
aa4ca0bac7 update documentation settings, enable live-reload 2025-01-29 09:40:54 +01:00
761ac541da update documentation (p3) 2025-01-29 09:25:45 +01:00
3bfbcbc3e0 add option to show signature in report and update settings UI 2025-01-29 09:16:26 +01:00
9d50115cb2 update documentation (p2) 2025-01-28 16:24:38 +01:00
75c12ffda5 fix crash in Loan Window 2025-01-28 16:10:56 +01:00
96a519a8f3 fix typo in settings 2025-01-28 16:03:08 +01:00
91d1576939 update documentation (p1) 2025-01-28 16:02:47 +01:00
00cdd5c36b replace icon, remove variable 2025-01-28 14:25:18 +01:00
2a451dc749 fix report generation bug, change modality 2025-01-28 14:17:43 +01:00
1d213e1f6a fix typo 2025-01-28 13:52:37 +01:00
3ecc918dd7 update settings, icons 2025-01-28 13:52:30 +01:00
049992f0a7 fix some small stuff, add icons to main UI, add shortcuts 2025-01-28 13:52:03 +01:00
d3cc6a35a3 disable log 2025-01-27 11:37:09 +01:00
c427202b2a add explanation about auto signature generation, fix loan ui bug
loan UI now colors rows correctly and data is being displayed on change
2025-01-27 10:53:55 +01:00
20b53cea69 fix dependency issue 2025-01-24 10:51:00 +01:00
cef79c9375 exclude dev group from being synced automatically 2025-01-24 10:43:55 +01:00
17fd893875 Bump version: 0.2.18 → 0.2.19 2025-01-24 10:38:11 +01:00
b7eb2a1820 update 2025-01-24 10:35:42 +01:00
f1ee4089a3 update documentation, rework documentation thread, rework book dataclass, fix newentry bug 2025-01-24 10:17:16 +01:00
b112b09e82 update launch scripts to use uv 2025-01-24 08:24:32 +01:00
05c76d49fd delete unneeded files 2025-01-24 08:23:30 +01:00
c929739210 add omegaconf dependency, rework launch scripts to check if venv exists 2025-01-24 08:10:59 +01:00
056546a920 add launch scripts for windows 2025-01-23 19:29:49 +01:00
708cd39f8e Bump version: 0.2.17 → 0.2.18 2025-01-21 16:32:20 +01:00
9cbbd696dc update changelog for v0.2.17 with additional tests for the release script 2025-01-21 15:20:26 +01:00
8eee280226 Bump version: 0.2.16 → 0.2.17 2025-01-21 15:19:37 +01:00
a007cb4c96 Bump version: 0.2.15 → 0.2.16 2025-01-21 13:56:12 +01:00
3ba1693674 Bump version: 0.2.14 → 0.2.15 2025-01-21 13:54:01 +01:00
3f8124c925 Bump version: 0.2.13 → 0.2.14 2025-01-21 13:51:12 +01:00
ab7cffffad update changelog 2025-01-21 13:49:02 +01:00
1a7c6426e7 Bump version: 0.2.12 → 0.2.13 2025-01-21 13:48:24 +01:00
5547aad98f Bump version: 0.2.11 → 0.2.12 2025-01-21 13:48:17 +01:00
f1b1c3f5ee Bump version: 0.2.10 → 0.2.11 2025-01-21 13:48:08 +01:00
9ed7dfabb0 update changelog 2025-01-21 13:48:01 +01:00
1c7e34f9fc Bump version: 0.2.9 → 0.2.10 2025-01-21 12:41:38 +01:00
f6da80ca11 Bump version: 0.2.8 → 0.2.9 2025-01-21 12:23:31 +01:00
f5e27a8605 update changelog 2025-01-21 12:23:25 +01:00
131161eed2 Bump version: 0.2.7 → 0.2.8 2025-01-21 11:22:45 +01:00
2a688ffd8f Bump version: 0.2.6 → 0.2.7 2025-01-21 09:17:20 +01:00
a0a6f63974 update task, changelog 2025-01-21 09:17:15 +01:00
54ca85e4ef Bump version: 0.2.5 → 0.2.6 2025-01-20 11:20:08 +01:00
bc6ffb098a rm lockfile 2025-01-20 11:19:52 +01:00
344d436d63 update .gitignore 2025-01-20 11:18:33 +01:00
9cf49b8f38 update build command 2025-01-20 11:16:19 +01:00
c276ab587b format code 2025-01-20 11:13:36 +01:00
430878b41f Bump version: 0.2.4 → 0.2.5 2025-01-17 09:42:52 +01:00
9493ed2e24 version change 2025-01-17 09:42:42 +01:00
6ec0a9f104 revert version 2025-01-17 09:23:27 +01:00
2ef0ea42e8 version change 2025-01-17 09:22:51 +01:00
ce03d28936 version change 2025-01-17 09:11:47 +01:00
359f5e78a2 version change 2025-01-17 09:10:41 +01:00
dc470798d2 change version 2025-01-17 09:07:36 +01:00
4351e581e6 update 2025-01-17 09:06:43 +01:00
8ed1801a50 revert version 2025-01-17 08:44:59 +01:00
0775c66e4a enable tag creation 2025-01-17 08:44:22 +01:00
6c10589508 allow commits, change bumpversion toml 2025-01-13 12:45:02 +01:00
d73a62c3ea temporarily ignore config 2025-01-13 11:16:25 +01:00
62e0f279d0 add newLine 2025-01-13 11:15:03 +01:00
daf8d87b9d update deps, change config to restore changes, color overdue red in main, in loan color based on state 2025-01-13 11:14:27 +01:00
148adb937d filechanges 2025-01-13 11:13:00 +01:00
17e8d3c2b2 switch to maintained fork 2025-01-13 11:12:08 +01:00
9567d24cfa Bump version: 0.2.2 → 0.2.3 2025-01-13 08:09:01 +01:00
4b16bfd501 changes, add dotenv dependency 2025-01-13 08:08:54 +01:00
ee256040d9 Bump version: 0.2.1 → 0.2.2 2025-01-10 10:40:22 +01:00
1291f1eddc add changelog, release.ps1 2025-01-10 10:40:16 +01:00
c7a596f6d0 changes 2025-01-10 10:39:30 +01:00
d208013192 Bump version: 0.2.0 → 0.2.1 2025-01-10 09:35:48 +01:00
60fa34c235 change tasks, config 2025-01-10 09:35:43 +01:00
0d7dc28876 update code, switch to loguru 2025-01-10 09:35:18 +01:00
e915b47dda updates 2025-01-09 15:15:18 +01:00
6316fc72ab Merge pull request 'main to dev' (#10) from main into dev
Reviewed-on: WorldTeacher/LibrarySystem#10
2025-01-09 13:15:31 +01:00
106 changed files with 2552 additions and 1447 deletions

View File

@@ -1,11 +0,0 @@
[bumpversion]
current_version = 0.2.0
tag = True
commit = True
[bumpversion:file:src/__init__.py]
search = __version__ = "{current_version}"
replace = __version__ = "{new_version}"
[bumpversion:file:pyproject.toml]
search = version = "{current_version}"
replace = version = "{new_version}"

22
.bumpversion.toml Normal file
View File

@@ -0,0 +1,22 @@
[tool.bumpversion]
current_version = "0.3.2"
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
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 = ""
[[tool.bumpversion.files]]
filename = ".version"
[[tool.bumpversion.files]]
filename = "src/__init__.py"
[[tool.bumpversion.files]]
filename = "pyproject.toml"

19
.gitignore vendored
View File

@@ -216,10 +216,19 @@ compile_commands.json
*_qmlcache.qrc
.history/*
.history
depend
output/output/LOGtoJSON.exe
.pytest_cache
output
docs/
config.yaml
**/tempCodeRunnerFile.py
output/**
# Rust
target/
uv.lock
.history
.venv
venv
*.log

9
.trunk/.gitignore vendored
View File

@@ -1,9 +0,0 @@
*out
*logs
*actions
*notifications
*tools
plugins
user_trunk.yaml
user.yaml
tmp

View File

@@ -1,10 +0,0 @@
# This file controls the behavior of Trunk: https://docs.trunk.io/cli
# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml
version: 0.1
cli:
version: 1.22.8
plugins:
sources:
- id: trunk
ref: v1.6.4
uri: https://github.com/trunk-io/plugins

1
.version Normal file
View File

@@ -0,0 +1 @@
0.3.2

16
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/.trunk/*actions/": true,
"**/.trunk/*logs/": true,
"**/.trunk/*notifications/": true,
"**/.trunk/*out/": true,
"**/.trunk/*plugins/": true
},
"hide-files.files": []
}

128
.vscode/tasks.json vendored
View File

@@ -2,26 +2,13 @@
"version": "2.0.0",
"tasks": [
{
"label": "Build LibrarySystem (Debug)",
"label": "Build New Release",
"type": "shell",
"command": "pyinstaller",
"args": [
"--noconfirm",
"--onedir",
"--console",
"--icon",
"'${config:ApplicationIconPath}'",
"--name",
"LibrarySystem-debug",
"--contents-directory",
".",
"--clean",
"--add-data",
"'${config:configPath};config/'",
"--add-data",
"'${config:iconsPath};icons/'",
"'${workspaceFolder}/main_dev.py'"
"dependsOn": [
"Build LibrarySystem (Release)",
"Build LibrarySystem (Debug)"
],
"command": "python setup.py",
"group": {
"kind": "build",
"isDefault": true
@@ -32,28 +19,28 @@
"focus": false
},
// "dependsOn": "Compress dist Folder Debug",
"problemMatcher": "$pyinstaller"
"problemMatcher": "$python"
},
{
"label": "Build LibrarySystem (Release)",
"label": "Build LibrarySystem (Debug)",
"type": "shell",
"command": "pyinstaller",
"command": "uv",
"args": [
"--noconfirm",
"--onedir",
"--windowed",
"--name",
"LibrarySystem",
"--contents-directory",
".",
"--clean",
"--add-data",
"'${config:configPath};config/'",
"--add-data",
"'${config:iconsPath};icons/'",
"--icon",
"'${config:ApplicationIconPath}'",
"'${workspaceFolder}/main.py'"
"run",
"python",
"-m",
"nuitka",
"--standalone",
"--output-dir=dist",
"--include-package=PyQt6",
"--include-package=pygments",
"--include-data-dir=./config=config",
"--include-data-dir=./docs=docs",
"--include-data-dir=./icons=icons",
"--include-data-dir=./.venv/Lib/site-packages/PyQt6/=PyQt6/",
"--windows-icon-from-ico=icons/icon.ico",
"main_dev.py",
"--debug"
],
"group": {
"kind": "build",
@@ -62,50 +49,57 @@
"presentation": {
"reveal": "always",
"panel": "new",
"focus": false
"focus": false,
"close": true
},
"dependsOn": "Compress dist Folder Release",
"problemMatcher": "$pyinstaller"
// "dependsOn": "Compress dist Folder Debug",
"problemMatcher": "$python"
},
{
"label": "Build LibrarySystem (Release)",
"type": "shell",
"command": "uv",
"args": [
"run",
"python",
"-m",
"nuitka",
"--standalone",
"--output-dir=dist",
"--include-package=PyQt6",
"--include-package=pygments",
"--include-data-dir=./config=config",
"--include-data-dir=./docs=docs",
"--include-data-dir=./icons=icons",
"--include-data-dir=./.venv/Lib/site-packages/PyQt6/Qt6/plugins=PyQt6/Qt/plugins",
"--windows-icon-from-ico=icons/icon.ico",
"main.py"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "new",
"focus": false,
"close": true
},
"problemMatcher": "$python"
},
{
"label": "Run LibrarySystem (live)",
"type": "shell",
"command": "c:/Users/aky547/GitHub/LibrarySystem/.venv/Scripts/python.exe",
"args": [
"'c:/Users/aky547/GitHub/LibrarySystem/main_dev.py'",
"--ic-logging"
"'c:/Users/aky547/GitHub/LibrarySystem/main.py'",
"--debug"
],
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": "$python"
},
{
"label": "Compress dist Folder Debug",
"type": "shell",
"command": "Compress-Archive",
"args": [
"-Path",
"${workspaceFolder}/dist/LibrarySystem-debug/",
"-DestinationPath",
"${workspaceFolder}/output/LibrarySystem-debug.zip",
],
"group": "build",
"presentation": "panel"
},
{
"label": "Compress dist Folder Release",
"type": "shell",
"command": "Compress-Archive",
"args": [
"-Path",
"${workspaceFolder}/dist/LibrarySystem/",
"-DestinationPath",
"${workspaceFolder}/output/LibrarySystem.zip",
],
"group": "build",
"presentation": "panel"
}
]
}

View File

@@ -1,4 +1,4 @@
## Icons
if not stated elsewhere, all Icons are part of the Material Symbols Package provided by Google
### Specific Icons
- borrow_boks.svg Credits to Maxicons, Icon downloaded frmo thenounproject.com [Link](https://thenounproject.com/icon/borrow-book-3317975/)
- borrow_boks.svg Credits to Maxicons, Icon downloaded from thenounproject.com [Link](https://thenounproject.com/icon/borrow-book-3317975/)

20
LICENSE
View File

@@ -1,9 +1,21 @@
MIT License
Copyright (c) 2024 WorldTeacher
Copyright (c) 2025 WorldTeacher
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,6 +1,6 @@
# LibrarySystem
universal library system for facilities in the university. Currently hard-coded for the Library of the University of Education in Freiburg, Germany.
universal library system for facilities in the university. Currently hard-coded for the Library of the University of Education in Freiburg, Germany, but can be adapted to fit other libraries as long as the catalogue has a suitable format, or an open API
Other Libraries can be supported by rewriting the catalog and it's corresponding functions.
@@ -10,24 +10,31 @@ This is a library system for the different facilities in our university. Because
### Installation
#### Windows
using the latest git commit version:
```
git clone https://git.theprivateserver.de/WorldTeacher/LibrarySystem.git
cd LibrarySystem
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python main.py
```
building the software:
```
download the installer.bat
execute the file in a terminal
```
For windows, there are two ways to install the software:
1. using the latest git commit version:
~~or head over to [releases](https://git.theprivateserver.de/WorldTeacher/LibrarySystem/releases)
and download the latest version~~ (not yet supported)
Prerequisites:
- [uv](https://docs.astral.sh/uv/getting-started/installation/) and [Git](https://git-scm.com/downloads/win) are installed
```bash
git clone https://git.theprivateserver.de/WorldTeacher/LibrarySystem.git
cd LibrarySystem
uv sync # This will install all dependencies, including dev dependencies
source venv/Scrpits/activate(.bat|ps1) # This will activate the virtual environment
uv run python main.py
```
building the software:
```bash
uv run python build.py
```
This will create a build folder with the application in it. You can move the folder of the application anywhere you want
2. using the release:
~~see: [releases](https://git.theprivateserver.de/WorldTeacher/LibrarySystem/releases)
and download the latest version~~ (not yet supported)
### Configuration

0
backup/library.db Normal file
View File

View File

@@ -1,61 +0,0 @@
{
"version": "auto-py-to-exe-configuration_v1",
"pyinstallerOptions": [
{
"optionDest": "noconfirm",
"value": true
},
{
"optionDest": "onefile",
"value": false
},
{
"optionDest": "console",
"value": false
},
{
"optionDest": "name",
"value": "LibrarySystem"
},
{
"optionDest": "contents_directory",
"value": "."
},
{
"optionDest": "clean_build",
"value": true
},
{
"optionDest": "strip",
"value": false
},
{
"optionDest": "noupx",
"value": false
},
{
"optionDest": "disable_windowed_traceback",
"value": false
},
{
"optionDest": "uac_admin",
"value": false
},
{
"optionDest": "uac_uiaccess",
"value": false
},
{
"optionDest": "argv_emulation",
"value": false
},
{
"optionDest": "bootloader_ignore_signals",
"value": false
}
],
"nonPyinstallerOptions": {
"increaseRecursionLimit": true,
"manualArguments": ""
}
}

View File

@@ -1,77 +0,0 @@
{
"version": "auto-py-to-exe-configuration_v1",
"pyinstallerOptions": [
{
"optionDest": "noconfirm",
"value": true
},
{
"optionDest": "filenames",
"value": "C:/Users/aky547/GitHub/LibrarySystem/main_dev.py"
},
{
"optionDest": "onefile",
"value": false
},
{
"optionDest": "console",
"value": true
},
{
"optionDest": "icon_file",
"value": "C:/Users/aky547/Downloads/1490971308-map-icons-7_82746.ico"
},
{
"optionDest": "name",
"value": "LibrarySystem-debug"
},
{
"optionDest": "contents_directory",
"value": "."
},
{
"optionDest": "clean_build",
"value": true
},
{
"optionDest": "strip",
"value": false
},
{
"optionDest": "noupx",
"value": false
},
{
"optionDest": "disable_windowed_traceback",
"value": false
},
{
"optionDest": "uac_admin",
"value": false
},
{
"optionDest": "uac_uiaccess",
"value": false
},
{
"optionDest": "argv_emulation",
"value": false
},
{
"optionDest": "bootloader_ignore_signals",
"value": false
},
{
"optionDest": "datas",
"value": "C:/Users/aky547/GitHub/LibrarySystem/config;config/"
},
{
"optionDest": "datas",
"value": "C:/Users/aky547/GitHub/LibrarySystem/icons;icons/"
}
],
"nonPyinstallerOptions": {
"increaseRecursionLimit": true,
"manualArguments": ""
}
}

17
build.py Normal file
View File

@@ -0,0 +1,17 @@
import os
import shutil
def build_release():
print("Building Application")
os.system(
"uv run python -m nuitka --standalone --output-dir=build --include-package=PyQt6 --include-package=pygments --include-data-dir=./config=config --include-data-dir=./docs=docs --include-data-dir=./icons=icons --include-data-dir=./.venv/Lib/site-packages/PyQt6/=PyQt6 --windows-icon-from-ico=icons/icon.ico main.py"
)
shutil.copytree(
".venv/Lib/site-packages/PyQt6/", "build/main.dist/PyQt6/", dirs_exist_ok=True
)
shutil.move("build/main.dist", "build/LibrarySystem")
if __name__ == "__main__":
build_release()

View File

@@ -1,77 +0,0 @@
{
"version": "auto-py-to-exe-configuration_v1",
"pyinstallerOptions": [
{
"optionDest": "noconfirm",
"value": true
},
{
"optionDest": "filenames",
"value": "C:/Users/aky547/GitHub/LibrarySystem/main.py"
},
{
"optionDest": "onefile",
"value": false
},
{
"optionDest": "console",
"value": false
},
{
"optionDest": "icon_file",
"value": "C:/Users/aky547/Downloads/1490971308-map-icons-7_82746.ico"
},
{
"optionDest": "name",
"value": "LibrarySystem"
},
{
"optionDest": "contents_directory",
"value": "."
},
{
"optionDest": "clean_build",
"value": true
},
{
"optionDest": "strip",
"value": false
},
{
"optionDest": "noupx",
"value": false
},
{
"optionDest": "disable_windowed_traceback",
"value": false
},
{
"optionDest": "uac_admin",
"value": false
},
{
"optionDest": "uac_uiaccess",
"value": false
},
{
"optionDest": "argv_emulation",
"value": false
},
{
"optionDest": "bootloader_ignore_signals",
"value": false
},
{
"optionDest": "datas",
"value": "C:/Users/aky547/GitHub/LibrarySystem/config;config/"
},
{
"optionDest": "datas",
"value": "C:/Users/aky547/GitHub/LibrarySystem/icons;icons/"
}
],
"nonPyinstallerOptions": {
"increaseRecursionLimit": true,
"manualArguments": ""
}
}

33
changelog.md Normal file
View File

@@ -0,0 +1,33 @@
# Changelog
## v0.2.17
- More tests for the release script
## v0.2.13
- Release bugfixes
## v0.2.10
- Small changes to the release script, trying to fix a bug where assets are not added to the release
## v0.2.8
- Updated the release script to use the tea application to create releases with files
- Updated the release script to use the new release system
## v0.2.7
- reworked release script to create releases
## v0.2.6
- changed build command
- small fixes, coloring the user loan table based on book status
## v0.2.4 - v0.2.5
-Testing only
## v0.2.3
- started implementing the updated release script, aimimg to create automated releases that can be grabbed using the updater, which will be created thereafter
## v0.2.2
- fixed minor bugs in release script
## v0.2.1
- Changed logging to use loguru
- reworked cli arguments to be working
- suppressed mkdocs server from hogging the cli and not showing debug info when requested

View File

@@ -107,26 +107,7 @@ class Config:
if self._config is None:
raise RuntimeError("Configuration not loaded")
self._config.debug = value
@property
def log_debug(self)->bool:
if self._config is None:
raise RuntimeError("Configuration not loaded")
return self._config.log_debug
@log_debug.setter
def log_debug(self, value: bool):
if self._config is None:
raise RuntimeError("Configuration not loaded")
self._config.log_debug = value
@property
def ic_logging(self)->bool:
if self._config is None:
raise RuntimeError("Configuration not loaded")
return self._config.ic_logging
@ic_logging.setter
def ic_logging(self, value:bool):
if self._config is None:
raise RuntimeError("Configuration not loaded")
self._config.ic_logging = value
def save(self):
if self._config is None:
raise RuntimeError("Configuration not loaded")
@@ -167,10 +148,37 @@ class Config:
raise KeyError(f"Option {keys[0]} not found in configuration")
else:
self._config[key] = value
def get_changes(self, other):
# compare self to other, return changes
changes = {}
for key in self._config:
if self._config[key] != other[key]:
changes[key] = self._config[key]
return changes
if __name__ == "__main__":
cfg = Config("config/settings.yaml")
#print(cfg.database.path)
cfg.database.path = "nopathhere"
#print(cfg.database.path)
cfg.save()
#cfg.updateValue("database.path", "Test")
other = {
"institution_name": "Test",
"default_loan_duration": 7,
"inactive_user_deletion": 365,
"database": {
"path": "./database",
"name": "library.db",
"backupLocation": "./backup",
"do_backup": True,
},
"report": {"generate_report": True, "path": "./report", "report_day": 0},
"shortcuts": [
{"name": "Rueckgabemodus", "default": "F5", "current": "F5"},
{"name": "Nutzer", "default": "F6", "current": "F6"},
{"name": "Hilfe", "default": "F1", "current": "F1"},
{"name": "Bericht_erstellen", "default": "F7", "current": "F7"},
{"name": "Ausleihhistorie", "default": "F8", "current": "F8"},
],
"advanced_refresh": False,
"catalogue": True,
"debug": True,
"documentation": True,
}
print(cfg.get_changes(other))

View File

@@ -1,4 +1,4 @@
institution_name: Test
institution_name: Testbibliothek Psychologie
default_loan_duration: 7
inactive_user_deletion: 365
database:
@@ -10,6 +10,7 @@ report:
generate_report: true
path: ./report
report_day: 0
show_signature: true
shortcuts:
- name: Rueckgabemodus
default: F5
@@ -29,6 +30,4 @@ shortcuts:
advanced_refresh: false
catalogue: true
debug: false
log_debug: false
ic_logging: false
documentation: true
documentation: true

BIN
database/library.db Normal file

Binary file not shown.

15
docs/Allgemeines.md Normal file
View File

@@ -0,0 +1,15 @@
# Allgemeines
Hier werden alle allgemeinen Informationen zur Anwendung aufgeführt, die nicht direkt in die anderen Bereiche passen.
## Datenbankbackup
Bei jedem Schließen der Anwendung wird ein Backup der Datenbank erstellt. Dieses Backup wird im Sicherungspfad gespeichert, der Sicherungspfad ist in den Einstellungen einsehbar und änderbar.
Sollte der normale Speicherpfad nicht existieren oder nicht erreichbar sein (im Falle eines Netzwerklaufwerks), wird der Backuppfad verwendet. Beim Schließen der Anwendung wird ein Fehler angezeigt, dass das Erstellen des Backups nicht erfolgreich war. Solange der originale Pfad nicht erreichbar ist, wird der Backuppfad verwendet.
Sobald der originale Pfad wieder erreichbar ist, wird die Datenbank in den originalen Pfad kopiert, die veraltete Datenbank wird gelöscht und der Backuppfad wird wieder verwendet.
## Datenbankarchiv
Um eventuelle Datenbeschädigungen zu vermeiden, wird die Datenbank bei jedem Beenden der Anwendung in ein Archiv kopiert. Dieses Archiv wird im Archivpfad gespeichert, der Archivpfad nutzt den Sicherungspfad als grundlage und erstellt einen neuen Ordner "archive" in diesem Pfad.

View File

@@ -14,3 +14,8 @@ Wenn "Yes" geklickt wird, erscheint ein neues Fenster zum anlegen eines neuen Ex
![AddNewBook](images/book_addNew.png)
Über das + Symbol können neue Exemplare hinzugefügt werden. Es ist empfohlen, die Signatur jeweils um +1 zu erhöhen, um eine eindeutige Zuordnung zu gewährleisten.
!!! Info
Die neueste Version erstellt die Nummer `+X` automatisch, basierend auf Basis des bereits entliehenen Buchs

View File

@@ -3,7 +3,7 @@
!!! info
Die Ausleihhistorie kann vom Ausleihsystem immer aufgerufen werden. Dazu kann man entweder das Menu öffnen (Fenster -> Ausleihhistorie) oder den festgelegten Shortcut verwenden.
Die Ausleihhistorie kann vom Ausleihsystem immer aufgerufen werden. Dazu kann man entweder das Menu öffnen (Fenster -> Ausleihhistorie) oder den festgelegten Shortcut verwenden.
# Bedienung
Hier werden alle Medien angezeigt.

View File

@@ -4,7 +4,7 @@
## Oberfläche
![Nutzeroberfläche ohne Bewerkungen](images/main_marked%20areas.png)
![Nutzeroberfläche ohne Bemerkungen](images/main_marked%20areas.png)
Die Oberfläche kann generell in drei Bereiche unterteilt werden:
@@ -27,6 +27,10 @@ Hier werden folgende Daten angezeigt
- Ausleihe bis: bis wann das Medium ausgeliehen wird, Zeitraum wird in den Einstellungen angepasst
- Nutzer anlegen: ein Knopf, um einen neuen Nutzer anzulegen (2)
!!! Info "Manuell Medien hinzufügen"
Über das Plus (8) können manuell Medien hinzugefügt werden. Dies kann sowohl im Ausleih- als auch Rückgabemodus durchgeführt werden. Im Ausleihmodus wird das Medium direkt auf das offene Konto entliehen, im Rückgabemodus wird das Medium nur in die Datenbank eingetragen.
### Nutzerdaten
Hier werden die Nutzerdaten angezeigt. Vorraussetzung ist, dass ein Nutzer angelegt und geöffnet wurde, oder dass ein Medium zurückgegeben wurde.
Dieser Bereich beschränkt sich auf folgende Inhalte:
@@ -46,13 +50,13 @@ Das Feld der Historie listet alle Medien auf, die im aktiven Prozess ausgeliehen
## Ausleihen
Um ein Medium auszuleihen, muss zuerst ein Nutzer geöffnet sein. Dazu entweder den Knopf neben Modus drücken, oder den Shortcut (Standard: `F5`) verwenden.
Um ein Medium auszuleihen, muss zuerst ein Nutzer geöffnet werden. Dazu entweder den Knopf neben Modus drücken, oder den Shortcut (Standard: `F5`) verwenden.
Die Oberfläche sieht dann wie folgt aus:
![Ausleihe](images/main_loan_active.png)
Der Cursor wird automatisch auf die Matrikelnummer gesetzt. Hier kann entweder die vollständige Nummer, oder ein Teil eingegeben werden. Sollten mehrere Nummern dem Teilfilter ensprechen, wird eine Auswahl angezeigt. (s. [MultiUser](MultiUser.md))
Der Cursor wird automatisch auf die Matrikelnummer gesetzt. Hier kann entweder die vollständige Nummer oder ein Teil eingegeben werden. Sollten mehrere Nummern dem Teilfilter entsprechen, wird eine Auswahl angezeigt. (s. [MultiUser](MultiUser.md))
Nach der Auswahl wird das entsprechende Konto geöffnet und die Ausleihe kann durchgeführt werden.
![Ausleihe](images/activeLoan.png)
@@ -60,7 +64,7 @@ Nach der Auswahl wird das entsprechende Konto geöffnet und die Ausleihe kann du
Sollte der aktive Nutzer aktive Ausleihen haben, so wird die Anzahl der Medien neben "Anzahl Ausleihen" angezeigt. Das nächste Rückgabedatum wird ebenfalls angezeigt. Über einen Klick auf die Zahl der Ausleihen gelangen Sie zur [Übersicht der Ausleihen des Nutzers](Nutzeroberfläche.md).
Um ein Medium auszuleihen, muss die Signatur in die entsprechende Zeile eingegeben werden. Sollte die Signatur nicht in der Datenbank existieren, wird der definierte Katalog geprüft. Wird das Medium gefunden, wird es in die Datenbank übernommen und die Ausleihe wird durchgeführt. Sollte das Medium nicht gefunden werden, wird eine Fehlermeldung angezeigt.
Um ein Medium auszuleihen, muss die Signatur in die entsprechende Zeile eingegeben werden. Sollte die Signatur nicht in der Datenbank existieren, wird der zuvor festgelegte Katalog geprüft. Wird das Medium gefunden, wird es in die Datenbank übernommen und die Ausleihe wird durchgeführt. Sollte das Medium nicht gefunden werden, wird eine Fehlermeldung angezeigt.
![FehlerAusleihe](images/err_noBook.png)
@@ -68,7 +72,7 @@ Um ein Medium auszuleihen, muss die Signatur in die entsprechende Zeile eingegeb
Die Signatur muss mindestens ein Leerzeichen enthalten, ansonsten wird eine Fehlermeldung angezeigt.
Sonderfälle siehe [AusleiheSonderfälle](Ausleihe_Sonderfälle.md)
Sonderfälle siehe [Sonderfälle in der Ausleihe](Ausleihe_Sonderfälle.md)
## Rückgaben

View File

@@ -11,10 +11,14 @@ Diese Oberfläche kann immer von der [Hauptoberfläche](Ausleihsystem.md) geöff
Um einen Bericht zu erstellen, müssen folgende Kriterien erfüllt sein:
- Zeitspanne festgelegt (Entweder über den Slider, oder über die Woche / Monat / Jahr Knöpfe)
- Datenformat ausgewählt
- Zeitspanne festgelegt (Entweder über den Slider, oder über die Buttons für Woche / Monat / Jahr)
- Dateiformat muss festgelegt worden sein.
Nachdem diese Kriterien erfüllt sind, kann der Bericht über den Knopf `Bericht erstellen` erstellt werden. Der Bericht wird erstellt, bei größeren Datensätzen kann es länger dauern, eine Fortschrittsanzeige gibt an, wie weit der Prozess ist.
!!! info "Optional: Signatur"
Optional kann ein Haken bei `Signatur anzeigen` gesetzt werden. Der Bericht wird nun die Signatur der ausgeführten Aktion enthalten.
Bei größeren Datensätzen kann es länger dauern. Eine Fortschrittsanzeige gibt an, wie weit der Prozess ist.
Wurde der Bericht erfolgreich erstellt, sieht die Oberfläche wie folgt aus:

View File

@@ -2,8 +2,50 @@
![Einstellungen](images/settings.png)
## Bedienung
Hier werden die Einstellungen geändert. Sobald ein Wert geändert wird, ist es möglich die Einstellungen rückgängig zu machen, oder die Änderungen zu speichern.
Hier werden die Einstellungen geändert. Sobald ein Wert geändert wird, ist es möglich die Einstellungen rückgängig zu machen oder die Änderungen zu speichern.
## Einstellungsoptionen
### Name der Einrichtung
Hier kann der Name der Einrichtung geändert werden. Dieser wird in der Kopfzeile der Anwendung angezeigt und im Katalog verwendet um Exemplare zu finden.
### Leihdauer
Hier kann die Leihdauer festgelegt werden. Standardmäßig ist diese auf 7 Tage gesetzt
### Inaktive Nutzer löschen
Hier kann festgelegt werden, wie lange Inaktive Nutzer im System bleiben. Dieser Zeitraum wird ab dem letzten Öffnen des Nutzerkontos berechnet. Standardmäßig ist dieser auf 365 Tage gesetzt.
### Erweiterter Rückgabemodus
Wird hier der Haken gesetzt, ändert sich die Bedienung der Anwendung. Der Shortcut "F5" wechselt nicht länger zwischen Ausleihe und Rückgabe. Stattdessen führt ein Druck auf "F5" dazu, dass das offene Rückgabekonto geschlossen wird. Dies ist dann vorteilhaft, wenn mehrere Medien von verschiedenen Personen zurückgebucht werden sollen.
### Datenbank
Hier werden die Datenbankoptionen geändert.
- **Speicherort**: Hier wird der Speicherort der Datenbank geändert. Standardmäßig ist dieser auf den Ordner der Anwendung gesetzt (database)
- **Datenbankname**: Hier wird der Name der Datenbank geändert. Standardmäßig ist dieser auf "library.db" gesetzt
- **Sicherungspfad**: Hier wird der Pfad für die Sicherung der Datenbank geändert. Standardmäßig ist dieser auf den Ordner der Anwendung gesetzt (backup)
### Bericht
Hier werden die Einstellungen für die Berichte geändert.
- **Tag**: Der Wochentag, an dem die Berichte erstellt werden sollen
- **Berichte erstellen**: Ist der Haken gesetzt, werden Berichte automatisch erstellt
- **Signatur anzeigen**: Ist der Haken gesetzt, wird die Signatur in den Berichten angezeigt
- **Speicherpfad**: Speicherort für Berichte, standardmäßig ist dieser auf den Ordner der Anwendung gesetzt (report)
!!! Info
Automatische Berichte werden in diesem Format erstellt:
`report_<Jahr>_<Kalenderwoche>.tsv`
Wird die Anwendung am Tag der Berichterstellung mehrfach geöffnet, wird nur ein Bericht erstellt
### Shortcuts
Hier können die Shortcuts angepasst werden. Eine Änderung kann über einen Doppelklick auf das Feld "Aktuell" initiiert werden.
Anschließend kann der gewünschte Shortcut eingegeben werden.
(Eine Änderung der Shortcuts erfordert einen Neustart der Anwendung)
## Besonderheiten
Der Knopf neben Speicherort, Datenbankname, Sicherungspfad und Speicherpfad kann verwendet werden, um den Pfad gezielt zu setzen.
@@ -11,11 +53,8 @@ Beim Datenbanknamen wird allerdings nur der Name der Datenbank übernommen
## Hinweis
Einige Aktionen (bspw. Änderungen der Shortcuts) erfordern einen Neustart der Anwendung. Dies wird beim Speichern der Einstellungen mit folgendem Dialog dargestelt:
Einige Aktionen (bspw. Änderungen der Shortcuts) erfordern einen Neustart der Anwendung. Dies wird beim Speichern der Einstellungen mit folgendem Dialog dargestellt:
![restart](images/restart.png)
Im Anschluss an diesen Dialog erscheint ein neuer Dialog:
![restart Application](images/settings_changed_restart.png)
Mit einem Klick auf "Ja" wird die Anwendung neu gestartet und die Änderungen übernommen. Mit einem Klick auf "Nein" werden die Änderungen nicht übernommen und die Anwendung bleibt im aktuellen Zustand.

View File

@@ -2,7 +2,7 @@
![alt text](images/user_main.png)
!!! info
Die Nutzeroberfläche kann nur geöffnet werden, wenn ein Nutzer offen ist. Ansonsten wird ein Fehler angezeigt. (s. unten)
Die Nutzeroberfläche kann nur geöffnet werden, wenn ein Nutzer ausgewählt wurde. Ansonsten wird ein Fehler angezeigt. (s. unten)
![Error](images/err_nouser.png)
@@ -18,14 +18,14 @@
- (4) Medien:
Umfasst unter anderem Feld (5), welches ein neues Fenster zum [verlängern](ausleihe verlängern.md) der Ausleihe öffnet.
Mit einem Klick auf
- Alle Ausleihen
- Aktuell entliehen
- Überzogen
Umfasst unter anderem Feld (5), welches ein neues Fenster zum [verlängern](ausleihe verlängern.md) der Ausleihe öffnet.
Mit einem Klick auf
- Alle Ausleihen
- Aktuell entliehen
- Überzogen
werden die Einträge der Tabelle gefiltert. Zusätzlich kann mithilfe der Eingabezeile unter den Filteroptionen gezielt nach einem Titel oder einer Signatur gesucht werden.
- (5) Verlängern:
Um Medien zu verlängern, müssen diese in der Tabelle angeklickt werden. Mit Strg können mehrere Medien gleichzeitig ausgewählt und verlängert werden. Hierzu wird ein neues Fenster geöffnet, siehe [Ausleihe verlängern](ausleihe verlängern.md).
Um Medien zu verlängern, müssen diese in der Tabelle angeklickt werden. Mit Strg können mehrere Medien gleichzeitig ausgewählt und verlängert werden. Hierzu wird ein neues Fenster geöffnet, siehe [Ausleihe verlängern](ausleihe verlängern.md).

View File

@@ -2,8 +2,7 @@
![Oberfläche](images/extend.png)
## Information
Die Ausleihe verlängern kann nur geöffnet werden, wenn ein Nutzer offen ist.
Diese Oberfläche erlaubt es, eine oder mehrere Medien zu verlängern. Hierzu muss ein neues, in der Zukunft liegendes Datum ausgewählt und mit OK bestätigt werden.
Um eine Ausleihe zu verlängern, öffnen Sie zunächst den Nutzer und klicken Sie auf "Fenster" > "Nutzer". Wählen Sie den oder die zu verlängernden Titel aus und klicken Sie auf "Ausgewählte Verlängern". Um mehrere Titel auf einmal zu verlängern, halten Sie die Strg-Taste gedrückt und klicken Sie auf die gewünschten Titel. Anschließend klicken Sie auf "Ausgewählte Verlängern".
Hierzu muss ein neues, in der Zukunft liegendes Datum ausgewählt und mit OK bestätigt werden.
In der Datenbank wird nun das neue Datum gespeichert und die Einträge in der Tabelle werden aktualisiert.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -17,5 +17,6 @@ Unterbereiche umfassen:
- [Ausleihhistorie](Ausleihhistorie.md) - Historie der Ausleihen
- [Bericht erstellen](Bericht erstellen.md) - Bericht für einen festgelegten Zeitrahmen erstellen
- [Einstellungen](Einstellungen.md) - Einstellungen der Anwendung ändern
- [Allgemeines](Allgemeines.md) - Allgemeine Informationen zur Anwendung

View File

@@ -1,103 +0,0 @@
import os
import shutil
from pathlib import Path
ORIGIN = "C:/testing/source_2"
BACKUP = "C:/Databasebackup"
FILE = "database.db"
def handle_file():
"""
Handles file creation, movement, and backup based on path and backup existence.
Args:
path (str): The desired path for the file.
filename (str): The name of the file.
backup_location (str): The location for backups.
Returns:
str: The final path of the file.
"""
full = Path(ORIGIN) / FILE
full_path = str(full)
backup = Path(BACKUP) / FILE
backup_path = str(backup)
origin_reachable = os.path.exists(full_path)
backup_reachable = os.path.exists(backup_path)
print(origin_reachable, backup_reachable)
if not origin_reachable and not backup_reachable:
make_dirs(ORIGIN, BACKUP)
# if not os.path.exists(full_path):
# print("File does not exist, creating file")
# create_file(full_path)
if os.path.exists(backup_path) and ".backup" in os.listdir(BACKUP):
print("Used backup previously, overwriting file")
#overwrite file at source with backup
shutil.copy(backup_path, full_path)
os.remove(BACKUP + "/.backup")
def make_dirs(full_path, backup_path):
"""
Creates directories if they do not exist and moves the file to the desired location.
Args:
full_path (str): The full path of the file.
backup_path (str): The backup path of the file.
"""
if not os.path.exists(full_path):
os.makedirs(full_path)
if not os.path.exists(backup_path):
os.makedirs(backup_path)
def create_file(full_path):
"""
Creates a file at the desired location.
Args:
full_path (str): The full path of the file.
"""
with open(full_path, "w") as f:
f.write("")
def handle_folder_reachability(original_path, backup_path):
"""
Checks if the original folder is reachable. If not, creates a backup.
If the original folder becomes reachable again, restores the backup.
Args:
original_path (str): Path to the original folder.
backup_path (str): Path to the backup folder.
Returns:
str: Path to the current accessible folder.
"""
backup_file = os.path.join(backup_path, ".backup")
try:
os.makedirs(original_path)
except FileExistsError:
pass
if not os.path.exists(original_path):
#original folder not reachable, use backup path and create .backup file
if not os.path.exists(backup_path):
os.makedirs(backup_path)
with open(backup_file, "w") as f:
f.write("")
# Create an empty backup file as a marker
return backup_path +"/" + FILE
else:
# Original folder is reachable, check for backup
if os.path.exists(backup_file):
# Restore backup
shutil.rmtree(original_path) # Remove original folder to avoid conflicts
shutil.move(backup_path, original_path)
#os.remove(backup_file)
#remove backup file from original path
os.remove(original_path + "/.backup")
os.makedirs(backup_path)
return original_path +"/" + FILE
if __name__=="__main__":
print(handle_folder_reachability(ORIGIN, BACKUP)) # should create a new file at C:/newdatabase/database.db)

1
icons/add.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"/></svg>

After

Width:  |  Height:  |  Size: 182 B

1
icons/help.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>

After

Width:  |  Height:  |  Size: 695 B

1
icons/history.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M480-120q-138 0-240.5-91.5T122-440h82q14 104 92.5 172T480-200q117 0 198.5-81.5T760-480q0-117-81.5-198.5T480-760q-69 0-129 32t-101 88h110v80H120v-240h80v94q51-64 124.5-99T480-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T840-480q0 75-28.5 140.5t-77 114q-48.5 48.5-114 77T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z"/></svg>

After

Width:  |  Height:  |  Size: 444 B

View File

@@ -1,4 +1,4 @@
color: '#B89230' #Hex code of the color
color: '#737373' #Hex code of the color
icons:
addBook: add_book.svg
add_user: add_user.svg
@@ -16,3 +16,8 @@ icons:
warning: warning.svg
delete: delete.svg
restart: restart.svg
quit: quit.svg
history: history.svg
help: help.svg
support: support.svg
add: add.svg

1
icons/quit.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-84 31.5-156.5T197-763l56 56q-44 44-68.5 102T160-480q0 134 93 227t227 93q134 0 227-93t93-227q0-67-24.5-125T707-707l56-56q54 54 85.5 126.5T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm-40-360v-440h80v440h-80Z"/></svg>

After

Width:  |  Height:  |  Size: 396 B

1
icons/support.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M480-280q17 0 28.5-11.5T520-320q0-17-11.5-28.5T480-360q-17 0-28.5 11.5T440-320q0 17 11.5 28.5T480-280Zm-40-160h80v-240h-80v240ZM330-120 120-330v-300l210-210h300l210 210v300L630-120H330Zm34-80h232l164-164v-232L596-760H364L200-596v232l164 164Zm116-280Z"/></svg>

After

Width:  |  Height:  |  Size: 375 B

View File

@@ -1,76 +0,0 @@
@echo off
echo print Installing Python 3.12.7
echo downloading..... please wait
curl -o python-3.12.7-amd64.exe https://www.python.org/ftp/python/3.12.7/python-3.12.7-amd64.exe
echo Installing Python 3.12.7
python-3.12.7-amd64.exe /quiet InstallAllUsers=0 PrependPath=1 Include_test=0
echo Python 3.12.7 installed
echo Please confirm the installation by opening a new terminal and typing python --version
echo If the version is 3.12.7, then the installation was successful
pause
echo downloading the repository
curl -o LibrarySystem.zip https://git.theprivateserver.de/WorldTeacher/LibrarySystem/archive/main.zip
echo Extracting the repository
tar -xf LibrarySystem.zip
cd into the extracted folder
cd librarysystem
echo Installing the required packages
python -m venv venv
call venv\Scripts\activate.bat
echo Activated the virtual environment
echo Cleaning up the environment
@echo off
echo Uninstalling all Python packages...
@REM Uninstall all packages in the virtual environment
pip freeze > temp_requirements.txt
for /F "delims=" %%i in (temp_requirements.txt) do pip uninstall -y %%i
@REM Clean up the temporary file
del temp_requirements.txt
echo All packages uninstalled.
echo Installing the required packages
pip install -r requirements.txt
echo Installation completed
echo Building the application
call pyinstaller --noconfirm --onedir --windowed --icon "icons/icon.ico" --name "LibrarySystem" --clean --add-data "config;config/" --add-data "icons;icons/" "main.py"
echo compiling done, please confirm the build by checking the dist folder
echo If the build is successful, you can run the application by running the LibrarySystem.exe file in the folder
pause
set /p compile="Build successful? (y/n) "
if %compile% == y (
echo Build successful
exit
) else (
echo Build failed
echo switching over to manual mode using auto-py-to-exe
echo installing auto-py-to-exe
pip install auto-py-to-exe
echo auto-py-to-exe installed
echo running auto-py-to-exe
echo --------------------
echo Please go to settings > Import config.json
echo Select the build.app.json
echo Change / Set these values:
echo - Script Location: main.py
echo - Icon: icons/icon.ico
echo - Additional Files:
echo - config: config/
echo - icons: icons/
echo - site: site/
echo Click on the Convert .py to .exe button
echo the completed build will be in the output folder
echo --------------------
call auto-py-to-exe
pause
)

24
launch.cmd Normal file
View File

@@ -0,0 +1,24 @@
@echo off
REM Check if .venv exists
if exist .venv (
REM Activate the virtual environment
call .venv\Scripts\activate.bat
) else (
REM Run uv sync if .venv does not exist
uv sync
call .venv\Scripts\activate.bat
)
REM Perform a git pull
git pull
REM Run uv sync if .venv exists (already activated)
uv sync
REM Start main.py
uv run python main.py
REM Deactivate the virtual environment if it was activated
if exist .venv (
deactivate
)

22
launch.ps1 Normal file
View File

@@ -0,0 +1,22 @@
# Check if .venv exists
if (Test-Path .venv) {
# Activate the virtual environment
.\.venv\Scripts\Activate.ps1
} else {
# Run uv sync if .venv does not exist
uv sync
.\.venv\Scripts\Activate.ps1
}
# Perform a git pull
git pull
# Run uv sync if .venv exists (already activated)
uv sync
# Start main.py
uv run python main.py
# Deactivate the virtual environment if it was activated
if (Test-Path .venv) {
deactivate
}

View File

@@ -1,15 +1,4 @@
# from src.ui.main_ui import launch
from src.ui.main_ui import launch
from src.updater import Update
import os
if __name__ == "__main__":
Update()
with open("config/.updater", "r") as f:
contents = f.read().splitlines()
command = [line for line in contents if "command" in line][0].split(":")[1]
if "~" in command:
command = command.replace("~", str(os.getcwd()))
os.system(command)
# launch("--debug")
launch()

View File

@@ -1,4 +1,5 @@
site_name: LibrarySystem
repo_url: https://git.theprivateserver.de/WorldTeacher/LibrarySystem
theme:
features:
- search.suggest

View File

@@ -1,12 +1,38 @@
[project]
name = "librarysystem"
version = "0.2.0"
description = "Add your description here"
version = "0.3.2"
description = "A library system for loaning books and managing the users."
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
dependencies = [
"beautifulsoup4>=4.12.3",
"loguru>=0.7.3",
"mkdocs>=1.6.1",
"mkdocs-material>=9.5.49",
"mkdocs-material-extensions>=1.3.1",
"omegaconf>=2.3.0",
"prettytable>=3.12.0",
"pyqt6>=6.8.0",
"requests>=2.32.3",
]
[dependency-groups]
dev = [
"bump-my-version>=0.29.0",
"icecream>=2.1.4",
"nuitka>=2.5.9",
"python-dotenv>=1.0.1",
"ruff>=0.9.2",
]
[tool.ruff]
exclude = [
"dist",
".git",
".vscode",
]
indent-width = 4
include = ["pyproject.toml", "src/**/*.py", "scripts/**/*.py","tests/**/*.py"]
[tool.ruff.lint]
fixable = ["ALL"]

47
release.ps1 Normal file
View File

@@ -0,0 +1,47 @@
# Enable strict mode
Set-StrictMode -Version Latest
# Run Python setup.py
Write-Host "Running setup.py..."
python setup.py
if ($LASTEXITCODE -ne 0) {
Write-Error "Python script failed. Exiting."
exit 1
}
# Get the latest Git tag
Write-Host "Fetching the latest Git tag..."
$latestTag = git describe --tags --abbrev=0
if (-not $latestTag) {
Write-Error "No Git tags found. Exiting."
exit 1
}
Write-Host "Latest tag: $latestTag"
# Read the changelog for the current version
Write-Host "Reading changelog for version $latestTag..."
$changelogPath = "changelog.md"
if (-not (Test-Path $changelogPath)) {
Write-Error "Changelog file not found at $changelogPath. Exiting."
exit 1
}
# Extract the changes for the current version from the changelog
$changelogContent = Get-Content $changelogPath -Raw
$changesPattern = "(?s)# $latestTag\b(.*?)(?=^#|\Z)"
$changes = if ($changelogContent -match $changesPattern) {
$matches[1].Trim()
} else {
Write-Error "No changes found for version $latestTag in the changelog. Exiting."
exit 1
}
# Create a new release with tea
Write-Host "Creating a new release with tea..."
$releaseTitle = "LibrarySystem - Version $latestTag"
$rel_comment = "#Changes in this release: `n$changes`n"
$rel = tea release create --title $releaseTitle --note $rel_comment --tag $latestTag
if (-not $rel) {
Write-Error "Failed to create a new release. Exiting."
exit 1
}

Binary file not shown.

47
setup.py Normal file
View File

@@ -0,0 +1,47 @@
import os
with open("pyproject.toml", "r") as file:
lines = file.readlines()
for line in lines:
if "name" in line:
name = line.split("=")[1].strip().replace('"', "")
break
with open(".version", "r") as file:
version = file.read().strip()
print(f"Name: {name}, Version: {version}")
def rename_folders():
for folder in os.listdir("dist"):
if folder.endswith(".dist"):
if "_dev" in folder:
os.rename(
os.path.join("dist", folder),
os.path.join("dist", f"{name}-{version}-dev"),
)
else:
os.rename(
os.path.join("dist", folder),
os.path.join("dist", f"{name}-{version}"),
)
def remove_other_folders():
for folder in os.listdir("dist"):
if not name in folder:
os.remove(os.path.join("dist", folder))
def compress_folders():
print("Compressing folders")
import shutil
for folder in os.listdir("dist"):
if name in folder and not folder.endswith(".zip"):
print(f"Compressing {folder}")
shutil.make_archive(f"dist/{folder}", "zip", f"dist/{folder}")
if __name__ == "__main__":
rename_folders()
compress_folders()

View File

@@ -1,61 +1,82 @@
import sys
from config import Config
__version__ = "0.2.0"
from loguru import logger
from datetime import datetime
import atexit
import argparse
__version__ = "0.3.2"
__author__ = "Alexander Kirchner"
__email__ = "alexander.kirchner@ph-freiburg.de"
__contacts__ = "alexander.kirchner@ph-freiburg.de,christian.berger@ph-freiburg.de"
__license__ = "MIT"
docport = 6543
docport = 8000
config = Config("config/settings.yaml")
valid_args = ["--debug", "--log", "--no-backup", "--ic-logging", "--version", "-h","--no-documentation"]
_config = Config("config/settings.yaml")._config
# Store original values that might be overridden by CLI
args_description = {
"--debug": "Enable debug mode",
"--log": "Enable logging",
"--no-backup": "Disable database backup",
"--ic-logging": "Enable icecream logging (not available in production)",
"--version": "Show version",
"-h": "Show help message and exit",
"--no-documentation": "Disable documentation server and shortcut"
}
args = sys.argv[1:]
if any(arg not in valid_args for arg in args):
print("Invalid argument present")
print([arg for arg in args if arg not in valid_args])
sys.exit()
def help():
print("Ausleihsystem")
print("Ein Ausleihsystem für Handbibliotheken")
print("Version: {}".format(__version__))
print("Valide Argumente:")
print("args")
print("--------")
print("usage: main.py [-h] [--debug] [--log] [--no-backup] [--ic-logging] [--version] [--no-documentation]")
print("options:")
for arg in valid_args:
print(f"{arg} : {args_description[arg]}")
# based on the arguments, set the config values
if"-h" in args:
help()
sys.exit()
if "--debug" in args:
args = argparse.ArgumentParser()
args.add_argument(
"--debug", help="Debugging mode, active for the active run", action="store_true"
)
args.add_argument(
"--no-backup", help="Disable backups for the active run", action="store_true"
)
args.add_argument("--version", help="Print version", action="store_true")
args.add_argument(
"--no-documentation",
help="Disable documentation for the active run",
action="store_true",
)
args = args.parse_args()
if args.version:
print(f"Version: {__version__}")
sys.exit(0)
# Override config values temporarily without saving
changes_made = False
if args.debug:
config.debug = True
if "--log" in args:
config.log_debug = True
if "--no-backup" in args:
config.no_backup = True
if "--ic-logging" in args:
config.ic_logging = True
if "--no-documentation" in args:
changes_made = True
if args.no_backup:
config.database.do_backup = False
changes_made = True
if args.no_documentation:
config.documentation = False
if "--version" in args:
print(__version__)
sys.exit()
changes_made = True
if changes_made:
config.save()
log = logger
log.remove()
log.add("logs/application.log", rotation="1 week", compression="zip")
# add a log for the current day
log.add(
f"logs/{datetime.now().strftime('%Y-%m-%d')}.log",
rotation="1 day",
compression="zip",
)
if config.debug:
import sys
log.add(
sys.stderr,
)
def restore_config():
log.debug("Restoring configuration")
if not changes_made:
return
values = config.get_changes(_config)
config._config = _config
config.save()
log.debug(f"Restored configuration, changed values: {values}")

View File

@@ -1,4 +1,5 @@
__help__ = "This package contains the logic of the application."
from .database import Database
from .catalogue import Catalogue
from .backup import Backup
from .backup import Backup
from .documentation_thread import DocumentationThread

View File

@@ -1,8 +1,7 @@
import os
import sys
import shutil
from src import config
import datetime
class Backup:
def __init__(self):
@@ -11,7 +10,16 @@ class Backup:
self.backup = False
if not os.path.exists(config.database.backupLocation):
os.makedirs(config.database.backupLocation)
if config.database.do_backup == True:
backupPath = config.database.backupLocation
# create an archive path based on the backuppath, one level up with a new folder called archive
# example: backuppath = /home/user/backup
# result: archivepath = /home/user/archive
self.archivePath = os.path.join(os.path.dirname(backupPath), "archive")
# check if the archive path exists, if not create it
if not os.path.exists(self.archivePath):
os.makedirs(self.archivePath)
if config.database.do_backup is True:
self.checkpaths()
config.database.do_backup = self.backup
@@ -20,6 +28,17 @@ class Backup:
self.backup = True
def createBackup(self):
if os.path.exists(self.archivePath) and os.path.exists(self.source_path):
# copy the active database to the archive path, add _[date]
day = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
# copy the active database to the archive path, add _[date]
shutil.copy(
self.source_path,
os.path.join(
self.archivePath, config.database.name + "_" + day + ".archive"
),
)
if self.backup:
if os.path.exists(self.source_path):
if os.path.exists(self.backup_path):

View File

@@ -1,12 +1,11 @@
import requests
from bs4 import BeautifulSoup
from src import config
from src import config, log
from src.schemas import Book
from src.utils import Log
URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndex/Search?type0%5B%5D=allfields&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=au&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ti&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ct&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=isn&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ta&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=co&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=py&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pp&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pu&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=si&lookfor0%5B%5D={}&join=AND&bool0%5B%5D=AND&type0%5B%5D=zr&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=cc&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND"
BASE = "https://rds.ibs-bw.de"
log = Log("Catalogue")
class Catalogue:
def __init__(self, timeout=5):
@@ -24,6 +23,7 @@ class Catalogue:
return True
except requests.exceptions.RequestException as e:
log.error(f"Could not connect to google.com: {e}")
def search_book(self, searchterm: str):
response = requests.get(URL.format(searchterm), timeout=self.timeout)
return response.text

View File

@@ -1,36 +1,39 @@
import sqlite3 as sql
import os
import shutil
from src import config
from src import config, log
from src.schemas import USERS, MEDIA, LOANS, User, Book, Loan
from src.utils import stringToDate, Log, debugMessage as dbg
from src.utils import stringToDate
from PyQt6 import QtCore
log = Log("Database")
FILE = config.database.name
class Database:
def __init__(self, db_path: str = None):
'''
"""
Default constructor for the database class
Args:
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
'''
"""
if db_path is None:
self.db_path = self.handle_folder_reachability(config.database.path, config.database.backupLocation)
self.db_path = self.handle_folder_reachability(
config.database.path, config.database.backupLocation
)
else:
self.db_path = db_path
if not os.path.exists(config.database.path):
try:
os.makedirs(config.database.path)
except FileNotFoundError:
dbg(self.db_path)
log.error(f"Path {config.database.path} not found")
if not os.path.exists(config.database.backupLocation):
os.makedirs(config.database.backupLocation)
#if main path does not exist, try to create it. if that fails, use the backuplocation
dbg(self.db_path)
# if main path does not exist, try to create it. if that fails, use the backuplocation
log.debug("Checking Database Path {}", self.db_path)
self.checkDatabaseStatus()
def handle_folder_reachability(self, original_path, backup_path):
@@ -49,50 +52,59 @@ class Database:
backup_file = os.path.join(backup_path, ".backup")
if not os.path.exists(original_path):
#original folder not reachable, use backup path and create .backup file
# original folder not reachable, use backup path and create .backup file
if not os.path.exists(backup_path):
os.makedirs(backup_path)
with open(backup_file, "w") as f:
f.write("")
# Create an empty backup file as a marker
return backup_path +"/" + FILE
return backup_path + "/" + FILE
else:
dbg("Original Path Exists, using this path")
log.info("Original Path Exists, using this path")
# Original folder is reachable, check for backup
if os.path.exists(backup_file):
# Restore backup
shutil.rmtree(original_path) # Remove original folder to avoid conflicts
shutil.rmtree(
original_path
) # Remove original folder to avoid conflicts
os.rename(backup_path, original_path)
# (backup_path, original_path)
#os.remove(backup_file)
#remove backup file from original path
# os.remove(backup_file)
# remove backup file from original path
os.remove(original_path + "/.backup")
os.makedirs(backup_path)
return original_path +"/" + FILE
return original_path + "/" + FILE
def checkDatabasePath(self):
self.db_path = config.database.path + "/" + config.database.name
#if backup file in backup location, move database to main location, delete backup file
# if backup file in backup location, move database to main location, delete backup file
if os.path.exists(config.database.backupLocation + "/backup"):
if os.path.exists(self.db_path):
os.remove(self.db_path)
os.rename(f"{config.database.backupLocation}/{config.database.name}", self.db_path)
#remove backup file
os.rename(
f"{config.database.backupLocation}/{config.database.name}",
self.db_path,
)
# remove backup file
os.remove(config.database.backupLocation + "/backup")
return self.db_path
else:
#keep using backup file
self.db_path = config.database.backupLocation + "/" + config.database.name
# keep using backup file
self.db_path = (
config.database.backupLocation + "/" + config.database.name
)
if not os.path.exists(config.database.path):
try:
os.makedirs(config.database.path)
except:
self.db_path = config.database.backupLocation + "/" + config.database.name
self.db_path = (
config.database.backupLocation + "/" + config.database.name
)
if not os.path.exists(config.database.backupLocation):
os.makedirs(config.database.backupLocation)
#create a backup file in the backup location
# create a backup file in the backup location
with open(f"{config.database.backupLocation}/backup.txt", "w") as f:
f.write("Backup File")
return self.db_path
@@ -105,27 +117,27 @@ class Database:
# self.insertSubjects()
def connect(self) -> sql.Connection:
'''
"""
Connect to the database
Returns:
sql.Connection: The active connection to the database
'''
"""
return sql.connect(self.db_path)
def close_connection(self, conn: sql.Connection):
'''
"""
closes the connection to the database
Args:
----
- conn (sql.Connection): the connection to be closed
'''
"""
conn.close()
def createDatabase(self):
log.info("Creating Database")
#print("Creating Database")
# print("Creating Database")
if not os.path.exists(self.db_path):
os.makedirs(self.db_path)
conn = self.connect()
@@ -150,12 +162,12 @@ class Database:
def tableCheck(self):
# check if database has tables
'''
"""
Get the contents of the
Returns:
Union[List[Tuple], None]: Returns a list of tuples containing the table names or None if no tables are present
'''
"""
try:
with sql.connect(self.db_path) as conn:
cursor = conn.cursor()
@@ -171,6 +183,7 @@ class Database:
result = cursor.fetchall()
self.close_connection(conn)
return result
def checkUserExists(self, key, value) -> list[User] | bool:
query = f"SELECT * FROM users WHERE {key} like '%{value}%'"
conn = self.connect()
@@ -182,7 +195,9 @@ class Database:
users = cursor.fetchall()
for index, user in enumerate(users):
users[index] = User(userid=user[1], username=user[2], email=user[3], id=user[0])
users[index] = User(
userid=user[1], username=user[2], email=user[3], id=user[0]
)
self.close_connection(conn)
return users
@@ -199,7 +214,7 @@ class Database:
return False
self.close_connection(conn)
return True
def getUserBy(self, key, value) -> User:
conn = self.connect()
cursor = conn.cursor()
@@ -210,7 +225,6 @@ class Database:
return user
def getUser(self, user_id) -> User:
conn = self.connect()
cursor = conn.cursor()
cursor.execute(f"SELECT * FROM users")
@@ -220,20 +234,16 @@ class Database:
for res in result:
if res[0] == user_id:
user = User(userid=res[1], username=res[2], email=res[3], id=res[0])
dbg(f"Returning User {user}")
log.info(f"Returning User {user}")
log.debug(f"Returning User {user}")
return user
else:
for res in result:
if res[1] == user_id:
user = User(userid=res[1], username=res[2], email=res[3], id=res[0])
dbg(f"Returning User {user}")
log.debug(f"Returning User {user}")
log.info(f"Returning User {user}")
return user
raise ValueError(f"User {user_id} not found")
#return User(userid="gelöscht", username="gelöscht", email="gelöscht", id="gelöscht")
# user = User(userid=result[1], username=result[2], email=result[3],id = result[0])
# return user
def getUserId(self, username) -> User:
conn = self.connect()
@@ -241,12 +251,12 @@ class Database:
cursor.execute(f"SELECT * FROM users WHERE username = '{username}'")
result = cursor.fetchone()
self.close_connection(conn)
user = User(userid=result[1], username=result[2], email=result[3],id = result[0])
user = User(userid=result[1], username=result[2], email=result[3], id=result[0])
log.info(f"Returning User {user}")
return user
def updateUser(self, username, user_id, usermail):
log.debug(f"Updating User {userno}, {username}, {usermail}")
log.debug(f"Updating User {user_id}, {username}, {usermail}")
conn = self.connect()
cursor = conn.cursor()
cursor.execute(
@@ -254,17 +264,21 @@ class Database:
)
conn.commit()
self.close_connection(conn)
def setUserActiveDate(self, userid,date):
def setUserActiveDate(self, userid, date):
query = f"UPDATE users SET lastActive = '{date}' WHERE user_id = '{userid}'"
conn = self.connect()
cursor = conn.cursor()
cursor.execute(query)
conn.commit()
dbg(f"Setting User {userid} to active on {date}")
log.debug(f"Setting User {userid} to active on {date}")
def renameInactiveUsers(self):
lastYear = QtCore.QDate.currentDate().addDays(int(f"-{config.delete_inactive_user_duration}")).toString("yyyy-MM-dd")
lastYear = (
QtCore.QDate.currentDate()
.addDays(int(f"-{config.delete_inactive_user_duration}"))
.toString("yyyy-MM-dd")
)
query = f"SELECT id FROM users WHERE lastActive < '{lastYear}'"
conn = self.connect()
cursor = conn.cursor()
@@ -276,26 +290,28 @@ class Database:
hasLoans = self.hasLoans(user[0])
if not hasLoans:
self.deleteUser(user)
def hasLoans(self, userid)->bool:
def hasLoans(self, userid) -> bool:
query = f"SELECT * FROM loans WHERE user_id = '{userid}' AND returned = 0"
conn = self.connect()
cursor = conn.cursor()
cursor.execute(query)
result = cursor.fetchall()
result = cursor.fetchall()
self.close_connection(conn)
return False if len(result) == 0 else True
def deleteUser(self, userid):
log.debug(f"Deleting User {userid}")
conn = self.connect()
cursor = conn.cursor()
cursor.execute(f"UPDATE users SET username='gelöscht', usermail = 'gelöscht', user_id='gelöscht' WHERE id = '{userid}'")
cursor.execute(
f"UPDATE users SET username='gelöscht', usermail = 'gelöscht', user_id='gelöscht' WHERE id = '{userid}'"
)
conn.commit()
self.close_connection(conn)
def getActiveLoans(self, userid):
dbg("id", str(userid))
log.debug("id: {}", userid)
conn = self.connect()
cursor = conn.cursor()
try:
@@ -312,8 +328,9 @@ class Database:
def getMediaList(self):
query = "SELECT signature FROM media"
result = self.query(query)
return [res[0] for res in result]
def getAllLoans(self):
loan_data = []
query = "SELECT * FROM loans"
@@ -335,6 +352,7 @@ class Database:
)
loan_data.append(l)
return loan_data
def insertLoan(self, userid, mediaid, loandate, duedate):
log.debug(f"Inserting Loan {userid}, {mediaid}, {loandate}, {duedate}")
query = f"INSERT INTO loans (user_id, media_id, loan_date, return_date) Values ('{userid}', '{mediaid}', '{loandate}', '{duedate}')"
@@ -344,7 +362,7 @@ class Database:
conn.commit()
self.close_connection(conn)
def insertMedia(self, media):
def insertMedia(self, media: Book):
log.debug(f"Inserting Media {media}")
query = f"INSERT OR IGNORE INTO media (ppn, title, signature, isbn,link) VALUES ('{media.ppn}', '{media.title}', '{media.signature}', '{media.isbn}','{media.link}')" # , '{media.link}'
log.info(f"Query: |{query}|")
@@ -360,6 +378,7 @@ class Database:
def getLoansBy(self, field, value):
# query all loans, sort by date descending and return
pass
def getMediaSimilarSignatureByID(self, media_id) -> list[Book]:
log.info(f"Getting Media Similar to {media_id}")
query = f"SELECT * FROM media WHERE id = '{media_id}'"
@@ -368,7 +387,7 @@ class Database:
cursor.execute(query)
result = cursor.fetchone()
signature = result[1]
#print(signature)
# print(signature)
query = f"SELECT * FROM media WHERE signature LIKE '%{signature}%'"
cursor.execute(query)
result = cursor.fetchall()
@@ -405,7 +424,7 @@ class Database:
)
return res
def getAllMedia(self, user_id):
def getAllMedia(self, user_id) -> list[Book]:
# get all books that have the user id in the loans table
query = f"SELECT * FROM loans WHERE user_id = '{user_id}'"
conn = self.connect()
@@ -488,7 +507,7 @@ class Database:
cursor = conn.cursor()
cursor.execute(query)
result = cursor.fetchone()
dbg("Result", response=result)
log.debug(f"Result: {result}")
self.close_connection(conn)
if result is not None:
return result[0]

View File

@@ -1,9 +1,10 @@
from PyQt6.QtCore import QThread, pyqtSignal
from src.utils import launch_documentation
from src.utils.documentation import run_mkdocs
class DocumentationThread(QThread):
def __init__(self):
super().__init__()
def run(self):
launch_documentation()
# launch_documentation()
run_mkdocs()

3
src/logic/k10plus.py Normal file
View File

@@ -0,0 +1,3 @@
import requests
URL = "https://sru.k10plus.de/opac-de-627!rec=1?version=1.1&operation=searchRetrieve&query="

View File

@@ -1,4 +1,4 @@
from .database import LOANS, MEDIA, USERS
from .user import User
from .book import Book
from .loan import Loan
from .loan import Loan

View File

@@ -3,14 +3,14 @@ from dataclasses import dataclass
@dataclass
class Book:
title: str = ""
ppn: int = ""
signature: str = ""
isbn: str = ""
link: str = ""
database_id: int = ""
link: str = ""
loan_from: str = ""
loan_to: str = ""
returned: int = ""
returned_date: str = ""
title: str | None = None
ppn: int | None = None
signature: str | None = None
isbn: str | None = None
link: str | None = None
database_id: int | None = None
link: str | None = None
loan_from: str | None = None
loan_to: str | None = None
returned: int | None = None
returned_date: str | None = None

View File

@@ -5,7 +5,7 @@ username TEXT NOT NULL,
usermail TEXT NOT NULL,
lastActive TEXT);
""" # id == matrikelnr,
#matrikelnr TEXT NOT NULL,
# matrikelnr TEXT NOT NULL,
MEDIA = """CREATE TABLE IF NOT EXISTS media (
id INTEGER PRIMARY KEY AUTOINCREMENT,
signature TEXT NOT NULL,

View File

@@ -12,4 +12,4 @@ class Loan:
returned: int
returned_date: str
book: Book
user_name: str
user_name: str

View File

@@ -1,12 +1,23 @@
from dataclasses import dataclass
from typing import Any
@dataclass
class User:
username: str
userid: Any
email: str
id : int = None
id: int = None
def __repr__(self):
return f"Name: {self.username}\nMatrikelnr.: {self.userid}\neMail: {self.email}"
def match(self, testuser: "User"):
name = testuser.username
user_id = testuser.userid
email = testuser.email
if name == self.username and email == self.email and user_id == self.userid:
return True
else:
return False

25
src/ui/addBook.py Normal file
View File

@@ -0,0 +1,25 @@
from .sources.Ui_dialog_addBook import Ui_Dialog
from PyQt6 import QtWidgets, QtCore, QtGui
from src.logic.database import Database
from src.schemas.book import Book
from src.utils import Icon
class addBook(QtWidgets.QDialog, Ui_Dialog):
def __init__(self):
super(addBook, self).__init__()
self.setupUi(self)
self.setWindowTitle("Buch hinzufügen")
self.setWindowIcon(Icon("addBook").icon)
self.btn_save.clicked.connect(self.addBook)
self.btn_cancel.clicked.connect(self.close)
self.db = Database()
self.book_id = None
def addBook(self):
title = self.book_title.text()
signature = self.book_signature.text()
book = Book(title=title, signature=signature)
id = self.db.insertMedia(book)
if id:
self.book_id = id
self.accept()

View File

@@ -1,8 +1,10 @@
from src import log
from .sources.Ui_dialog_createUser import Ui_Dialog
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtGui import QRegularExpressionValidator
from src.logic import Database
from src.utils import Icon, Log
from src.utils import Icon
class CreateUser(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, fieldname, data):
@@ -38,6 +40,8 @@ class CreateUser(QtWidgets.QDialog, Ui_Dialog):
self.userno.textChanged.connect(
lambda: self.validateInputUserno(self.userno.text(), "int")
)
log.info("User creation dialog opened")
def checkFields(self):
if (
self.username.hasAcceptableInput()
@@ -58,7 +62,11 @@ class CreateUser(QtWidgets.QDialog, Ui_Dialog):
usermail = self.user_mail.text()
if self.db.insertUser(username, userno, usermail):
self.userid = userno
log.info(f"User {username} created")
else:
log.error(
f"User {username} could not be created, input was: {username}, {userno}, {usermail}"
)
self.setStatusTipMessage(
"Benutzer konnte nicht erstellt werden, bitte überprüfen Sie die Eingaben"
)
@@ -85,4 +93,4 @@ class CreateUser(QtWidgets.QDialog, Ui_Dialog):
def launch():
app = QtWidgets.QApplication([])
window = CreateUser("id", "123456")
window.exec()
window.exec()

View File

@@ -2,6 +2,7 @@ from .sources.Ui_dialog_extendLoanDuration import Ui_Dialog
from PyQt6 import QtWidgets, QtCore
from src.utils import Icon
class ExtendLoan(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, user, media):
super(ExtendLoan, self).__init__()
@@ -17,9 +18,9 @@ class ExtendLoan(QtWidgets.QDialog, Ui_Dialog):
self.buttonBox.accepted.connect(self.extendLoan)
def extendLoan(self):
#print("Extend Loan")
# print("Extend Loan")
selectedDate = self.extenduntil.selectedDate()
#print(selectedDate)
# print(selectedDate)
self.extendDate = selectedDate
self.close()

View File

@@ -1,9 +1,9 @@
from .sources.Ui_main_Loans import Ui_MainWindow
from PyQt6 import QtCore, QtGui, QtWidgets
from src import log
from .user import UserUI
from src.logic import Database
from src.utils import stringToDate, Icon
from src.utils import debugMessage as dbg
from icecream import ic
TABLETOFIELDTRANSLATE = {
@@ -23,8 +23,7 @@ class LoanWindow(QtWidgets.QMainWindow, Ui_MainWindow):
QtWidgets.QHeaderView.ResizeMode.Stretch
)
self.db = Database()
self.loans = []
self.loadLoans()
self.loans = self.loadLoans()
# lineedits
self.searchbar.textChanged.connect(self.limitResults)
@@ -37,15 +36,15 @@ class LoanWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# table
self.loanTable.doubleClicked.connect(self.showUser)
log.info("Loan history window opened")
self.show()
def selfpass(self):
pass
def insertRow(self, data):
dbg(contents=data)
log.debug(f"Inserting row: {data}")
retdate = ""
if data.returned_date != "":
retdate = stringToDate(data.returned_date).toString("dd.MM.yyyy")
@@ -74,12 +73,45 @@ class LoanWindow(QtWidgets.QMainWindow, Ui_MainWindow):
),
)
self.loanTable.setItem(0, 6, QtWidgets.QTableWidgetItem(retdate))
book = data.book
book.loan_to = data.return_date
book.load_from = data.loan_date
book.returned = data.returned
match self.check_book(book):
case "overdue":
for i in range(7):
self.loanTable.item(0, i).setBackground(
QtGui.QColor(255, 0, 0, 100)
)
case "ok":
for i in range(7):
self.loanTable.item(0, i).setBackground(
QtGui.QColor(105, 255, 51, 100)
)
case "returned":
for i in range(7):
self.loanTable.item(0, i).setBackground(
QtGui.QColor(102, 153, 153, 100)
)
def check_book(self, book):
today = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
returnDate = stringToDate(book.loan_to).toString("yyyy-MM-dd")
returned = book.returned
if returned == 1:
return "returned"
else:
if returnDate < today:
return "overdue"
else:
return "ok"
def loadLoans(self):
loans = self.db.getAllLoans()
for loan in loans:
self.insertRow(loan)
self.loans = loans
return loans
def filterResults(self):
mode = (
@@ -89,6 +121,7 @@ class LoanWindow(QtWidgets.QMainWindow, Ui_MainWindow):
if self.radio_current.isChecked()
else "overdue"
)
log.debug("Switching mode to {}", mode)
self.loanTable.setRowCount(0)
today = QtCore.QDate.currentDate()
for loan in self.loans:
@@ -112,7 +145,7 @@ class LoanWindow(QtWidgets.QMainWindow, Ui_MainWindow):
limiter = str(limiter)
searchfield = self.searchFields.currentText()
searchfield = TABLETOFIELDTRANSLATE[searchfield]
dbg(limiter=limiter, search=searchfield)
log.debug(f"Searching for: {limiter} in {searchfield}")
self.loanTable.setRowCount(0)
for loan in self.loans:
fielddata = eval(f"loan.{searchfield}")
@@ -125,7 +158,7 @@ class LoanWindow(QtWidgets.QMainWindow, Ui_MainWindow):
row = self.loanTable.currentRow()
user_name = self.loanTable.item(row, 3).text()
user = self.db.getUserId(user_name)
self.user = UserUI(user.username, user.id, user.email)
self.user = UserUI(user)
self.user.show()

View File

@@ -1,11 +1,13 @@
import os
import sys
import atexit
import datetime
import webbrowser
from src import config, __email__, docport
from src.logic import Database, Catalogue, Backup
from src.utils import stringToDate, Icon, Log
from src.utils import debugMessage as dbg
from PyQt6 import QtCore, QtWidgets
from omegaconf import OmegaConf
from src import config, __contacts__, docport, log, restore_config
from src.logic import Database, Catalogue, Backup, DocumentationThread
from src.utils import stringToDate, Icon
from src.utils.createReport import generate_report
from src.schemas import Book
from .sources.Ui_main_UserInterface import Ui_MainWindow
@@ -17,18 +19,17 @@ from .settings import Settings
from .newBook import NewBook
from .loans import LoanWindow
from .reportUi import ReportUi
from PyQt6 import QtCore, QtWidgets
from omegaconf import OmegaConf
from src.logic.documentation_thread import DocumentationThread
from .addBook import addBook
backup = Backup()
cat = Catalogue()
log = Log("main")
dbg(backup=config.database.do_backup, catalogue=config.catalogue)
def getShortcut(shortcuts, name):
shortcut = [cut for cut in shortcuts if cut["name"] == name][0]
return shortcut["current"]
class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainUI, self).__init__()
@@ -46,10 +47,12 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.actionBericht_erstellen.triggered.connect(self.generateReport)
self.actionDokumentation_ffnen.triggered.connect(self.openDocumentation)
self.actionBeenden.triggered.connect(self.shutdown)
def __mail():
webbrowser.open(f"mailto:{__email__}")
webbrowser.open(f"mailto:{__contacts__}")
self.actionProblem_melden.triggered.connect(__mail)
#if close button is pressed call shutdown
# if close button is pressed call shutdown
self.closeEvent = self.shutdown
# Buttons
self.btn_show_lentmedia.clicked.connect(self.showUser)
@@ -57,6 +60,7 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.btn_createNewUser.setText("")
self.btn_createNewUser.setIcon(Icon("add_user").overwriteColor("#1E90FF"))
self.mode.clicked.connect(self.changeMode)
self.addBook.clicked.connect(self.addBookAction)
# LineEdits
self.input_userno.returnPressed.connect(
@@ -98,30 +102,54 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
log.info("Backup enabled")
else:
log.warning("Backup disabled")
# set Action Icons
Icon("settings", self.actionEinstellungen)
Icon("user", self.actionNutzer)
Icon("quit", self.actionBeenden)
Icon("report", self.actionBericht_erstellen)
Icon("history", self.actionAusleihhistorie)
Icon("help", self.actionDokumentation_ffnen)
Icon("support", self.actionProblem_melden)
Icon("add", self.addBook)
self.show()
def addBookAction(self):
add = addBook()
add.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
add.exec()
result = add.result()
book_id = add.book_id
if result == 1:
if self.activeUser:
self.loanMedia(self.activeUser.id, book_id)
# log.debug(f"UserID: {self.activeUser.id}, BookID: {book_id}")
def shutdown(self, *args):
#kill documentation thread
# kill documentation thread
log.info("Shutting down")
if config.documentation:
self.docu.terminate()
sys.exit()
def assignShortcuts(self):
shortcuts = config.shortcuts
shortcuts = OmegaConf.to_container(shortcuts)
#convert to dictconfig
# convert to dictconfig
self.actionDokumentation_ffnen.setShortcut(getShortcut(shortcuts, "Hilfe"))
self.actionAusleihhistorie.setShortcut(getShortcut(shortcuts, "Ausleihhistorie"))
self.actionBericht_erstellen.setShortcut(getShortcut(shortcuts, "Bericht_erstellen"))
self.actionAusleihhistorie.setShortcut(
getShortcut(shortcuts, "Ausleihhistorie")
)
self.actionBericht_erstellen.setShortcut(
getShortcut(shortcuts, "Bericht_erstellen")
)
self.actionNutzer.setShortcut(getShortcut(shortcuts, "Nutzer"))
self.actionRueckgabemodus.setShortcut(getShortcut(shortcuts, "Rueckgabemodus"))
self.actionRueckgabemodus.setShortcut(getShortcut(shortcuts, "Rueckgabemodus"))
def generateReport(self):
log.info("Generating Report")
report = ReportUi()
report.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
report.exec()
def showLoanHistory(self):
@@ -141,20 +169,22 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
settings = Settings()
settings.exec()
result = settings.result()
print(settings.settingschanged, settings.restart_required)
if result == 1:
#dialog to ask if program should be restarted
# print(settings.settingschanged, settings.restart_required)
if result == 1 and settings.restart_required:
# dialog to ask if program should be restarted
dialog = QtWidgets.QMessageBox()
dialog.setWindowTitle("Einstellungen geändert")
dialog.setIcon(QtWidgets.QMessageBox.Icon.Information)
dialog.setWindowIcon(Icon("settings").icon)
dialog.setText("Einstellungen wurden geändert\nProgramm neu starten?")
dialog.setWindowIcon(Icon("restart").icon)
dialog.setText(
"Einstellungen wurden geändert\nDas Programm muss neu gestartet werden?"
)
dialog.setStandardButtons(
QtWidgets.QMessageBox.StandardButton.Yes
| QtWidgets.QMessageBox.StandardButton.No
)
dialog.setDefaultButton(QtWidgets.QMessageBox.StandardButton.No)
#translate buttons
# translate buttons
yes = dialog.button(QtWidgets.QMessageBox.StandardButton.Yes)
yes.setText("Ja")
no = dialog.button(QtWidgets.QMessageBox.StandardButton.No)
@@ -164,7 +194,7 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
if result == QtWidgets.QMessageBox.StandardButton.Yes:
self.restart()
# reload settings
#print(config)
# print(config)
def openDocumentation(self):
log.info("Opening Documentation")
@@ -178,22 +208,18 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
dialog.setText("Dokumentation nicht verfügbar")
dialog.exec()
def restart(self):
#log restart
dbg("Restarting Program")
# log restart
log.info("Restarting Program")
import os
python_executable = sys.executable
args = sys.argv[:]
args.insert(0, sys.executable)
os.execvp(python_executable, args)
def changeMode(self):
log.info("Changing Mode")
dbg(f"Current mode: {self.activeState}")
log.info("Changing Mode, current mode is {}", self.activeState)
self.input_username.clear()
stayReturn = False
if config.advanced_refresh and self.userdata.toPlainText() != "":
@@ -205,18 +231,18 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.label_7.hide()
self.nextReturnDate.hide()
self.mediaOverview.setRowCount(0)
self.activeUser = None #! remove if last user should be kept
self.activeUser = None #! remove if last user should be kept
if self.activeState == "Rückgabe":
if stayReturn:
self.activateReturnMode()
else: self.activateLoanMode()
else:
self.activateLoanMode()
else:
self.activateReturnMode()
def activateLoanMode(self):
dbg("Activating Loan Mode")
log.info("Activating Loan Mode")
self.input_username.setEnabled(True)
self.input_userno.setEnabled(True)
self.duedate.setEnabled(True)
@@ -229,12 +255,14 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.activeState = "Ausleihe"
if self.input_userno.text() == "" or self.input_username.text() == "":
self.input_file_ident.setEnabled(False)
self.input_file_ident.setPlaceholderText("Bitte zuerst Nutzerdaten eingeben")
self.input_file_ident.setPlaceholderText(
"Bitte zuerst Nutzerdaten eingeben"
)
else:
self.input_file_ident.setEnabled(True)
def activateReturnMode(self):
dbg("Activating Return Mode")
log.info("Activating Return Mode")
self.input_username.setEnabled(False)
self.input_userno.setEnabled(False)
# set mode background color to orange
@@ -244,11 +272,12 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.mode.setText("Rückgabe")
self.input_file_ident.setEnabled(True)
self.input_file_ident.setPlaceholderText("Buchidentifikation eingeben")
self.input_username.setPlaceholderText("Bitte erst in den Ausleihmodus wechseln")
self.input_username.setPlaceholderText(
"Bitte erst in den Ausleihmodus wechseln"
)
self.input_userno.setPlaceholderText("Bitte erst in den Ausleihmodus wechseln")
self.input_file_ident.setFocus()
def showUser(self):
log.info(f"Showing User {self.activeUser}")
if self.activeUser is None:
# create warning dialog
log.info("Showing no user selected warning")
@@ -260,12 +289,10 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
dialog.exec()
return
self.user_ui = UserUI(
self.activeUser
)
self.user_ui = UserUI(self.activeUser)
# self.user_ui.setFields("John Doe", "123456789", "test@mail.com")
self.user_ui.show()
def setUserData(self):
log.info("Setting User Data")
self.input_username.setText(str(self.activeUser.username))
@@ -277,9 +304,11 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
def createUser(self):
log.info("Creating User")
user = CreateUser(fieldname="id", data="")
user.setWindowModality(
QtCore.Qt.WindowModality.ApplicationModal
) # Block MainUI fom being accessed
user.exec()
userid = user.userid
print(userid)
if userid:
log.info(f"User created {userid}")
data = self.db.getUserBy("user_id", userid)
@@ -295,7 +324,7 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
def checkUser(self, fieldname, data):
log.info(f"Checking User {fieldname}, {data}")
#print("Checking User", fieldname, data)
# print("Checking User", fieldname, data)
# set fieldname as key and data as variable
user = self.db.checkUserExists(fieldname, data)
if not user:
@@ -315,28 +344,32 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
multi.exec()
self.activeUser = multi.userdata
else:
#print("User found", user[0])
self.activeUser = user[0]
log.debug("User: {}", self.activeUser)
if self.activeUser is not None:
log.info(f"User found {self.activeUser}")
#print("User found", self.activeUser)
log.debug(self.activeUser.__dict__)
self.setUserData()
self.input_file_ident.setFocus()
self.mode.setText("Ausleihe")
#print(self.activeUser.__dict__)
loans = self.db.getActiveLoans(self.activeUser.id)
dbg(loans=loans)
log.debug("Active Loans", loans)
self.btn_show_lentmedia.setText(loans)
retdate = self.db.selectClosestReturnDate(self.activeUser.id)
if retdate:
date = stringToDate(retdate).toString("dd.MM.yyyy")
today = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
# if retdate is in past, set nextReturnDate color to red
if retdate < today:
self.nextReturnDate.setStyleSheet("color: red")
else:
self.nextReturnDate.setStyleSheet("color: black")
self.nextReturnDate.setText(date)
self.nextReturnDate.show()
self.label_7.show()
self.input_file_ident.setEnabled(True)
self.input_file_ident.setPlaceholderText("Buchidentifikation eingeben")
self.input_file_ident.setFocus()
def moveToLine(self, line):
log.debug("Moving to Line", line)
line.setFocus()
@@ -354,13 +387,15 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
dialog.setWindowTitle("Ungültige Eingabe")
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
dialog.setWindowIcon(Icon("warning").overwriteColor("#EA3323"))
dialog.setText("Eingabe ist nicht in der Datenbank\nBitte prüfen und erneut eingeben")
dialog.setText(
"Eingabe ist nicht in der Datenbank\nBitte prüfen und erneut eingeben"
)
dialog.exec()
self.input_file_ident.setFocus()
self.input_file_ident.clear()
return
else:
if not " " in value:
if " " not in value:
# create warning dialog
log.info("Invalid Input")
dialog = QtWidgets.QMessageBox()
@@ -374,18 +409,19 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
return
self.mediaAdd(value)
self.input_file_ident.setFocus()
def mediaAdd(self, identifier):
dbg("Adding Media", identifier = identifier)
log.info("Adding Media", identifier=identifier)
self.input_file_ident.clear()
self.input_file_ident.setEnabled(False)
user_id = self.activeUser.id
media = Book(signature=identifier)
book_id = self.db.checkMediaExists(media)
dbg(f"Book ID: {book_id}, User ID: {user_id}", media=media)
log.debug(f"Book ID: {book_id}, User ID: {user_id}", media=media)
if not book_id:
dbg("Book not found, searching catalogue")
if config.catalogue == True:
log.info("Book not found, searching catalogue")
if config.catalogue:
media = cat.get_book(identifier)
if not media:
self.setStatusTipMessage("Buch nicht gefunden")
@@ -402,8 +438,8 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
elif book_id:
if isinstance(book_id, list) and len(book_id) > 1:
#print("Multiple Books found")
# TODO: implement book selection dialog
raise NotImplementedError("Multiple books found")
return
else:
if isinstance(book_id, int):
@@ -411,7 +447,7 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
# check if book is already loaned
loaned = self.db.checkLoanState(book_id[0])
if loaned:
#print("Book already loaned")
# print("Book already loaned")
self.setStatusTipMessage("Buch bereits entliehen")
# dialog with yes no to create new entry
dialog = QtWidgets.QMessageBox()
@@ -432,19 +468,29 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
return
newentry = NewEntry([book_id[0]])
newentry.exec()
if newentry.result() == 1: # only create dialog if new entry was created
if (
newentry.result() == 1
): # only create dialog if new entry was created
self.setStatusTipMessage("Neues Exemplar hinzugefügt")
#print(created_ids)
# print(created_ids)
self.input_file_ident.setEnabled(True)
newentries = newentry.newIds
if newentries:
for entry in newentries:
book = self.db.getMedia(entry)
self.loanMedia(user_id, [entry], book)
dbg("inserted duplicated book into database")
log.debug(
"Inserting duplicated book {} with id {} to user {}".format(
book, entry, user_id
)
)
self.loanMedia(user_id, [entry])
log.info("inserted duplicated book into database")
else:
log.info("No new entry created")
self.input_file_ident.setEnabled(True)
return
else:
#print("Book not loaned, loaning now")
# print("Book not loaned, loaning now")
self.loanMedia(user_id, book_id)
def loanMedia(self, user_id, book_id):
@@ -455,7 +501,7 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.duedate.date().toString("yyyy-MM-dd"),
)
media = self.db.getMedia(book_id[0])
#print(media)
# print(media)
self.mediaOverview.insertRow(0)
self.mediaOverview.setItem(0, 0, QtWidgets.QTableWidgetItem(media.signature))
self.mediaOverview.setItem(0, 1, QtWidgets.QTableWidgetItem(media.title))
@@ -471,19 +517,19 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.input_file_ident.setEnabled(True)
def returnMedia(self, identifier):
#print("Returning Media", identifier)
# print("Returning Media", identifier)
# get book id from database
# self.
identifier = Book(
isbn=identifier, title=identifier, signature=identifier, ppn=identifier
)
book_id = self.db.checkMediaExists(identifier)
#print(book_id)
# print(book_id)
if book_id:
# check if book is already loaned
loaned = self.db.checkLoanState(book_id[0])
if loaned:
#print("Book already loaned, returning now")
# print("Book already loaned, returning now")
user = self.db.getUserByLoan(book_id[0])
# set userdata in lineedits
self.activeUser = user
@@ -492,7 +538,9 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
book_id[0], self.currentDate.toString("yyyy-MM-dd")
)
self.mediaOverview.insertRow(0)
self.mediaOverview.setItem(0, 0, QtWidgets.QTableWidgetItem(book.signature))
self.mediaOverview.setItem(
0, 0, QtWidgets.QTableWidgetItem(book.signature)
)
self.mediaOverview.setItem(0, 1, QtWidgets.QTableWidgetItem(book.title))
self.mediaOverview.setItem(
0, 2, QtWidgets.QTableWidgetItem("Zurückgegeben")
@@ -502,15 +550,13 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.db.getActiveLoans(self.activeUser.id)
)
else:
#print("Book not loaned")
# print("Book not loaned")
self.setStatusTipMessage("Buch nicht entliehen")
self.input_file_ident.clear()
else:
dbg("Book not found")
#print("Book not found")
#self.input_file_ident.setPlaceholderText(f"Buch {identifier} nicht gefunden")
log.error("Book not found, identifier", identifier)
# print("Book not found")
# self.input_file_ident.setPlaceholderText(f"Buch {identifier} nicht gefunden")
def setStatusTipMessage(self, message):
dialog = QtWidgets.QMessageBox()
@@ -519,29 +565,40 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
dialog.setWindowIcon(Icon("error").overwriteColor("#EA3323"))
dialog.setText(message)
dialog.exec()
def exit_handler():
dbg("Exiting, creating backup")
app = QtWidgets.QApplication(sys.argv)
#print(backup.backup)
log.info(
"Exiting, creating backup, renaming inactive users, creating report if day matches"
)
restore_config()
QtWidgets.QApplication(sys.argv)
# print(backup.backup)
# generate report if monday
if datetime.datetime.now().weekday() == config.report.report_day:
log.info("Generating Report")
generate_report()
dbg("Generated Report")
Database().renameInactiveUsers()
if config.database.do_backup:
state = backup.createBackup()
# create dialog to show state
if state == True:
if state:
return
else:
dialog = QtWidgets.QMessageBox()
# set icon
dialog.setWindowIcon(Icon("backup").icon)
dialog.setWindowTitle("Backup")
dialog.setText("Backup konnte nicht erstellt werden")
errormsg = "Backup konnte nicht erstellt werden\nGrund: {}"
files = os.listdir(config.database.backupLocation)
if ".backup" in files:
errormsg = errormsg.format("Normaler speicherort nicht gefunden")
else:
errormsg = errormsg.format("Backuppfad nicht gefunden")
dialog.setText(errormsg)
dialog.exec()
dbg("Exiting", backupstate=state)
log.info("Exiting, backup:", state)
else:
dialog = QtWidgets.QMessageBox()
# set icon
@@ -554,27 +611,55 @@ def exit_handler():
dialog.setWindowTitle("Backup nicht möglich")
dialog.setText("Backup konnte nicht erstellt werden\nGrund: {}".format(reason))
dialog.exec()
log.info("Exiting")
sys.exit()
def launch(*argv):
options = sys.argv
if argv:
options += [arg for arg in argv]
options = [arg for arg in options if arg.startswith("--")]
#print("Launching Main UI")
#print(options)
QtCore.QLocale().setDefault(QtCore.QLocale(QtCore.QLocale.Language.German, QtCore.QLocale.Country.Germany))
options += [arg for arg in options if arg.startswith("--")]
# add options to sys.argv
# print(options)
# print("Launching Main UI")
QtCore.QLocale().setDefault(
QtCore.QLocale(QtCore.QLocale.Language.German, QtCore.QLocale.Country.Germany)
)
SYSTEM_LANGUAGE = QtCore.QLocale().system().name()
# Load base QT translations from the normal place
app = QtWidgets.QApplication([])
main_ui = MainUI()
#translate ui to system language
MainUI()
# translate ui to system language
if SYSTEM_LANGUAGE:
translator = QtCore.QTranslator()
#do not use ascii encoding
# do not use ascii encoding
translator.load(f"qt_{SYSTEM_LANGUAGE}", "translations")
translator.load("app.qm", "translations")
app.installTranslator(translator)
app.installTranslator(translator)
atexit.register(exit_handler)
sys.exit(app.exec())
# sys.exit(app.exec())
# print("Launching Main UI")
# print(options)
QtCore.QLocale().setDefault(
QtCore.QLocale(QtCore.QLocale.Language.German, QtCore.QLocale.Country.Germany)
)
SYSTEM_LANGUAGE = QtCore.QLocale().system().name()
# Load base QT translations from the normal place
app = QtWidgets.QApplication([])
MainUI()
# translate ui to system language
if SYSTEM_LANGUAGE:
translator = QtCore.QTranslator()
# do not use ascii encoding
translator.load(f"qt_{SYSTEM_LANGUAGE}", "translations")
translator.load("app.qm", "translations")
app.installTranslator(translator)
atexit.register(exit_handler)
sys.exit(app.exec())
# sys.exit(app.exec())

View File

@@ -2,7 +2,7 @@ from .sources.Ui_dialog_multipleUserfound import Ui_Dialog
from PyQt6 import QtCore, QtGui, QtWidgets
from src.schemas import User
from src.utils import Icon
from src import log
class MultiUserFound(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, users: list[User]):
@@ -27,15 +27,20 @@ class MultiUserFound(QtWidgets.QDialog, Ui_Dialog):
self.tableWidget.cellClicked.connect(self.selectUser)
def selectUser(self, row, column):
#print(row, column)
user = User(
userid=self.tableWidget.item(row, 0).text(),
# print(row, column)
selected_user = User(
userid=int(self.tableWidget.item(row, 0).text()),
username=self.tableWidget.item(row, 1).text(),
email=self.tableWidget.item(row, 2).text(),
)
self.userdata = user
# find the selecter in the self.users list
for user in self.users:
if user.match(selected_user):
self.userdata = user
break
log.debug("User selected: {}", self.userdata)
def displayUsers(self):
for user in self.users:
self.tableWidget.insertRow(0)

View File

@@ -4,6 +4,7 @@ from src.logic import Database
from src.schemas import Book
from src.utils import Icon
class NewEntry(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, title_id: list[int]):
super(NewEntry, self).__init__()
@@ -19,15 +20,15 @@ class NewEntry(QtWidgets.QDialog, Ui_Dialog):
self.populateTable()
self.btn_addNewBook.clicked.connect(self.addEntry)
self.buttonBox.accepted.connect(self.insertEntry)
#disable buttonbox accepted
self.buttonBox.button(
QtWidgets.QDialogButtonBox.StandardButton.Ok
).setEnabled(False)
# disable buttonbox accepted
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setEnabled(
False
)
def addEntry(self):
self.buttonBox.button(
QtWidgets.QDialogButtonBox.StandardButton.Ok
).setEnabled(True)
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setEnabled(
True
)
# clone last row and its data
row = self.tableWidget.rowCount()
self.tableWidget.insertRow(row)
@@ -35,19 +36,31 @@ class NewEntry(QtWidgets.QDialog, Ui_Dialog):
self.tableWidget.setItem(
row, i, QtWidgets.QTableWidgetItem(self.tableWidget.item(row - 1, i))
)
if i == 2 and "+" in self.tableWidget.item(row, i).text():
entry = self.tableWidget.item(row, i).text().split("+")[1]
entry = str(int(entry) + 1)
self.tableWidget.setItem(
row,
i,
QtWidgets.QTableWidgetItem(
self.tableWidget.item(row, i).text().split("+")[0] + "+" + entry
),
)
if i == 2:
if "+" in self.tableWidget.item(row, i).text():
entry = self.tableWidget.item(row, i).text().split("+")[1]
entry = str(int(entry) + 1)
self.tableWidget.setItem(
row,
i,
QtWidgets.QTableWidgetItem(
self.tableWidget.item(row, i).text().split("+")[0]
+ "+"
+ entry
),
)
else:
self.tableWidget.setItem(
row,
i,
QtWidgets.QTableWidgetItem(
self.tableWidget.item(row, i).text() + "+1"
),
)
def populateTable(self):
for title in self.titles:
#print(title)
# print(title)
entries = self.db.getMediaSimilarSignatureByID(title)
# sort by signature
entries.sort(key=lambda x: x.signature, reverse=True)
@@ -59,7 +72,11 @@ class NewEntry(QtWidgets.QDialog, Ui_Dialog):
0, 2, QtWidgets.QTableWidgetItem(entry.signature)
)
self.tableWidget.setItem(0, 3, QtWidgets.QTableWidgetItem(entry.ppn))
# set row to be not editable
for i in range(4):
self.tableWidget.item(0, i).setFlags(
QtCore.Qt.ItemFlag.ItemIsEnabled
)
def insertEntry(self):
# get all rows, convert them to Book and insert into database
for row in range(self.tableWidget.rowCount()):
@@ -73,7 +90,7 @@ class NewEntry(QtWidgets.QDialog, Ui_Dialog):
signature=signature,
ppn=eval(ppn),
)
#print(book)
# print(book)
if not self.db.checkMediaExists(book):
newBookId = self.db.insertMedia(book)
self.newIds.append(newBookId)

View File

@@ -4,6 +4,7 @@ from src.utils import Icon
from src.utils.reportThread import ReportThread
from src.logic import Database
import os
from src import config, log
class ReportUi(QtWidgets.QDialog, Ui_Dialog):
@@ -31,14 +32,19 @@ class ReportUi(QtWidgets.QDialog, Ui_Dialog):
self.format_txt.clicked.connect(lambda: self.rthread.setFormat("txt"))
self.format_csv.clicked.connect(lambda: self.rthread.setFormat("tsv"))
self.format_csv.clicked.connect(lambda: self.generateReport.setEnabled(True))
self.format_txt.clicked.connect(lambda: self.generateReport.setEnabled(True))
self.format_txt.clicked.connect(lambda: self.generateReport.setEnabled(True)) #
self.signature.clicked.connect(self.setSignature)
# sliders
self.dayslider.valueChanged.connect(self.set_days)
self.dayslider.valueChanged.connect(self.set_days_slider)
self.show()
# labels
self.label_4.hide()
def setSignature(self):
show_signature = self.signature.isChecked()
config.report.show_signature = show_signature
def set_days_by_radio(self):
if self.radio_year.isChecked():
self.set_days(365)
@@ -50,15 +56,26 @@ class ReportUi(QtWidgets.QDialog, Ui_Dialog):
self.set_days(7)
self.dayslider.setValue(7)
def set_days(self, value):
# if value is not 7,30,365, deactivate radio buttons
if value != 7 and value != 30 and value != 365:
self.radioButton.setChecked(True)
def set_days(self, days=None):
self.days = days
self.days = value
self.dayValue.setText(str(value))
self.dayValue.setText(str(self.days))
def set_days_slider(self):
slider_value = self.dayslider.value()
self.set_days(slider_value)
match slider_value:
case 365:
self.radio_year.setChecked(True)
case 30:
self.radio_month.setChecked(True)
case 7:
self.radio_week.setChecked(True)
case _:
self.radioButton.setChecked(True)
def generate_report(self):
# self.set_days()
log.debug("Generating report for the last " + str(self.days) + " days")
self.rthread.setDays(self.days)
self.rthread.report_signal.connect(self.report_generated)
self.rthread.report_nums_signal.connect(self.show_progress)
@@ -68,7 +85,6 @@ class ReportUi(QtWidgets.QDialog, Ui_Dialog):
self.rthread.start()
def reset(self):
self.days = 0
self.reportprogress.hide()
self.reportprogress.setValue(0)
self.label_4.setText("Fortschritt:")
@@ -90,7 +106,7 @@ class ReportUi(QtWidgets.QDialog, Ui_Dialog):
def report_generated(self):
self.reportlink.setOpenExternalLinks(True)
fileformat = self.rthread.format
#print(fileformat)
# print(fileformat)
self.reportlink.setText(
f'<a href="file:///{os.getcwd()}/report.{fileformat}">Report</a>'
)

View File

@@ -1,18 +1,18 @@
from .sources.Ui_dialog_settings import Ui_Dialog
from PyQt6 import QtWidgets, QtCore
from src import config, log
from src.utils import Icon
from src import config
from src.utils import debugMessage as dbg
from omegaconf import OmegaConf
import os
class Settings(QtWidgets.QDialog, Ui_Dialog):
def __init__(self):
super(Settings, self).__init__()
self.setupUi(self)
self.setWindowTitle("Einstellungen")
self.setWindowIcon(Icon("settings").icon)
#variables
# variables
self.originalSettings = config.to_Omegaconf()
self.changedSettings = config.to_Omegaconf()
self.shortcuts = config.shortcuts
@@ -20,12 +20,10 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
self.settingschanged = False
self.restart_required = False
# buttonbox
self.buttonBox.accepted.connect(self.saveSettings)
self.buttonBox.rejected.connect(self.close)
self.loadSettings()
self.populateShortcuts()
# buttons
@@ -36,36 +34,39 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
self.btn_select_database_name.clicked.connect(self.selectDatabaseName)
self.btn_select_report_path.clicked.connect(self.selectReportPath)
self.returnMode.clicked.connect(self.returnModeSetting)
#other
#stretch columns
self.shortcutchanger.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.Stretch)
# other
# stretch columns
self.shortcutchanger.horizontalHeader().setSectionResizeMode(
0, QtWidgets.QHeaderView.ResizeMode.Stretch
)
def returnModeSetting(self):
currentstate = self.returnMode.isChecked()
if self.originalSettings.advanced_refresh != currentstate:
self.enableButtonBox()
def populateShortcuts(self):
for shortcut in self.shortcuts:
name = shortcut["name"]
default = shortcut["default"]
current = shortcut["current"]
self.addShortcut(name, default, current)
#assume the shortcuts will be changed
self.settingschanged = True
# assume the shortcuts will be changed
self.settingschanged = True
def addShortcut(self, name, default, current):
#remove all pages from shortcutchanger
#add new page with name, default and current
# remove all pages from shortcutchanger
# add new page with name, default and current
self.shortcutchanger.insertRow(0)
self.shortcutchanger.setItem(0, 0, QtWidgets.QTableWidgetItem(name))
self.shortcutchanger.setItem(0, 1, QtWidgets.QTableWidgetItem(default))
#add keysequenceedit
# add keysequenceedit
keysequenceedit = QtWidgets.QKeySequenceEdit()
keysequenceedit.setKeySequence(current)
self.shortcutchanger.setCellWidget(0, 2, keysequenceedit)
def selectBackupLocation(self):
backupLocation = QtWidgets.QFileDialog.getExistingDirectory(
self,
@@ -93,7 +94,7 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
True
)
self.settingschanged = True
def selectDatabasePath(self):
databasePath = QtWidgets.QFileDialog.getExistingDirectory(
self, "Select Database Path", self.originalSettings.database.path
@@ -107,7 +108,7 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
)
self.settingschanged = True
self.restart_required = True
def selectDatabaseName(self):
# filepicker with filter to select only .db files if a file is selected, set name to the lineedit and set database_path
databaseName = QtWidgets.QFileDialog.getOpenFileName(
@@ -125,7 +126,7 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
)
self.settingschanged = True
self.restart_required = True
def getShortcuts(self):
shortcuts = []
for row in range(self.shortcutchanger.rowCount()):
@@ -140,7 +141,7 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
}
)
return shortcuts
def sortShortcuts(self, shortcuts):
short = []
for shortcut in shortcuts:
@@ -161,16 +162,14 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
report_path = self.report_path.text()
refresh_state = self.returnMode.isChecked()
shortcuts = self.getShortcuts()
#shortcuts to omegaconf.DictConfig
# shortcuts to omegaconf.DictConfig
shortcuts = OmegaConf.create(shortcuts)
if database_path != self.originalSettings.database.path :
signature = self.signature.isChecked()
if database_path != self.originalSettings.database.path:
os.makedirs(database_path, exist_ok=True)
self.restart_required = True
# create new Settings
self.changedSettings.institution_name = institution_name
self.changedSettings.loan_duration = default_loan_duration
@@ -178,85 +177,85 @@ class Settings(QtWidgets.QDialog, Ui_Dialog):
self.changedSettings.database.path = database_path
self.changedSettings.database.name = database_name
self.changedSettings.delete_inactive_user_duration = delete_inactive_users
self.changedSettings.report.report_day = report_day
self.changedSettings.report.report_day = report_day
self.changedSettings.report.path = report_path
self.changedSettings.report.generate_report = report_generate
self.changedSettings.report.show_signature = signature
self.changedSettings.advanced_refresh = refresh_state
self.changedSettings.shortcuts = shortcuts
changed = self.changedSettings
changed = self.changedSettings
original = self.originalSettings
if changed == original:
self.settingschanged = False
self.restart_required = False
dbg("Settings not changed")
log.info("Settings not changed")
else:
self.settingschanged = True
#compare if database or shortcuts were changed
# compare if database or shortcuts were changed
database = original.database == changed.database
shortcuts = self.shortcuts == self.sortShortcuts(changed.shortcuts)
if not database or not shortcuts:
if not database or not shortcuts:
self.restart_required = True
dbg(f"Settings changed, restart required: {self.restart_required}",database=database,shortcuts=shortcuts)
log.info(
f"Settings changed, restart required: {self.restart_required}",
)
# save the new settings
if self.settingschanged:
# save the settings
config.updateValue("institution_name", self.changedSettings.institution_name)
config.updateValue("default_loan_duration", self.changedSettings.loan_duration)
config.updateValue("database.backupLocation", self.changedSettings.database.backupLocation)
config.updateValue(
"institution_name", self.changedSettings.institution_name
)
config.updateValue(
"default_loan_duration", self.changedSettings.loan_duration
)
config.updateValue(
"database.backupLocation", self.changedSettings.database.backupLocation
)
config.updateValue("database.path", self.changedSettings.database.path)
config.updateValue("database.name", self.changedSettings.database.name)
config.updateValue("inactive_user_deletion", self.changedSettings.inactive_user_deletion)
config.updateValue("report.report_day", self.changedSettings.report.report_day)
config.updateValue("report.generate_report", self.changedSettings.report.generate_report)
config.updateValue(
"inactive_user_deletion", self.changedSettings.inactive_user_deletion
)
config.updateValue(
"report.report_day", self.changedSettings.report.report_day
)
config.updateValue(
"report.generate_report", self.changedSettings.report.generate_report
)
config.updateValue("report.path", self.changedSettings.report.path)
config.updateValue("advanced_refresh", self.changedSettings.advanced_refresh)
config.updateValue(
"advanced_refresh", self.changedSettings.advanced_refresh
)
config.updateValue("shortcuts", self.changedSettings.shortcuts)
config.updateValue(
"report.show_signature", self.changedSettings.report.show_signature
)
self.originalSettings = self.changedSettings
config.save()
if self.restart_required:
self.restart()
self.close()
def restart(self):
dialog = QtWidgets.QMessageBox()
dialog.setIcon(QtWidgets.QMessageBox.Icon.Information)
dialog.setText("Neustart erforderlich")
dialog.setInformativeText(
"Das Programm muss neu gestartet werden, um die Änderungen zu übernehmen."
)
dialog.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Ok)
dialog.setDefaultButton(QtWidgets.QMessageBox.StandardButton.Ok)
dialog.setWindowTitle("Neustart erforderlich")
dialog.setWindowIcon(Icon("restart").icon)
dialog.exec()
def DiscardSettings(self):
self.loadSettings()
self.restart_required = False
self.settingschanged = False
def loadSettings(self):
self.institution_name.setText(config.institution_name)
self.default_loan_duration.setValue(
int(config.loan_duration)
)
self.default_loan_duration.setValue(int(config.loan_duration))
self.delete_inactive_user_duration.setValue(
int(config.delete_inactive_user_duration)
)
self.database_backupLocation.setText(
config.database.backupLocation
)
self.database_backupLocation.setText(config.database.backupLocation)
self.database_path.setText(config.database.path)
self.database_name.setText(config.database.name)
self.report_day.setCurrentIndex(config.report.report_day)
self.check_generate_report.setChecked(config.report.generate_report)
self.report_path.setText(config.report.path)
self.returnMode.setChecked(config.advanced_refresh)
self.signature.setChecked(config.report.show_signature)
pass

View File

@@ -17,7 +17,12 @@ class Ui_Dialog(object):
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
spacerItem = QtWidgets.QSpacerItem(
40,
20,
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Minimum,
)
self.horizontalLayout.addItem(spacerItem)
self.btn_addNewBook = QtWidgets.QToolButton(parent=Dialog)
self.btn_addNewBook.setObjectName("btn_addNewBook")
@@ -38,13 +43,16 @@ class Ui_Dialog(object):
self.verticalLayout.addWidget(self.tableWidget)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
| QtWidgets.QDialogButtonBox.StandardButton.Ok
)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):

View File

@@ -37,15 +37,23 @@ class Ui_Dialog(object):
self.gridLayout.addWidget(self.username, 0, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Save)
self.buttonBox.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
| QtWidgets.QDialogButtonBox.StandardButton.Save
)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 4, 1, 1, 1)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
spacerItem = QtWidgets.QSpacerItem(
20,
40,
QtWidgets.QSizePolicy.Policy.Minimum,
QtWidgets.QSizePolicy.Policy.Expanding,
)
self.gridLayout.addItem(spacerItem, 3, 0, 1, 1)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.username, self.userno)
Dialog.setTabOrder(self.userno, self.user_mail)

View File

@@ -21,7 +21,10 @@ class Ui_Dialog(object):
self.gridLayout.addWidget(self.extenduntil, 1, 2, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
| QtWidgets.QDialogButtonBox.StandardButton.Ok
)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 2, 2, 1, 1)
self.label = QtWidgets.QLabel(parent=Dialog)
@@ -33,11 +36,13 @@ class Ui_Dialog(object):
self.gridLayout.addWidget(self.label, 0, 2, 1, 1)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Bitte das Verlängerungsdatum auswählen"))
self.label.setText(
_translate("Dialog", "Bitte das Verlängerungsdatum auswählen")
)

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\LibrarySystem\src\ui\sources\dialog_generateReport.ui'
#
# Created by: PyQt6 UI code generator 6.6.1
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
@@ -12,6 +12,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setWindowModality(QtCore.Qt.WindowModality.NonModal)
Dialog.resize(375, 245)
Dialog.setMinimumSize(QtCore.QSize(40, 0))
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
@@ -21,9 +22,11 @@ class Ui_Dialog(object):
self.verticalLayout.addWidget(self.label)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.label_2 = QtWidgets.QLabel(parent=Dialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
self.radioButton = QtWidgets.QRadioButton(parent=Dialog)
self.radioButton.setText("")
self.radioButton.setCheckable(True)
self.radioButton.setObjectName("radioButton")
self.gridLayout.addWidget(self.radioButton, 4, 2, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.radio_week = QtWidgets.QRadioButton(parent=Dialog)
@@ -36,6 +39,9 @@ class Ui_Dialog(object):
self.radio_year.setObjectName("radio_year")
self.horizontalLayout.addWidget(self.radio_year)
self.gridLayout.addLayout(self.horizontalLayout, 1, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=Dialog)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.dayValue = QtWidgets.QLineEdit(parent=Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -48,15 +54,24 @@ class Ui_Dialog(object):
self.dayValue.setReadOnly(True)
self.dayValue.setObjectName("dayValue")
self.gridLayout.addWidget(self.dayValue, 0, 2, 1, 1)
self.radioButton = QtWidgets.QRadioButton(parent=Dialog)
self.radioButton.setText("")
self.radioButton.setCheckable(True)
self.radioButton.setObjectName("radioButton")
self.gridLayout.addWidget(self.radioButton, 3, 2, 1, 1)
self.reportlink = QtWidgets.QLabel(parent=Dialog)
self.reportlink.setText("")
self.reportlink.setObjectName("reportlink")
self.gridLayout.addWidget(self.reportlink, 3, 1, 1, 1)
self.gridLayout.addWidget(self.reportlink, 4, 1, 1, 1)
self.frame = QtWidgets.QFrame(parent=Dialog)
self.frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
self.frame.setLineWidth(0)
self.frame.setObjectName("frame")
self.gridLayout_2 = QtWidgets.QGridLayout(self.frame)
self.gridLayout_2.setObjectName("gridLayout_2")
self.format_csv = QtWidgets.QRadioButton(parent=self.frame)
self.format_csv.setObjectName("format_csv")
self.gridLayout_2.addWidget(self.format_csv, 0, 1, 1, 1)
self.format_txt = QtWidgets.QRadioButton(parent=self.frame)
self.format_txt.setObjectName("format_txt")
self.gridLayout_2.addWidget(self.format_txt, 0, 0, 1, 1)
self.gridLayout.addWidget(self.frame, 2, 1, 1, 1)
self.dayslider = QtWidgets.QSlider(parent=Dialog)
self.dayslider.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
self.dayslider.setMinimum(1)
@@ -67,23 +82,12 @@ class Ui_Dialog(object):
self.dayslider.setTickInterval(10)
self.dayslider.setObjectName("dayslider")
self.gridLayout.addWidget(self.dayslider, 0, 1, 1, 1)
self.frame = QtWidgets.QFrame(parent=Dialog)
self.frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
self.frame.setLineWidth(0)
self.frame.setObjectName("frame")
self.gridLayout_2 = QtWidgets.QGridLayout(self.frame)
self.gridLayout_2.setObjectName("gridLayout_2")
self.format_txt = QtWidgets.QRadioButton(parent=self.frame)
self.format_txt.setObjectName("format_txt")
self.gridLayout_2.addWidget(self.format_txt, 0, 0, 1, 1)
self.format_csv = QtWidgets.QRadioButton(parent=self.frame)
self.format_csv.setObjectName("format_csv")
self.gridLayout_2.addWidget(self.format_csv, 0, 1, 1, 1)
self.gridLayout.addWidget(self.frame, 2, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=Dialog)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=Dialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
self.signature = QtWidgets.QCheckBox(parent=Dialog)
self.signature.setObjectName("signature")
self.gridLayout.addWidget(self.signature, 3, 1, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
self.label_4 = QtWidgets.QLabel(parent=Dialog)
self.label_4.setObjectName("label_4")
@@ -108,12 +112,13 @@ class Ui_Dialog(object):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Wieviele Tage sollen im Bericht erfasst werden?"))
self.label_2.setText(_translate("Dialog", "Tage"))
self.radio_week.setText(_translate("Dialog", "Woche"))
self.radio_month.setText(_translate("Dialog", "Monat"))
self.radio_year.setText(_translate("Dialog", "Jahr"))
self.format_txt.setText(_translate("Dialog", "Text"))
self.format_csv.setText(_translate("Dialog", "Excel"))
self.label_3.setText(_translate("Dialog", "Dateiformat"))
self.format_csv.setText(_translate("Dialog", "Excel"))
self.format_txt.setText(_translate("Dialog", "Text"))
self.label_2.setText(_translate("Dialog", "Tage"))
self.signature.setText(_translate("Dialog", "Signatur anzeigen"))
self.label_4.setText(_translate("Dialog", "Fortschritt:"))
self.generateReport.setText(_translate("Dialog", " Bericht erstellen"))

View File

@@ -20,13 +20,16 @@ class Ui_Dialog(object):
self.horizontalLayout.addWidget(self.textEdit)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Vertical)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
| QtWidgets.QDialogButtonBox.StandardButton.Ok
)
self.buttonBox.setObjectName("buttonBox")
self.horizontalLayout.addWidget(self.buttonBox)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):

View File

@@ -19,8 +19,12 @@ class Ui_Dialog(object):
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.tableWidget = QtWidgets.QTableWidget(parent=Dialog)
self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
self.tableWidget.setEditTriggers(
QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
)
self.tableWidget.setSelectionBehavior(
QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows
)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(3)
self.tableWidget.setRowCount(0)
@@ -33,19 +37,27 @@ class Ui_Dialog(object):
self.verticalLayout.addWidget(self.tableWidget)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
| QtWidgets.QDialogButtonBox.StandardButton.Ok
)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Es wurden mehrere passende Personen gefunden. Bitte die richtige Person auswählen."))
self.label.setText(
_translate(
"Dialog",
"Es wurden mehrere passende Personen gefunden. Bitte die richtige Person auswählen.",
)
)
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("Dialog", "Matrikelnr."))
item = self.tableWidget.horizontalHeaderItem(1)

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\LibrarySystem\src\ui\sources\dialog_settings.ui'
#
# Created by: PyQt6 UI code generator 6.6.1
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
@@ -92,25 +92,22 @@ class Ui_Dialog(object):
self.formLayout.setWidget(6, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_9)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.btn_select_report_path = QtWidgets.QToolButton(parent=Dialog)
self.btn_select_report_path.setObjectName("btn_select_report_path")
self.gridLayout.addWidget(self.btn_select_report_path, 2, 2, 1, 1)
self.label_10 = QtWidgets.QLabel(parent=Dialog)
self.label_10.setText("")
self.label_10.setObjectName("label_10")
self.gridLayout.addWidget(self.label_10, 1, 0, 1, 1)
self.label_8 = QtWidgets.QLabel(parent=Dialog)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 3, 0, 1, 1)
self.label_11 = QtWidgets.QLabel(parent=Dialog)
self.label_11.setObjectName("label_11")
self.gridLayout.addWidget(self.label_11, 0, 0, 1, 1)
self.check_generate_report = QtWidgets.QCheckBox(parent=Dialog)
self.check_generate_report.setObjectName("check_generate_report")
self.gridLayout.addWidget(self.check_generate_report, 1, 1, 1, 1)
self.report_path = QtWidgets.QLineEdit(parent=Dialog)
self.report_path.setObjectName("report_path")
self.gridLayout.addWidget(self.report_path, 2, 1, 1, 1)
self.label_8 = QtWidgets.QLabel(parent=Dialog)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 2, 0, 1, 1)
self.label_11 = QtWidgets.QLabel(parent=Dialog)
self.label_11.setObjectName("label_11")
self.gridLayout.addWidget(self.label_11, 0, 0, 1, 1)
self.gridLayout.addWidget(self.report_path, 3, 1, 1, 1)
self.label_10 = QtWidgets.QLabel(parent=Dialog)
self.label_10.setText("")
self.label_10.setObjectName("label_10")
self.gridLayout.addWidget(self.label_10, 1, 0, 1, 1)
self.report_day = QtWidgets.QComboBox(parent=Dialog)
self.report_day.setObjectName("report_day")
self.report_day.addItem("")
@@ -119,6 +116,12 @@ class Ui_Dialog(object):
self.report_day.addItem("")
self.report_day.addItem("")
self.gridLayout.addWidget(self.report_day, 0, 1, 1, 1)
self.btn_select_report_path = QtWidgets.QToolButton(parent=Dialog)
self.btn_select_report_path.setObjectName("btn_select_report_path")
self.gridLayout.addWidget(self.btn_select_report_path, 3, 2, 1, 1)
self.signature = QtWidgets.QCheckBox(parent=Dialog)
self.signature.setObjectName("signature")
self.gridLayout.addWidget(self.signature, 2, 1, 1, 1)
self.formLayout.setLayout(6, QtWidgets.QFormLayout.ItemRole.FieldRole, self.gridLayout)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
@@ -162,7 +165,7 @@ class Ui_Dialog(object):
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Name der Einrichtung"))
self.label_2.setText(_translate("Dialog", "Leihdauer"))
self.label_13.setText(_translate("Dialog", "Tage(n)"))
self.label_13.setText(_translate("Dialog", "Tage"))
self.label_7.setText(_translate("Dialog", "Inaktive Nutzer\n"
"Löschen nach"))
self.label_12.setText(_translate("Dialog", "Tage(n)"))
@@ -176,15 +179,16 @@ class Ui_Dialog(object):
self.btn_select_database_name.setText(_translate("Dialog", "..."))
self.btn_select_database_backupLocation.setText(_translate("Dialog", "..."))
self.label_9.setText(_translate("Dialog", "Bericht"))
self.btn_select_report_path.setText(_translate("Dialog", "..."))
self.check_generate_report.setText(_translate("Dialog", "Bericht erstellen"))
self.label_8.setText(_translate("Dialog", "Speicherpfad"))
self.label_11.setText(_translate("Dialog", "Tag"))
self.check_generate_report.setText(_translate("Dialog", "Bericht erstellen"))
self.report_day.setItemText(0, _translate("Dialog", "Montag"))
self.report_day.setItemText(1, _translate("Dialog", "Dienstag"))
self.report_day.setItemText(2, _translate("Dialog", "Mittwoch"))
self.report_day.setItemText(3, _translate("Dialog", "Donnerstag"))
self.report_day.setItemText(4, _translate("Dialog", "Freitag"))
self.btn_select_report_path.setText(_translate("Dialog", "..."))
self.signature.setText(_translate("Dialog", "Signatur anzeigen"))
item = self.shortcutchanger.horizontalHeaderItem(0)
item.setText(_translate("Dialog", "Name"))
item = self.shortcutchanger.horizontalHeaderItem(1)

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\LibrarySystem\src\ui\sources\main_Loans.ui'
#
# Created by: PyQt6 UI code generator 6.6.1
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
@@ -67,16 +67,8 @@ class Ui_MainWindow(object):
self.loanTable.setHorizontalHeaderItem(6, item)
self.verticalLayout.addWidget(self.loanTable)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 899, 22))
self.menubar.setObjectName("menubar")
self.menuDatei = QtWidgets.QMenu(parent=self.menubar)
self.menuDatei.setObjectName("menuDatei")
MainWindow.setMenuBar(self.menubar)
self.actionBeenden = QtGui.QAction(parent=MainWindow)
self.actionBeenden.setObjectName("actionBeenden")
self.menuDatei.addAction(self.actionBeenden)
self.menubar.addAction(self.menuDatei.menuAction())
self.retranslateUi(MainWindow)
self.actionBeenden.triggered.connect(MainWindow.close) # type: ignore
@@ -105,6 +97,5 @@ class Ui_MainWindow(object):
item.setText(_translate("MainWindow", "entliehen bis"))
item = self.loanTable.horizontalHeaderItem(6)
item.setText(_translate("MainWindow", "Zurückgegeben am"))
self.menuDatei.setTitle(_translate("MainWindow", "Datei"))
self.actionBeenden.setText(_translate("MainWindow", "Beenden"))
self.actionBeenden.setShortcut(_translate("MainWindow", "Q"))

View File

@@ -19,6 +19,38 @@ class Ui_MainWindow(object):
self.verticalLayout.setObjectName("verticalLayout")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.label_2 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
self.input_username = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_username.setObjectName("input_username")
self.gridLayout.addWidget(self.input_username, 2, 1, 1, 1)
self.input_userno = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_userno.setObjectName("input_userno")
self.gridLayout.addWidget(self.input_userno, 1, 1, 1, 1)
self.label = QtWidgets.QLabel(parent=self.centralwidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
self.input_file_ident = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_file_ident.setObjectName("input_file_ident")
self.gridLayout.addWidget(self.input_file_ident, 3, 1, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_6.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_5 = QtWidgets.QLabel(parent=self.centralwidget)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.horizontalLayout.addWidget(self.label_5)
self.mode = QtWidgets.QPushButton(parent=self.centralwidget)
self.mode.setObjectName("mode")
self.horizontalLayout.addWidget(self.mode)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.duedate = QtWidgets.QDateEdit(parent=self.centralwidget)
@@ -38,32 +70,6 @@ class Ui_MainWindow(object):
self.label_3 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 3, 0, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_6.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_5 = QtWidgets.QLabel(parent=self.centralwidget)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.horizontalLayout.addWidget(self.label_5)
self.mode = QtWidgets.QPushButton(parent=self.centralwidget)
self.mode.setObjectName("mode")
self.horizontalLayout.addWidget(self.mode)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.label = QtWidgets.QLabel(parent=self.centralwidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
self.input_username = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_username.setObjectName("input_username")
self.gridLayout.addWidget(self.input_username, 2, 1, 1, 1)
self.input_file_ident = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_file_ident.setObjectName("input_file_ident")
self.gridLayout.addWidget(self.input_file_ident, 3, 1, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
@@ -72,12 +78,10 @@ class Ui_MainWindow(object):
self.btn_createNewUser.setObjectName("btn_createNewUser")
self.horizontalLayout_3.addWidget(self.btn_createNewUser)
self.gridLayout.addLayout(self.horizontalLayout_3, 0, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
self.input_userno = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_userno.setObjectName("input_userno")
self.gridLayout.addWidget(self.input_userno, 1, 1, 1, 1)
self.addBook = QtWidgets.QToolButton(parent=self.centralwidget)
self.addBook.setText("")
self.addBook.setObjectName("addBook")
self.gridLayout.addWidget(self.addBook, 3, 2, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
@@ -143,7 +147,7 @@ class Ui_MainWindow(object):
self.menuFenster = QtWidgets.QMenu(parent=self.menubar)
self.menuFenster.setObjectName("menuFenster")
self.menuHilfe = QtWidgets.QMenu(parent=self.menubar)
self.menuHilfe.setGeometry(QtCore.QRect(2484, 209, 181, 94))
self.menuHilfe.setGeometry(QtCore.QRect(2347, 134, 181, 94))
self.menuHilfe.setObjectName("menuHilfe")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
@@ -188,13 +192,13 @@ class Ui_MainWindow(object):
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_3.setText(_translate("MainWindow", "Signatur"))
self.label_2.setText(_translate("MainWindow", "Benutzername"))
self.label.setText(_translate("MainWindow", "Matrikelnummer"))
self.label_6.setText(_translate("MainWindow", "Ausleihe bis"))
self.label_5.setText(_translate("MainWindow", "Modus"))
self.mode.setText(_translate("MainWindow", "Rückgabe"))
self.label.setText(_translate("MainWindow", "Matrikelnummer"))
self.label_3.setText(_translate("MainWindow", "Signatur"))
self.btn_createNewUser.setText(_translate("MainWindow", "Neuen Nutzer anlegen"))
self.label_2.setText(_translate("MainWindow", "Benutzername"))
self.groupBox.setTitle(_translate("MainWindow", "Nutzerdaten"))
self.groupBox_2.setTitle(_translate("MainWindow", "Ausleihdaten"))
self.label_4.setText(_translate("MainWindow", "Anzahl Ausleihen"))
@@ -210,7 +214,9 @@ class Ui_MainWindow(object):
self.menuFenster.setTitle(_translate("MainWindow", "Fenster"))
self.menuHilfe.setTitle(_translate("MainWindow", "Hilfe"))
self.actionEinstellungen.setText(_translate("MainWindow", "Einstellungen"))
self.actionEinstellungen.setShortcut(_translate("MainWindow", "Alt+S"))
self.actionBeenden.setText(_translate("MainWindow", "Beenden"))
self.actionBeenden.setShortcut(_translate("MainWindow", "Alt+Q"))
self.actionRueckgabemodus.setText(_translate("MainWindow", "Rückgabemodus"))
self.actionRueckgabemodus.setShortcut(_translate("MainWindow", "F5"))
self.actionNutzer.setText(_translate("MainWindow", "Nutzer"))

View File

@@ -26,7 +26,12 @@ class Ui_MainWindow(object):
self.frame.setObjectName("frame")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
spacerItem = QtWidgets.QSpacerItem(
40,
20,
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Minimum,
)
self.horizontalLayout.addItem(spacerItem)
self.btn_userChange_save = QtWidgets.QPushButton(parent=self.frame)
self.btn_userChange_save.setStatusTip("")
@@ -35,7 +40,12 @@ class Ui_MainWindow(object):
self.btn_userchange_cancel = QtWidgets.QPushButton(parent=self.frame)
self.btn_userchange_cancel.setObjectName("btn_userchange_cancel")
self.horizontalLayout.addWidget(self.btn_userchange_cancel)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
spacerItem1 = QtWidgets.QSpacerItem(
40,
20,
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Minimum,
)
self.horizontalLayout.addItem(spacerItem1)
self.gridLayout.addWidget(self.frame, 3, 1, 1, 1)
self.label = QtWidgets.QLabel(parent=self.centralwidget)
@@ -94,7 +104,12 @@ class Ui_MainWindow(object):
self.radio_overdueLoans = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_overdueLoans.setObjectName("radio_overdueLoans")
self.horizontalLayout_2.addWidget(self.radio_overdueLoans)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
spacerItem2 = QtWidgets.QSpacerItem(
40,
20,
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Minimum,
)
self.horizontalLayout_2.addItem(spacerItem2)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
@@ -107,7 +122,12 @@ class Ui_MainWindow(object):
self.searchfilter.addItem("")
self.searchfilter.addItem("")
self.horizontalLayout_3.addWidget(self.searchfilter)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
spacerItem3 = QtWidgets.QSpacerItem(
40,
20,
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Minimum,
)
self.horizontalLayout_3.addItem(spacerItem3)
self.btn_extendSelectedMedia = QtWidgets.QPushButton(parent=self.centralwidget)
self.btn_extendSelectedMedia.setEnabled(False)
@@ -117,10 +137,16 @@ class Ui_MainWindow(object):
self.UserMediaTable = QtWidgets.QTableWidget(parent=self.centralwidget)
self.UserMediaTable.setMouseTracking(True)
self.UserMediaTable.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.UserMediaTable.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.UserMediaTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.UserMediaTable.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff
)
self.UserMediaTable.setEditTriggers(
QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
)
self.UserMediaTable.setAlternatingRowColors(True)
self.UserMediaTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
self.UserMediaTable.setSelectionBehavior(
QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows
)
self.UserMediaTable.setObjectName("UserMediaTable")
self.UserMediaTable.setColumnCount(6)
self.UserMediaTable.setRowCount(0)
@@ -177,11 +203,15 @@ class Ui_MainWindow(object):
self.label_5.setText(_translate("MainWindow", "Nutzer Löschen"))
self.label_4.setText(_translate("MainWindow", "Medien"))
self.radio_allLoanedMedia.setText(_translate("MainWindow", "Alle Ausleihen"))
self.radio_currentlyLoaned.setText(_translate("MainWindow", "Aktuell entliehen"))
self.radio_currentlyLoaned.setText(
_translate("MainWindow", "Aktuell entliehen")
)
self.radio_overdueLoans.setText(_translate("MainWindow", "Überzogen"))
self.searchfilter.setItemText(0, _translate("MainWindow", "Titel"))
self.searchfilter.setItemText(1, _translate("MainWindow", "Signatur"))
self.btn_extendSelectedMedia.setText(_translate("MainWindow", "Ausgewählte Verlängern"))
self.btn_extendSelectedMedia.setText(
_translate("MainWindow", "Ausgewählte Verlängern")
)
self.UserMediaTable.setSortingEnabled(True)
item = self.UserMediaTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "ISBN"))

View File

@@ -2,6 +2,9 @@
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>

View File

@@ -0,0 +1,54 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/dialog_addBook.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(262, 100)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.book_signature = QtWidgets.QLineEdit(parent=Dialog)
self.book_signature.setObjectName("book_signature")
self.gridLayout.addWidget(self.book_signature, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=Dialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.label = QtWidgets.QLabel(parent=Dialog)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.book_title = QtWidgets.QLineEdit(parent=Dialog)
self.book_title.setObjectName("book_title")
self.gridLayout.addWidget(self.book_title, 0, 1, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.btn_save = QtWidgets.QPushButton(parent=Dialog)
self.btn_save.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
self.btn_save.setObjectName("btn_save")
self.horizontalLayout.addWidget(self.btn_save)
self.btn_cancel = QtWidgets.QPushButton(parent=Dialog)
self.btn_cancel.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
self.btn_cancel.setObjectName("btn_cancel")
self.horizontalLayout.addWidget(self.btn_cancel)
self.gridLayout.addLayout(self.horizontalLayout, 2, 1, 1, 1)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.book_title, self.book_signature)
Dialog.setTabOrder(self.book_signature, self.btn_save)
Dialog.setTabOrder(self.btn_save, self.btn_cancel)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label_2.setText(_translate("Dialog", "Signatur"))
self.label.setText(_translate("Dialog", "Titel"))
self.btn_save.setText(_translate("Dialog", "Speichern"))
self.btn_cancel.setText(_translate("Dialog", "Abbrechen"))

View File

@@ -0,0 +1,61 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/dialog_createUser.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
Dialog.resize(400, 132)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.userno = QtWidgets.QLineEdit(parent=Dialog)
self.userno.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhDigitsOnly)
self.userno.setObjectName("userno")
self.gridLayout.addWidget(self.userno, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=Dialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=Dialog)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.user_mail = QtWidgets.QLineEdit(parent=Dialog)
self.user_mail.setObjectName("user_mail")
self.gridLayout.addWidget(self.user_mail, 2, 1, 1, 1)
self.label = QtWidgets.QLabel(parent=Dialog)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.username = QtWidgets.QLineEdit(parent=Dialog)
self.username.setObjectName("username")
self.gridLayout.addWidget(self.username, 0, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Save)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 4, 1, 1, 1)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
self.gridLayout.addItem(spacerItem, 3, 0, 1, 1)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.username, self.userno)
Dialog.setTabOrder(self.userno, self.user_mail)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Nutzer anlegen"))
self.userno.setPlaceholderText(_translate("Dialog", "102888557"))
self.label_2.setText(_translate("Dialog", "Matrikelnummer"))
self.label_3.setText(_translate("Dialog", "Mail"))
self.user_mail.setPlaceholderText(_translate("Dialog", "email@ph-freiburg.de"))
self.label.setText(_translate("Dialog", "Name, Vorname"))
self.username.setPlaceholderText(_translate("Dialog", "Nachname, Vorname"))

View File

@@ -0,0 +1,43 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/dialog_extendLoanDuration.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
Dialog.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.extenduntil = QtWidgets.QCalendarWidget(parent=Dialog)
self.extenduntil.setObjectName("extenduntil")
self.gridLayout.addWidget(self.extenduntil, 1, 2, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 2, 2, 1, 1)
self.label = QtWidgets.QLabel(parent=Dialog)
font = QtGui.QFont()
font.setPointSize(11)
font.setBold(True)
self.label.setFont(font)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 2, 1, 1)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Bitte das Verlängerungsdatum auswählen"))

View File

@@ -2,6 +2,9 @@
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
@@ -29,10 +32,13 @@
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<item row="4" column="2">
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>Tage</string>
<string/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
@@ -61,6 +67,13 @@
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Dateiformat</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="dayValue">
<property name="sizePolicy">
@@ -89,23 +102,42 @@
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QLabel" name="reportlink">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QRadioButton" name="format_csv">
<property name="text">
<string>Excel</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="format_txt">
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="dayslider">
<property name="focusPolicy">
@@ -131,39 +163,17 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Tage</string>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="format_txt">
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="format_csv">
<property name="text">
<string>Excel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<item row="3" column="1">
<widget class="QCheckBox" name="signature">
<property name="text">
<string>Dateiformat</string>
<string>Signatur anzeigen</string>
</property>
</widget>
</item>

View File

@@ -0,0 +1,119 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/dialog_generateReport.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(375, 247)
Dialog.setMinimumSize(QtCore.QSize(40, 0))
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(parent=Dialog)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.label_2 = QtWidgets.QLabel(parent=Dialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.radio_week = QtWidgets.QRadioButton(parent=Dialog)
self.radio_week.setObjectName("radio_week")
self.horizontalLayout.addWidget(self.radio_week)
self.radio_month = QtWidgets.QRadioButton(parent=Dialog)
self.radio_month.setObjectName("radio_month")
self.horizontalLayout.addWidget(self.radio_month)
self.radio_year = QtWidgets.QRadioButton(parent=Dialog)
self.radio_year.setObjectName("radio_year")
self.horizontalLayout.addWidget(self.radio_year)
self.gridLayout.addLayout(self.horizontalLayout, 1, 1, 1, 1)
self.dayValue = QtWidgets.QLineEdit(parent=Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.dayValue.sizePolicy().hasHeightForWidth())
self.dayValue.setSizePolicy(sizePolicy)
self.dayValue.setMinimumSize(QtCore.QSize(0, 0))
self.dayValue.setMaximumSize(QtCore.QSize(40, 16777215))
self.dayValue.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.dayValue.setReadOnly(True)
self.dayValue.setObjectName("dayValue")
self.gridLayout.addWidget(self.dayValue, 0, 2, 1, 1)
self.radioButton = QtWidgets.QRadioButton(parent=Dialog)
self.radioButton.setText("")
self.radioButton.setCheckable(True)
self.radioButton.setObjectName("radioButton")
self.gridLayout.addWidget(self.radioButton, 3, 2, 1, 1)
self.reportlink = QtWidgets.QLabel(parent=Dialog)
self.reportlink.setText("")
self.reportlink.setObjectName("reportlink")
self.gridLayout.addWidget(self.reportlink, 3, 1, 1, 1)
self.dayslider = QtWidgets.QSlider(parent=Dialog)
self.dayslider.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
self.dayslider.setMinimum(1)
self.dayslider.setMaximum(365)
self.dayslider.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.dayslider.setInvertedControls(True)
self.dayslider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksAbove)
self.dayslider.setTickInterval(10)
self.dayslider.setObjectName("dayslider")
self.gridLayout.addWidget(self.dayslider, 0, 1, 1, 1)
self.frame = QtWidgets.QFrame(parent=Dialog)
self.frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
self.frame.setLineWidth(0)
self.frame.setObjectName("frame")
self.gridLayout_2 = QtWidgets.QGridLayout(self.frame)
self.gridLayout_2.setObjectName("gridLayout_2")
self.format_txt = QtWidgets.QRadioButton(parent=self.frame)
self.format_txt.setObjectName("format_txt")
self.gridLayout_2.addWidget(self.format_txt, 0, 0, 1, 1)
self.format_csv = QtWidgets.QRadioButton(parent=self.frame)
self.format_csv.setObjectName("format_csv")
self.gridLayout_2.addWidget(self.format_csv, 0, 1, 1, 1)
self.gridLayout.addWidget(self.frame, 2, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=Dialog)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
self.label_4 = QtWidgets.QLabel(parent=Dialog)
self.label_4.setObjectName("label_4")
self.verticalLayout.addWidget(self.label_4)
self.reportprogress = QtWidgets.QProgressBar(parent=Dialog)
self.reportprogress.setProperty("value", 24)
self.reportprogress.setTextVisible(True)
self.reportprogress.setInvertedAppearance(False)
self.reportprogress.setObjectName("reportprogress")
self.verticalLayout.addWidget(self.reportprogress)
self.generateReport = QtWidgets.QPushButton(parent=Dialog)
self.generateReport.setObjectName("generateReport")
self.verticalLayout.addWidget(self.generateReport)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.radio_week, self.radio_month)
Dialog.setTabOrder(self.radio_month, self.radio_year)
Dialog.setTabOrder(self.radio_year, self.generateReport)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Wieviele Tage sollen im Bericht erfasst werden?"))
self.label_2.setText(_translate("Dialog", "Tage"))
self.radio_week.setText(_translate("Dialog", "Woche"))
self.radio_month.setText(_translate("Dialog", "Monat"))
self.radio_year.setText(_translate("Dialog", "Jahr"))
self.format_txt.setText(_translate("Dialog", "Text"))
self.format_csv.setText(_translate("Dialog", "Excel"))
self.label_3.setText(_translate("Dialog", "Dateiformat"))
self.label_4.setText(_translate("Dialog", "Fortschritt:"))
self.generateReport.setText(_translate("Dialog", " Bericht erstellen"))

View File

@@ -49,7 +49,7 @@
</size>
</property>
<property name="text">
<string>Tage(n)</string>
<string>Tage</string>
</property>
</widget>
</item>
@@ -174,31 +174,7 @@ Löschen nach</string>
</item>
<item row="6" column="1">
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="2">
<widget class="QToolButton" name="btn_select_report_path">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="check_generate_report">
<property name="text">
<string>Bericht erstellen</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="report_path"/>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Speicherpfad</string>
@@ -212,6 +188,23 @@ Löschen nach</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="check_generate_report">
<property name="text">
<string>Bericht erstellen</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="report_path"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="report_day">
<item>
@@ -241,6 +234,20 @@ Löschen nach</string>
</item>
</widget>
</item>
<item row="3" column="2">
<widget class="QToolButton" name="btn_select_report_path">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="signature">
<property name="text">
<string>Signatur anzeigen</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="1">

View File

@@ -0,0 +1,161 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/dialog_settings.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(492, 306)
self.formLayout = QtWidgets.QFormLayout(Dialog)
self.formLayout.setObjectName("formLayout")
self.label = QtWidgets.QLabel(parent=Dialog)
self.label.setObjectName("label")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label)
self.institution_name = QtWidgets.QLineEdit(parent=Dialog)
self.institution_name.setObjectName("institution_name")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.FieldRole, self.institution_name)
self.label_3 = QtWidgets.QLabel(parent=Dialog)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_3)
self.databasesettings = QtWidgets.QGridLayout()
self.databasesettings.setObjectName("databasesettings")
self.database_name = QtWidgets.QLineEdit(parent=Dialog)
self.database_name.setObjectName("database_name")
self.databasesettings.addWidget(self.database_name, 1, 1, 1, 1)
self.label_4 = QtWidgets.QLabel(parent=Dialog)
self.label_4.setObjectName("label_4")
self.databasesettings.addWidget(self.label_4, 0, 0, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=Dialog)
self.label_6.setObjectName("label_6")
self.databasesettings.addWidget(self.label_6, 2, 0, 1, 1)
self.database_path = QtWidgets.QLineEdit(parent=Dialog)
self.database_path.setObjectName("database_path")
self.databasesettings.addWidget(self.database_path, 0, 1, 1, 1)
self.database_backupLocation = QtWidgets.QLineEdit(parent=Dialog)
self.database_backupLocation.setObjectName("database_backupLocation")
self.databasesettings.addWidget(self.database_backupLocation, 2, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(parent=Dialog)
self.label_5.setObjectName("label_5")
self.databasesettings.addWidget(self.label_5, 1, 0, 1, 1)
self.btn_select_database_path = QtWidgets.QToolButton(parent=Dialog)
self.btn_select_database_path.setObjectName("btn_select_database_path")
self.databasesettings.addWidget(self.btn_select_database_path, 0, 2, 1, 1)
self.btn_select_database_name = QtWidgets.QToolButton(parent=Dialog)
self.btn_select_database_name.setObjectName("btn_select_database_name")
self.databasesettings.addWidget(self.btn_select_database_name, 1, 2, 1, 1)
self.btn_select_database_backupLocation = QtWidgets.QToolButton(parent=Dialog)
self.btn_select_database_backupLocation.setObjectName("btn_select_database_backupLocation")
self.databasesettings.addWidget(self.btn_select_database_backupLocation, 2, 2, 1, 1)
self.formLayout.setLayout(5, QtWidgets.QFormLayout.ItemRole.FieldRole, self.databasesettings)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Discard|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setObjectName("buttonBox")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.ItemRole.FieldRole, self.buttonBox)
self.label_9 = QtWidgets.QLabel(parent=Dialog)
self.label_9.setObjectName("label_9")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_9)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.btn_select_report_path = QtWidgets.QToolButton(parent=Dialog)
self.btn_select_report_path.setObjectName("btn_select_report_path")
self.gridLayout.addWidget(self.btn_select_report_path, 2, 2, 1, 1)
self.label_10 = QtWidgets.QLabel(parent=Dialog)
self.label_10.setText("")
self.label_10.setObjectName("label_10")
self.gridLayout.addWidget(self.label_10, 1, 0, 1, 1)
self.check_generate_report = QtWidgets.QCheckBox(parent=Dialog)
self.check_generate_report.setObjectName("check_generate_report")
self.gridLayout.addWidget(self.check_generate_report, 1, 1, 1, 1)
self.report_path = QtWidgets.QLineEdit(parent=Dialog)
self.report_path.setObjectName("report_path")
self.gridLayout.addWidget(self.report_path, 2, 1, 1, 1)
self.label_8 = QtWidgets.QLabel(parent=Dialog)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 2, 0, 1, 1)
self.label_11 = QtWidgets.QLabel(parent=Dialog)
self.label_11.setObjectName("label_11")
self.gridLayout.addWidget(self.label_11, 0, 0, 1, 1)
self.report_day = QtWidgets.QComboBox(parent=Dialog)
self.report_day.setObjectName("report_day")
self.report_day.addItem("")
self.report_day.addItem("")
self.report_day.addItem("")
self.report_day.addItem("")
self.report_day.addItem("")
self.gridLayout.addWidget(self.report_day, 0, 1, 1, 1)
self.formLayout.setLayout(6, QtWidgets.QFormLayout.ItemRole.FieldRole, self.gridLayout)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.delete_inactive_user_duration = QtWidgets.QSpinBox(parent=Dialog)
self.delete_inactive_user_duration.setMaximum(9999)
self.delete_inactive_user_duration.setProperty("value", 365)
self.delete_inactive_user_duration.setObjectName("delete_inactive_user_duration")
self.horizontalLayout.addWidget(self.delete_inactive_user_duration)
self.label_12 = QtWidgets.QLabel(parent=Dialog)
self.label_12.setMaximumSize(QtCore.QSize(43, 16777215))
self.label_12.setObjectName("label_12")
self.horizontalLayout.addWidget(self.label_12)
self.formLayout.setLayout(3, QtWidgets.QFormLayout.ItemRole.FieldRole, self.horizontalLayout)
self.label_7 = QtWidgets.QLabel(parent=Dialog)
self.label_7.setObjectName("label_7")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_7)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.default_loan_duration = QtWidgets.QSpinBox(parent=Dialog)
self.default_loan_duration.setProperty("value", 7)
self.default_loan_duration.setObjectName("default_loan_duration")
self.horizontalLayout_2.addWidget(self.default_loan_duration)
self.label_13 = QtWidgets.QLabel(parent=Dialog)
self.label_13.setMaximumSize(QtCore.QSize(43, 16777215))
self.label_13.setObjectName("label_13")
self.horizontalLayout_2.addWidget(self.label_13)
self.formLayout.setLayout(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.horizontalLayout_2)
self.label_2 = QtWidgets.QLabel(parent=Dialog)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_2)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.institution_name, self.database_path)
Dialog.setTabOrder(self.database_path, self.database_name)
Dialog.setTabOrder(self.database_name, self.database_backupLocation)
Dialog.setTabOrder(self.database_backupLocation, self.btn_select_database_path)
Dialog.setTabOrder(self.btn_select_database_path, self.btn_select_database_name)
Dialog.setTabOrder(self.btn_select_database_name, self.btn_select_database_backupLocation)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "Name der Einrichtung"))
self.label_3.setText(_translate("Dialog", "Datenbank"))
self.label_4.setText(_translate("Dialog", "Speicherort"))
self.label_6.setText(_translate("Dialog", "Sicherungspfad"))
self.label_5.setText(_translate("Dialog", "Datenbankname"))
self.btn_select_database_path.setText(_translate("Dialog", "..."))
self.btn_select_database_name.setText(_translate("Dialog", "..."))
self.btn_select_database_backupLocation.setText(_translate("Dialog", "..."))
self.label_9.setText(_translate("Dialog", "Bericht"))
self.btn_select_report_path.setText(_translate("Dialog", "..."))
self.check_generate_report.setText(_translate("Dialog", "Bericht erstellen"))
self.label_8.setText(_translate("Dialog", "Speicherpfad"))
self.label_11.setText(_translate("Dialog", "Tag"))
self.report_day.setItemText(0, _translate("Dialog", "Montag"))
self.report_day.setItemText(1, _translate("Dialog", "Dienstag"))
self.report_day.setItemText(2, _translate("Dialog", "Mittwoch"))
self.report_day.setItemText(3, _translate("Dialog", "Donnerstag"))
self.report_day.setItemText(4, _translate("Dialog", "Freitag"))
self.label_12.setText(_translate("Dialog", "Tage(n)"))
self.label_7.setText(_translate("Dialog", "Inaktive Nutzer\n"
"Löschen nach"))
self.label_13.setText(_translate("Dialog", "Tage(n)"))
self.label_2.setText(_translate("Dialog", "Leihdauer"))

View File

@@ -132,23 +132,6 @@
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>899</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuDatei">
<property name="title">
<string>Datei</string>
</property>
<addaction name="actionBeenden"/>
</widget>
<addaction name="menuDatei"/>
</widget>
<action name="actionBeenden">
<property name="text">
<string>Beenden</string>

View File

@@ -0,0 +1,110 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/main_Loans.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(899, 658)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.radio_all = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_all.setChecked(True)
self.radio_all.setObjectName("radio_all")
self.horizontalLayout.addWidget(self.radio_all)
self.radio_current = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_current.setObjectName("radio_current")
self.horizontalLayout.addWidget(self.radio_current)
self.radio_overdue = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_overdue.setObjectName("radio_overdue")
self.horizontalLayout.addWidget(self.radio_overdue)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.verticalLayout.addLayout(self.horizontalLayout)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.searchbar = QtWidgets.QLineEdit(parent=self.centralwidget)
self.searchbar.setObjectName("searchbar")
self.horizontalLayout_2.addWidget(self.searchbar)
self.searchFields = QtWidgets.QComboBox(parent=self.centralwidget)
self.searchFields.setObjectName("searchFields")
self.searchFields.addItem("")
self.searchFields.addItem("")
self.searchFields.addItem("")
self.horizontalLayout_2.addWidget(self.searchFields)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.loanTable = QtWidgets.QTableWidget(parent=self.centralwidget)
self.loanTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.loanTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection)
self.loanTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
self.loanTable.setObjectName("loanTable")
self.loanTable.setColumnCount(7)
self.loanTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(4, item)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(5, item)
item = QtWidgets.QTableWidgetItem()
self.loanTable.setHorizontalHeaderItem(6, item)
self.verticalLayout.addWidget(self.loanTable)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 899, 22))
self.menubar.setObjectName("menubar")
self.menuDatei = QtWidgets.QMenu(parent=self.menubar)
self.menuDatei.setObjectName("menuDatei")
MainWindow.setMenuBar(self.menubar)
self.actionBeenden = QtGui.QAction(parent=MainWindow)
self.actionBeenden.setObjectName("actionBeenden")
self.menuDatei.addAction(self.actionBeenden)
self.menubar.addAction(self.menuDatei.menuAction())
self.retranslateUi(MainWindow)
self.actionBeenden.triggered.connect(MainWindow.close) # type: ignore
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.radio_all.setText(_translate("MainWindow", "Alle Ausleihen"))
self.radio_current.setText(_translate("MainWindow", "Aktuell Entliehene Medien"))
self.radio_overdue.setText(_translate("MainWindow", "Überzogene Medien"))
self.searchFields.setItemText(0, _translate("MainWindow", "Titel"))
self.searchFields.setItemText(1, _translate("MainWindow", "Signatur"))
self.searchFields.setItemText(2, _translate("MainWindow", "Nutzer"))
item = self.loanTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "ISBN"))
item = self.loanTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Signatur"))
item = self.loanTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Titel"))
item = self.loanTable.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "Nutzerkonto"))
item = self.loanTable.horizontalHeaderItem(4)
item.setText(_translate("MainWindow", "entliehen am"))
item = self.loanTable.horizontalHeaderItem(5)
item.setText(_translate("MainWindow", "entliehen bis"))
item = self.loanTable.horizontalHeaderItem(6)
item.setText(_translate("MainWindow", "Zurückgegeben am"))
self.menuDatei.setTitle(_translate("MainWindow", "Datei"))
self.actionBeenden.setText(_translate("MainWindow", "Beenden"))
self.actionBeenden.setShortcut(_translate("MainWindow", "Q"))

View File

@@ -17,6 +17,63 @@
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,10,20">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Benutzername</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="input_username"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="input_userno"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Matrikelnummer</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="input_file_ident"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Ausleihe bis</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Modus</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mode">
<property name="text">
<string>Rückgabe</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
@@ -69,53 +126,6 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Ausleihe bis</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Modus</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mode">
<property name="text">
<string>Rückgabe</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Matrikelnummer</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="input_username"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="input_file_ident"/>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@@ -140,16 +150,13 @@
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<item row="3" column="2">
<widget class="QToolButton" name="addBook">
<property name="text">
<string>Benutzername</string>
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="input_userno"/>
</item>
</layout>
</item>
<item>
@@ -281,8 +288,8 @@
<widget class="QMenu" name="menuHilfe">
<property name="geometry">
<rect>
<x>2484</x>
<y>209</y>
<x>2347</x>
<y>134</y>
<width>181</width>
<height>94</height>
</rect>
@@ -303,11 +310,17 @@
<property name="text">
<string>Einstellungen</string>
</property>
<property name="shortcut">
<string>Alt+S</string>
</property>
</action>
<action name="actionBeenden">
<property name="text">
<string>Beenden</string>
</property>
<property name="shortcut">
<string>Alt+Q</string>
</property>
</action>
<action name="actionRueckgabemodus">
<property name="text">

View File

@@ -0,0 +1,229 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/main_UserInterface.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 602)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.duedate = QtWidgets.QDateEdit(parent=self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.duedate.sizePolicy().hasHeightForWidth())
self.duedate.setSizePolicy(sizePolicy)
self.duedate.setMinimumSize(QtCore.QSize(130, 0))
self.duedate.setMaximumSize(QtCore.QSize(100, 16777215))
self.duedate.setBaseSize(QtCore.QSize(70, 0))
self.duedate.setObjectName("duedate")
self.horizontalLayout_4.addWidget(self.duedate)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout_4.addItem(spacerItem)
self.gridLayout.addLayout(self.horizontalLayout_4, 5, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 3, 0, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_6.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_5 = QtWidgets.QLabel(parent=self.centralwidget)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.horizontalLayout.addWidget(self.label_5)
self.mode = QtWidgets.QLabel(parent=self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mode.sizePolicy().hasHeightForWidth())
self.mode.setSizePolicy(sizePolicy)
self.mode.setMinimumSize(QtCore.QSize(62, 0))
self.mode.setMaximumSize(QtCore.QSize(62, 16777215))
self.mode.setBaseSize(QtCore.QSize(62, 0))
self.mode.setAutoFillBackground(False)
self.mode.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.mode.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.mode.setLineWidth(2)
self.mode.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.mode.setObjectName("mode")
self.horizontalLayout.addWidget(self.mode)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.label = QtWidgets.QLabel(parent=self.centralwidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
self.input_username = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_username.setObjectName("input_username")
self.gridLayout.addWidget(self.input_username, 2, 1, 1, 1)
self.input_file_ident = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_file_ident.setObjectName("input_file_ident")
self.gridLayout.addWidget(self.input_file_ident, 3, 1, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout_3.addItem(spacerItem1)
self.btn_createNewUser = QtWidgets.QPushButton(parent=self.centralwidget)
self.btn_createNewUser.setObjectName("btn_createNewUser")
self.horizontalLayout_3.addWidget(self.btn_createNewUser)
self.gridLayout.addLayout(self.horizontalLayout_3, 0, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
self.input_userno = QtWidgets.QLineEdit(parent=self.centralwidget)
self.input_userno.setObjectName("input_userno")
self.gridLayout.addWidget(self.input_userno, 1, 1, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.groupBox.setObjectName("groupBox")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.groupBox)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.userdata = QtWidgets.QTextEdit(parent=self.groupBox)
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
font.setBold(True)
self.userdata.setFont(font)
self.userdata.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.userdata.setReadOnly(True)
self.userdata.setObjectName("userdata")
self.horizontalLayout_2.addWidget(self.userdata)
self.groupBox_2 = QtWidgets.QGroupBox(parent=self.groupBox)
self.groupBox_2.setObjectName("groupBox_2")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_2)
self.gridLayout_2.setObjectName("gridLayout_2")
self.btn_show_lentmedia = QtWidgets.QPushButton(parent=self.groupBox_2)
self.btn_show_lentmedia.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
self.btn_show_lentmedia.setText("")
self.btn_show_lentmedia.setObjectName("btn_show_lentmedia")
self.gridLayout_2.addWidget(self.btn_show_lentmedia, 0, 1, 1, 1)
self.label_4 = QtWidgets.QLabel(parent=self.groupBox_2)
self.label_4.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 0, 0, 1, 1)
self.label_7 = QtWidgets.QLabel(parent=self.groupBox_2)
self.label_7.setObjectName("label_7")
self.gridLayout_2.addWidget(self.label_7, 1, 0, 1, 1)
self.nextReturnDate = QtWidgets.QLabel(parent=self.groupBox_2)
self.nextReturnDate.setText("")
self.nextReturnDate.setObjectName("nextReturnDate")
self.gridLayout_2.addWidget(self.nextReturnDate, 1, 1, 1, 1)
self.horizontalLayout_2.addWidget(self.groupBox_2)
self.horizontalLayout_2.setStretch(0, 3)
self.horizontalLayout_2.setStretch(1, 1)
self.verticalLayout.addWidget(self.groupBox)
self.mediaOverview = QtWidgets.QTableWidget(parent=self.centralwidget)
self.mediaOverview.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.mediaOverview.setObjectName("mediaOverview")
self.mediaOverview.setColumnCount(3)
self.mediaOverview.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.mediaOverview.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.mediaOverview.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.mediaOverview.setHorizontalHeaderItem(2, item)
self.verticalLayout.addWidget(self.mediaOverview)
self.verticalLayout.setStretch(1, 10)
self.verticalLayout.setStretch(2, 20)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
self.menuDatei = QtWidgets.QMenu(parent=self.menubar)
self.menuDatei.setObjectName("menuDatei")
self.menuHotkeys = QtWidgets.QMenu(parent=self.menubar)
self.menuHotkeys.setObjectName("menuHotkeys")
self.menuFenster = QtWidgets.QMenu(parent=self.menubar)
self.menuFenster.setObjectName("menuFenster")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionEinstellungen = QtGui.QAction(parent=MainWindow)
self.actionEinstellungen.setObjectName("actionEinstellungen")
self.actionBeenden = QtGui.QAction(parent=MainWindow)
self.actionBeenden.setObjectName("actionBeenden")
self.actionRueckgabemodus = QtGui.QAction(parent=MainWindow)
self.actionRueckgabemodus.setObjectName("actionRueckgabemodus")
self.actionNutzer = QtGui.QAction(parent=MainWindow)
self.actionNutzer.setObjectName("actionNutzer")
self.actionNutzer_2 = QtGui.QAction(parent=MainWindow)
self.actionNutzer_2.setObjectName("actionNutzer_2")
self.actionAusleihistorie = QtGui.QAction(parent=MainWindow)
self.actionAusleihistorie.setObjectName("actionAusleihistorie")
self.actionBericht_erstellen = QtGui.QAction(parent=MainWindow)
self.actionBericht_erstellen.setObjectName("actionBericht_erstellen")
self.actionNutzer_3 = QtGui.QAction(parent=MainWindow)
self.actionNutzer_3.setObjectName("actionNutzer_3")
self.menuDatei.addAction(self.actionEinstellungen)
self.menuDatei.addAction(self.actionBeenden)
self.menuHotkeys.addAction(self.actionRueckgabemodus)
self.menuFenster.addAction(self.actionNutzer)
self.menuFenster.addAction(self.actionAusleihistorie)
self.menuFenster.addAction(self.actionBericht_erstellen)
self.menubar.addAction(self.menuDatei.menuAction())
self.menubar.addAction(self.menuHotkeys.menuAction())
self.menubar.addAction(self.menuFenster.menuAction())
self.retranslateUi(MainWindow)
self.actionBeenden.triggered.connect(MainWindow.close) # type: ignore
QtCore.QMetaObject.connectSlotsByName(MainWindow)
MainWindow.setTabOrder(self.btn_createNewUser, self.input_userno)
MainWindow.setTabOrder(self.input_userno, self.input_username)
MainWindow.setTabOrder(self.input_username, self.input_file_ident)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_3.setText(_translate("MainWindow", "Signatur"))
self.label_6.setText(_translate("MainWindow", "Ausleihe bis"))
self.label_5.setText(_translate("MainWindow", "Modus"))
self.mode.setText(_translate("MainWindow", "Rückgabe"))
self.label.setText(_translate("MainWindow", "Matrikelnummer"))
self.btn_createNewUser.setText(_translate("MainWindow", "Neuen Nutzer anlegen"))
self.label_2.setText(_translate("MainWindow", "Benutzername"))
self.groupBox.setTitle(_translate("MainWindow", "Nutzerdaten"))
self.groupBox_2.setTitle(_translate("MainWindow", "Ausleihdaten"))
self.label_4.setText(_translate("MainWindow", "Anzahl Ausleihen"))
self.label_7.setText(_translate("MainWindow", "Nächstes Rückgabedatum"))
item = self.mediaOverview.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Signatur"))
item = self.mediaOverview.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Titel"))
item = self.mediaOverview.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Status"))
self.menuDatei.setTitle(_translate("MainWindow", "Datei"))
self.menuHotkeys.setTitle(_translate("MainWindow", "Hotkeys"))
self.menuFenster.setTitle(_translate("MainWindow", "Fenster"))
self.actionEinstellungen.setText(_translate("MainWindow", "Einstellungen"))
self.actionBeenden.setText(_translate("MainWindow", "Beenden"))
self.actionRueckgabemodus.setText(_translate("MainWindow", "Rückgabemodus"))
self.actionRueckgabemodus.setShortcut(_translate("MainWindow", "F5"))
self.actionNutzer.setText(_translate("MainWindow", "Nutzer"))
self.actionNutzer.setShortcut(_translate("MainWindow", "F6"))
self.actionNutzer_2.setText(_translate("MainWindow", "Nutzer"))
self.actionAusleihistorie.setText(_translate("MainWindow", "Ausleihhistorie"))
self.actionAusleihistorie.setShortcut(_translate("MainWindow", "F8"))
self.actionBericht_erstellen.setText(_translate("MainWindow", "Bericht erstellen"))
self.actionBericht_erstellen.setShortcut(_translate("MainWindow", "F7"))
self.actionNutzer_3.setText(_translate("MainWindow", "Nutzer"))

View File

@@ -0,0 +1,197 @@
# Form implementation generated from reading ui file '/home/alexander/GitHub/LibrarySystem/src/ui/sources/main_userData.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# 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.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.frame = QtWidgets.QFrame(parent=self.centralwidget)
self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
self.frame.setObjectName("frame")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.btn_userChange_save = QtWidgets.QPushButton(parent=self.frame)
self.btn_userChange_save.setStatusTip("")
self.btn_userChange_save.setObjectName("btn_userChange_save")
self.horizontalLayout.addWidget(self.btn_userChange_save)
self.btn_userchange_cancel = QtWidgets.QPushButton(parent=self.frame)
self.btn_userchange_cancel.setObjectName("btn_userchange_cancel")
self.horizontalLayout.addWidget(self.btn_userchange_cancel)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.gridLayout.addWidget(self.frame, 3, 1, 1, 1)
self.label = QtWidgets.QLabel(parent=self.centralwidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.user_no = QtWidgets.QLineEdit(parent=self.centralwidget)
self.user_no.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.user_no.setReadOnly(True)
self.user_no.setObjectName("user_no")
self.gridLayout.addWidget(self.user_no, 1, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.name = QtWidgets.QLineEdit(parent=self.centralwidget)
self.name.setObjectName("name")
self.gridLayout.addWidget(self.name, 0, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.mail = QtWidgets.QLineEdit(parent=self.centralwidget)
self.mail.setObjectName("mail")
self.gridLayout.addWidget(self.mail, 2, 1, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_5 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_5.setObjectName("label_5")
self.horizontalLayout_4.addWidget(self.label_5)
self.deleteUser = QtWidgets.QToolButton(parent=self.centralwidget)
self.deleteUser.setMinimumSize(QtCore.QSize(30, 30))
self.deleteUser.setText("")
self.deleteUser.setObjectName("deleteUser")
self.horizontalLayout_4.addWidget(self.deleteUser)
self.gridLayout.addLayout(self.horizontalLayout_4, 3, 0, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
self.line = QtWidgets.QFrame(parent=self.centralwidget)
self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.line.setObjectName("line")
self.verticalLayout.addWidget(self.line)
self.label_4 = QtWidgets.QLabel(parent=self.centralwidget)
font = QtGui.QFont()
font.setPointSize(12)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.verticalLayout.addWidget(self.label_4)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.radio_allLoanedMedia = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_allLoanedMedia.setChecked(False)
self.radio_allLoanedMedia.setObjectName("radio_allLoanedMedia")
self.horizontalLayout_2.addWidget(self.radio_allLoanedMedia)
self.radio_currentlyLoaned = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_currentlyLoaned.setChecked(True)
self.radio_currentlyLoaned.setObjectName("radio_currentlyLoaned")
self.horizontalLayout_2.addWidget(self.radio_currentlyLoaned)
self.radio_overdueLoans = QtWidgets.QRadioButton(parent=self.centralwidget)
self.radio_overdueLoans.setObjectName("radio_overdueLoans")
self.horizontalLayout_2.addWidget(self.radio_overdueLoans)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout_2.addItem(spacerItem2)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.searchbox = QtWidgets.QLineEdit(parent=self.centralwidget)
self.searchbox.setObjectName("searchbox")
self.horizontalLayout_3.addWidget(self.searchbox)
self.searchfilter = QtWidgets.QComboBox(parent=self.centralwidget)
self.searchfilter.setObjectName("searchfilter")
self.searchfilter.addItem("")
self.searchfilter.addItem("")
self.horizontalLayout_3.addWidget(self.searchfilter)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout_3.addItem(spacerItem3)
self.btn_extendSelectedMedia = QtWidgets.QPushButton(parent=self.centralwidget)
self.btn_extendSelectedMedia.setEnabled(False)
self.btn_extendSelectedMedia.setObjectName("btn_extendSelectedMedia")
self.horizontalLayout_3.addWidget(self.btn_extendSelectedMedia)
self.verticalLayout.addLayout(self.horizontalLayout_3)
self.UserMediaTable = QtWidgets.QTableWidget(parent=self.centralwidget)
self.UserMediaTable.setMouseTracking(True)
self.UserMediaTable.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.UserMediaTable.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.UserMediaTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.UserMediaTable.setAlternatingRowColors(True)
self.UserMediaTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
self.UserMediaTable.setObjectName("UserMediaTable")
self.UserMediaTable.setColumnCount(6)
self.UserMediaTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.UserMediaTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.UserMediaTable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.UserMediaTable.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.UserMediaTable.setHorizontalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem()
self.UserMediaTable.setHorizontalHeaderItem(4, item)
item = QtWidgets.QTableWidgetItem()
self.UserMediaTable.setHorizontalHeaderItem(5, item)
self.UserMediaTable.horizontalHeader().setDefaultSectionSize(156)
self.UserMediaTable.horizontalHeader().setMinimumSectionSize(43)
self.UserMediaTable.horizontalHeader().setSortIndicatorShown(True)
self.UserMediaTable.verticalHeader().setDefaultSectionSize(31)
self.UserMediaTable.verticalHeader().setMinimumSectionSize(25)
self.verticalLayout.addWidget(self.UserMediaTable)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
self.statusbar.setSizeGripEnabled(True)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
MainWindow.setTabOrder(self.name, self.mail)
MainWindow.setTabOrder(self.mail, self.btn_userChange_save)
MainWindow.setTabOrder(self.btn_userChange_save, self.btn_userchange_cancel)
MainWindow.setTabOrder(self.btn_userchange_cancel, self.radio_allLoanedMedia)
MainWindow.setTabOrder(self.radio_allLoanedMedia, self.radio_currentlyLoaned)
MainWindow.setTabOrder(self.radio_currentlyLoaned, self.radio_overdueLoans)
MainWindow.setTabOrder(self.radio_overdueLoans, self.searchbox)
MainWindow.setTabOrder(self.searchbox, self.searchfilter)
MainWindow.setTabOrder(self.searchfilter, self.btn_extendSelectedMedia)
MainWindow.setTabOrder(self.btn_extendSelectedMedia, self.UserMediaTable)
MainWindow.setTabOrder(self.UserMediaTable, self.user_no)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.btn_userChange_save.setText(_translate("MainWindow", "Speichern"))
self.btn_userchange_cancel.setText(_translate("MainWindow", "Abbrechen"))
self.label.setText(_translate("MainWindow", "Name, Vorname"))
self.label_3.setText(_translate("MainWindow", "Mail"))
self.label_2.setText(_translate("MainWindow", "Matrikelnummer"))
self.label_5.setText(_translate("MainWindow", "Nutzer Löschen"))
self.label_4.setText(_translate("MainWindow", "Medien"))
self.radio_allLoanedMedia.setText(_translate("MainWindow", "Alle Ausleihen"))
self.radio_currentlyLoaned.setText(_translate("MainWindow", "Aktuell entliehen"))
self.radio_overdueLoans.setText(_translate("MainWindow", "Überzogen"))
self.searchfilter.setItemText(0, _translate("MainWindow", "Titel"))
self.searchfilter.setItemText(1, _translate("MainWindow", "Signatur"))
self.btn_extendSelectedMedia.setText(_translate("MainWindow", "Ausgewählte Verlängern"))
self.UserMediaTable.setSortingEnabled(True)
item = self.UserMediaTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "ISBN"))
item = self.UserMediaTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Signatur"))
item = self.UserMediaTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Titel"))
item = self.UserMediaTable.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "entliehen am"))
item = self.UserMediaTable.horizontalHeaderItem(4)
item.setText(_translate("MainWindow", "entliehen bis"))
item = self.UserMediaTable.horizontalHeaderItem(5)
item.setText(_translate("MainWindow", "Rückgabe am"))

View File

@@ -1,10 +1,11 @@
from .sources.Ui_main_userData import Ui_MainWindow
from PyQt6 import QtCore, QtGui, QtWidgets
from src import log
from src.logic import Database
from src.schemas import User
from src.schemas import User, Book
from .extendLoan import ExtendLoan
from src.utils import stringToDate, Icon
from src.utils import debugMessage as dbg
import datetime
TABLETOFIELDTRANSLATE = {
"Titel": "title",
@@ -33,7 +34,9 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.deleteUser.clicked.connect(self.userDelete)
self.deleteUser.setIcon(Icon("delete").overwriteColor("red"))
self.deleteUser.setEnabled(False)
self.deleteUser.setToolTip("Nutzer löschen nicht möglich, solange Medien ausgeliehen sind")
self.deleteUser.setToolTip(
"Nutzer löschen nicht möglich, solange Medien ausgeliehen sind"
)
self.btn_extendSelectedMedia.setEnabled(False)
# radioButtons
@@ -45,8 +48,9 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.frame.hide()
if self.UserMediaTable.rowCount() == 0:
self.btn_extendSelectedMedia.setEnabled(False)
self.deleteUser.setEnabled( True)
else: self.btn_extendSelectedMedia.setEnabled(True)
self.deleteUser.setEnabled(True)
else:
self.btn_extendSelectedMedia.setEnabled(True)
# table
self.UserMediaTable.horizontalHeader().setSectionResizeMode(
@@ -61,10 +65,21 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.name.textChanged.connect(self.showFrame)
self.user_no.textChanged.connect(self.showFrame)
self.mail.textChanged.connect(self.showFrame)
self.show()
def check_book(self, book: Book):
today = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
returnDate = stringToDate(book.loan_to).toString("yyyy-MM-dd")
returned = book.returned
if returned == 1:
return "returned"
else:
if returnDate < today:
return "overdue"
else:
return "ok"
def userDelete(self):
self.db.deleteUser(self.user_id)
dialog = QtWidgets.QMessageBox()
@@ -84,7 +99,7 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
for item in self.UserMediaTable.selectedItems():
if item.column() == 1:
signature = item.text()
#print(signature)
# print(signature)
self.db.extendLoanDuration(signature, extendDate)
self.userMedia = []
self.UserMediaTable.setRowCount(0)
@@ -95,11 +110,10 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
limiter = self.searchbox.text().lower()
searchfield = self.searchfilter.currentText()
searchfield = TABLETOFIELDTRANSLATE[searchfield]
# dbg(limiter=limiter, search=searchfield)
self.UserMediaTable.setRowCount(0)
for loan in self.userMedia:
#print("looping loans")
# print("looping loans")
fielddata = eval(f"loan.{searchfield}")
if isinstance(fielddata, str):
fielddata = fielddata.lower()
@@ -149,12 +163,12 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
if self.radio_currentlyLoaned.isChecked()
else "overdue"
)
#print(mode)
# print(mode)
if self.userMedia == []:
books = self.db.getAllMedia(self.user_id)
for book in books:
self.userMedia.append(book)
#print(self.userMedia)
# print(self.userMedia)
self.UserMediaTable.setRowCount(0)
for book in self.userMedia:
@@ -166,7 +180,7 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
continue
elif mode == "overdue":
# book not returned and todays date is greater than todate
dbg(book=book)
log.debug("Book: {}".format(book))
if book.returned_date is not None:
continue
# if todate is greater than current date, continue
@@ -174,7 +188,8 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
continue
self.addBookToTable(book)
#print(book.title)
# print(book.title)
def addBookToTable(self, book):
self.UserMediaTable.insertRow(0)
# item0 = isbn
@@ -213,6 +228,22 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
else stringToDate(book.returned_date).toString("dd.MM.yyyy")
),
)
match self.check_book(book):
case "overdue":
for i in range(6):
self.UserMediaTable.item(0, i).setBackground(
QtGui.QColor(255, 0, 0, 100)
)
case "ok":
for i in range(6):
self.UserMediaTable.item(0, i).setBackground(
QtGui.QColor(105, 255, 51, 100)
)
case "returned":
for i in range(6):
self.UserMediaTable.item(0, i).setBackground(
QtGui.QColor(102, 153, 153, 100)
)
def launch():
@@ -222,4 +253,4 @@ def launch():
window = UserUI("Test", "3613899476", "sdf@f.de")
window.show()
sys.exit(app.exec())
sys.exit(app.exec())

View File

@@ -1,5 +1,2 @@
from .log import Log
from .icon import Icon
from .debug import debugMessage
from .stringtodate import stringToDate
from .documentation import launch_documentation

View File

@@ -7,13 +7,14 @@ from PyQt6.QtCore import QDate
from src import config
import datetime
# query all loans that happened in the last 7 days
def generate_report():
'''Generate an excel report for all actions that happened in the last seven days
"""Generate an excel report for all actions that happened in the last seven days
Returns:
str: a string represeting the generated table
'''
"""
db = Database()
path = db.db_path
year = datetime.datetime.now().year
@@ -23,9 +24,12 @@ def generate_report():
report_path = os.path.join(config.report.path, f"report_{year}_{week}.tsv")
day = QDate.currentDate().addDays(-7).toString("yyyy-MM-dd")
query = f"""SELECT * FROM loans WHERE loan_date >= '{day}';"""
#print(query)
# print(query)
colnames = ["UserId", "Title", "Action", "Datum"]
if config.report.show_signature:
# insert the signature column at the second position
colnames.insert(2, "Signature")
table = PrettyTable(colnames)
table.align[colnames[0]] = "l"
table.align[colnames[1]] = "l"
@@ -41,19 +45,15 @@ def generate_report():
loan_action_date = stringToDate(
loan[3] if loan[5] == 0 else loan[6]
).toString("dd.MM.yyyy")
table.add_row(
[
loan[1],
db.getMedia(loan[2]).title,
loan_action,
loan_action_date,
]
)
# #print(table)
# # wruitng the table to a file
# with open("report.txt", "w", encoding="utf-8") as f:
# f.write(str(table))
row = [
loan[1],
db.getMedia(loan[2]).title,
loan_action,
loan_action_date,
]
if config.report.show_signature:
row.insert(2, db.getMedia(loan[2]).signature)
table.add_row(row)
tsv_table = table.get_csv_string().replace(",", "\t")
# write the file
with open(report_path, "w", encoding="utf-8") as f:

View File

@@ -1,18 +0,0 @@
from src import config
from icecream import ic
from src.utils import Log
log = Log("debugMessage")
def debugMessage(*args, **kwargs):
startmessage = "Logging debug message"
# join args and kwargs to a string
message = " ".join(args)
for key, value in kwargs.items():
message += f" {key}: {value}"
if config.debug:
if config.log_debug:
log.info(f"{startmessage}: {message}")
if config.ic_logging == True:
ic(message)
else: print(message)
return message

View File

@@ -1,22 +1,19 @@
from pyramid.config import Configurator
from wsgiref.simple_server import make_server
from src import docport
import os
def website():
config = Configurator()
import sys
# Set up static file serving from the 'site/' directory
config.add_static_view(name='/', path=os.path.join(os.getcwd(), 'site'), cache_max_age=3600)
app = config.make_wsgi_app()
return app
def run_mkdocs():
with open(os.devnull, "w") as devnull:
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = devnull
sys.stderr = devnull
try:
os.system("mkdocs serve -q")
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
def launch_documentation():
app = website()
server = make_server('localhost', 6543, app)
print("Serving MkDocs documentation on http://0.0.0.0:{}".format(docport))
server.serve_forever()
if __name__ == '__main__':
if __name__ == "__main__":
pass

Some files were not shown because too many files have changed in this diff Show More