Enhance API and configuration for Telegram miniapp
- Added support for CORS origins and a new environment variable for miniapp access control. - Implemented date validation for API requests to ensure correct date formats. - Updated FastAPI app to allow access without Telegram initData for local development. - Enhanced error handling and logging for better debugging. - Added tests for API functionality and Telegram initData validation. - Updated README with new environment variable details and testing instructions. - Modified Docker and Git ignore files to include additional directories and files.
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
const accessDeniedEl = document.getElementById("accessDenied");
|
||||
const headerEl = document.querySelector(".header");
|
||||
const weekdaysEl = document.querySelector(".weekdays");
|
||||
const prevBtn = document.getElementById("prevMonth");
|
||||
const nextBtn = document.getElementById("nextMonth");
|
||||
|
||||
function isoDate(d) {
|
||||
return d.toISOString().slice(0, 10);
|
||||
@@ -33,7 +35,33 @@
|
||||
}
|
||||
|
||||
function getInitData() {
|
||||
return (window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.initData) || "";
|
||||
var fromSdk = (window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.initData) || "";
|
||||
if (fromSdk) return fromSdk;
|
||||
var hash = window.location.hash ? window.location.hash.slice(1) : "";
|
||||
if (hash.indexOf("tgWebAppData=") === 0) {
|
||||
try {
|
||||
return decodeURIComponent(hash.substring("tgWebAppData=".length));
|
||||
} catch (e) {
|
||||
return hash.substring("tgWebAppData=".length);
|
||||
}
|
||||
}
|
||||
var q = window.location.search ? new URLSearchParams(window.location.search).get("tgWebAppData") : null;
|
||||
if (q) {
|
||||
try {
|
||||
return decodeURIComponent(q);
|
||||
} catch (e) {
|
||||
return q;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function getInitDataDebug() {
|
||||
var sdk = !!(window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.initData);
|
||||
var hash = window.location.hash ? window.location.hash.slice(1) : "";
|
||||
var hashHasData = hash.indexOf("tgWebAppData=") === 0;
|
||||
var queryHasData = !!(window.location.search && new URLSearchParams(window.location.search).get("tgWebAppData"));
|
||||
return "SDK: " + (sdk ? "да" : "нет") + ", hash: " + (hashHasData ? hash.length + " симв." : "нет") + ", query: " + (queryHasData ? "да" : "нет");
|
||||
}
|
||||
|
||||
function isLocalhost() {
|
||||
@@ -49,6 +77,8 @@
|
||||
loadingEl.classList.add("hidden");
|
||||
errorEl.hidden = true;
|
||||
accessDeniedEl.hidden = false;
|
||||
var debugEl = document.getElementById("accessDeniedDebug");
|
||||
if (debugEl) debugEl.textContent = getInitDataDebug();
|
||||
}
|
||||
|
||||
function hideAccessDenied() {
|
||||
@@ -65,12 +95,23 @@
|
||||
const initData = getInitData();
|
||||
const headers = {};
|
||||
if (initData) headers["X-Telegram-Init-Data"] = initData;
|
||||
const res = await fetch(url, { headers: headers });
|
||||
if (res.status === 403) {
|
||||
throw new Error("ACCESS_DENIED");
|
||||
var controller = new AbortController();
|
||||
var timeoutId = setTimeout(function () { controller.abort(); }, 15000);
|
||||
try {
|
||||
var res = await fetch(url, { headers: headers, signal: controller.signal });
|
||||
clearTimeout(timeoutId);
|
||||
if (res.status === 403) {
|
||||
throw new Error("ACCESS_DENIED");
|
||||
}
|
||||
if (!res.ok) throw new Error("Ошибка загрузки");
|
||||
return res.json();
|
||||
} catch (e) {
|
||||
clearTimeout(timeoutId);
|
||||
if (e.name === "AbortError") {
|
||||
throw new Error("Не удалось загрузить данные. Проверьте интернет.");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
if (!res.ok) throw new Error("Ошибка загрузки");
|
||||
return res.json();
|
||||
}
|
||||
|
||||
function renderCalendar(year, month, dutiesByDate) {
|
||||
@@ -92,7 +133,7 @@
|
||||
cell.className = "day" + (isOther ? " other-month" : "") + (isToday ? " today" : "") + (dayDuties.length ? " has-duty" : "");
|
||||
cell.innerHTML =
|
||||
"<span class=\"num\">" + d.getDate() + "</span>" +
|
||||
(dayDuties.length ? "<span class=\"day-duties\">" + dayDuties.map(function (x) { return x.full_name; }).join(", ") + "</span>" : "");
|
||||
(dayDuties.length ? "<span class=\"day-duties\">" + dayDuties.map(function (x) { return escapeHtml(x.full_name); }).join(", ") + "</span>" : "");
|
||||
calendarEl.appendChild(cell);
|
||||
d.setDate(d.getDate() + 1);
|
||||
}
|
||||
@@ -151,13 +192,28 @@
|
||||
loadingEl.classList.add("hidden");
|
||||
}
|
||||
|
||||
async function loadMonth() {
|
||||
var _initData = getInitData();
|
||||
if (!_initData && !isLocalhost()) {
|
||||
showAccessDenied();
|
||||
return;
|
||||
function runWhenReady(cb) {
|
||||
if (window.Telegram && window.Telegram.WebApp) {
|
||||
if (window.Telegram.WebApp.ready) {
|
||||
window.Telegram.WebApp.ready();
|
||||
}
|
||||
if (window.Telegram.WebApp.expand) {
|
||||
window.Telegram.WebApp.expand();
|
||||
}
|
||||
setTimeout(cb, 0);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
function setNavEnabled(enabled) {
|
||||
if (prevBtn) prevBtn.disabled = !enabled;
|
||||
if (nextBtn) nextBtn.disabled = !enabled;
|
||||
}
|
||||
|
||||
async function loadMonth() {
|
||||
hideAccessDenied();
|
||||
setNavEnabled(false);
|
||||
loadingEl.classList.remove("hidden");
|
||||
errorEl.hidden = true;
|
||||
const from = isoDate(firstDayOfMonth(current));
|
||||
@@ -170,12 +226,19 @@
|
||||
} catch (e) {
|
||||
if (e.message === "ACCESS_DENIED") {
|
||||
showAccessDenied();
|
||||
setNavEnabled(true);
|
||||
if (window.Telegram && window.Telegram.WebApp && !window._initDataRetried) {
|
||||
window._initDataRetried = true;
|
||||
setTimeout(loadMonth, 1200);
|
||||
}
|
||||
return;
|
||||
}
|
||||
showError(e.message || "Не удалось загрузить данные.");
|
||||
setNavEnabled(true);
|
||||
return;
|
||||
}
|
||||
loadingEl.classList.add("hidden");
|
||||
setNavEnabled(true);
|
||||
}
|
||||
|
||||
document.getElementById("prevMonth").addEventListener("click", function () {
|
||||
@@ -187,5 +250,5 @@
|
||||
loadMonth();
|
||||
});
|
||||
|
||||
loadMonth();
|
||||
runWhenReady(loadMonth);
|
||||
})();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<div class="access-denied" id="accessDenied" hidden>
|
||||
<p>Доступ запрещён.</p>
|
||||
<p class="muted">Откройте календарь из Telegram.</p>
|
||||
<p class="debug" id="accessDeniedDebug"></p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
|
||||
@@ -166,6 +166,12 @@ body {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.access-denied .debug {
|
||||
font-size: 0.75rem;
|
||||
margin-top: 12px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.access-denied[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user