mirror of
https://github.com/wowlikon/LiB.git
synced 2026-02-04 04:31:09 +00:00
Добавление временной авторизации
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
$(() => {
|
$(() => {
|
||||||
$("#login-tab").on("click", function () {
|
$("#login-tab").on("click", function () {
|
||||||
$("#login-tab")
|
$(this)
|
||||||
.removeClass("text-gray-400 hover:text-gray-600")
|
.removeClass("text-gray-400 hover:text-gray-600")
|
||||||
.addClass("text-gray-700 bg-gray-50 border-b-2 border-gray-500");
|
.addClass("text-gray-700 bg-gray-50 border-b-2 border-gray-500");
|
||||||
$("#register-tab")
|
$("#register-tab")
|
||||||
@@ -12,7 +12,7 @@ $(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#register-tab").on("click", function () {
|
$("#register-tab").on("click", function () {
|
||||||
$("#register-tab")
|
$(this)
|
||||||
.removeClass("text-gray-400 hover:text-gray-600")
|
.removeClass("text-gray-400 hover:text-gray-600")
|
||||||
.addClass("text-gray-700 bg-gray-50 border-b-2 border-gray-500");
|
.addClass("text-gray-700 bg-gray-50 border-b-2 border-gray-500");
|
||||||
$("#login-tab")
|
$("#login-tab")
|
||||||
@@ -23,6 +23,15 @@ $(() => {
|
|||||||
$("#login-form").addClass("hidden");
|
$("#login-form").addClass("hidden");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("body").on("click", ".toggle-password", function () {
|
||||||
|
const $btn = $(this);
|
||||||
|
const $input = $btn.siblings("input");
|
||||||
|
|
||||||
|
const isPassword = $input.attr("type") === "password";
|
||||||
|
$input.attr("type", isPassword ? "text" : "password");
|
||||||
|
$btn.find("svg").toggleClass("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
$("#register-password").on("input", function () {
|
$("#register-password").on("input", function () {
|
||||||
const password = $(this).val();
|
const password = $(this).val();
|
||||||
let strength = 0;
|
let strength = 0;
|
||||||
@@ -74,6 +83,7 @@ $(() => {
|
|||||||
const username = $("#login-username").val();
|
const username = $("#login-username").val();
|
||||||
const password = $("#login-password").val();
|
const password = $("#login-password").val();
|
||||||
|
|
||||||
|
const rememberMe = $("#remember-me").prop("checked");
|
||||||
$submitBtn.prop("disabled", true).text("Вход...");
|
$submitBtn.prop("disabled", true).text("Вход...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -82,10 +92,17 @@ $(() => {
|
|||||||
formData.append("password", password);
|
formData.append("password", password);
|
||||||
|
|
||||||
const data = await Api.postForm("/api/auth/token", formData);
|
const data = await Api.postForm("/api/auth/token", formData);
|
||||||
|
const storage = rememberMe ? localStorage : sessionStorage;
|
||||||
|
|
||||||
|
storage.setItem("access_token", data.access_token);
|
||||||
|
if (rememberMe && data.refresh_token) {
|
||||||
|
storage.setItem("refresh_token", data.refresh_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
const otherStorage = rememberMe ? sessionStorage : localStorage;
|
||||||
|
otherStorage.removeItem("access_token");
|
||||||
|
otherStorage.removeItem("refresh_token");
|
||||||
|
|
||||||
localStorage.setItem("access_token", data.access_token);
|
|
||||||
if (data.refresh_token)
|
|
||||||
localStorage.setItem("refresh_token", data.refresh_token);
|
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Utils.showToast(error.message || "Ошибка входа", "error");
|
Utils.showToast(error.message || "Ошибка входа", "error");
|
||||||
@@ -117,7 +134,11 @@ $(() => {
|
|||||||
try {
|
try {
|
||||||
await Api.post("/api/auth/register", userData);
|
await Api.post("/api/auth/register", userData);
|
||||||
Utils.showToast("Регистрация успешна! Войдите в систему.", "success");
|
Utils.showToast("Регистрация успешна! Войдите в систему.", "success");
|
||||||
setTimeout(() => window.location.reload(), 1500);
|
|
||||||
|
setTimeout(() => {
|
||||||
|
$("#login-tab").trigger("click");
|
||||||
|
$("#login-username").val(userData.username);
|
||||||
|
}, 1500);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = error.message;
|
let msg = error.message;
|
||||||
if (Array.isArray(error.detail)) {
|
if (Array.isArray(error.detail)) {
|
||||||
@@ -128,11 +149,4 @@ $(() => {
|
|||||||
$submitBtn.prop("disabled", false).text("Зарегистрироваться");
|
$submitBtn.prop("disabled", false).text("Зарегистрироваться");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("body").on("click", ".toggle-password", function () {
|
|
||||||
const $input = $(this).siblings("input");
|
|
||||||
const type = $input.attr("type") === "password" ? "text" : "password";
|
|
||||||
$input.attr("type", type);
|
|
||||||
$(this).find("svg").toggleClass("hidden");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ $(document).ready(() => {
|
|||||||
document.title = `LiB - ${author.name}`;
|
document.title = `LiB - ${author.name}`;
|
||||||
renderAuthor(author);
|
renderAuthor(author);
|
||||||
renderBooks(author.books);
|
renderBooks(author.books);
|
||||||
if (window.canManage) {
|
if (window.canManage()) {
|
||||||
$("#edit-author-btn")
|
$("#edit-author-btn")
|
||||||
.attr("href", `/author/${author.id}/edit`)
|
.attr("href", `/author/${author.id}/edit`)
|
||||||
.removeClass("hidden");
|
.removeClass("hidden");
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ $(document).ready(() => {
|
|||||||
currentBook = book;
|
currentBook = book;
|
||||||
document.title = `LiB - ${book.title}`;
|
document.title = `LiB - ${book.title}`;
|
||||||
renderBook(book);
|
renderBook(book);
|
||||||
if (window.canManage) {
|
if (window.canManage()) {
|
||||||
$("#edit-book-btn")
|
$("#edit-book-btn")
|
||||||
.attr("href", `/book/${book.id}/edit`)
|
.attr("href", `/book/${book.id}/edit`)
|
||||||
.removeClass("hidden");
|
.removeClass("hidden");
|
||||||
@@ -123,7 +123,7 @@ $(document).ready(() => {
|
|||||||
$container.empty();
|
$container.empty();
|
||||||
const config = getStatusConfig(book.status);
|
const config = getStatusConfig(book.status);
|
||||||
|
|
||||||
if (window.canManage) {
|
if (window.canManage()) {
|
||||||
const $dropdownHTML = $(`
|
const $dropdownHTML = $(`
|
||||||
<div class="relative inline-block text-left w-full md:w-auto">
|
<div class="relative inline-block text-left w-full md:w-auto">
|
||||||
<button id="status-toggle-btn" type="button" class="w-full justify-center md:w-auto inline-flex items-center px-4 py-2 rounded-full text-sm font-semibold transition-all shadow-sm ${config.bgClass} ${config.textClass} hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400">
|
<button id="status-toggle-btn" type="button" class="w-full justify-center md:w-auto inline-flex items-center px-4 py-2 rounded-full text-sm font-semibold transition-all shadow-sm ${config.bgClass} ${config.textClass} hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400">
|
||||||
|
|||||||
@@ -403,7 +403,7 @@ $(document).ready(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function showAdminControls() {
|
function showAdminControls() {
|
||||||
if (window.canManage) {
|
if (window.canManage()) {
|
||||||
$("#admin-actions").removeClass("hidden");
|
$("#admin-actions").removeClass("hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
if (!window.canManage) return;
|
if (!window.canManage()) return;
|
||||||
setTimeout(() => window.canManage, 100);
|
setTimeout(() => window.canManage, 100);
|
||||||
|
|
||||||
const $form = $("#create-author-form");
|
const $form = $("#create-author-form");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
if (!window.canManage) return;
|
if (!window.canManage()) return;
|
||||||
setTimeout(() => window.canManage, 100);
|
setTimeout(() => window.canManage, 100);
|
||||||
|
|
||||||
let allAuthors = [];
|
let allAuthors = [];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
if (!window.canManage) return;
|
if (!window.canManage()) return;
|
||||||
setTimeout(() => window.canManage, 100);
|
setTimeout(() => window.canManage, 100);
|
||||||
|
|
||||||
const $form = $("#create-genre-form");
|
const $form = $("#create-genre-form");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
if (!window.canManage) return;
|
if (!window.canManage()) return;
|
||||||
setTimeout(() => window.canManage, 100);
|
setTimeout(() => window.canManage, 100);
|
||||||
|
|
||||||
const pathParts = window.location.pathname.split("/");
|
const pathParts = window.location.pathname.split("/");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
if (!window.canManage) {
|
if (!window.canManage()) {
|
||||||
Utils.showToast("У вас недостаточно прав", "error");
|
Utils.showToast("У вас недостаточно прав", "error");
|
||||||
setTimeout(() => (window.location.href = "/"), 1500);
|
setTimeout(() => (window.location.href = "/"), 1500);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
const token = localStorage.getItem("access_token");
|
const token = StorageHelper.get("access_token");
|
||||||
if (!token) {
|
if (!token) {
|
||||||
window.location.href = "/auth";
|
window.location.href = "/auth";
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,11 +1,74 @@
|
|||||||
|
@keyframes shake {
|
||||||
|
0%,
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
10%,
|
||||||
|
30%,
|
||||||
|
50%,
|
||||||
|
70%,
|
||||||
|
90% {
|
||||||
|
transform: translateX(-5px);
|
||||||
|
}
|
||||||
|
20%,
|
||||||
|
40%,
|
||||||
|
60%,
|
||||||
|
80% {
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dropdownFade {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-soft {
|
||||||
|
0%,
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Novem";
|
font-family: "Novem";
|
||||||
src: url("novem.regular.ttf") format("truetype");
|
src: url(novem.regular.ttf) format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Dited";
|
font-family: "Dited";
|
||||||
src: url("dited.regular.ttf") format("truetype");
|
src: url(dited.regular.ttf) format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -13,9 +76,9 @@ h1 {
|
|||||||
letter-spacing: 10px;
|
letter-spacing: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2,
|
|
||||||
.book-id,
|
.book-id,
|
||||||
.book-status,
|
.book-status,
|
||||||
|
h2,
|
||||||
nav ul li a {
|
nav ul li a {
|
||||||
font-family: "Dited", sans-serif;
|
font-family: "Dited", sans-serif;
|
||||||
letter-spacing: 2.5px;
|
letter-spacing: 2.5px;
|
||||||
@@ -73,7 +136,7 @@ nav ul li a {
|
|||||||
top: 6px;
|
top: 6px;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border: solid white;
|
border: solid #fff;
|
||||||
border-width: 0 2px 2px 0;
|
border-width: 0 2px 2px 0;
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
@@ -96,17 +159,6 @@ button:disabled {
|
|||||||
animation: fadeIn 0.3s ease-in-out;
|
animation: fadeIn 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex.justify-center.gap-4 button:hover {
|
.flex.justify-center.gap-4 button:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
@@ -115,30 +167,10 @@ button:disabled {
|
|||||||
animation: shake 0.5s ease-in-out;
|
animation: shake 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes shake {
|
#req-digit,
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
10%,
|
|
||||||
30%,
|
|
||||||
50%,
|
|
||||||
70%,
|
|
||||||
90% {
|
|
||||||
transform: translateX(-5px);
|
|
||||||
}
|
|
||||||
20%,
|
|
||||||
40%,
|
|
||||||
60%,
|
|
||||||
80% {
|
|
||||||
transform: translateX(5px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#req-length,
|
#req-length,
|
||||||
#req-upper,
|
|
||||||
#req-lower,
|
#req-lower,
|
||||||
#req-digit {
|
#req-upper {
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,17 +185,6 @@ button:disabled {
|
|||||||
animation: fadeIn 0.3s ease-in-out;
|
animation: fadeIn 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#login-tab,
|
#login-tab,
|
||||||
#register-tab {
|
#register-tab {
|
||||||
font-family: "Dited", sans-serif;
|
font-family: "Dited", sans-serif;
|
||||||
@@ -175,17 +196,6 @@ button:disabled {
|
|||||||
animation: dropdownFade 0.1s ease-out;
|
animation: dropdownFade 0.1s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes dropdownFade {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-5px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#user-arrow.rotate-180 {
|
#user-arrow.rotate-180 {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
@@ -198,16 +208,6 @@ button:disabled {
|
|||||||
min-width: 140px;
|
min-width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse-soft {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-pulse-soft {
|
.animate-pulse-soft {
|
||||||
animation: pulse-soft 2s ease-in-out infinite;
|
animation: pulse-soft 2s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
@@ -216,32 +216,21 @@ button:disabled {
|
|||||||
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
|
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-fade-in-up {
|
.animate-fade-in-up {
|
||||||
animation: fadeInUp 0.5s ease-out forwards;
|
animation: fadeInUp 0.5s ease-out forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card:hover svg {
|
.stat-card:hover svg {
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card svg {
|
.stat-card svg,
|
||||||
|
.stat-card:hover svg {
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gradient-text {
|
.gradient-text {
|
||||||
background: linear-gradient(135deg, #374151 0%, #6b7280 100%);
|
background: linear-gradient(135deg, #374151 0, #6b7280 100%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
|
const StorageHelper = {
|
||||||
|
get: (key) => {
|
||||||
|
return localStorage.getItem(key) || sessionStorage.getItem(key);
|
||||||
|
},
|
||||||
|
getCurrentStorage: () => {
|
||||||
|
return localStorage.getItem("refresh_token")
|
||||||
|
? localStorage
|
||||||
|
: sessionStorage;
|
||||||
|
},
|
||||||
|
clearAll: () => {
|
||||||
|
localStorage.removeItem("access_token");
|
||||||
|
localStorage.removeItem("refresh_token");
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
sessionStorage.removeItem("access_token");
|
||||||
|
sessionStorage.removeItem("refresh_token");
|
||||||
|
sessionStorage.removeItem("user");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const Utils = {
|
const Utils = {
|
||||||
escapeHtml: (text) => {
|
escapeHtml: (text) => {
|
||||||
if (!text) return "";
|
if (!text) return "";
|
||||||
@@ -59,7 +78,8 @@ const Api = {
|
|||||||
|
|
||||||
async request(endpoint, options = {}) {
|
async request(endpoint, options = {}) {
|
||||||
const fullUrl = this.getBaseUrl() + endpoint;
|
const fullUrl = this.getBaseUrl() + endpoint;
|
||||||
const token = localStorage.getItem("access_token");
|
const token = StorageHelper.get("access_token");
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...options.headers,
|
...options.headers,
|
||||||
@@ -74,11 +94,13 @@ const Api = {
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(fullUrl, config);
|
const response = await fetch(fullUrl, config);
|
||||||
|
|
||||||
if (response.status === 401) {
|
const isLoginRequest = endpoint.includes("/auth/token");
|
||||||
|
|
||||||
|
if (response.status === 401 && !isLoginRequest) {
|
||||||
const refreshed = await Auth.tryRefresh();
|
const refreshed = await Auth.tryRefresh();
|
||||||
if (refreshed) {
|
if (refreshed) {
|
||||||
headers["Authorization"] =
|
headers["Authorization"] =
|
||||||
`Bearer ${localStorage.getItem("access_token")}`;
|
`Bearer ${StorageHelper.get("access_token")}`;
|
||||||
const retryResponse = await fetch(fullUrl, { ...options, headers });
|
const retryResponse = await fetch(fullUrl, { ...options, headers });
|
||||||
if (retryResponse.ok) {
|
if (retryResponse.ok) {
|
||||||
return retryResponse.json();
|
return retryResponse.json();
|
||||||
@@ -90,7 +112,11 @@ const Api = {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
throw new Error(errorData.detail || `Error ${response.status}`);
|
throw new Error(
|
||||||
|
errorData.detail ||
|
||||||
|
errorData.error_description ||
|
||||||
|
`Ошибка ${response.status}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -131,16 +157,16 @@ const Api = {
|
|||||||
|
|
||||||
const Auth = {
|
const Auth = {
|
||||||
logout: () => {
|
logout: () => {
|
||||||
localStorage.removeItem("access_token");
|
StorageHelper.clearAll();
|
||||||
localStorage.removeItem("refresh_token");
|
|
||||||
localStorage.removeItem("user");
|
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
},
|
},
|
||||||
|
|
||||||
tryRefresh: async () => {
|
tryRefresh: async () => {
|
||||||
const refreshToken = localStorage.getItem("refresh_token");
|
const refreshToken = StorageHelper.get("refresh_token");
|
||||||
if (!refreshToken) return false;
|
if (!refreshToken) return false;
|
||||||
|
|
||||||
|
const activeStorage = StorageHelper.getCurrentStorage();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/auth/refresh", {
|
const response = await fetch("/api/auth/refresh", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -150,8 +176,8 @@ const Auth = {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
localStorage.setItem("access_token", data.access_token);
|
activeStorage.setItem("access_token", data.access_token);
|
||||||
localStorage.setItem("refresh_token", data.refresh_token);
|
activeStorage.setItem("refresh_token", data.refresh_token);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -161,14 +187,17 @@ const Auth = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
init: async () => {
|
init: async () => {
|
||||||
const token = localStorage.getItem("access_token");
|
const token = StorageHelper.get("access_token");
|
||||||
const refreshToken = localStorage.getItem("refresh_token");
|
const refreshToken = StorageHelper.get("refresh_token");
|
||||||
|
|
||||||
if (!token && !refreshToken) {
|
if (!token && !refreshToken) {
|
||||||
localStorage.removeItem("user");
|
localStorage.removeItem("user");
|
||||||
|
sessionStorage.removeItem("user");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const activeStorage = StorageHelper.getCurrentStorage();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response = await fetch("/api/auth/me", {
|
let response = await fetch("/api/auth/me", {
|
||||||
headers: { Authorization: "Bearer " + token },
|
headers: { Authorization: "Bearer " + token },
|
||||||
@@ -179,7 +208,7 @@ const Auth = {
|
|||||||
if (refreshed) {
|
if (refreshed) {
|
||||||
response = await fetch("/api/auth/me", {
|
response = await fetch("/api/auth/me", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer " + localStorage.getItem("access_token"),
|
Authorization: "Bearer " + StorageHelper.get("access_token"),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -187,7 +216,7 @@ const Auth = {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const user = await response.json();
|
const user = await response.json();
|
||||||
localStorage.setItem("user", JSON.stringify(user));
|
activeStorage.setItem("user", JSON.stringify(user));
|
||||||
document.dispatchEvent(new CustomEvent("auth:login", { detail: user }));
|
document.dispatchEvent(new CustomEvent("auth:login", { detail: user }));
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@@ -195,15 +224,13 @@ const Auth = {
|
|||||||
console.error("Auth check failed", e);
|
console.error("Auth check failed", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.removeItem("access_token");
|
StorageHelper.clearAll();
|
||||||
localStorage.removeItem("refresh_token");
|
|
||||||
localStorage.removeItem("user");
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
window.getUser = function () {
|
window.getUser = function () {
|
||||||
const userJson = localStorage.getItem("user");
|
const userJson = StorageHelper.get("user");
|
||||||
if (!userJson) return null;
|
if (!userJson) return null;
|
||||||
try {
|
try {
|
||||||
return JSON.parse(userJson);
|
return JSON.parse(userJson);
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ block content %}
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||||
onclick="togglePassword(this)"
|
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="eye-open w-5 h-5"
|
class="eye-open w-5 h-5"
|
||||||
@@ -190,7 +189,6 @@ block content %}
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||||
onclick="togglePassword(this)"
|
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="eye-open w-5 h-5"
|
class="eye-open w-5 h-5"
|
||||||
@@ -259,7 +257,6 @@ block content %}
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||||
onclick="togglePassword(this)"
|
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="eye-open w-5 h-5"
|
class="eye-open w-5 h-5"
|
||||||
|
|||||||
Reference in New Issue
Block a user