Compare commits

..

No commits in common. "step4" and "api" have entirely different histories.
step4 ... api

17 changed files with 184 additions and 461 deletions

View File

@ -1,110 +0,0 @@
import sys
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QPushButton, QLabel, QMessageBox, QFileDialog)
from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
import requests
class PassportForm(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("PAssportForms")
self.main_layout = QHBoxLayout()
self.form_layout = QVBoxLayout()
self.data_layout = QFormLayout()
self.number_input = QLineEdit()
self.name_input = QLineEdit()
self.surname_input = QLineEdit()
self.gender_input = QLineEdit()
self.fingerprint_url_input = QLineEdit()
self.photo_url_input = QLineEdit()
self.data_layout.addRow("Passport Number", self.number_input)
self.data_layout.addRow("Name", self.name_input)
self.data_layout.addRow("Surname", self.surname_input)
self.data_layout.addRow("Gender", self.gender_input)
self.data_layout.addRow("Fingerprint URL", self.fingerprint_url_input)
self.data_layout.addRow("Photo URL", self.photo_url_input)
self.load_button = QPushButton("Load Data")
self.load_button.clicked.connect(self.load_data)
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.submit_form)
self.form_layout.addLayout(self.data_layout)
self.form_layout.addWidget(self.load_button)
self.form_layout.addWidget(self.submit_button)
self.image_layout = QVBoxLayout()
self.photo_label = QLabel("Photo")
self.photo_label.setFixedSize(200, 200)
self.photo_label.setStyleSheet("border: 1px solid black;")
self.photo_label.setAlignment(Qt.AlignCenter)
self.fingerprint_label = QLabel("Fingerprint")
self.fingerprint_label.setFixedSize(200, 200)
self.fingerprint_label.setStyleSheet("border: 1px solid black;")
self.fingerprint_label.setAlignment(Qt.AlignCenter)
self.image_layout.addWidget(self.photo_label)
self.image_layout.addWidget(self.fingerprint_label)
self.main_layout.addLayout(self.form_layout)
self.main_layout.addLayout(self.image_layout)
self.setLayout(self.main_layout)
def load_data(self):
passport_number = self.number_input.text()
response = requests.get(f"http://localhost:9999/passport/{passport_number}")
if response.status_code == 200:
data = response.json()
self.name_input.setText(data['name'])
self.surname_input.setText(data['surname'])
self.gender_input.setText(data['gender'])
self.fingerprint_url_input.setText(data['fingerprint_url'])
self.photo_url_input.setText(data['photo_url'])
self.load_image(self.photo_label, f"http://localhost:9999/static/imgs/data/{passport_number}-zdjecie.jpg")
self.load_image(self.fingerprint_label, f"http://localhost:9999/static/imgs/data/{passport_number}-odcisk.jpg")
else:
QMessageBox.critical(self, "Error", "Failed to load passport data")
def load_image(self, label, url):
response = requests.get(url)
if response.status_code == 200:
pixmap = QPixmap()
pixmap.loadFromData(response.content)
label.setPixmap(pixmap.scaled(label.size(), Qt.KeepAspectRatio))
else:
label.setText("Image not found")
def submit_form(self):
passport_data = {
"number": self.number_input.text(),
"name": self.name_input.text(),
"surname": self.surname_input.text(),
"gender": self.gender_input.text(),
"fingerprint_url": self.fingerprint_url_input.text(),
"photo_url": self.photo_url_input.text()
}
response = requests.post("http://localhost:9999/passport/", json=passport_data)
if response.status_code == 200:
QMessageBox.information(self, "Success", "Passport data submitted successfully")
else:
QMessageBox.critical(self, "Error", "Failed to submit passport data")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = PassportForm()
window.show()
sys.exit(app.exec())

View File

@ -161,165 +161,3 @@ xmap <c-c><c-c> <Plug>SlimeRegionSend
nmap <c-c><c-c> :<c-u>call SendCell('^#%%')<cr> nmap <c-c><c-c> :<c-u>call SendCell('^#%%')<cr>
nmap <c-c>v <Plug>SlimeConfig nmap <c-c>v <Plug>SlimeConfig
" https://raw.githubusercontent.com/neoclide/coc.nvim/master/doc/coc-example-config.vim
" May need for Vim (not Neovim) since coc.nvim calculates byte offset by count
" utf-8 byte sequence
set encoding=utf-8
" Some servers have issues with backup files, see #649
set nobackup
set nowritebackup
" Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
" delays and poor user experience
set updatetime=300
" Always show the signcolumn, otherwise it would shift the text each time
" diagnostics appear/become resolved
set signcolumn=yes
" Use tab for trigger completion with characters ahead and navigate
" NOTE: There's always complete item selected by default, you may want to enable
" no select by `"suggest.noselect": true` in your configuration file
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config
inoremap <silent><expr> <TAB>
\ coc#pum#visible() ? coc#pum#next(1) :
\ CheckBackspace() ? "\<Tab>" :
\ coc#refresh()
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"
" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
function! CheckBackspace() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
" Use <c-space> to trigger completion
if has('nvim')
inoremap <silent><expr> <c-space> coc#refresh()
else
inoremap <silent><expr> <c-@> coc#refresh()
endif
" Use `[g` and `]g` to navigate diagnostics
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)
" GoTo code navigation
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
" Use K to show documentation in preview window
nnoremap <silent> K :call ShowDocumentation()<CR>
function! ShowDocumentation()
if CocAction('hasProvider', 'hover')
call CocActionAsync('doHover')
else
call feedkeys('K', 'in')
endif
endfunction
" Highlight the symbol and its references when holding the cursor
autocmd CursorHold * silent call CocActionAsync('highlight')
" Symbol renaming
nmap <leader>rn <Plug>(coc-rename)
" Formatting selected code
xmap <leader>f <Plug>(coc-format-selected)
nmap <leader>f <Plug>(coc-format-selected)
augroup mygroup
autocmd!
" Setup formatexpr specified filetype(s)
autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
" Update signature help on jump placeholder
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
augroup end
" Applying code actions to the selected code block
" Example: `<leader>aap` for current paragraph
xmap <leader>a <Plug>(coc-codeaction-selected)
nmap <leader>a <Plug>(coc-codeaction-selected)
" Remap keys for applying code actions at the cursor position
nmap <leader>ac <Plug>(coc-codeaction-cursor)
" Remap keys for apply code actions affect whole buffer
nmap <leader>as <Plug>(coc-codeaction-source)
" Apply the most preferred quickfix action to fix diagnostic on the current line
nmap <leader>qf <Plug>(coc-fix-current)
" Remap keys for applying refactor code actions
nmap <silent> <leader>re <Plug>(coc-codeaction-refactor)
xmap <silent> <leader>r <Plug>(coc-codeaction-refactor-selected)
nmap <silent> <leader>r <Plug>(coc-codeaction-refactor-selected)
" Run the Code Lens action on the current line
nmap <leader>cl <Plug>(coc-codelens-action)
" Map function and class text objects
" NOTE: Requires 'textDocument.documentSymbol' support from the language server
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)
xmap ic <Plug>(coc-classobj-i)
omap ic <Plug>(coc-classobj-i)
xmap ac <Plug>(coc-classobj-a)
omap ac <Plug>(coc-classobj-a)
" Remap <C-f> and <C-b> to scroll float windows/popups
if has('nvim-0.4.0') || has('patch-8.2.0750')
nnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
nnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
inoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(1)\<cr>" : "\<Right>"
inoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(0)\<cr>" : "\<Left>"
vnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
vnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
endif
" Use CTRL-S for selections ranges
" Requires 'textDocument/selectionRange' support of language server
nmap <silent> <C-s> <Plug>(coc-range-select)
xmap <silent> <C-s> <Plug>(coc-range-select)
" Add `:Format` command to format current buffer
command! -nargs=0 Format :call CocActionAsync('format')
" Add `:Fold` command to fold current buffer
command! -nargs=? Fold :call CocAction('fold', <f-args>)
" Add `:OR` command for organize imports of the current buffer
command! -nargs=0 OR :call CocActionAsync('runCommand', 'editor.action.organizeImport')
" Add (Neo)Vim's native statusline support
" NOTE: Please see `:h coc-status` for integrations with external plugins that
" provide custom statusline: lightline.vim, vim-airline
set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}
" Mappings for CoCList
" Show all diagnostics
nnoremap <silent><nowait> <space>a :<C-u>CocList diagnostics<cr>
" Manage extensions
nnoremap <silent><nowait> <space>e :<C-u>CocList extensions<cr>
" Show commands
nnoremap <silent><nowait> <space>c :<C-u>CocList commands<cr>
" Find symbol of current document
nnoremap <silent><nowait> <space>o :<C-u>CocList outline<cr>
" Search workspace symbols
nnoremap <silent><nowait> <space>s :<C-u>CocList -I symbols<cr>
" Do default action for next item
nnoremap <silent><nowait> <space>j :<C-u>CocNext<CR>
" Do default action for previous item
nnoremap <silent><nowait> <space>k :<C-u>CocPrev<CR>
" Resume latest coc list
nnoremap <silent><nowait> <space>p :<C-u>CocListResume<CR>

View File

@ -24,11 +24,3 @@ from sqlalchemy import text
with engine.connect() as conn: with engine.connect() as conn:
result = conn.execute(text("select 'hello world'")) result = conn.execute(text("select 'hello world'"))
print(result.all()) print(result.all())
#%%
with engine.connect() as conn:
result = conn.execute(text("show tables;"))
#%%
for row in result.fetchall():
print(row)

View File

@ -1,28 +1,21 @@
# app/main.py # app/main.py
# ---
from fastapi import FastAPI, HTTPException, Depends from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.database import SessionLocal, engine
from app import models, schemas
from typing import List, Optional from app.database import SessionLocal
from app.models import PassportData
# ddfrom starlette.middleware.base import BaseHTTPMiddleware
# from starlette.responses import Response
# class CustomMIMEMiddleware(BaseHTTPMiddleware):
# async def dispatch(self, request, call_next):
# response = await call_next(request)
# if request.url.path.endswith('.vue'):
# response.headers['Content-Type'] = 'application/javascript'
# return response
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from typing import List, Optional
app = FastAPI() app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static") app.mount("/static", StaticFiles(directory="static"), name="static")
models.Base.metadata.create_all(bind=engine) # Dependency to get DB session
def get_db(): def get_db():
db = SessionLocal() db = SessionLocal()
try: try:
@ -30,18 +23,24 @@ def get_db():
finally: finally:
db.close() db.close()
@app.post("/passport/", response_model=schemas.PassportData) class PassportDataRequest(BaseModel):
def create_passport_data(passport_data: schemas.PassportDataCreate, db: Session = Depends(get_db)): number: str
db_passport_data = models.PassportData(**passport_data.dict()) name: str
db.add(db_passport_data) surname: str
gender: str
@app.post("/passport_data/")
def create_passport_data(request: PassportDataRequest, db: Session = Depends(get_db)):
db_passport = PassportData(number=request.number, name=request.name, surname=request.surname, gender=request.gender)
db.add(db_passport)
db.commit() db.commit()
db.refresh(db_passport_data) db.refresh(db_passport)
return db_passport_data return db_passport
@app.get("/passport/{passport_number}", response_model=schemas.PassportData) @app.get("/passport_data/{passport_number}")
def read_passport_data(passport_number: str, db: Session = Depends(get_db)): def read_passport_data(passport_number: str, db: Session = Depends(get_db)):
db_passport_data = db.query(models.PassportData).filter(models.PassportData.number == passport_number).first() db_passport = db.query(PassportData).filter(PassportData.number == passport_number).first()
if db_passport_data is None: if db_passport is None:
raise HTTPException(status_code=404, detail="Passport data not found") raise HTTPException(status_code=404, detail="Passport data not found")
return schemas.PassportData.from_orm(db_passport_data) return db_passport

View File

@ -1,13 +1,13 @@
# app/models.py # app/models.py
from sqlalchemy import Column, Integer, String from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from app.database import Base from app.database import Base
class PassportData(Base): class PassportData(Base):
__tablename__ = 'passport_data' __tablename__ = 'passport_data'
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
number = Column(String(255), unique=True, nullable=False) number = Column(String(255), unique=True, nullable=False)
name = Column(String(255), nullable=True) name = Column(String(255), nullable=False)
surname = Column(String(255), nullable=True) surname = Column(String(255), nullable=False)
gender = Column(String(255), nullable=True) gender = Column(String(255), nullable=False)
fingerprint_url = Column(String(255), nullable=True) # New field for fingerprint image URL
photo_url = Column(String(255), nullable=True) # New field for photo image URL

View File

@ -1,21 +0,0 @@
# app/schemas.py
from pydantic import BaseModel
from typing import Optional
class PassportDataBase(BaseModel):
number: str
name: Optional[str] = None
surname: Optional[str] = None
gender: Optional[str] = None
fingerprint_url: Optional[str] = None
photo_url: Optional[str] = None
class PassportDataCreate(PassportDataBase):
pass
class PassportData(PassportDataBase):
id: int
class Config:
orm_mode = True # Poprawne przypisanie

View File

@ -1,76 +1,25 @@
# entrypoint.py from app.database import engine
#%% from app.models import Base
from app.database import engine, SessionLocal
from app.models import Base, PassportData
import argparse import argparse
import uvicorn import uvicorn
import os
#%% def main(port):
def load_data_from_directory(directory_path: str, db_session): # Create the database
files = os.listdir(directory_path)
passport_data = {}
for file in files:
file_parts = file.split('-')
if len(file_parts) != 2:
continue
passport_number = file_parts[0]
file_type = file_parts[1].split('.')[0]
if passport_number not in passport_data:
passport_data[passport_number] = {
"fingerprint_url": None,
"photo_url": None
}
file_path = os.path.join(directory_path, file)
if file_type == 'odcisk':
passport_data[passport_number]["fingerprint_url"] = file_path
elif file_type == 'zdjecie':
passport_data[passport_number]["photo_url"] = file_path
for number, data in passport_data.items():
passport_entry = PassportData(
number=number,
name=None,
surname=None,
gender=None,
fingerprint_url=data["fingerprint_url"],
photo_url=data["photo_url"]
)
db_session.add(passport_entry)
print (passport_entry)
db_session.commit()
#%%
def main(port, data_dir):
print("Creating database tables...") print("Creating database tables...")
Base.metadata.create_all(bind=engine) Base.metadata.create_all(bind=engine)
print("Database tables created.") print("Database tables created.")
db_session = SessionLocal() # Run the FastAPI app using uvicorn
try: # uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True)
print(f"Loading data from directory: {data_dir}")
load_data_from_directory(data_dir, db_session)
print("Data loaded into database.")
finally:
db_session.close()
# uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True)
#%% main(9999,"data")
#%%
if __name__ == "__main__": if __name__ == "__main__":
# Create argument parser
parser = argparse.ArgumentParser(description="Run the FastAPI app") parser = argparse.ArgumentParser(description="Run the FastAPI app")
# Add port argument, default is 9999
parser.add_argument("--port", type=int, default=9999, help="Port to run the FastAPI app on") parser.add_argument("--port", type=int, default=9999, help="Port to run the FastAPI app on")
parser.add_argument("--data-dir", type=str, default="data", help="Directory containing passport data files") # Parse arguments
args = parser.parse_args() args = parser.parse_args()
main(args.port, args.data_dir) main(args.port)

View File

@ -1,11 +0,0 @@
curl -X POST "http://localhost:9999/passport/" \
-H "Content-Type: application/json" \
-d '{
"number": "444",
"name": null,
"surname": null,
"gender": null,
"fingerprint_url": "data/444-odcisk.jpg",
"photo_url": "data/444-zdjecie.jpg"
}'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -3,14 +3,38 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Passport Form App</title> <title>Library Management</title>
<link rel="stylesheet" href="./style.css"> <link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<header>Library Management</header>
<div id="app"></div> <div class="container">
<script src="./js/axios.min.js"></script> <aside class="sidebar">
<script type="module" src="./script.js"></script> <h2>Add Author</h2>
<form id="addAuthorForm">
<input type="text" id="authorName" placeholder="Author Name" required>
<button type="submit">Add Author</button>
</form>
<h2>Add Book</h2>
<form id="addBookForm">
<input type="text" id="bookTitle" placeholder="Book Title" required>
<select id="bookAuthorId">
<!-- Autorzy będą dodawani tutaj dynamicznie -->
</select>
<button type="submit">Add Book</button>
</form>
</aside>
<main class="content">
<h2>Authors</h2>
<ul id="authorsList"></ul>
<h2>Books</h2>
<ul id="booksList"></ul>
<button id="loadBooksWithAuthors">Load Books with Authors</button>
<ul id="booksWithAuthorsList"></ul>
</main>
</div>
<footer>2024 Library Management System</footer>
<script src="script.js"></script>
</body> </body>
</html> </html>

View File

@ -1,16 +1,69 @@
import { createApp } from './js/vue.esm-browser.js'; const BASE_URL = 'http://qstack.pl:1111'; // Zaktualizuj zgodnie z konfiguracją Twojego serwera
import PassportForm from './components/Tabs.js';
const App = { document.addEventListener('DOMContentLoaded', function() {
name: 'App', loadAuthors();
components: { loadBooks();
PassportForm });
},
template: ` document.getElementById('addAuthorForm').addEventListener('submit', function(e) {
<div id="app"> e.preventDefault();
<PassportForm /> const authorName = document.getElementById('authorName').value;
</div> fetch(`${BASE_URL}/authors/`, {
`, method: 'POST',
}; headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: authorName }),
})
.then(response => response.json())
.then(() => {
loadAuthors(); // Ponowne ładowanie listy autorów po dodaniu nowego autora
})
.catch(error => console.error('Error:', error));
});
document.getElementById('addBookForm').addEventListener('submit', function(e) {
e.preventDefault();
const bookTitle = document.getElementById('bookTitle').value;
const bookAuthorId = document.getElementById('bookAuthorId').value;
fetch(`${BASE_URL}/books/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: bookTitle, author_id: parseInt(bookAuthorId, 10) }),
})
.then(response => response.json())
.then(() => {
loadBooks(); // Ponowne ładowanie listy książek po dodaniu nowej książki
})
.catch(error => console.error('Error:', error));
});
function loadAuthors() {
fetch(`${BASE_URL}/authors/`)
.then(response => response.json())
.then(data => {
const authorsSelect = document.getElementById('bookAuthorId');
authorsSelect.innerHTML = '<option value="">Select an Author</option>'; // Dodaj domyślną opcję
data.forEach(author => {
const option = document.createElement('option');
option.value = author.id;
option.textContent = author.name;
authorsSelect.appendChild(option);
});
})
.catch(error => console.error('Error:', error));
}
function loadBooks() {
fetch(`${BASE_URL}/books/`)
.then(response => response.json())
.then(data => {
const booksList = document.getElementById('booksList');
booksList.innerHTML = '';
data.forEach(book => {
const listItem = document.createElement('li');
listItem.textContent = `${book.title} - Author ID: ${book.author_id}`;
booksList.appendChild(listItem);
});
})
.catch(error => console.error('Error:', error));
}
createApp(App).mount('#app');

View File

@ -1,33 +1,43 @@
.passport-form { body, html {
display: flex; margin: 0;
justify-content: center; padding: 0;
align-items: flex-start; font-family: Arial, sans-serif;
margin-top: 20px; }
}
.form-container { header, footer {
display: flex; background-color: #333;
flex-direction: column; color: #fff;
align-items: flex-start; text-align: center;
margin-right: 20px; padding: 1rem 0;
} }
.form-field { .container {
display: flex;
min-height: calc(100vh - 100px); /* Adjust based on header/footer height */
}
.sidebar {
width: 30%;
padding: 20px;
background-color: #f4f4f4;
}
.content {
flex-grow: 1;
padding: 20px;
}
form > * {
display: block;
margin-bottom: 10px; margin-bottom: 10px;
} }
.form-field label { button {
margin-right: 10px; cursor: pointer;
} }
.images-container { ul {
display: flex; list-style-type: none;
flex-direction: column; padding-left: 0;
align-items: flex-start; }
}
.images-container img {
max-width: 200px;
margin-bottom: 10px;
}