mirror of
https://github.com/EDeev/worldlang.git
synced 2026-10-07 20:49:41 +03:00
Экранирование данных из API перед вставкой в HTML
Названия и описания курсов, имена репетиторов, адреса и описания мест на карте вставлялись в разметку как есть — запись с HTML в общем учебном API выполнилась бы у каждого посетителя. Добавлена esc() в utils.js, через неё проходят все подстановки данных в HTML-шаблонах app.js, account.js и map.js.
This commit is contained in:
parent
ec60a92004
commit
e94e27267c
4 changed files with 47 additions and 36 deletions
|
|
@ -118,13 +118,13 @@ function renderOrders() {
|
|||
c => c.id === order.course_id
|
||||
);
|
||||
orderName = course ? course.name :
|
||||
`Курс #${order.course_id}`;
|
||||
`Курс #${esc(order.course_id)}`;
|
||||
} else if (order.tutor_id && order.tutor_id > 0) {
|
||||
const tutor = AccountState.tutors.find(
|
||||
t => t.id === order.tutor_id
|
||||
);
|
||||
orderName = tutor ? `Репетитор: ${tutor.name}` :
|
||||
`Репетитор #${order.tutor_id}`;
|
||||
`Репетитор #${esc(order.tutor_id)}`;
|
||||
}
|
||||
|
||||
const orderDate = formatDateTimeWithoutSeconds(
|
||||
|
|
@ -133,22 +133,22 @@ function renderOrders() {
|
|||
);
|
||||
|
||||
tr.innerHTML = `
|
||||
<td>${orderNumber}</td>
|
||||
<td>${orderName}</td>
|
||||
<td>${orderDate}</td>
|
||||
<td>${esc(orderNumber)}</td>
|
||||
<td>${esc(orderName)}</td>
|
||||
<td>${esc(orderDate)}</td>
|
||||
<td>${formatPrice(order.price)}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button class="btn btn-info view-order-btn"
|
||||
data-order-id="${order.id}">
|
||||
data-order-id="${esc(order.id)}">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
<button class="btn btn-warning edit-order-btn"
|
||||
data-order-id="${order.id}">
|
||||
data-order-id="${esc(order.id)}">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger delete-order-btn"
|
||||
data-order-id="${order.id}">
|
||||
data-order-id="${esc(order.id)}">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -254,7 +254,7 @@ function viewOrderDetails(orderId) {
|
|||
if (course) {
|
||||
orderTitle = course.name;
|
||||
teacherInfo = `<p><strong>Преподаватель:</strong>
|
||||
${course.teacher}</p>`;
|
||||
${esc(course.teacher)}</p>`;
|
||||
}
|
||||
} else if (order.tutor_id && order.tutor_id > 0) {
|
||||
const tutor = AccountState.tutors.find(
|
||||
|
|
@ -284,7 +284,7 @@ function viewOrderDetails(orderId) {
|
|||
options.push('Доступ к интерактивной онлайн-платформе (+50%)');
|
||||
|
||||
const optionsBadges = options.map(opt =>
|
||||
`<span class="badge bg-secondary me-1 mb-1">${opt}</span>`
|
||||
`<span class="badge bg-secondary me-1 mb-1">${esc(opt)}</span>`
|
||||
).join('');
|
||||
|
||||
const contactData = ContactDataStorage.get(order.id);
|
||||
|
|
@ -294,16 +294,16 @@ function viewOrderDetails(orderId) {
|
|||
contactInfo = `
|
||||
<hr>
|
||||
<h6>Контактные данные:</h6>
|
||||
<p><strong>Имя:</strong> ${contactData.name}</p>
|
||||
<p><strong>Телефон:</strong> ${contactData.phone}</p>
|
||||
<p><strong>Email:</strong> ${contactData.email}</p>
|
||||
<p><strong>Имя:</strong> ${esc(contactData.name)}</p>
|
||||
<p><strong>Телефон:</strong> ${esc(contactData.phone)}</p>
|
||||
<p><strong>Email:</strong> ${esc(contactData.email)}</p>
|
||||
${contactData.message ?
|
||||
`<p><strong>Сообщение:</strong> ${contactData.message}</p>`
|
||||
: ''}
|
||||
`;
|
||||
}
|
||||
|
||||
let detailsHTML = `<h5>${orderTitle}</h5>${teacherInfo}`;
|
||||
let detailsHTML = `<h5>${esc(orderTitle)}</h5>${teacherInfo}`;
|
||||
let priceLabel = '';
|
||||
|
||||
if (order.course_id && order.course_id > 0) {
|
||||
|
|
@ -312,9 +312,9 @@ function viewOrderDetails(orderId) {
|
|||
${formatDate(order.date_start)}</p>
|
||||
<p><strong>Время:</strong> ${formatTime(order.time_start)}</p>
|
||||
<p><strong>Продолжительность:</strong>
|
||||
${order.duration} часов</p>
|
||||
${esc(order.duration)} часов</p>
|
||||
<p><strong>Количество студентов:</strong>
|
||||
${order.persons}</p>
|
||||
${esc(order.persons)}</p>
|
||||
${options.length > 0 ?
|
||||
`<p><strong>Выбранные опции:</strong><br>${optionsBadges}</p>`
|
||||
: ''}
|
||||
|
|
@ -328,9 +328,9 @@ function viewOrderDetails(orderId) {
|
|||
}
|
||||
|
||||
detailsHTML += `
|
||||
${contactInfo}
|
||||
${esc(contactInfo)}
|
||||
<hr>
|
||||
<h5>${priceLabel}</h5>
|
||||
<h5>${esc(priceLabel)}</h5>
|
||||
`;
|
||||
|
||||
content.innerHTML = detailsHTML;
|
||||
|
|
|
|||
12
js/app.js
12
js/app.js
|
|
@ -163,7 +163,7 @@ function renderCourses() {
|
|||
|
||||
item.innerHTML = `
|
||||
<div class="course-item-header">
|
||||
<h5 class="course-item-title">${course.name}</h5>
|
||||
<h5 class="course-item-title">${esc(course.name)}</h5>
|
||||
<span class="badge level-badge
|
||||
${getLevelBadgeClass(course.level)}">
|
||||
${getLevelText(course.level)}
|
||||
|
|
@ -175,12 +175,12 @@ function renderCourses() {
|
|||
<div class="course-item-details">
|
||||
<div>
|
||||
<i class="bi bi-person"></i>
|
||||
<span>${course.teacher}</span>
|
||||
<span>${esc(course.teacher)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<i class="bi bi-clock"></i>
|
||||
<span>${course.total_length} недель,
|
||||
${course.week_length} ч/нед</span>
|
||||
<span>${esc(course.total_length)} недель,
|
||||
${esc(course.week_length)} ч/нед</span>
|
||||
</div>
|
||||
<div>
|
||||
<i class="bi bi-cash"></i>
|
||||
|
|
@ -582,13 +582,13 @@ function renderTutors() {
|
|||
<i class="bi bi-person-circle"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td>${tutor.name}</td>
|
||||
<td>${esc(tutor.name)}</td>
|
||||
<td><span class="badge level-badge
|
||||
${getLevelBadgeClass(tutor.language_level)}">
|
||||
${getLevelText(tutor.language_level)}
|
||||
</span></td>
|
||||
<td>${tutor.languages_offered.join(', ')}</td>
|
||||
<td>${tutor.work_experience} лет</td>
|
||||
<td>${esc(tutor.work_experience)} лет</td>
|
||||
<td>${formatPrice(tutor.price_per_hour)}/час</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary select-tutor-btn">
|
||||
|
|
|
|||
20
js/map.js
20
js/map.js
|
|
@ -109,12 +109,12 @@ function initMap() {
|
|||
const placemark = new ymaps.Placemark(
|
||||
resource.coords,
|
||||
{
|
||||
balloonContentHeader: `<strong>${resource.name}</strong>`,
|
||||
balloonContentHeader: `<strong>${esc(resource.name)}</strong>`,
|
||||
balloonContentBody: `
|
||||
<p class="mb-1"><i class="bi bi-geo-alt"></i> ${resource.address}</p>
|
||||
<p class="mb-1"><i class="bi bi-clock"></i> ${resource.hours}</p>
|
||||
<p class="mb-1"><i class="bi bi-telephone"></i> ${resource.phone}</p>
|
||||
<p class="mb-0"><i class="bi bi-info-circle"></i> ${resource.description}</p>
|
||||
<p class="mb-1"><i class="bi bi-geo-alt"></i> ${esc(resource.address)}</p>
|
||||
<p class="mb-1"><i class="bi bi-clock"></i> ${esc(resource.hours)}</p>
|
||||
<p class="mb-1"><i class="bi bi-telephone"></i> ${esc(resource.phone)}</p>
|
||||
<p class="mb-0"><i class="bi bi-info-circle"></i> ${esc(resource.description)}</p>
|
||||
`,
|
||||
hintContent: resource.name
|
||||
},
|
||||
|
|
@ -130,11 +130,11 @@ function initMap() {
|
|||
const item = document.createElement('div');
|
||||
item.className = 'resource-item';
|
||||
item.innerHTML = `
|
||||
<h6>${resource.name}</h6>
|
||||
<p class="mb-1"><i class="bi bi-geo-alt me-1"></i>${resource.address}</p>
|
||||
<p class="mb-1"><i class="bi bi-clock me-1"></i>${resource.hours}</p>
|
||||
<p class="mb-1"><i class="bi bi-telephone me-1"></i>${resource.phone}</p>
|
||||
<p class="mb-0 text-muted small">${resource.description}</p>
|
||||
<h6>${esc(resource.name)}</h6>
|
||||
<p class="mb-1"><i class="bi bi-geo-alt me-1"></i>${esc(resource.address)}</p>
|
||||
<p class="mb-1"><i class="bi bi-clock me-1"></i>${esc(resource.hours)}</p>
|
||||
<p class="mb-1"><i class="bi bi-telephone me-1"></i>${esc(resource.phone)}</p>
|
||||
<p class="mb-0 text-muted small">${esc(resource.description)}</p>
|
||||
`;
|
||||
|
||||
item.addEventListener('click', () => {
|
||||
|
|
|
|||
15
js/utils.js
15
js/utils.js
|
|
@ -1,3 +1,14 @@
|
|||
// Экранирование данных перед вставкой в HTML (данные приходят из общего учебного API);
|
||||
// utils.js подключается раньше app.js, account.js и map.js, поэтому esc() доступна во всех них
|
||||
function esc(value) {
|
||||
return String(value ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
// Показать уведомление с автоматическим удалением
|
||||
function showNotification(message, type = 'info') {
|
||||
const notificationArea = document.getElementById('notificationArea');
|
||||
|
|
@ -24,8 +35,8 @@ function showNotification(message, type = 'info') {
|
|||
notification.className = `alert ${alertClass} alert-dismissible
|
||||
fade show notification`;
|
||||
notification.innerHTML = `
|
||||
<i class="bi ${iconClass} me-2"></i>
|
||||
${message}
|
||||
<i class="bi ${esc(iconClass)} me-2"></i>
|
||||
${esc(message)}
|
||||
<button type="button" class="btn-close"
|
||||
data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue