18 Commits
Author SHA1 Message Date
MH.Dmitrii 66b6878e50 cache images
Build Docker / deploy (push) Successful in 40s
Build Docker / build (push) Successful in 35s
2026-03-19 03:06:41 +03:00
MH.Dmitrii 7bdf422c32 fix js
Build Docker / deploy (push) Successful in 51s
Build Docker / build (push) Successful in 34s
2026-03-19 03:00:41 +03:00
MH.Dmitrii 9a259cb637 fix logout button
Build Docker / deploy (push) Successful in 40s
Build Docker / build (push) Successful in 35s
2026-03-19 02:57:02 +03:00
MH.Dmitrii 54072eb87d logout button fix
Build Docker / deploy (push) Successful in 40s
Build Docker / build (push) Successful in 35s
2026-03-19 02:53:17 +03:00
MH.Dmitrii ecf374685f error handle 0.152
Build Docker / deploy (push) Successful in 38s
Build Docker / build (push) Successful in 34s
2026-03-19 02:48:16 +03:00
MH.Dmitrii 62d58e30cd remake apis 0.151
Build Docker / deploy (push) Successful in 44s
Build Docker / build (push) Successful in 34s
2026-03-19 02:41:39 +03:00
MH.Dmitrii a13b88bd32 fix font types 0.150
Build Docker / deploy (push) Successful in 49s
Build Docker / build (push) Successful in 36s
2026-03-19 02:25:51 +03:00
MH.Dmitrii ea7bfc64f2 fix jss 0.149
Build Docker / deploy (push) Successful in 55s
Build Docker / build (push) Successful in 35s
2026-03-19 02:09:25 +03:00
MH.Dmitrii 0e2a17a3e3 fix login.js 0.148
Build Docker / deploy (push) Successful in 38s
Build Docker / build (push) Successful in 39s
2026-03-19 02:00:48 +03:00
MH.Dmitrii 185cefe250 fix login.js 0.147
Build Docker / deploy (push) Successful in 45s
Build Docker / build (push) Successful in 44s
2026-03-19 01:58:13 +03:00
MH.Dmitrii 25ec2c7bcb fix jss 0.146
Build Docker / deploy (push) Successful in 41s
Build Docker / build (push) Successful in 38s
2026-03-19 01:52:57 +03:00
MH.Dmitrii b667cde3d7 fix caddyfile 0.145
Build Docker / deploy (push) Successful in 1m40s
Build Docker / build (push) Successful in 36s
2026-03-19 01:47:41 +03:00
MH.Dmitrii d30af82765 fix caddy file 0.134
Build Docker / deploy (push) Successful in 48s
Build Docker / build (push) Successful in 42s
2026-03-19 01:43:57 +03:00
MH.Dmitrii efd8510853 fix caddy file 0.133
Build Docker / deploy (push) Successful in 38s
Build Docker / build (push) Successful in 34s
2026-03-19 01:32:00 +03:00
MH.Dmitrii e558aa6bdd fix caddy 0.132
Build Docker / deploy (push) Successful in 50s
Build Docker / build (push) Successful in 38s
2026-03-19 01:29:09 +03:00
MH.Dmitrii bd9210a3b5 fix caddy 0.131
Build Docker / deploy (push) Successful in 39s
Build Docker / build (push) Successful in 34s
2026-03-19 01:22:49 +03:00
MH.Dmitrii 1eba5623a3 fix caddyfile 0.130
Build Docker / deploy (push) Successful in 50s
Build Docker / build (push) Successful in 32s
2026-03-19 01:16:07 +03:00
MH.Dmitrii c762662231 fix caddyfile
Build Docker / deploy (push) Successful in 1m6s
Build Docker / build (push) Successful in 36s
2026-03-19 01:12:24 +03:00
8 changed files with 162 additions and 141 deletions
+23 -5
View File
@@ -4,14 +4,32 @@ http://ru.homyk.space {
https://ru.homyk.space {
encode gzip
# --- API ---
handle /api/* {
reverse_proxy backend:{$PORT}
}
# --- Frontend ---
root * /srv
handle_path /main/* {
@images path_regexp \.(jpg|jpeg|png|webp|gif|svg)$
header @images Cache-Control "public, max-age=604800"
forward_auth backend:{$PORT} {
uri /api/verify
copy_headers Authorization
}
root * /srv/main
file_server
}
handle_errors {
@unauth expression {http.error.status_code} == 401
redir @unauth / 302
}
handle {
root * /srv/auth
file_server {
index login.html
}
}
log {
output file /data/logs/caddy.log {
@@ -20,7 +38,7 @@ https://ru.homyk.space {
roll_keep_for 72h
}
format json
}
}
}
https://music.homyk.space {
encode gzip
@@ -37,5 +55,5 @@ https://music.homyk.space {
roll_keep_for 72h
}
format json
}
}
}
+33 -9
View File
@@ -1,16 +1,21 @@
from fastapi import FastAPI, Depends, HTTPException,status
from fastapi import FastAPI, Depends, HTTPException,status, Response, Cookie
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import server.backend.schema.pydantic as pydantic
import server.backend.database.db as db
from server.backend.auth.JWT import signJWT, decodeJWT
api = FastAPI(openapi_url="/api/openapi.json",docs_url="/api/docs", redoc_url="/api/redoc")
security = HTTPBearer()
security = HTTPBearer(auto_error=False)
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
token = credentials.credentials
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security),
token_cookie: str = Cookie(default=None)
):
token = credentials.credentials if credentials else token_cookie
if not token:
raise HTTPException(status_code=401, detail="Not authenticated")
user = decodeJWT(token)
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
raise HTTPException(status_code=401, detail="Invalid token")
return user
async def check_roles(user=Depends(get_current_user)):
user_check = await db.list_user(user["user_id"])
@@ -58,10 +63,29 @@ async def list_users(user=Depends(check_roles)):
list_of_users = await db.list_users()
return list_of_users
@api.post("/api/auth",response_model=pydantic.Token)
async def auth(code:pydantic.UserAccess):
@api.post("/api/auth")
async def auth(code: pydantic.UserAccess, response: Response):
login = await db.login_user(code)
if login == None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Forbidden")
if login is None:
raise HTTPException(status_code=401, detail="Forbidden")
token = signJWT(login)
response.set_cookie(
key="token",
value=token,
httponly=True,
secure=True,
samesite="strict"
)
return {"access_token": token, "token_type": "bearer"}
@api.get("/api/verify")
async def verify(token: str = Cookie(default=None)):
if not token:
raise HTTPException(status_code=401, detail="No token")
user = decodeJWT(token)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return {"status": "ok"}
@api.post("/api/logout")
async def logout(response: Response):
response.delete_cookie(key="token")
return {"status": "ok"}
+35 -44
View File
@@ -1,39 +1,29 @@
function getToken() {
return localStorage.getItem("token") || sessionStorage.getItem("token");
}
function tokenCheck(){
const token = getToken();
if (token) {
window.location.href = "http://localhost:5500/server/frontend/main/index.html";
}
}
document.getElementById('loginForm').addEventListener('submit', async function (e) {
document.addEventListener('DOMContentLoaded', () => {
fetch('/api/verify', { credentials: 'include' })
.then(r => { if (r.ok) window.location.href = '/main/'; })
.catch(() => {});
document.getElementById('loginForm').addEventListener('submit', async function(e) {
e.preventDefault();
const password = document.getElementById('password').value;
const userData = {
password
};
const code = document.getElementById('password').value;
try {
const response = await fetch("http://localhost:8000/api/auth", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
password: userData.password
}),
const response = await fetch('/api/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // ← чтобы браузер принял cookie
body: JSON.stringify({ code })
});
const data = await response.json(); // читаем только один раз
if (response.ok) { // сохраняем только при успехе
// в sessionstorage до перезахода в браузер(
sessionStorage.setItem("token", data.access_token);
const data = await response.json();
window.location.href = 'http://localhost:5500/server/frontend/main/index.html';
} else { //парсинг и вывод ошибок, если есть
if (response.ok) {
window.location.href = '/main/';
} else {
if (Array.isArray(data.detail)) {
const messages = data.detail.map(e => {
const field = e.loc.filter(locPart => locPart !== 'body').join(' -> ');
const field = e.loc.filter(p => p !== 'body').join(' -> ');
return `${field}: ${e.msg}`;
});
showError(messages);
@@ -46,28 +36,29 @@ document.getElementById('loginForm').addEventListener('submit', async function (
} catch (err) {
showError(['Connection error: ' + err.message]);
}
});
});
function showError(messages){ //Добавление их на form со стилями
function showError(messages) {
let errorElem = document.getElementById('formError');
let container = document.getElementById('glass-container');
if (!errorElem){
if (!errorElem) {
errorElem = document.createElement('div');
errorElem.style.transition="3s";
errorElem.id = 'formError';
errorElem.style.color = 'red';
errorElem.style.marginTop = '20px';
errorElem.style.fontSize = '14px';
errorElem.style.fontWeight = '100';
errorElem.style.marginBottom = '20px';
errorElem.style.lineHeight="120%";
errorElem.style.height = 'auto';
const form = document.getElementById('loginForm');
form.insertAdjacentElement('afterend', errorElem);
};
errorElem.style.cssText = `
color: red;
margin-top: 20px;
margin-bottom: 20px;
font-size: 14px;
font-weight: 100;
line-height: 120%;
transition: 3s;
`;
document.getElementById('loginForm').insertAdjacentElement('afterend', errorElem);
}
errorElem.innerHTML = '';
messages.forEach(msg => {
const li = document.createElement('li');
li.style.listStyleType="none";
li.style.listStyleType = 'none';
li.textContent = msg;
errorElem.appendChild(li);
});
+42 -56
View File
@@ -1,69 +1,55 @@
function getToken() {
return localStorage.getItem("token") || sessionStorage.getItem("token");
}
function tokenCheck(){
const token = getToken();
if (!token) {
window.location.href = "http://localhost:5500/server/frontend/auth/login.html";
}
}
tokenCheck()
document.getElementById('logoutForm').addEventListener('submit', async function (e) {
e.preventDefault();
localStorage.removeItem("token");
sessionStorage.removeItem("token");
tokenCheck();
});
document.addEventListener("DOMContentLoaded", () => {
const form = document.querySelector(".form-info");
form.addEventListener("submit", async (e) => {
// Проверка авторизации через cookie
fetch('/api/verify', { credentials: 'include' })
.then(r => { if (!r.ok) window.location.href = '/'; })
.catch(() => { window.location.href = '/'; });
// Logout — удаляем cookie на бэкенде
document.getElementById('logoutForm').addEventListener('click', async function(e) {
e.preventDefault();
await fetch('/api/logout', {
method: 'POST',
credentials: 'include'
});
window.location.href = '/';
});
document.querySelector(".form-info").addEventListener("submit", async (e) => {
e.preventDefault();
// try {
// собираем данные из формы
const name = document.getElementById('ffname').value || "";
const middlename = document.getElementById('fmname').value || "";
const surname = document.getElementById('flname').value || "";
const text_field = document.getElementById('text_field')?.value || "";
const food = document.querySelector('input[name="food"]:checked')?.value || "";
const types_of_alco = Array.from(document.querySelectorAll('input[name="drink"]:checked'))
.map(el => el.value)
.join(', ');
const guestData = {
name: name,
middlename: middlename,
surname: surname,
text_field: text_field,
name: document.getElementById('ffname').value || "",
middlename: document.getElementById('fmname').value || "",
surname: document.getElementById('flname').value || "",
text_field: document.getElementById('text_field')?.value || "",
activated: true,
types_of_food: food,
types_of_alco: types_of_alco
types_of_food: document.querySelector('input[name="food"]:checked')?.value || "",
types_of_alco: Array.from(document.querySelectorAll('input[name="drink"]:checked'))
.map(el => el.value)
.join(', ')
};
console.log(guestData)
// отправка на /api/update с Authorization
// const updateResponse = await fetch('/api/update', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// 'Authorization': `Bearer ${token}`
// },
// body: JSON.stringify(guestData)
// });
try {
const response = await fetch('/api/update', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // ← токен идёт через cookie
body: JSON.stringify(guestData)
});
// if (!updateResponse.ok) {
// throw new Error('Ошибка при отправке формы');
// }
if (!response.ok) {
const err = await response.json();
throw new Error(JSON.stringify(err.detail || 'Ошибка при отправке'));
}
// const updateData = await updateResponse.json();
// console.log('Форма успешно отправлена:', updateData);
const data = await response.json();
console.log('Успешно:', data);
alert('Данные сохранены!');
// } catch (err) {
// console.error(err);
// alert('Ошибка: ' + err.message);
// }
} catch (err) {
console.error(err);
alert('Ошибка: ' + err.message);
}
});
});
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -1
View File
@@ -469,8 +469,10 @@
<button type="submit" class="answer_btn" id="bsubmit">
Подтвердить участие
</button>
</form>
<button type="logout" class="answer_btn" id="logoutForm">
Выйти
</button>
</div>
</section>
</main>