Merge pull request 'production' (#7) from production into main
This commit is contained in:
commit
8153b08690
117
build.ipynb
117
build.ipynb
@ -775,9 +775,10 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"[Service]\n",
|
"[Service]\n",
|
||||||
"WorkingDirectory=/app/production\n",
|
"WorkingDirectory=/app/production\n",
|
||||||
"ExecStart=/app/production/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30081 --workers 8\n",
|
"ExecStart=/app/production/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30081 --workers 3\n",
|
||||||
"Restart=always\n",
|
"Restart=always\n",
|
||||||
"EnvironmentFile=/app/production/env\n",
|
"EnvironmentFile=/app/production/env\n",
|
||||||
|
"CPUWeight=60\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Install]\n",
|
"[Install]\n",
|
||||||
"WantedBy=default.target\n",
|
"WantedBy=default.target\n",
|
||||||
@ -798,23 +799,23 @@
|
|||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"%%bash\n",
|
"# %%bash\n",
|
||||||
"ssh kultmost 'tee /etc/systemd/system/fastapi.service >/dev/null' <<'EOF'\n",
|
"# ssh kultmost 'tee /etc/systemd/system/fastapi.service >/dev/null' <<'EOF'\n",
|
||||||
"[Unit]\n",
|
"# [Unit]\n",
|
||||||
"Description=FastAPI prod service\n",
|
"# Description=FastAPI prod service\n",
|
||||||
"After=network.target\n",
|
"# After=network.target\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Service]\n",
|
"# [Service]\n",
|
||||||
"WorkingDirectory=/app/production\n",
|
"# WorkingDirectory=/app/production\n",
|
||||||
"ExecStart=/app/production/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30080 --workers 8\n",
|
"# ExecStart=/app/production/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30080 --workers 8\n",
|
||||||
"Restart=always\n",
|
"# Restart=always\n",
|
||||||
"EnvironmentFile=/app/production/env\n",
|
"# EnvironmentFile=/app/production/env\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Install]\n",
|
"# [Install]\n",
|
||||||
"WantedBy=default.target\n",
|
"# WantedBy=default.target\n",
|
||||||
"EOF\n",
|
"# EOF\n",
|
||||||
"\n",
|
"\n",
|
||||||
"ssh kultmost 'systemctl daemon-reload && systemctl enable --now fastapi.service && systemctl status --no-pager -l fastapi.service'\n"
|
"# ssh kultmost 'systemctl daemon-reload && systemctl enable --now fastapi.service && systemctl status --no-pager -l fastapi.service'\n"
|
||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
@ -837,23 +838,23 @@
|
|||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"%%bash\n",
|
"# %%bash\n",
|
||||||
"ssh kultmost 'tee /etc/systemd/system/staging.service >/dev/null' <<'EOF'\n",
|
"# ssh kultmost 'tee /etc/systemd/system/staging.service >/dev/null' <<'EOF'\n",
|
||||||
"[Unit]\n",
|
"# [Unit]\n",
|
||||||
"Description=FastAPI stag service\n",
|
"# Description=FastAPI stag service\n",
|
||||||
"After=network.target\n",
|
"# After=network.target\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Service]\n",
|
"# [Service]\n",
|
||||||
"WorkingDirectory=/app/staging\n",
|
"# WorkingDirectory=/app/staging\n",
|
||||||
"ExecStart=/app/staging/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30082 --reload\n",
|
"# ExecStart=/app/staging/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30082 --reload\n",
|
||||||
"Restart=always\n",
|
"# Restart=always\n",
|
||||||
"EnvironmentFile=/app/staging/env\n",
|
"# EnvironmentFile=/app/staging/env\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Install]\n",
|
"# [Install]\n",
|
||||||
"WantedBy=default.target\n",
|
"# WantedBy=default.target\n",
|
||||||
"EOF\n",
|
"# EOF\n",
|
||||||
"\n",
|
"\n",
|
||||||
"ssh kultmost 'systemctl daemon-reload && systemctl enable --now staging.service && systemctl status --no-pager -l staging.service'\n"
|
"# ssh kultmost 'systemctl daemon-reload && systemctl enable --now staging.service && systemctl status --no-pager -l staging.service'\n"
|
||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
@ -876,21 +877,21 @@
|
|||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"%%bash\n",
|
"# %%bash\n",
|
||||||
"'tee /etc/systemd/system/staging.service >/dev/null' <<'EOF'\n",
|
"# 'tee /etc/systemd/system/staging.service >/dev/null' <<'EOF'\n",
|
||||||
"[Unit]\n",
|
"# [Unit]\n",
|
||||||
"Description=FastAPI stag service\n",
|
"# Description=FastAPI stag service\n",
|
||||||
"After=network.target\n",
|
"# After=network.target\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Service]\n",
|
"# [Service]\n",
|
||||||
"WorkingDirectory=$pwd\n",
|
"# WorkingDirectory=$pwd\n",
|
||||||
"ExecStart=$pwd/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30082 --reload\n",
|
"# ExecStart=$pwd/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30082 --reload\n",
|
||||||
"Restart=always\n",
|
"# Restart=always\n",
|
||||||
"EnvironmentFile=$pwd/env\n",
|
"# EnvironmentFile=$pwd/env\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Install]\n",
|
"# [Install]\n",
|
||||||
"WantedBy=default.target\n",
|
"# WantedBy=default.target\n",
|
||||||
"EOF"
|
"# EOF"
|
||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
@ -905,23 +906,23 @@
|
|||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"%%bash\n",
|
"# %%bash\n",
|
||||||
"ssh kultmost 'tee /etc/systemd/system/staging.service >/dev/null' <<'EOF'\n",
|
"# ssh kultmost 'tee /etc/systemd/system/staging.service >/dev/null' <<'EOF'\n",
|
||||||
"[Unit]\n",
|
"# [Unit]\n",
|
||||||
"Description=FastAPI stag service\n",
|
"# Description=FastAPI stag service\n",
|
||||||
"After=network.target\n",
|
"# After=network.target\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Service]\n",
|
"# [Service]\n",
|
||||||
"WorkingDirectory=/app/staging\n",
|
"# WorkingDirectory=/app/staging\n",
|
||||||
"ExecStart=/app/staging/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30082 --reload\n",
|
"# ExecStart=/app/staging/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 30082 --reload\n",
|
||||||
"Restart=always\n",
|
"# Restart=always\n",
|
||||||
"EnvironmentFile=/app/staging/env\n",
|
"# EnvironmentFile=/app/staging/env\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[Install]\n",
|
"# [Install]\n",
|
||||||
"WantedBy=default.target\n",
|
"# WantedBy=default.target\n",
|
||||||
"EOF\n",
|
"# EOF\n",
|
||||||
"\n",
|
"\n",
|
||||||
"ssh kultmost 'systemctl daemon-reload && systemctl enable --now staging.service && systemctl status --no-pager -l staging.service'\n"
|
"# ssh kultmost 'systemctl daemon-reload && systemctl enable --now staging.service && systemctl status --no-pager -l staging.service'\n"
|
||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
@ -974,7 +975,7 @@
|
|||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!ssh kultmost 'systemctl restart fastapi.service'"
|
"# !ssh kultmost 'systemctl restart fastapi.service'"
|
||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
@ -989,7 +990,7 @@
|
|||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!ssh kultmost 'systemctl status fastapi.service'"
|
"# !ssh kultmost 'systemctl status fastapi.service'"
|
||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
|
|||||||
19
main.ipynb
19
main.ipynb
@ -80,7 +80,6 @@
|
|||||||
"import uuid\n",
|
"import uuid\n",
|
||||||
"import bcrypt\n",
|
"import bcrypt\n",
|
||||||
"from typing import List, Any, Dict, Optional, Union\n",
|
"from typing import List, Any, Dict, Optional, Union\n",
|
||||||
"from datetime import timedelta\n",
|
|
||||||
"from urllib.parse import urlencode\n",
|
"from urllib.parse import urlencode\n",
|
||||||
"from bson import ObjectId\n",
|
"from bson import ObjectId\n",
|
||||||
"from PIL import Image\n",
|
"from PIL import Image\n",
|
||||||
@ -473,6 +472,24 @@
|
|||||||
],
|
],
|
||||||
"display_name": ".venv"
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "edb712bd",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"@app.get(\"/cron/08\", response_model=dict)\n",
|
||||||
|
"async def cron_08(background_tasks: BackgroundTasks):\n",
|
||||||
|
" async for doc in posts_collection.find({\n",
|
||||||
|
" '_id': {'$gte': ObjectId.from_datetime(datetime.now() - timedelta(days=1))},\n",
|
||||||
|
" '$or':[{'vk':[]},{'tg':[]},{'fb':[]},{'inst':[]},{'max':[]}]\n",
|
||||||
|
" }):\n",
|
||||||
|
" background_tasks.add_task(publish_social_post, bson_clear(doc))\n",
|
||||||
|
" return {'ok': True}\n"
|
||||||
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
|
|||||||
11
main.py
11
main.py
@ -19,7 +19,6 @@ from starlette.middleware.gzip import GZipMiddleware
|
|||||||
import uuid
|
import uuid
|
||||||
import bcrypt
|
import bcrypt
|
||||||
from typing import List, Any, Dict, Optional, Union
|
from typing import List, Any, Dict, Optional, Union
|
||||||
from datetime import timedelta
|
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@ -303,6 +302,16 @@ async def posts_temp(user,request):
|
|||||||
request=request, name="profile/posts.html", context={ "user": user, 'cards': data}
|
request=request, name="profile/posts.html", context={ "user": user, 'cards': data}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.get("/cron/08", response_model=dict)
|
||||||
|
async def cron_08(background_tasks: BackgroundTasks):
|
||||||
|
async for doc in posts_collection.find({
|
||||||
|
'_id': {'$gte': ObjectId.from_datetime(datetime.now() - timedelta(days=1))},
|
||||||
|
'$or':[{'vk':[]},{'tg':[]},{'fb':[]},{'inst':[]},{'max':[]}]
|
||||||
|
}):
|
||||||
|
background_tasks.add_task(publish_social_post, bson_clear(doc))
|
||||||
|
return {'ok': True}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/cron/day")
|
@app.get("/cron/day")
|
||||||
async def cron_every_day(token: str = Security(get_token)):
|
async def cron_every_day(token: str = Security(get_token)):
|
||||||
res = await competitions_col.update_many(
|
res = await competitions_col.update_many(
|
||||||
|
|||||||
BIN
static/IMG_20260904_063446.jpg
Normal file
BIN
static/IMG_20260904_063446.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
270
static/script/select.js
Normal file
270
static/script/select.js
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const root = document.getElementById('dd-modal-root') || document.body;
|
||||||
|
|
||||||
|
// Утилиты парсинга
|
||||||
|
function parseList(attr) {
|
||||||
|
if (!attr) return [];
|
||||||
|
try {
|
||||||
|
const fixed = attr.replace(/'/g, '"');
|
||||||
|
return JSON.parse(fixed);
|
||||||
|
} catch (e) {
|
||||||
|
return String(attr).split(',').map(s => s.trim()).filter(Boolean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSavedValue(el) {
|
||||||
|
const v = el.getAttribute('data-value');
|
||||||
|
if (!v) return [];
|
||||||
|
try {
|
||||||
|
return JSON.parse(v);
|
||||||
|
} catch (e) {
|
||||||
|
return v.includes(',')
|
||||||
|
? v.split(',').map(s => s.trim()).filter(Boolean)
|
||||||
|
: [v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openModalForInput(triggerEl) {
|
||||||
|
const listRaw = triggerEl.getAttribute('data-list') || '[]';
|
||||||
|
const options = parseList(listRaw);
|
||||||
|
const isRadio = triggerEl.getAttribute('data-radio') === '1' ||
|
||||||
|
triggerEl.getAttribute('data-radio') === 'true';
|
||||||
|
const takeAll = triggerEl.getAttribute('data-takeall') === '1' ||
|
||||||
|
triggerEl.getAttribute('data-takeall') === 'true';
|
||||||
|
const allowCustom = triggerEl.getAttribute('data-custom') === '1' ||
|
||||||
|
triggerEl.getAttribute('data-custom') === 'true';
|
||||||
|
|
||||||
|
const title = triggerEl.getAttribute('data-title') || 'Выберите';
|
||||||
|
const saveLabel = triggerEl.getAttribute('data-label') || 'Сохранить';
|
||||||
|
const customPlaceholder = triggerEl.getAttribute('data-custom_placeholder') || 'Добавить...';
|
||||||
|
|
||||||
|
const initial = parseSavedValue(triggerEl);
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const backdrop = document.createElement('div');
|
||||||
|
backdrop.className = 'dd-modal-backdrop';
|
||||||
|
|
||||||
|
const modal = document.createElement('div');
|
||||||
|
modal.className = 'dd-modal';
|
||||||
|
modal.innerHTML = `
|
||||||
|
<div class="dd-header">
|
||||||
|
<strong>${title}</strong>
|
||||||
|
<button class="dd-close" aria-label="Закрыть">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="dd-custom-container" style="margin-top:8px;"></div>
|
||||||
|
<div class="dd-body"></div>
|
||||||
|
<div class="dd-actions" style="margin-top:12px;">
|
||||||
|
<button class="dd-save">${saveLabel}</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
backdrop.appendChild(modal);
|
||||||
|
root.appendChild(backdrop);
|
||||||
|
|
||||||
|
const body = modal.querySelector('.dd-body');
|
||||||
|
const customContainer = modal.querySelector('.dd-custom-container');
|
||||||
|
const saveBtn = modal.querySelector('.dd-save');
|
||||||
|
const closeBtn = modal.querySelector('.dd-close');
|
||||||
|
|
||||||
|
const groupName = 'dd-group-' + Date.now() + Math.random().toString(36).slice(2);
|
||||||
|
|
||||||
|
let currentOptions = options.slice();
|
||||||
|
let selected = initial.slice();
|
||||||
|
|
||||||
|
function renderOptions() {
|
||||||
|
body.innerHTML = '';
|
||||||
|
|
||||||
|
// "Выбрать все"
|
||||||
|
if (takeAll) {
|
||||||
|
const wrapper = createOption('Выбрать все', true, groupName, isRadio);
|
||||||
|
const takeAllInput = wrapper.querySelector('input');
|
||||||
|
takeAllInput.id = 'takeAll';
|
||||||
|
takeAllInput.checked = selected.length === 0 || selected.includes('Выбрать все');
|
||||||
|
body.appendChild(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOptions.forEach(opt => {
|
||||||
|
const label = typeof opt === 'object' ? opt.name : String(opt);
|
||||||
|
const tooltip = typeof opt === 'object' ? opt.tooltip : null;
|
||||||
|
const count = typeof opt === 'object' ? opt.count : null;
|
||||||
|
|
||||||
|
|
||||||
|
const wrapper = createOption(label, false, groupName, isRadio, tooltip, count);
|
||||||
|
const input = wrapper.querySelector('input');
|
||||||
|
input.checked = selected.includes(label);
|
||||||
|
body.appendChild(wrapper);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOption(label, isTakeAll, name, isRadio, tooltip = null, count = null) {
|
||||||
|
const wrapper = document.createElement('label');
|
||||||
|
wrapper.className = 'dd-option';
|
||||||
|
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = isRadio ? 'radio' : 'checkbox';
|
||||||
|
input.name = name;
|
||||||
|
input.value = label;
|
||||||
|
input.className = 'offer-checkbox';
|
||||||
|
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.textContent = label;
|
||||||
|
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'some-class';
|
||||||
|
|
||||||
|
// count
|
||||||
|
if (count !== undefined && count !== null) {
|
||||||
|
const countNode = document.createElement('span');
|
||||||
|
countNode.textContent = count;
|
||||||
|
div.appendChild(countNode);
|
||||||
|
}
|
||||||
|
// tooltip
|
||||||
|
if (tooltip) {
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.className = 'tooltip-trigger';
|
||||||
|
img.dataset.tooltip = tooltip;
|
||||||
|
img.src = '/static/help.svg';
|
||||||
|
img.alt = 'Подсказка';
|
||||||
|
div.appendChild(img);
|
||||||
|
}
|
||||||
|
span.appendChild(div);
|
||||||
|
wrapper.append(input, span);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowCustom) {
|
||||||
|
customContainer.innerHTML = `
|
||||||
|
<div style="display:flex;gap:8px;align-items:center;flex-direction:column;">
|
||||||
|
<input type="text" class="dd-custom-input" placeholder="${customPlaceholder}"
|
||||||
|
style="flex:1;padding:6px;border:1px solid #ccc;width:100%;border-radius:4px;">
|
||||||
|
<button class="dd-custom-add" style="padding:6px 8px;width:100%;border-radius:5px;background:#5F1798;color:white;">
|
||||||
|
Добавить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const customInput = customContainer.querySelector('.dd-custom-input');
|
||||||
|
const customAdd = customContainer.querySelector('.dd-custom-add');
|
||||||
|
|
||||||
|
const addCustom = (val) => {
|
||||||
|
val = String(val).trim();
|
||||||
|
if (!val) return;
|
||||||
|
|
||||||
|
if (!currentOptions.some(o => String(o) === val && typeof o !== 'object')) {
|
||||||
|
currentOptions.push(val);
|
||||||
|
triggerEl.setAttribute('data-list', JSON.stringify(currentOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRadio) {
|
||||||
|
selected = [val];
|
||||||
|
} else if (!selected.includes(val)) {
|
||||||
|
selected.push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderOptions();
|
||||||
|
updateCheckedState();
|
||||||
|
};
|
||||||
|
|
||||||
|
customAdd.addEventListener('click', () => {
|
||||||
|
addCustom(customInput.value);
|
||||||
|
customInput.value = '';
|
||||||
|
customInput.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
customInput.addEventListener('keydown', e => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
addCustom(customInput.value);
|
||||||
|
customInput.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCheckedState() {
|
||||||
|
Array.from(body.querySelectorAll('input')).forEach(inp => {
|
||||||
|
inp.checked = selected.includes(inp.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectChecked() {
|
||||||
|
return Array.from(body.querySelectorAll('input:checked')).map(i => i.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
const result = collectChecked();
|
||||||
|
triggerEl.setAttribute('data-value', isRadio ? (result[0] ?? '') : JSON.stringify(result));
|
||||||
|
|
||||||
|
if (triggerEl.type && triggerEl.type !== 'hidden') {
|
||||||
|
triggerEl.value = isRadio ? (result[0] ?? '') : result.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
backdrop.remove();
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчики закрытия
|
||||||
|
closeBtn.addEventListener('click', closeModal);
|
||||||
|
saveBtn.addEventListener('click', closeModal);
|
||||||
|
backdrop.addEventListener('click', e => {
|
||||||
|
if (e.target === backdrop) closeModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Логика "Выбрать все"
|
||||||
|
function setupTakeAll() {
|
||||||
|
const takeAllInput = document.getElementById('takeAll');
|
||||||
|
if (!takeAllInput) return;
|
||||||
|
|
||||||
|
const allInputs = () => Array.from(body.querySelectorAll('input.offer-checkbox'));
|
||||||
|
|
||||||
|
takeAllInput.addEventListener('change', () => {
|
||||||
|
if (takeAllInput.checked) {
|
||||||
|
selected = [];
|
||||||
|
allInputs().forEach(inp => {
|
||||||
|
if (inp !== takeAllInput) inp.checked = false;
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Сброс "Выбрать все" при выборе других
|
||||||
|
body.addEventListener('change', e => {
|
||||||
|
const inp = e.target;
|
||||||
|
if (inp.type !== 'checkbox' || inp === takeAllInput) return;
|
||||||
|
|
||||||
|
if (inp.checked) {
|
||||||
|
takeAllInput.checked = false;
|
||||||
|
} else {
|
||||||
|
const anyChecked = allInputs().some(x => x !== takeAllInput && x.checked);
|
||||||
|
takeAllInput.checked = !anyChecked;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderOptions();
|
||||||
|
setupTakeAll();
|
||||||
|
updateCheckedState();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Главный обработчик
|
||||||
|
document.addEventListener('click', async function(e) {
|
||||||
|
const trigger = e.target.closest('[data-select="1"]');
|
||||||
|
if (!trigger) return;
|
||||||
|
|
||||||
|
const input = trigger.querySelector('input');
|
||||||
|
if (input) {
|
||||||
|
input.readOnly = true;
|
||||||
|
input.blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const result = await openModalForInput(trigger);
|
||||||
|
if (result && result.length) {
|
||||||
|
trigger.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
})();
|
||||||
138
static/script/share.js
Normal file
138
static/script/share.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
async function imageWithTextBlob(imageUrl, text, options = {}) {
|
||||||
|
const response = await fetch(imageUrl, {
|
||||||
|
mode: 'cors',
|
||||||
|
credentials: 'same-origin',
|
||||||
|
});
|
||||||
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||||
|
const imageBlob = await response.blob();
|
||||||
|
const imageBitmap = await createImageBitmap(imageBlob);
|
||||||
|
|
||||||
|
// OffscreenCanvas (works in modern browsers; fallback to normal canvas if needed)
|
||||||
|
const canvas = typeof OffscreenCanvas !== 'undefined'
|
||||||
|
? new OffscreenCanvas(
|
||||||
|
options.width ?? imageBitmap.width,
|
||||||
|
options.height ?? imageBitmap.height
|
||||||
|
)
|
||||||
|
: document.createElement('canvas');
|
||||||
|
|
||||||
|
const width = canvas.width ?? (options.width ?? imageBitmap.width);
|
||||||
|
const height = canvas.height ?? (options.height ?? imageBitmap.height);
|
||||||
|
|
||||||
|
if (!(canvas instanceof OffscreenCanvas)) {
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d', { alpha: true });
|
||||||
|
|
||||||
|
// Draw image
|
||||||
|
ctx.drawImage(imageBitmap, 0, 0, width, height);
|
||||||
|
|
||||||
|
// No text: return original bitmap as blob
|
||||||
|
if (!text?.trim()) {
|
||||||
|
if (canvas.convertToBlob) {
|
||||||
|
return canvas.convertToBlob({
|
||||||
|
type: options.type ?? 'image/png',
|
||||||
|
quality: options.quality ?? 0.92,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return await new Promise((resolve) =>
|
||||||
|
canvas.toBlob((b) => resolve(b), options.type ?? 'image/png', options.quality ?? 0.92)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Text rendering ===
|
||||||
|
const basePadding = options.basePadding ?? 8; // internal left/right/top padding
|
||||||
|
const fontSize = options.fontSize ?? Math.round(width * 0.05);
|
||||||
|
ctx.font = `${fontSize}px ${options.fontFamily ?? 'sans-serif'}`;
|
||||||
|
ctx.textBaseline = 'bottom';
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
|
||||||
|
const textColor = options.textColor ?? '#5F1798';
|
||||||
|
const bgColor = options.bgColor ?? '#fff';
|
||||||
|
const strokeColor = options.strokeColor ?? 'rgba(0,0,0,0.35)';
|
||||||
|
const shadowBlur = options.shadowBlur ?? 6;
|
||||||
|
const maxWidth = width - basePadding * 2 - (options.extraPadding ?? 0);
|
||||||
|
|
||||||
|
// Wrap text into lines
|
||||||
|
const words = text.split(' ');
|
||||||
|
let line = '';
|
||||||
|
const lines = [];
|
||||||
|
for (const word of words) {
|
||||||
|
const testLine = line ? line + ' ' + word : word;
|
||||||
|
if (ctx.measureText(testLine).width > maxWidth && line) {
|
||||||
|
lines.push(line);
|
||||||
|
line = word;
|
||||||
|
} else {
|
||||||
|
line = testLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line) lines.push(line);
|
||||||
|
|
||||||
|
const lineHeight = fontSize + (options.lineGap ?? 6);
|
||||||
|
|
||||||
|
// Extra internal bottom padding inside the rounded box
|
||||||
|
const internalBottomPadding = options.internalBottomPadding ?? Math.round(fontSize * 0.35);
|
||||||
|
const boxHeight = lines.length * lineHeight + basePadding + internalBottomPadding;
|
||||||
|
|
||||||
|
const maxLineWidth = Math.max(...lines.map((l) => ctx.measureText(l).width));
|
||||||
|
const boxWidth = maxLineWidth + basePadding * 2;
|
||||||
|
|
||||||
|
// Distance from the very bottom of the image to the bottom of the text box
|
||||||
|
const bottomPadding = options.bottomPadding ?? Math.round(fontSize * 0.9);
|
||||||
|
|
||||||
|
const boxX = (width - boxWidth) / 2;
|
||||||
|
const boxY = height - bottomPadding - boxHeight;
|
||||||
|
const radius = options.radius ?? 8;
|
||||||
|
|
||||||
|
// Background rounded rect
|
||||||
|
ctx.save();
|
||||||
|
ctx.fillStyle = bgColor;
|
||||||
|
ctx.shadowColor = strokeColor;
|
||||||
|
ctx.shadowBlur = shadowBlur;
|
||||||
|
roundRect(ctx, boxX, boxY, boxWidth, boxHeight, radius, true, false);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
// Text
|
||||||
|
ctx.fillStyle = textColor;
|
||||||
|
ctx.shadowColor = 'transparent';
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const lineY = boxY + basePadding + (i + 1) * lineHeight - (lineHeight - fontSize) / 2;
|
||||||
|
const lineX = width / 2;
|
||||||
|
|
||||||
|
if (options.outline) {
|
||||||
|
ctx.lineWidth = options.outlineWidth ?? 2;
|
||||||
|
ctx.strokeStyle = options.outlineColor ?? 'rgba(255,255,255,0.8)';
|
||||||
|
ctx.strokeText(lines[i], lineX, lineY);
|
||||||
|
}
|
||||||
|
ctx.fillText(lines[i], lineX, lineY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to blob
|
||||||
|
if (canvas.convertToBlob) {
|
||||||
|
return await canvas.convertToBlob({
|
||||||
|
type: options.type ?? 'image/png',
|
||||||
|
quality: options.quality ?? 0.92,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return await new Promise((resolve) =>
|
||||||
|
canvas.toBlob((b) => resolve(b), options.type ?? 'image/png', options.quality ?? 0.92)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function roundRect(ctx, x, y, w, h, r, fill, stroke) {
|
||||||
|
if (typeof r === 'number') r = { tl: r, tr: r, br: r, bl: r };
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x + r.tl, y);
|
||||||
|
ctx.lineTo(x + w - r.tr, y);
|
||||||
|
ctx.quadraticCurveTo(x + w, y, x + w, y + r.tr);
|
||||||
|
ctx.lineTo(x + w, y + h - r.br);
|
||||||
|
ctx.quadraticCurveTo(x + w, y + h, x + w - r.br, y + h);
|
||||||
|
ctx.lineTo(x + r.bl, y + h);
|
||||||
|
ctx.quadraticCurveTo(x, y + h, x, y + h - r.bl);
|
||||||
|
ctx.lineTo(x, y + r.tl);
|
||||||
|
ctx.quadraticCurveTo(x, y, x + r.tl, y);
|
||||||
|
ctx.closePath();
|
||||||
|
if (fill) ctx.fill();
|
||||||
|
if (stroke) ctx.stroke();
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox
|
|||||||
|
|
||||||
workbox.setConfig({ debug: false });
|
workbox.setConfig({ debug: false });
|
||||||
|
|
||||||
const CACHE_NAME = 'app-cache-v2.1.5';
|
const CACHE_NAME = 'app-cache-v2.1.6';
|
||||||
const MIN_VALID_SIZE = 500;
|
const MIN_VALID_SIZE = 500;
|
||||||
|
|
||||||
const ASSETS_TO_CACHE = [
|
const ASSETS_TO_CACHE = [
|
||||||
@ -19,6 +19,8 @@ const ASSETS_TO_CACHE = [
|
|||||||
'/static/event3.jpg',
|
'/static/event3.jpg',
|
||||||
'/static/event4.jpg',
|
'/static/event4.jpg',
|
||||||
'/static/event5.jpg',
|
'/static/event5.jpg',
|
||||||
|
'/static/script/share.js',
|
||||||
|
'/static/script/select.js',
|
||||||
'/static/event6.jpg',
|
'/static/event6.jpg',
|
||||||
'/static/event7.webp',
|
'/static/event7.webp',
|
||||||
'/partner',
|
'/partner',
|
||||||
|
|||||||
@ -97,8 +97,10 @@ picture{cursor: zoom-in;}
|
|||||||
</head>
|
</head>
|
||||||
<body {% if request.cookies.zoom%}style="zoom: {{ request.cookies.zoom }}%"{%endif%} onload="adjustBodyStyle()">
|
<body {% if request.cookies.zoom%}style="zoom: {{ request.cookies.zoom }}%"{%endif%} onload="adjustBodyStyle()">
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
|
||||||
function setSecureCookie(name, value, days = 7) {const date = new Date();date.setTime(date.getTime() + (days * 86400000));document.cookie = `${name}=${encodeURIComponent(value)}; expires=${date.toUTCString()}; path=/; SameSite=Strict; Secure`;}
|
function setSecureCookie(name, value, days = 7) {const date = new Date();date.setTime(date.getTime() + (days * 86400000));document.cookie = `${name}=${encodeURIComponent(value)}; expires=${date.toUTCString()}; path=/; SameSite=Strict; Secure`;}
|
||||||
var userAgent = navigator.userAgent;var isFirefox = userAgent.indexOf("Firefox") !== -1;function isOldFirefox() {var match = userAgent.match(/Firefox\/(\d+)/);return match && parseInt(match[1], 10) < 126;};function iOS() {return ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) || (userAgent.includes("Mac") && "ontouchend" in document);};function adjustBodyStyle() {var body = document.body;var width;if (iOS()) {width = screen.width;} else {width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 360;};const zoom = (width < 700) ? width * 100 / 400 : (width < 900) ? width * 100 / 800 : width * 100 / 1600;if (isFirefox && isOldFirefox()) {body.style.MozTransform = `scale(${zoom}%)`;body.style.MozTransformOrigin = '0% 0%';body.style.width = (width < 901) ? '360px' : '1600px';body.style.position = 'absolute';};setSecureCookie("zoom", zoom, 7);body.style.zoom = `${zoom}%`;};adjustBodyStyle();window.addEventListener('resize', adjustBodyStyle, { passive: true });
|
var userAgent = navigator.userAgent;var isFirefox = userAgent.indexOf("Firefox") !== -1;function isOldFirefox() {var match = userAgent.match(/Firefox\/(\d+)/);return match && parseInt(match[1], 10) < 126;};function iOS() {return ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) || (userAgent.includes("Mac") && "ontouchend" in document);};function adjustBodyStyle() {var body = document.body;var width;if (iOS()) {width = screen.width;} else {width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 360;};const zoom = (width < 700) ? width * 100 / 400 : (width < 900) ? width * 100 / 800 : width * 100 / 1600;if (isFirefox && isOldFirefox()) {body.style.MozTransform = `scale(${zoom}%)`;body.style.MozTransformOrigin = '0% 0%';body.style.width = (width < 901) ? '360px' : '1600px';body.style.position = 'absolute';};setSecureCookie("zoom", zoom, 7);body.style.zoom = `${zoom}%`;};adjustBodyStyle();window.addEventListener('resize', adjustBodyStyle, { passive: true });
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
<div id="modal" class="modal" style="display: none;cursor: zoom-out;">
|
<div id="modal" class="modal" style="display: none;cursor: zoom-out;">
|
||||||
@ -111,6 +113,7 @@ var userAgent = navigator.userAgent;var isFirefox = userAgent.indexOf("Firefox")
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
document.querySelectorAll('picture').forEach(picture => {
|
document.querySelectorAll('picture').forEach(picture => {
|
||||||
picture.addEventListener('click', function() {
|
picture.addEventListener('click', function() {
|
||||||
@ -144,14 +147,17 @@ var userAgent = navigator.userAgent;var isFirefox = userAgent.indexOf("Firefox")
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
function closeModalPic() {const modalImg = document.getElementById('modalImg');modalImg.src = '';document.getElementById('modal').style.display = 'none';}
|
function closeModalPic() {const modalImg = document.getElementById('modalImg');modalImg.src = '';document.getElementById('modal').style.display = 'none';}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
{% raw %}
|
{% raw %}
|
||||||
function showToast(e={}){let{message:t="",status:a="info",duration:l=4e3}=e,n=document.querySelector(".toast-container");n||((n=document.createElement("div")).className="toast-container",document.body.appendChild(n));let s=document.createElement("div");s.className=`toast ${a}`;let d=document.createElement("div");d.className="accent";let c=document.createElement("div");c.className="toast-header";let i=document.createElement("div");i.textContent=t;let o=document.createElement("button");o.className="toast-close",o.innerHTML="✕",c.appendChild(i),c.appendChild(o),s.appendChild(d),s.appendChild(c),n.appendChild(s),requestAnimationFrame(()=>s.classList.add("show"));let r=!1,p=()=>{r||(r=!0,s.classList.remove("show"),setTimeout(()=>{s.parentNode&&s.parentNode.removeChild(s)},380))};return o.addEventListener("click",p),s.addEventListener("click",e=>{e.target===s&&p()}),l>0&&setTimeout(p,l),{close:p}}
|
function showToast(e={}){let{message:t="",status:a="info",duration:l=4e3}=e,n=document.querySelector(".toast-container");n||((n=document.createElement("div")).className="toast-container",document.body.appendChild(n));let s=document.createElement("div");s.className=`toast ${a}`;let d=document.createElement("div");d.className="accent";let c=document.createElement("div");c.className="toast-header";let i=document.createElement("div");i.textContent=t;let o=document.createElement("button");o.className="toast-close",o.innerHTML="✕",c.appendChild(i),c.appendChild(o),s.appendChild(d),s.appendChild(c),n.appendChild(s),requestAnimationFrame(()=>s.classList.add("show"));let r=!1,p=()=>{r||(r=!0,s.classList.remove("show"),setTimeout(()=>{s.parentNode&&s.parentNode.removeChild(s)},380))};return o.addEventListener("click",p),s.addEventListener("click",e=>{e.target===s&&p()}),l>0&&setTimeout(p,l),{close:p}}
|
||||||
{% endraw %}
|
{% endraw %}
|
||||||
{% if notify %}
|
{% if notify %}
|
||||||
showToast({message: '{{notify.text}}', status: '{{notify.status}}', duration:{{notify.duration}}});
|
showToast({message: '{{notify.text}}', status: '{{notify.status}}', duration:{{notify.duration}}});
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<div id="shareModal"
|
<div id="shareModal"
|
||||||
style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.4);align-items:center;justify-content:center;z-index: 3000;">
|
style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.4);align-items:center;justify-content:center;z-index: 3000;">
|
||||||
@ -172,14 +178,13 @@ function showToast(e={}){let{message:t="",status:a="info",duration:l=4e3}=e,n=do
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function imageWithTextBlob(imageUrl, text, options = {}) {
|
async function imageWithTextBlob(imageUrl, text, options = {}) {
|
||||||
const response = await fetch(imageUrl, {
|
const response = await fetch(imageUrl, {
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||||
|
|
||||||
const imageBlob = await response.blob();
|
const imageBlob = await response.blob();
|
||||||
const imageBitmap = await createImageBitmap(imageBlob);
|
const imageBitmap = await createImageBitmap(imageBlob);
|
||||||
|
|
||||||
@ -204,7 +209,7 @@ async function imageWithTextBlob(imageUrl, text, options = {}) {
|
|||||||
// Draw image
|
// Draw image
|
||||||
ctx.drawImage(imageBitmap, 0, 0, width, height);
|
ctx.drawImage(imageBitmap, 0, 0, width, height);
|
||||||
|
|
||||||
// No text: return original bitmap as blob (rendered)
|
// No text: return original bitmap as blob
|
||||||
if (!text?.trim()) {
|
if (!text?.trim()) {
|
||||||
if (canvas.convertToBlob) {
|
if (canvas.convertToBlob) {
|
||||||
return canvas.convertToBlob({
|
return canvas.convertToBlob({
|
||||||
@ -218,7 +223,7 @@ async function imageWithTextBlob(imageUrl, text, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === Text rendering ===
|
// === Text rendering ===
|
||||||
const basePadding = 6;
|
const basePadding = options.basePadding ?? 8; // internal left/right/top padding
|
||||||
const fontSize = options.fontSize ?? Math.round(width * 0.05);
|
const fontSize = options.fontSize ?? Math.round(width * 0.05);
|
||||||
ctx.font = `${fontSize}px ${options.fontFamily ?? 'sans-serif'}`;
|
ctx.font = `${fontSize}px ${options.fontFamily ?? 'sans-serif'}`;
|
||||||
ctx.textBaseline = 'bottom';
|
ctx.textBaseline = 'bottom';
|
||||||
@ -246,11 +251,17 @@ async function imageWithTextBlob(imageUrl, text, options = {}) {
|
|||||||
if (line) lines.push(line);
|
if (line) lines.push(line);
|
||||||
|
|
||||||
const lineHeight = fontSize + (options.lineGap ?? 6);
|
const lineHeight = fontSize + (options.lineGap ?? 6);
|
||||||
const boxHeight = lines.length * lineHeight + basePadding * 2;
|
|
||||||
|
// Extra internal bottom padding inside the rounded box
|
||||||
|
const internalBottomPadding = options.internalBottomPadding ?? Math.round(fontSize * 0.35);
|
||||||
|
const boxHeight = lines.length * lineHeight + basePadding + internalBottomPadding;
|
||||||
|
|
||||||
const maxLineWidth = Math.max(...lines.map((l) => ctx.measureText(l).width));
|
const maxLineWidth = Math.max(...lines.map((l) => ctx.measureText(l).width));
|
||||||
const boxWidth = maxLineWidth + basePadding * 2;
|
const boxWidth = maxLineWidth + basePadding * 2;
|
||||||
|
|
||||||
const bottomPadding = options.bottomPadding ?? Math.round(fontSize * 0.6);
|
// Distance from the very bottom of the image to the bottom of the text box
|
||||||
|
const bottomPadding = options.bottomPadding ?? Math.round(fontSize * 0.9);
|
||||||
|
|
||||||
const boxX = (width - boxWidth) / 2;
|
const boxX = (width - boxWidth) / 2;
|
||||||
const boxY = height - bottomPadding - boxHeight;
|
const boxY = height - bottomPadding - boxHeight;
|
||||||
const radius = options.radius ?? 8;
|
const radius = options.radius ?? 8;
|
||||||
@ -266,6 +277,7 @@ async function imageWithTextBlob(imageUrl, text, options = {}) {
|
|||||||
// Text
|
// Text
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
ctx.shadowColor = 'transparent';
|
ctx.shadowColor = 'transparent';
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
const lineY = boxY + basePadding + (i + 1) * lineHeight - (lineHeight - fontSize) / 2;
|
const lineY = boxY + basePadding + (i + 1) * lineHeight - (lineHeight - fontSize) / 2;
|
||||||
const lineX = width / 2;
|
const lineX = width / 2;
|
||||||
@ -289,7 +301,6 @@ async function imageWithTextBlob(imageUrl, text, options = {}) {
|
|||||||
canvas.toBlob((b) => resolve(b), options.type ?? 'image/png', options.quality ?? 0.92)
|
canvas.toBlob((b) => resolve(b), options.type ?? 'image/png', options.quality ?? 0.92)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function roundRect(ctx, x, y, w, h, r, fill, stroke) {
|
function roundRect(ctx, x, y, w, h, r, fill, stroke) {
|
||||||
if (typeof r === 'number') r = { tl: r, tr: r, br: r, bl: r };
|
if (typeof r === 'number') r = { tl: r, tr: r, br: r, bl: r };
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
@ -306,8 +317,6 @@ function roundRect(ctx, x, y, w, h, r, fill, stroke) {
|
|||||||
if (fill) ctx.fill();
|
if (fill) ctx.fill();
|
||||||
if (stroke) ctx.stroke();
|
if (stroke) ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const shareModal = document.getElementById('shareModal');
|
const shareModal = document.getElementById('shareModal');
|
||||||
const closeshareModal = document.getElementById('closeModal');
|
const closeshareModal = document.getElementById('closeModal');
|
||||||
@ -340,11 +349,9 @@ shareBtns.forEach(btn => {
|
|||||||
const text = btn.dataset.text || document.title;
|
const text = btn.dataset.text || document.title;
|
||||||
const image = btn.dataset.image;
|
const image = btn.dataset.image;
|
||||||
const imagetext = btn.dataset.imagetext || '';
|
const imagetext = btn.dataset.imagetext || '';
|
||||||
|
|
||||||
let blob = null;
|
let blob = null;
|
||||||
let file = null;
|
let file = null;
|
||||||
let objectUrl = null;
|
let objectUrl = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (image) {
|
if (image) {
|
||||||
const imageUrl = window.location.origin + image;
|
const imageUrl = window.location.origin + image;
|
||||||
@ -355,10 +362,8 @@ shareBtns.forEach(btn => {
|
|||||||
console.log(`Generated blob for "${imagetext}" | size: ${blob.size} | url: ${imageUrl}`);
|
console.log(`Generated blob for "${imagetext}" | size: ${blob.size} | url: ${imageUrl}`);
|
||||||
const filename = `shared-image-${Date.now()}.png`;
|
const filename = `shared-image-${Date.now()}.png`;
|
||||||
file = new File([blob], filename, { type: blob.type });
|
file = new File([blob], filename, { type: blob.type });
|
||||||
|
|
||||||
// Создаём object URL только если хотим (необязательно для navigator.share)
|
// Создаём object URL только если хотим (необязательно для navigator.share)
|
||||||
objectUrl = URL.createObjectURL(file);
|
objectUrl = URL.createObjectURL(file);
|
||||||
|
|
||||||
if (navigator.canShare && navigator.canShare({ files: [file] })) {
|
if (navigator.canShare && navigator.canShare({ files: [file] })) {
|
||||||
await navigator.share({
|
await navigator.share({
|
||||||
title: text,
|
title: text,
|
||||||
@ -386,15 +391,12 @@ shareBtns.forEach(btn => {
|
|||||||
objectUrl = null;
|
objectUrl = null;
|
||||||
}
|
}
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
|
|
||||||
// Удаляем ссылки, чтобы GC мог собрать объекты
|
// Удаляем ссылки, чтобы GC мог собрать объекты
|
||||||
blob = null;
|
blob = null;
|
||||||
file = null;
|
file = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function openshareModal(link, text) {
|
function openshareModal(link, text) {
|
||||||
vk.href = buildShareUrl('vk', link, text);
|
vk.href = buildShareUrl('vk', link, text);
|
||||||
tg.href = buildShareUrl('tg', link, text);
|
tg.href = buildShareUrl('tg', link, text);
|
||||||
@ -406,15 +408,12 @@ shareBtns.forEach(btn => {
|
|||||||
copyBtn.dataset.link = link;
|
copyBtn.dataset.link = link;
|
||||||
shareModal.style.display = 'flex'
|
shareModal.style.display = 'flex'
|
||||||
}
|
}
|
||||||
|
|
||||||
closeshareModal.addEventListener('click', () => {
|
closeshareModal.addEventListener('click', () => {
|
||||||
shareModal.style.display = 'none';
|
shareModal.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
shareModal.addEventListener('click', (e) => {
|
shareModal.addEventListener('click', (e) => {
|
||||||
if (e.target === shareModal) shareModal.style.display = 'none';
|
if (e.target === shareModal) shareModal.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
async function copyToClipboard(text) {
|
async function copyToClipboard(text) {
|
||||||
try {
|
try {
|
||||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
@ -434,151 +433,20 @@ shareBtns.forEach(btn => {
|
|||||||
showToast({message: 'Не удалось скопировать ссылку', status: 'error'});
|
showToast({message: 'Не удалось скопировать ссылку', status: 'error'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCopyMessage() {
|
function showCopyMessage() {
|
||||||
copyMsg.style.display = 'inline';
|
copyMsg.style.display = 'inline';
|
||||||
setTimeout(() => copyMsg.style.display = 'none', 2000);
|
setTimeout(() => copyMsg.style.display = 'none', 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyBtn.addEventListener('click', () => {
|
copyBtn.addEventListener('click', () => {
|
||||||
const link = copyBtn.dataset.link || window.location.href;
|
const link = copyBtn.dataset.link || window.location.href;
|
||||||
copyToClipboard(link);
|
copyToClipboard(link);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
(async () => {
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const parts_cookie = `; ${document.cookie}`.split(`; token=`);
|
(function() {
|
||||||
const token_old = parts_cookie.pop().split(';')[0];
|
|
||||||
|
|
||||||
if (!token_old) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let response = await fetch('/api/me');
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
response = await fetch('/api/old/login', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Network response was not ok');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (!data.username) {
|
|
||||||
response = await fetch('/api/old/login', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Network response was still not ok');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('There was a problem with the fetch operation:', error);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
let deferredPrompt = null;
|
|
||||||
let hasUserInteracted = false;
|
|
||||||
let promptTimeout = null;
|
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
navigator.serviceWorker.register('/sw.js').then(reg => {
|
|
||||||
reg.addEventListener('updatefound', () => {
|
|
||||||
const newWorker = reg.installing;
|
|
||||||
newWorker.addEventListener('statechange', () => {
|
|
||||||
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
|
|
||||||
console.log('New Service Worker ready');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
navigator.serviceWorker.addEventListener('message', event => {
|
|
||||||
if (event.data.type === 'SW_UPDATED') {
|
|
||||||
console.log('New Service Worker activated – reloading...');
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('beforeinstallprompt', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
deferredPrompt = e;
|
|
||||||
console.log('beforeinstallprompt: готово к установке');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const markInteractionAndTryShow = () => {
|
|
||||||
if (hasUserInteracted) return;
|
|
||||||
hasUserInteracted = true;
|
|
||||||
|
|
||||||
document.removeEventListener('click', markInteractionAndTryShow);
|
|
||||||
document.removeEventListener('keydown', markInteractionAndTryShow);
|
|
||||||
document.removeEventListener('touchstart', safeTouchHandler);
|
|
||||||
|
|
||||||
tryShowInstallPrompt();
|
|
||||||
};
|
|
||||||
|
|
||||||
let touchMoved = false;
|
|
||||||
const safeTouchHandler = (e) => {
|
|
||||||
if (e.touches.length > 1) return;
|
|
||||||
document.addEventListener('touchmove', () => touchMoved = true, { once: true });
|
|
||||||
document.addEventListener('touchend', () => {
|
|
||||||
if (!touchMoved) markInteractionAndTryShow();
|
|
||||||
touchMoved = false;
|
|
||||||
}, { once: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('click', markInteractionAndTryShow, { passive: true });
|
|
||||||
document.addEventListener('keydown', markInteractionAndTryShow, { passive: true });
|
|
||||||
document.addEventListener('touchstart', safeTouchHandler, { passive: true });
|
|
||||||
|
|
||||||
let scrollAllowed = false;
|
|
||||||
const scrollHandler = () => {
|
|
||||||
if (scrollAllowed && !hasUserInteracted) markInteractionAndTryShow();
|
|
||||||
};
|
|
||||||
document.addEventListener('scroll', scrollHandler, { passive: true });
|
|
||||||
|
|
||||||
document.addEventListener('click', () => scrollAllowed = true, { once: true });
|
|
||||||
document.addEventListener('touchstart', () => scrollAllowed = true, { once: true });
|
|
||||||
|
|
||||||
function tryShowInstallPrompt() {
|
|
||||||
if (!deferredPrompt) {
|
|
||||||
console.log('Промпт ещё не готов');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (promptTimeout) return;
|
|
||||||
|
|
||||||
promptTimeout = setTimeout(() => {
|
|
||||||
console.log('Показываем install-промпт');
|
|
||||||
deferredPrompt.prompt();
|
|
||||||
|
|
||||||
deferredPrompt.userChoice.then((choiceResult) => {
|
|
||||||
if (choiceResult.outcome === 'accepted') {
|
|
||||||
console.log('PWA установлен!');
|
|
||||||
} else {
|
|
||||||
console.log('Установка отклонена');
|
|
||||||
}
|
|
||||||
deferredPrompt = null;
|
|
||||||
promptTimeout = null;
|
|
||||||
});
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const root = document.getElementById('dd-modal-root') || document.body;
|
const root = document.getElementById('dd-modal-root') || document.body;
|
||||||
@ -709,21 +577,11 @@ shareBtns.forEach(btn => {
|
|||||||
img.alt = 'Подсказка';
|
img.alt = 'Подсказка';
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// куда-то добавляем div
|
|
||||||
span.appendChild(div);
|
span.appendChild(div);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
wrapper.append(input, span);
|
wrapper.append(input, span);
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Кастомные значения
|
|
||||||
if (allowCustom) {
|
if (allowCustom) {
|
||||||
customContainer.innerHTML = `
|
customContainer.innerHTML = `
|
||||||
<div style="display:flex;gap:8px;align-items:center;flex-direction:column;">
|
<div style="display:flex;gap:8px;align-items:center;flex-direction:column;">
|
||||||
@ -858,6 +716,98 @@ shareBtns.forEach(btn => {
|
|||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
// @license-end
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
|
let deferredPrompt = null;
|
||||||
|
let hasUserInteracted = false;
|
||||||
|
let promptTimeout = null;
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('/sw.js').then(reg => {
|
||||||
|
reg.addEventListener('updatefound', () => {
|
||||||
|
const newWorker = reg.installing;
|
||||||
|
newWorker.addEventListener('statechange', () => {
|
||||||
|
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
|
||||||
|
console.log('New Service Worker ready');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
navigator.serviceWorker.addEventListener('message', event => {
|
||||||
|
if (event.data.type === 'SW_UPDATED') {
|
||||||
|
console.log('New Service Worker activated – reloading...');
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('beforeinstallprompt', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
deferredPrompt = e;
|
||||||
|
console.log('beforeinstallprompt: готово к установке');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const markInteractionAndTryShow = () => {
|
||||||
|
if (hasUserInteracted) return;
|
||||||
|
hasUserInteracted = true;
|
||||||
|
|
||||||
|
document.removeEventListener('click', markInteractionAndTryShow);
|
||||||
|
document.removeEventListener('keydown', markInteractionAndTryShow);
|
||||||
|
document.removeEventListener('touchstart', safeTouchHandler);
|
||||||
|
|
||||||
|
tryShowInstallPrompt();
|
||||||
|
};
|
||||||
|
|
||||||
|
let touchMoved = false;
|
||||||
|
const safeTouchHandler = (e) => {
|
||||||
|
if (e.touches.length > 1) return;
|
||||||
|
document.addEventListener('touchmove', () => touchMoved = true, { once: true });
|
||||||
|
document.addEventListener('touchend', () => {
|
||||||
|
if (!touchMoved) markInteractionAndTryShow();
|
||||||
|
touchMoved = false;
|
||||||
|
}, { once: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', markInteractionAndTryShow, { passive: true });
|
||||||
|
document.addEventListener('keydown', markInteractionAndTryShow, { passive: true });
|
||||||
|
document.addEventListener('touchstart', safeTouchHandler, { passive: true });
|
||||||
|
|
||||||
|
let scrollAllowed = false;
|
||||||
|
const scrollHandler = () => {
|
||||||
|
if (scrollAllowed && !hasUserInteracted) markInteractionAndTryShow();
|
||||||
|
};
|
||||||
|
document.addEventListener('scroll', scrollHandler, { passive: true });
|
||||||
|
|
||||||
|
document.addEventListener('click', () => scrollAllowed = true, { once: true });
|
||||||
|
document.addEventListener('touchstart', () => scrollAllowed = true, { once: true });
|
||||||
|
|
||||||
|
function tryShowInstallPrompt() {
|
||||||
|
if (!deferredPrompt) {
|
||||||
|
console.log('Промпт ещё не готов');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (promptTimeout) return;
|
||||||
|
|
||||||
|
promptTimeout = setTimeout(() => {
|
||||||
|
console.log('Показываем install-промпт');
|
||||||
|
deferredPrompt.prompt();
|
||||||
|
|
||||||
|
deferredPrompt.userChoice.then((choiceResult) => {
|
||||||
|
if (choiceResult.outcome === 'accepted') {
|
||||||
|
console.log('PWA установлен!');
|
||||||
|
} else {
|
||||||
|
console.log('Установка отклонена');
|
||||||
|
}
|
||||||
|
deferredPrompt = null;
|
||||||
|
promptTimeout = null;
|
||||||
|
});
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<div id="dd-modal-root"></div>
|
<div id="dd-modal-root"></div>
|
||||||
|
|
||||||
@ -868,6 +818,7 @@ shareBtns.forEach(btn => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const modal = document.getElementById('modalToolTip');
|
const modal = document.getElementById('modalToolTip');
|
||||||
const modalText = document.getElementById('modalToolTipText');
|
const modalText = document.getElementById('modalToolTipText');
|
||||||
@ -897,6 +848,7 @@ shareBtns.forEach(btn => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -207,6 +207,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
/* ---------- Utility helpers (removed) ---------- */
|
/* ---------- Utility helpers (removed) ---------- */
|
||||||
|
|
||||||
@ -342,8 +343,10 @@ function bindLinkValidation({
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const competition = JSON.parse({{competition|tojson}})
|
const competition = JSON.parse({{competition|tojson}})
|
||||||
const competitionId = `{{competition_id}}`
|
const competitionId = `{{competition_id}}`
|
||||||
@ -432,8 +435,10 @@ document.getElementById('preview_poster').src = `/b/competition/${competition.po
|
|||||||
|
|
||||||
// date_finish.value = date_finish_date.toISOString().slice(0, 10);
|
// date_finish.value = date_finish_date.toISOString().slice(0, 10);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
var type = competition.type_;
|
var type = competition.type_;
|
||||||
|
|
||||||
function toggleType(clickedId) {
|
function toggleType(clickedId) {
|
||||||
@ -449,8 +454,10 @@ document.getElementById('preview_poster').src = `/b/competition/${competition.po
|
|||||||
type = 'paint';
|
type = 'paint';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const minInput = document.getElementById('min_val');
|
const minInput = document.getElementById('min_val');
|
||||||
const maxInput = document.getElementById('max_val');
|
const maxInput = document.getElementById('max_val');
|
||||||
@ -638,6 +645,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
{% macro section(user) -%}
|
{% macro section(user) -%}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
var type = 'paint';
|
var type = 'paint';
|
||||||
|
|
||||||
function toggleType(clickedId) {
|
function toggleType(clickedId) {
|
||||||
@ -18,6 +19,7 @@
|
|||||||
type = 'paint';
|
type = 'paint';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="c_sbrxk">
|
<form class="c_sbrxk">
|
||||||
@ -348,10 +350,13 @@ function bindLinkValidation({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% if user.send_address %}
|
{% if user.send_address %}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.getElementById('address').value = '{{ user.send_address[-1] }}'
|
document.getElementById('address').value = '{{ user.send_address[-1] }}'
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script defer>
|
<script defer>
|
||||||
@ -373,8 +378,10 @@ document.getElementById('address').value = '{{ user.send_address[-1] }}'
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTomorrowAtNoon();
|
setTomorrowAtNoon();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
// Основная логика
|
// Основная логика
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const minInput = document.getElementById('min_val');
|
const minInput = document.getElementById('min_val');
|
||||||
@ -568,6 +575,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// Инициализация
|
// Инициализация
|
||||||
// updateRange();
|
// updateRange();
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
|||||||
@ -153,6 +153,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
(function(){
|
(function(){
|
||||||
const input = document.getElementById('memberSearch');
|
const input = document.getElementById('memberSearch');
|
||||||
const container = document.querySelector('.c_cnedr');
|
const container = document.querySelector('.c_cnedr');
|
||||||
@ -178,6 +179,7 @@
|
|||||||
|
|
||||||
filter();
|
filter();
|
||||||
})();
|
})();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
52
templates/components/contacts.html
Normal file
52
templates/components/contacts.html
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{% macro details(user) -%}
|
||||||
|
<details style="margin-bottom: 1.25rem;">
|
||||||
|
<summary>Показать контакты</summary>
|
||||||
|
<div class="menua">
|
||||||
|
<a class="icona" href="/artists/{{user._id}}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
||||||
|
<path d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
||||||
|
</svg>
|
||||||
|
<span>Профиль</span>
|
||||||
|
</a>
|
||||||
|
<a class="icona" href="tel:{{user.phone.split(',')[-1].strip()}}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
||||||
|
<path d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
||||||
|
</svg>
|
||||||
|
<span>{{ user.phone.split(',')[-1].strip() }}</span>
|
||||||
|
</a>
|
||||||
|
<a class="icona" href="mailto:{{user.email}}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
||||||
|
<path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
||||||
|
</svg>
|
||||||
|
<span>{{user.email}}</span>
|
||||||
|
</a>
|
||||||
|
<div class="icona"><span>Написать</span></div>
|
||||||
|
<div class="icona">
|
||||||
|
<a class="icona" href="{% if user.vk_id %}https://vk.ru/im?sel={{user.vk_id}}{%else%}#{%endif%}" {% if
|
||||||
|
not user.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})" {%endif%}>
|
||||||
|
<img src="/static/icons/vk.svg" height="40">
|
||||||
|
</a>
|
||||||
|
<a class="icona" href="https://telegram.me/{{user.phone.split(',')[-1].strip()}}">
|
||||||
|
<img src="/static/icons/tg.svg" height="40">
|
||||||
|
<!-- <span>Написать в ТГ</span> -->
|
||||||
|
</a>
|
||||||
|
<a class="icona" href="https://max.ru/{{user.phone.split(',')[-1].strip()}}">
|
||||||
|
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
||||||
|
<!-- <span>Написать в MAX</span> -->
|
||||||
|
</a>
|
||||||
|
<a class="icona" href="https://wa.me/{{user.phone.split(',')[-1].strip()}}">
|
||||||
|
<img src="/static/icons/wapp.svg" height="40">
|
||||||
|
<!-- <span>Написать в WA</span> -->
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro style() -%}
|
||||||
|
<style>
|
||||||
|
.menua{width: 100%;display: flex;flex-direction: column;gap: 7px;margin: 10px 20px;}
|
||||||
|
.icona{display: flex;gap: 10px;align-items: center;}
|
||||||
|
.icona>span{color: #5F1798;}
|
||||||
|
</style>
|
||||||
|
{%- endmacro %}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{% macro section(user) -%}
|
{% macro section(user) -%}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function toggleMenu() {
|
function toggleMenu() {
|
||||||
const button = document.getElementById('menu_button');
|
const button = document.getElementById('menu_button');
|
||||||
const lines = button.querySelectorAll('.line');
|
const lines = button.querySelectorAll('.line');
|
||||||
@ -23,11 +24,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
menu2.classList.toggle('open', newState);
|
menu2.classList.toggle('open', newState);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% if user %}
|
{% if user %}
|
||||||
{% if user.notify %}
|
{% if user.notify %}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function removeShow() {
|
async function removeShow() {
|
||||||
document.getElementById('notificationsDropdown').classList.remove('show');
|
document.getElementById('notificationsDropdown').classList.remove('show');
|
||||||
document.getElementById('closeNotify').classList.remove('show');
|
document.getElementById('closeNotify').classList.remove('show');
|
||||||
@ -156,7 +159,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
addNotification(item.title, item.text, item.dateStr, item.link, item.read);
|
addNotification(item.title, item.text, item.dateStr, item.link, item.read);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<header class="c_xirl1">
|
<header class="c_xirl1">
|
||||||
@ -198,6 +202,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
{% if user and 'back' in user.get('scopes',[]) %}
|
{% if user and 'back' in user.get('scopes',[]) %}
|
||||||
<span id="backBtn" class="c_qmp95 b_fokm1 btn">Переключиться на Админа</span>
|
<span id="backBtn" class="c_qmp95 b_fokm1 btn">Переключиться на Админа</span>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
document.getElementById('backBtn').addEventListener('click', async () => {
|
document.getElementById('backBtn').addEventListener('click', async () => {
|
||||||
try {
|
try {
|
||||||
@ -213,7 +218,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span
|
<span
|
||||||
id="shareBtn" data-imagetext="🎨 Рекомендую! 👍"
|
id="shareBtn" data-imagetext="🎨 Рекомендую! 👍"
|
||||||
|
|||||||
@ -71,6 +71,7 @@
|
|||||||
console.error('Network error during logout', err);
|
console.error('Network error during logout', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
async function switchProfile() {
|
async function switchProfile() {
|
||||||
@ -86,6 +87,7 @@
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@ -122,5 +124,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
{% import "/components/header.html" as header %}
|
{% import "/components/header.html" as header %}
|
||||||
{% import "/components/footer.html" as footer %}
|
{% import "/components/footer.html" as footer %}
|
||||||
{% import "components/share.html" as share %}
|
{% import "components/share.html" as share %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}{{exhibition.title}} | Картины{% endblock %}
|
{% block title %}{{exhibition.title}} | Картины{% endblock %}
|
||||||
|
|
||||||
@ -42,6 +43,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<header class="c_77wsp b_qx462">
|
<header class="c_77wsp b_qx462">
|
||||||
<h2 class="c_aiv78 b_6jj0l">{{exhibition.title}}</h2>
|
<h2 class="c_aiv78 b_6jj0l">{{exhibition.title}}</h2>
|
||||||
|
<div class="b_xz6em">
|
||||||
|
<img src="/a/{{exhibition.user._id}}" class="b_ob59y">
|
||||||
|
<div class="c_9hjdk b_ffruz">
|
||||||
|
<span class="b_qla2q">Организатор</span>
|
||||||
|
<span class="c_zm0m4 b_09est">{{exhibition.user.username}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ contacts.details(exhibition.user) }}
|
||||||
{% if exhibition.get('tizer_file_id') or exhibition.get('tizer_link') %}
|
{% if exhibition.get('tizer_file_id') or exhibition.get('tizer_link') %}
|
||||||
<a class="c_wcdb7 b_ofiw3" href="{% if exhibition.get('tizer_link') %}{{exhibition.tizer_link}}{% else %}/b/exhibition/{{ exhibition.tizer_file_id }}{% endif %}" rel="noopener noreferrer" style="width: 100%;margin: 10px 0;">
|
<a class="c_wcdb7 b_ofiw3" href="{% if exhibition.get('tizer_link') %}{{exhibition.tizer_link}}{% else %}/b/exhibition/{{ exhibition.tizer_file_id }}{% endif %}" rel="noopener noreferrer" style="width: 100%;margin: 10px 0;">
|
||||||
<span class="b_j2ln2">Релиз выставки</span>
|
<span class="b_j2ln2">Релиз выставки</span>
|
||||||
@ -118,6 +127,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function saledPaintings(postId) {
|
function saledPaintings(postId) {
|
||||||
fetch(`/api/post/${postId}/sale`, {
|
fetch(`/api/post/${postId}/sale`, {
|
||||||
method: 'PUT'
|
method: 'PUT'
|
||||||
@ -148,8 +158,10 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
(function(){
|
(function(){
|
||||||
const input = document.getElementById('memberSearch');
|
const input = document.getElementById('memberSearch');
|
||||||
const container = document.querySelector('.c_cnedr');
|
const container = document.querySelector('.c_cnedr');
|
||||||
@ -175,6 +187,7 @@
|
|||||||
|
|
||||||
filter();
|
filter();
|
||||||
})();
|
})();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@ -195,6 +208,7 @@
|
|||||||
<meta name="description" content="{{exhibition.short_desc}}">
|
<meta name="description" content="{{exhibition.short_desc}}">
|
||||||
<meta property="og:site_name" content="Конкурсы | KULTMOST.АВТОПОСТ">
|
<meta property="og:site_name" content="Конкурсы | KULTMOST.АВТОПОСТ">
|
||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>
|
<style>
|
||||||
.b_0jst1 { color: #0ED646; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 700; line-height: normal; }
|
.b_0jst1 { color: #0ED646; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 700; line-height: normal; }
|
||||||
.b_vabj9 { align-items: center; background: rgba(14, 214, 70, 0.20); border-radius: 30px; display: flex; justify-content: center; padding: 1.5px 10px; }
|
.b_vabj9 { align-items: center; background: rgba(14, 214, 70, 0.20); border-radius: 30px; display: flex; justify-content: center; padding: 1.5px 10px; }
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% import "/components/header.html" as header %}
|
{% import "/components/header.html" as header %}
|
||||||
{% import "/components/footer.html" as footer %}
|
{% import "/components/footer.html" as footer %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
{% import "components/share.html" as share %}
|
{% import "components/share.html" as share %}
|
||||||
{% block title %}Выставки{% endblock %}
|
{% block title %}Выставки{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{{ header.section(user) }}
|
{{ header.section(user) }}
|
||||||
<section class="c_cr9xg">
|
<section class="c_cr9xg">
|
||||||
@ -16,71 +16,70 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="c_dbu4q">
|
<div class="c_dbu4q">
|
||||||
{% for exhibition in exhibitions %}
|
{% for exhibition in exhibitions %}
|
||||||
{% set link="/exhibition/{}".format(exhibition._id) %}
|
{% set link="/exhibition/{}".format(exhibition._id) %}
|
||||||
<article class="c_9fgdh b_ax8vz" id="l{{exhibition._id}}">
|
<article class="c_9fgdh b_ax8vz" id="l{{exhibition._id}}">
|
||||||
{% if link %}
|
{% if link %}<a href="{{link}}">{% endif %}
|
||||||
<a href="{{link}}">
|
<div class="b_ornr9">
|
||||||
{% endif %}
|
<picture>
|
||||||
<div class="b_ornr9">
|
<img crossorigin="anonymous" fetchpriority="high" loading="eager" alt="{{ exhibition.title }}"
|
||||||
<picture>
|
class="b_ornr9" src="/b/exhibition/{{ exhibition.poster_file_id }}"
|
||||||
<img crossorigin="anonymous" fetchpriority="high" loading="eager" alt="{{ exhibition.title }}" class="b_ornr9"
|
alt="Выставка {{exhibition.title }}">
|
||||||
src="/b/exhibition/{{ exhibition.poster_file_id }}" alt="Выставка {{exhibition.title }}">
|
</picture>
|
||||||
</picture>
|
</div>
|
||||||
</div>
|
{% if link %}</a>{% endif %}
|
||||||
{% if link %}
|
<div class="c_z3dpx b_73p10">
|
||||||
</a>
|
{% if link %}<a href="{{link}}" class="b_73p10">{% endif %}
|
||||||
{% endif %}
|
<div class="{% if now > exhibition.date_finish %}b_vabj9_2{%else%}b_vabj9{% endif %}">
|
||||||
<div class="c_z3dpx b_73p10">
|
{% if now > exhibition.date_finish %}
|
||||||
{% if link %}
|
<span class="c_95csi b_0jst1_2">Закончилась</span>
|
||||||
<a href="{{link}}" class="b_73p10">
|
{% elif now > exhibition.datetime_start %}
|
||||||
{% endif %}
|
<span class="c_95csi b_0jst1">Началась</span>
|
||||||
<div class="{% if now > exhibition.date_finish %}b_vabj9_2{%else%}b_vabj9{% endif %}">
|
{% else %}
|
||||||
{% if now > exhibition.date_finish %}
|
<span class="c_95csi b_0jst1">Формируется</span>
|
||||||
<span class="c_95csi b_0jst1_2">Закончилась</span>
|
{% endif %}
|
||||||
{% elif now > exhibition.datetime_start %}
|
</div>
|
||||||
<span class="c_95csi b_0jst1">Началась</span>
|
<header class="c_m876y b_9xtz9">
|
||||||
{% else %}
|
<h3 class="c_hysjg b_8f3uh">{{ exhibition.title }}</h3>
|
||||||
<span class="c_95csi b_0jst1">Формируется</span>
|
</header>
|
||||||
{% endif %}
|
<p class="c_2fr39 b_tfnz2">{{ exhibition.topic }}</p>
|
||||||
</div>
|
{% if link %}</a>{% endif %}
|
||||||
<header class="c_m876y b_9xtz9">
|
{% set creator = exhibition.get('user') %}
|
||||||
<h3 class="c_hysjg b_8f3uh">{{ exhibition.title }}</h3>
|
{% if creator %}
|
||||||
</header>
|
<div class="c_dbbe4 b_otttb">
|
||||||
<p class="c_2fr39 b_tfnz2">{{ exhibition.topic }}</p>
|
<img class="c_pm80w b_a68fq" src="/a/{{creator._id}}" alt="{{ creator.username | e }}"
|
||||||
{% set user = exhibition.get('user') %}
|
crossorigin="anonymous" fetchpriority="high" loading="eager">
|
||||||
<div class="c_dbbe4 b_otttb">
|
<div class="c_4402p b_ntazj">
|
||||||
{% if user %}
|
<p class="c_kvah4 b_ghosy">{{ creator.username | e }}</p>
|
||||||
<img class="c_pm80w b_a68fq" src="/a/{{user._id}}" alt="{{ user.username | e }}" crossorigin="anonymous" fetchpriority="high" loading="eager">
|
</div>
|
||||||
<div class="c_4402p b_ntazj">
|
</div>
|
||||||
<p class="c_kvah4 b_ghosy">{{ user.username | e }}</p>
|
{{ contacts.details(creator) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if exhibition.get('tizer_file_id') or exhibition.get('tizer_link') %}
|
||||||
|
<a class="c_aq9et"
|
||||||
|
href="{% if exhibition.get('tizer_link') %}{{exhibition.tizer_link}}{% else %}/b/exhibition/{{ exhibition.tizer_file_id }}{% endif %}"
|
||||||
|
rel="noopener noreferrer">
|
||||||
|
<span class="c_som9s">Релиз выставки</span>
|
||||||
|
</a>
|
||||||
|
{%endif%}
|
||||||
|
<a class="c_aq9et" href="{{link}}" rel="noopener noreferrer">
|
||||||
|
<span class="c_som9s">Список картин</span>
|
||||||
|
</a>
|
||||||
|
<p>Место проведения: {{ exhibition.get('place') }}</p>
|
||||||
|
<div class="b_otttb">
|
||||||
|
<span class="c_2fr39 b_tfnz2">С {{ ( exhibition.datetime_start.strftime('%d.%m.%Y')) if
|
||||||
|
exhibition.datetime_start else ''}}</span>
|
||||||
|
<span class="c_2fr39 b_tfnz2">По {{ ( exhibition.date_finish.strftime('%d.%m.%Y')) if
|
||||||
|
exhibition.date_finish else ''}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="fl">
|
||||||
|
<span class="c_2fr39 b_tfnz2" style="z-index: 2;">
|
||||||
|
{{ share.share('/exhibition/{}'.format(exhibition._id), exhibition.title,
|
||||||
|
'/b/exhibition/{}'.format(exhibition.poster_file_id), "Приглашаем на выставку") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p class="c_drpqj b_mp1wb">{{ (exhibition._id.generation_time.strftime('%d.%m.%Y')) if exhibition._id else ''}}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</article>
|
||||||
</div>
|
|
||||||
{% if exhibition.get('tizer_file_id') or exhibition.get('tizer_link') %}
|
|
||||||
<a class="c_aq9et" href="{% if exhibition.get('tizer_link') %}{{exhibition.tizer_link}}{% else %}/b/exhibition/{{ exhibition.tizer_file_id }}{% endif %}" rel="noopener noreferrer">
|
|
||||||
<span class="c_som9s">Релиз выставки</span>
|
|
||||||
</a>
|
|
||||||
{%endif%}
|
|
||||||
<a class="c_aq9et" href="{{link}}" rel="noopener noreferrer">
|
|
||||||
<span class="c_som9s">Список картин</span>
|
|
||||||
</a>
|
|
||||||
<p>Место проведения: {{ exhibition.get('place') }}</p>
|
|
||||||
<div class="b_otttb">
|
|
||||||
<span class="c_2fr39 b_tfnz2">С {{ ( exhibition.datetime_start.strftime('%d.%m.%Y')) if exhibition.datetime_start else ''}}</span>
|
|
||||||
<span class="c_2fr39 b_tfnz2">По {{ ( exhibition.date_finish.strftime('%d.%m.%Y')) if exhibition.date_finish else ''}}</span>
|
|
||||||
</div>
|
|
||||||
{% if link %}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<div class="fl">
|
|
||||||
<span class="c_2fr39 b_tfnz2" style="z-index: 2;">
|
|
||||||
{{ share.share('/exhibition/{}'.format(exhibition._id), exhibition.title, '/b/exhibition/{}'.format(exhibition.poster_file_id), "Приглашаем на выставку") }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="c_drpqj b_mp1wb">{{ (exhibition._id.generation_time.strftime('%d.%m.%Y')) if exhibition._id else ''}}</p>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -89,18 +88,10 @@
|
|||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
<style>/* Base (common) styles */
|
{{ contacts.style() }}
|
||||||
.c_aq9et {
|
<style>
|
||||||
cursor: pointer;
|
.c_aq9et {cursor: pointer;transition: transform 0.1s linear, box‑shadow 0.1s linear;box-shadow: 0 0 0 rgba(0, 0, 0, 0);}
|
||||||
transition: transform 0.1s linear, box‑shadow 0.1s linear;
|
.c_aq9et:active {transform: scale(0.9);box-shadow: 5px 5px 5px rgba(95, 23, 152, 0.32);}
|
||||||
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.c_aq9et:active {
|
|
||||||
transform: scale(0.9);
|
|
||||||
box-shadow: 5px 5px 5px rgba(95, 23, 152, 0.32);
|
|
||||||
}
|
|
||||||
|
|
||||||
article>a{width: 100%;}
|
article>a{width: 100%;}
|
||||||
picture>img{ width: 100%; object-fit: scale-down; }
|
picture>img{ width: 100%; object-fit: scale-down; }
|
||||||
.fl{display: flex;justify-content: space-between;width: 100%;}
|
.fl{display: flex;justify-content: space-between;width: 100%;}
|
||||||
@ -130,25 +121,20 @@ picture>img{ width: 100%; object-fit: scale-down; }
|
|||||||
.b_ornr9{height: auto;}
|
.b_ornr9{height: auto;}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>/* Base (common) styles */
|
<style>
|
||||||
.b_p0hpm { color: #5F1798; font-family: Inter; font-size: 42px; font-style: normal; font-weight: 700; line-height: normal; text-transform: uppercase; }
|
.b_p0hpm { color: #5F1798; font-family: Inter; font-size: 42px; font-style: normal; font-weight: 700; line-height: normal; text-transform: uppercase; }
|
||||||
/* Mobile */
|
|
||||||
@media (max-width: 699px) {
|
@media (max-width: 699px) {
|
||||||
.c_dbu4q { align-content: flex-start; align-items: flex-start; align-self: stretch; display: flex; flex-wrap: wrap; gap: 20px; justify-content: center; }
|
.c_dbu4q { align-content: flex-start; align-items: flex-start; align-self: stretch; display: flex; flex-wrap: wrap; gap: 20px; justify-content: center; }
|
||||||
.c_fwe1m { align-items: center; display: flex; flex-direction: column; gap: 20px; width: 335px; }
|
.c_fwe1m { align-items: center; display: flex; flex-direction: column; gap: 20px; width: 335px; }
|
||||||
.c_s7it2 { align-items: flex-start; align-self: stretch; display: flex; gap: 20px; justify-content: center; }
|
.c_s7it2 { align-items: flex-start; align-self: stretch; display: flex; gap: 20px; justify-content: center; }
|
||||||
.c_cr9xg { align-items: center; background: #FFF; display: flex; flex-direction: column; gap: 30px; }
|
.c_cr9xg { align-items: center; background: #FFF; display: flex; flex-direction: column; gap: 30px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tablet */
|
|
||||||
@media (min-width: 700px) and (max-width: 900px) {
|
@media (min-width: 700px) and (max-width: 900px) {
|
||||||
.c_dbu4q { align-content: flex-start; align-items: flex-start; align-self: stretch; display: flex; flex-wrap: wrap; gap: 20px; }
|
.c_dbu4q { align-content: flex-start; align-items: flex-start; align-self: stretch; display: flex; flex-wrap: wrap; gap: 20px; }
|
||||||
.c_fwe1m { align-items: flex-start; display: flex; flex-direction: column; gap: 20px; width: 335px; }
|
.c_fwe1m { align-items: flex-start; display: flex; flex-direction: column; gap: 20px; width: 335px; }
|
||||||
.c_s7it2 { align-items: flex-start; align-self: stretch; display: flex; gap: 20px; }
|
.c_s7it2 { align-items: flex-start; align-self: stretch; display: flex; gap: 20px; }
|
||||||
.c_cr9xg { align-items: center; background: #FFF; display: flex; flex-direction: column; gap: 30px; padding-left: 50px; }
|
.c_cr9xg { align-items: center; background: #FFF; display: flex; flex-direction: column; gap: 30px; padding-left: 50px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Desktop */
|
|
||||||
@media (min-width: 901px) {
|
@media (min-width: 901px) {
|
||||||
.c_dbu4q { align-content: flex-start; align-items: flex-start; display: flex; flex-wrap: wrap; gap: 20px; width: 100%; }
|
.c_dbu4q { align-content: flex-start; align-items: flex-start; display: flex; flex-wrap: wrap; gap: 20px; width: 100%; }
|
||||||
.c_fwe1m { align-items: flex-start; display: flex; flex-direction: column; flex-shrink: 0; gap: 20px; width: 335px; }
|
.c_fwe1m { align-items: flex-start; display: flex; flex-direction: column; flex-shrink: 0; gap: 20px; width: 335px; }
|
||||||
|
|||||||
@ -203,12 +203,16 @@
|
|||||||
</form>
|
</form>
|
||||||
{% if user.send_address %}
|
{% if user.send_address %}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.getElementById('address').value = '{{ user.send_address[-1] }}'
|
document.getElementById('address').value = '{{ user.send_address[-1] }}'
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.places %}
|
{% if user.places %}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.getElementById('place').value = '{{ user.places[-1] }}'
|
document.getElementById('place').value = '{{ user.places[-1] }}'
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script defer>
|
<script defer>
|
||||||
@ -363,6 +367,7 @@ function bindLinkValidation({
|
|||||||
linkErrorSelector: '#link-error-1'
|
linkErrorSelector: '#link-error-1'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script defer>
|
<script defer>
|
||||||
@ -384,6 +389,7 @@ function bindLinkValidation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTomorrowAtNoon();
|
setTomorrowAtNoon();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
|
|
||||||
@ -551,6 +557,7 @@ function bindLinkValidation({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -293,6 +293,7 @@ bindLinkValidation({
|
|||||||
linkInputSelector: '#tizer_link',
|
linkInputSelector: '#tizer_link',
|
||||||
linkErrorSelector: '#link-error-1'
|
linkErrorSelector: '#link-error-1'
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
function setTomorrowAtNoon() {
|
function setTomorrowAtNoon() {
|
||||||
@ -313,6 +314,7 @@ bindLinkValidation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTomorrowAtNoon();
|
setTomorrowAtNoon();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
|
|
||||||
@ -545,6 +547,7 @@ bindLinkValidation({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,7 @@ fetch('/api/me')
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('There was a problem with the fetch operation:', error);
|
console.error('There was a problem with the fetch operation:', error);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -60,19 +60,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function sendToNextPage(e) {
|
function sendToNextPage(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const email = document.getElementById('email').value.trim();
|
const email = document.getElementById('email').value.trim();
|
||||||
|
|
||||||
if (email) {
|
if (email) {
|
||||||
localStorage.setItem('restoreEmail', email);
|
localStorage.setItem('restoreEmail', email);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.href = "/restore{% if next %}?next={{next}}{% endif %}";
|
window.location.href = "/restore{% if next %}?next={{next}}{% endif %}";
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const emailInput = document.getElementById('email');
|
const emailInput = document.getElementById('email');
|
||||||
const passwordInput = document.getElementById('password');
|
const passwordInput = document.getElementById('password');
|
||||||
@ -210,9 +210,11 @@ function sendToNextPage(e) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section() }}
|
{{ footer.section() }}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
fetch('/api/me')
|
fetch('/api/me')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@ -229,6 +231,7 @@ fetch('/api/me')
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('There was a problem with the fetch operation:', error);
|
console.error('There was a problem with the fetch operation:', error);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -20,19 +20,19 @@
|
|||||||
<iframe id="modalVideoFrame" width="853" height="480" allow="autoplay; encrypted-media; fullscreen; picture-in-picture;" frameborder="0" allowfullscreen style="height: 100%;position: absolute;left: 0;transition: none;min-width: 100%;object-fit: scale-down;"></iframe>
|
<iframe id="modalVideoFrame" width="853" height="480" allow="autoplay; encrypted-media; fullscreen; picture-in-picture;" frameborder="0" allowfullscreen style="height: 100%;position: absolute;left: 0;transition: none;min-width: 100%;object-fit: scale-down;"></iframe>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
document.getElementById('openModalButtonVideo').addEventListener('click', function() {
|
document.getElementById('openModalButtonVideo').addEventListener('click', function() {
|
||||||
const modalVideoFrame = document.getElementById('modalVideoFrame');
|
const modalVideoFrame = document.getElementById('modalVideoFrame');
|
||||||
const modal = document.getElementById('modalVideo');
|
const modal = document.getElementById('modalVideo');
|
||||||
modalVideoFrame.src = 'https://vk.com/video_ext.php?oid=-213856894&id=456239020&hd=2';
|
modalVideoFrame.src = 'https://vk.com/video_ext.php?oid=-213856894&id=456239020&hd=2';
|
||||||
modal.style.display = 'flex';
|
modal.style.display = 'flex';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
function videocloseModalButton() {
|
function videocloseModalButton() {
|
||||||
document.getElementById('modalVideo').style.display = 'none';
|
document.getElementById('modalVideo').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
|||||||
@ -19,12 +19,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if news%}
|
{% if news%}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
document.getElementById('title').value = '{{news.title or ""}}';
|
document.getElementById('title').value = '{{news.title or ""}}';
|
||||||
document.getElementById('description').value = `{{news.description or ""}}`;
|
document.getElementById('description').value = `{{news.description or ""}}`;
|
||||||
document.getElementById('short_description').value = `{{news.short_description or ""}}`;
|
document.getElementById('short_description').value = `{{news.short_description or ""}}`;
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="c_rtopc">
|
<div class="c_rtopc">
|
||||||
@ -38,6 +40,7 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
const preview = document.getElementById('preview');
|
const preview = document.getElementById('preview');
|
||||||
|
|
||||||
@ -290,6 +293,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -21,9 +21,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if post%}
|
{% if post%}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.getElementById('title').value = `{{post.title or ""}}`
|
document.getElementById('title').value = `{{post.title or ""}}`
|
||||||
document.getElementById('description').value = `{{post.description or ""}}`
|
document.getElementById('description').value = `{{post.description or ""}}`
|
||||||
document.getElementById('short_description').value = `{{post.short_description or ""}}`
|
document.getElementById('short_description').value = `{{post.short_description or ""}}`
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="c_rtopc">
|
<div class="c_rtopc">
|
||||||
@ -37,6 +39,7 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
const preview = document.getElementById('preview');
|
const preview = document.getElementById('preview');
|
||||||
|
|
||||||
@ -289,6 +292,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -281,6 +281,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const images = [
|
const images = [
|
||||||
{% for media in news.orig_media %}
|
{% for media in news.orig_media %}
|
||||||
{ src: "/b/news/{{media}}" },
|
{ src: "/b/news/{{media}}" },
|
||||||
@ -386,6 +387,7 @@
|
|||||||
createSlides();
|
createSlides();
|
||||||
init();
|
init();
|
||||||
setTimeout(updateTransform, 100); // даём браузеру время на рендер
|
setTimeout(updateTransform, 100); // даём браузеру время на рендер
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -207,6 +207,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function saledPaintings(postId) {
|
function saledPaintings(postId) {
|
||||||
fetch(`/api/post/${postId}/sale`, {
|
fetch(`/api/post/${postId}/sale`, {
|
||||||
method: 'PUT'
|
method: 'PUT'
|
||||||
@ -237,8 +238,10 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const images = [
|
const images = [
|
||||||
{% for media in paint.medias_original %}
|
{% for media in paint.medias_original %}
|
||||||
{ src: "/b/posts/{{media}}" },
|
{ src: "/b/posts/{{media}}" },
|
||||||
@ -344,8 +347,10 @@
|
|||||||
createSlides();
|
createSlides();
|
||||||
init();
|
init();
|
||||||
setTimeout(updateTransform, 100); // даём браузеру время на рендер
|
setTimeout(updateTransform, 100); // даём браузеру время на рендер
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function deletePost(postId) {
|
function deletePost(postId) {
|
||||||
fetch(`/api/post/${postId}`, {
|
fetch(`/api/post/${postId}`, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
@ -374,6 +379,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -52,6 +52,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const post = JSON.parse({{ post|tojson }});
|
const post = JSON.parse({{ post|tojson }});
|
||||||
const postId = post._id;
|
const postId = post._id;
|
||||||
|
|
||||||
@ -415,6 +416,7 @@
|
|||||||
window.addEventListener('beforeunload', () => {
|
window.addEventListener('beforeunload', () => {
|
||||||
filesOrdered.forEach(revokeObjectURLSafe);
|
filesOrdered.forEach(revokeObjectURLSafe);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -21,10 +21,12 @@
|
|||||||
<label for="grade" class="c_z3ybu floating-label">Звание</label>
|
<label for="grade" class="c_z3ybu floating-label">Звание</label>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
showToast({message: 'Выберите из списка актуальное звание', status: 'info', duration:3000});
|
showToast({message: 'Выберите из списка актуальное звание', status: 'info', duration:3000});
|
||||||
});
|
});
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="c_aihm6 floating-group">
|
<div class="c_aihm6 floating-group">
|
||||||
<input name="title" id="title" class="c_xhd5k" required data-toast="Поле Название должно быть заполнено"/>
|
<input name="title" id="title" class="c_xhd5k" required data-toast="Поле Название должно быть заполнено"/>
|
||||||
@ -133,6 +135,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
const preview = document.getElementById('preview');
|
const preview = document.getElementById('preview');
|
||||||
const createBtn = document.getElementById('createBtn');
|
const createBtn = document.getElementById('createBtn');
|
||||||
@ -466,8 +469,10 @@
|
|||||||
window.addEventListener('beforeunload', () => {
|
window.addEventListener('beforeunload', () => {
|
||||||
filesOrdered.forEach(revokeObjectURLSafe);
|
filesOrdered.forEach(revokeObjectURLSafe);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
document.getElementById('genre').dataset.list=JSON.stringify([
|
document.getElementById('genre').dataset.list=JSON.stringify([
|
||||||
{
|
{
|
||||||
@ -588,6 +593,7 @@
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section() }}
|
{{ footer.section() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -39,6 +39,7 @@
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
{% macro scrips() -%}
|
{% macro scrips() -%}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function deletePost(postId) {
|
function deletePost(postId) {
|
||||||
fetch(`/api/post/${postId}`, {
|
fetch(`/api/post/${postId}`, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
@ -67,6 +68,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
{% macro style() -%}
|
{% macro style() -%}
|
||||||
|
|||||||
@ -105,6 +105,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function toggleDetails(cell) {
|
function toggleDetails(cell) {
|
||||||
const mainRow = cell.parentElement;
|
const mainRow = cell.parentElement;
|
||||||
const detailsRow = mainRow.nextElementSibling;
|
const detailsRow = mainRow.nextElementSibling;
|
||||||
@ -139,6 +140,7 @@ document.querySelectorAll('.main-row').forEach(row => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -60,6 +60,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function normalizeText(str) {
|
function normalizeText(str) {
|
||||||
return str
|
return str
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
@ -105,7 +106,8 @@ function normalizeText(str) {
|
|||||||
row.classList.toggle("hidden", !match);
|
row.classList.toggle("hidden", !match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -63,6 +63,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
(function(){
|
(function(){
|
||||||
const input = document.getElementById('memberSearch');
|
const input = document.getElementById('memberSearch');
|
||||||
const container = document.querySelector('.c_tihtk');
|
const container = document.querySelector('.c_tihtk');
|
||||||
@ -89,8 +90,10 @@
|
|||||||
// initial: show all
|
// initial: show all
|
||||||
filter();
|
filter();
|
||||||
})();
|
})();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.querySelectorAll('.post').forEach(postEl => {
|
document.querySelectorAll('.post').forEach(postEl => {
|
||||||
const fg = postEl.querySelector('.c_nb6gy.floating-group');
|
const fg = postEl.querySelector('.c_nb6gy.floating-group');
|
||||||
if (!fg) return;
|
if (!fg) return;
|
||||||
@ -133,6 +136,7 @@ document.querySelectorAll('.post').forEach(postEl => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script defer>
|
<script defer>
|
||||||
@ -364,6 +368,7 @@ function loadAndClick() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -404,6 +409,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
{% import "components/profile_card.html" as profile_card %}
|
{% import "components/profile_card.html" as profile_card %}
|
||||||
{% import "components/profile_nav.html" as profile_nav %}
|
{% import "components/profile_nav.html" as profile_nav %}
|
||||||
{% import "competition/list.html" as competition %}
|
{% import "competition/list.html" as competition %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}Где картины{% endblock %}
|
{% block title %}Где картины{% endblock %}
|
||||||
|
|
||||||
@ -25,7 +26,8 @@
|
|||||||
</figcaption>
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
{% for doc in data %}
|
{% for doc in data %}
|
||||||
<figure class="c_4b1hy b_uu2ub" data-delivery-id="{{doc._id}}" data-sender="{{doc.sender._id}}" data-receiver="{{doc.receiver._id}}">
|
<figure class="c_4b1hy b_uu2ub" data-delivery-id="{{doc._id}}" data-sender="{{doc.sender._id}}"
|
||||||
|
data-receiver="{{doc.receiver._id}}">
|
||||||
<figcaption class="c_3g8gh b_pvw5a" data-id="{{doc._id}}">
|
<figcaption class="c_3g8gh b_pvw5a" data-id="{{doc._id}}">
|
||||||
{% if doc.status == 'Ожидает отправки' %}
|
{% if doc.status == 'Ожидает отправки' %}
|
||||||
<div class="b_thlt1">
|
<div class="b_thlt1">
|
||||||
@ -44,205 +46,74 @@
|
|||||||
<span class="b_5dr47_2">{{doc.status}}</span>
|
<span class="b_5dr47_2">{{doc.status}}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.type == 'exhibition' and doc.get('exhibition') or doc.status == 'Продано' %}
|
{% if doc.type == 'exhibition' and doc.get('exhibition') or doc.status == 'Продано' %}
|
||||||
<p class="b_6spaf">{{doc.exhibition.title}}</p>
|
<p class="b_6spaf">{{doc.exhibition.title}}</p>
|
||||||
<p>Место проведения: {{ doc.exhibition.get('place') }}</p>
|
<p>Место проведения: {{ doc.exhibition.get('place') }}</p>
|
||||||
<div class="b_xz6em">
|
<div class="b_xz6em">
|
||||||
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
||||||
<div class="c_9hjdk b_ffruz">
|
<div class="c_9hjdk b_ffruz">
|
||||||
<span class="b_qla2q">Организатор</span>
|
<span class="b_qla2q">Организатор</span>
|
||||||
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if doc.get('user') and user._id == doc.user._id%}
|
{% if doc.get('user') and user._id == doc.user._id%}
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{{ contacts.details(doc.receiver) }}
|
||||||
<summary>Показать контакты</summary>
|
{% endif %}
|
||||||
<div class="menua">
|
{% if doc.get('user') %}
|
||||||
<a class="icona" href="/artists/{{doc.receiver._id}}">
|
<div class="b_xz6em">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
<img src="/a/{{doc.user._id}}" class="b_ob59y">
|
||||||
<path
|
<div class="c_9hjdk b_ffruz">
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
<span class="b_qla2q">Художник</span>
|
||||||
</svg>
|
<span class="c_zm0m4 b_09est">{{doc.user.username}}</span>
|
||||||
<span>Профиль</span>
|
</div>
|
||||||
</a>
|
</div>
|
||||||
<a class="icona" href="tel:{{doc.receiver.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
{% if user._id != doc.user._id%}
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
{{ contacts.details(doc.user) }}
|
||||||
<path
|
{% endif %}
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
{% endif %}
|
||||||
</svg>
|
|
||||||
<span>{{ doc.receiver.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{doc.receiver.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{doc.receiver.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if doc.receiver.vk_id %}https://vk.ru/im?sel={{doc.receiver.vk_id}}{%else%}#{%endif%}"
|
|
||||||
{% if not doc.receiver.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if doc.address %}
|
{% if doc.address %}
|
||||||
<p class="b_6spaf">Адрес: {{doc.address}}</p>
|
<p class="b_6spaf">Адрес: {{doc.address}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.back_address %}
|
{% if doc.back_address %}
|
||||||
<p class="b_6spaf">Адрес для возврата: {{doc.back_address}}</p>
|
<p class="b_6spaf">Адрес для возврата: {{doc.back_address}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.delivery_type %}
|
{% if doc.delivery_type %}
|
||||||
<p class="b_6spaf">Способ доставки: {{doc.delivery_type}}</p>
|
<p class="b_6spaf">Способ доставки: {{doc.delivery_type}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.track %}
|
{% if doc.track %}
|
||||||
<p class="b_6spaf">Трек-номер: {{doc.track}}</p>
|
<p class="b_6spaf">Трек-номер: {{doc.track}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.sender %}
|
{% if doc.sender %}
|
||||||
<div class="b_xz6em">
|
<div class="b_xz6em">
|
||||||
<img src="/a/{{doc.sender._id}}" class="b_ob59y">
|
<img src="/a/{{doc.sender._id}}" class="b_ob59y">
|
||||||
<div class="c_9hjdk b_ffruz">
|
<div class="c_9hjdk b_ffruz">
|
||||||
<span class="b_qla2q">Отправитель</span>
|
<span class="b_qla2q">Отправитель</span>
|
||||||
<span class="c_zm0m4 b_09est">{{doc.sender.username}}</span>
|
<span class="c_zm0m4 b_09est">{{doc.sender.username}}</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if user._id != doc.sender._id%}
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{% if user._id != doc.sender._id%}
|
||||||
<summary>Показать контакты</summary>
|
{{ contacts.details(doc.sender) }}
|
||||||
<div class="menua">
|
{% endif %}
|
||||||
<a class="icona" href="/artists/{{doc.sender._id}}">
|
{% endif %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
{% if doc.receiver %}
|
||||||
<path
|
<div class="b_xz6em">
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
||||||
</svg>
|
<div class="c_9hjdk b_ffruz">
|
||||||
<span>Профиль</span>
|
<span class="b_qla2q">Получатель</span>
|
||||||
</a>
|
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
||||||
<a class="icona" href="tel:{{doc.sender.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
<span class="b_qla2q">+7 *** *** {{ doc.receiver.phone[-4:] }}</span>
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ doc.sender.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{doc.sender.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{doc.sender.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if doc.sender.vk_id %}https://vk.ru/im?sel={{doc.sender.vk_id}}{%else%}#{%endif%}"
|
|
||||||
{% if not doc.sender.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{doc.sender.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{doc.sender.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{doc.sender.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if doc.receiver %}
|
|
||||||
<div class="b_xz6em">
|
|
||||||
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
|
||||||
<div class="c_9hjdk b_ffruz">
|
|
||||||
<span class="b_qla2q">Получатель</span>
|
|
||||||
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
|
||||||
<span class="b_qla2q">+7 *** *** {{ doc.receiver.phone[-4:] }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if user._id != doc.receiver._id%}
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{% if user._id != doc.receiver._id%}
|
||||||
<summary>Показать контакты</summary>
|
{{ contacts.details(doc.receiver) }}
|
||||||
<div class="menua">
|
{% endif %}
|
||||||
<a class="icona" href="/artists/{{doc.receiver._id}}">
|
{% endif %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
|
||||||
</svg>
|
|
||||||
<span>Профиль</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="tel:{{doc.receiver.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ doc.receiver.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{doc.receiver.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{doc.receiver.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if doc.receiver.vk_id %}https://vk.ru/im?sel={{doc.receiver.vk_id}}{%else%}#{%endif%}"
|
|
||||||
{% if not doc.receiver.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="b_6spaf">
|
<p class="b_6spaf">
|
||||||
{{ (doc._id.generation_time.strftime('%d.%m.%Y')) if doc._id else ''}}
|
{{ (doc._id.generation_time.strftime('%d.%m.%Y')) if doc._id else ''}}
|
||||||
<b>{{ '%02d' % ((doc._id.generation_time.hour + 3) % 24) if doc._id else '' }}:{{ '%02d' % doc._id.generation_time.minute if doc._id else '' }}</b>
|
<b>{{ '%02d' % ((doc._id.generation_time.hour + 3) % 24) if doc._id else '' }}:{{ '%02d' %
|
||||||
|
doc._id.generation_time.minute if doc._id else '' }}</b>
|
||||||
</p>
|
</p>
|
||||||
</figcaption>
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
@ -251,7 +122,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -259,6 +129,7 @@
|
|||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
{{ competition.style() }}
|
{{ competition.style() }}
|
||||||
{{ profile_nav.style() }}
|
{{ profile_nav.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>/* Base (common) styles */
|
<style>/* Base (common) styles */
|
||||||
.c_aihm6{width: 100%;}
|
.c_aihm6{width: 100%;}
|
||||||
.mw{margin: 0 20px;
|
.mw{margin: 0 20px;
|
||||||
@ -394,15 +265,6 @@ picture>img{ width: 100%; object-fit: scale-down; }
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
.menua{width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 7px;
|
|
||||||
margin: 10px 20px;}
|
|
||||||
.icona{display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: center;}
|
|
||||||
.icona>span{color: #5F1798;}
|
|
||||||
.c_hysjg {
|
.c_hysjg {
|
||||||
color: #0ED646;
|
color: #0ED646;
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
|
|||||||
@ -4,11 +4,13 @@
|
|||||||
{% import "components/profile_card.html" as profile_card %}
|
{% import "components/profile_card.html" as profile_card %}
|
||||||
{% import "components/profile_nav.html" as profile_nav %}
|
{% import "components/profile_nav.html" as profile_nav %}
|
||||||
{% import "competition/list.html" as competition %}
|
{% import "competition/list.html" as competition %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}Где картины{% endblock %}
|
{% block title %}Где картины{% endblock %}
|
||||||
|
|
||||||
{% macro render_doc(doc) %}
|
{% macro render_doc(doc) %}
|
||||||
<figure class="c_4b1hy b_uu2ub" data-exhibition_id="{{doc.get('exhibition_id')}}" data-delivery-id="{{doc._id}}" data-sender="{{doc.sender._id}}" data-receiver="{{doc.receiver._id}}">
|
<figure class="c_4b1hy b_uu2ub" data-exhibition_id="{{doc.get('exhibition_id')}}" data-delivery-id="{{doc._id}}"
|
||||||
|
data-sender="{{doc.sender._id}}" data-receiver="{{doc.receiver._id}}">
|
||||||
<img class="b_1fvkt" src="/b/posts/{{doc.img}}">
|
<img class="b_1fvkt" src="/b/posts/{{doc.img}}">
|
||||||
<figcaption class="c_3g8gh b_pvw5a" data-id="{{doc._id}}">
|
<figcaption class="c_3g8gh b_pvw5a" data-id="{{doc._id}}">
|
||||||
{% if doc.status == 'Ожидает отправки' %}
|
{% if doc.status == 'Ожидает отправки' %}
|
||||||
@ -33,235 +35,97 @@
|
|||||||
<h2 class="c_9hvtd b_f5fb2">{{doc.title}}</h2>
|
<h2 class="c_9hvtd b_f5fb2">{{doc.title}}</h2>
|
||||||
{% if doc.status == 'На выставке' %}
|
{% if doc.status == 'На выставке' %}
|
||||||
<label class="offer-label">
|
<label class="offer-label">
|
||||||
<input type="checkbox"
|
<input type="checkbox" onchange="saledPaintings('{{doc.post_id}}')" class="offer-checkbox" {% if
|
||||||
onchange="saledPaintings('{{doc.post_id}}')"
|
doc.status=='Продано' %}checked{%endif%}>
|
||||||
class="offer-checkbox"
|
|
||||||
{% if doc.status == 'Продано' %}checked{%endif%}>
|
|
||||||
<span>Продано</span>
|
<span>Продано</span>
|
||||||
</label>
|
</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.type == 'exhibition' and doc.get('exhibition') or doc.status == 'Продано' %}
|
{% if doc.type == 'exhibition' and doc.get('exhibition') or doc.status == 'Продано' %}
|
||||||
<p class="b_6spaf">{{doc.get('exhibition').title}}</p>
|
<p class="b_6spaf">{{doc.get('exhibition').title}}</p>
|
||||||
<div class="b_xz6em">
|
<div class="b_xz6em">
|
||||||
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
||||||
<div class="c_9hjdk b_ffruz">
|
<div class="c_9hjdk b_ffruz">
|
||||||
<span class="b_qla2q">Организатор</span>
|
<span class="b_qla2q">Организатор</span>
|
||||||
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if doc.get('user') and user._id == doc.user._id%}
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{% if doc.get('user') and user._id == doc.user._id%}
|
||||||
<summary>Показать контакты</summary>
|
{{ contacts.details(doc.receiver) }}
|
||||||
<div class="menua">
|
{% endif %}
|
||||||
<a class="icona" href="/artists/{{doc.receiver._id}}">
|
{% if doc.get('user') %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
<div class="b_xz6em">
|
||||||
<path
|
<img src="/a/{{doc.user._id}}" class="b_ob59y">
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
<div class="c_9hjdk b_ffruz">
|
||||||
</svg>
|
<span class="b_qla2q">Художник</span>
|
||||||
<span>Профиль</span>
|
<span class="c_zm0m4 b_09est">{{doc.user.username}}</span>
|
||||||
</a>
|
</div>
|
||||||
<a class="icona" href="tel:{{doc.receiver.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
</div>
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
{% if user._id != doc.user._id%}
|
||||||
<path
|
{{ contacts.details(doc.user) }}
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
{% endif %}
|
||||||
</svg>
|
{% endif %}
|
||||||
<span>{{ doc.receiver.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{doc.receiver.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{doc.receiver.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if doc.receiver.vk_id %}https://vk.ru/im?sel={{doc.receiver.vk_id}}{%else%}#{%endif%}"
|
|
||||||
{% if not doc.receiver.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if doc.address %}
|
{% if doc.address %}
|
||||||
<p class="b_6spaf">Адрес: {{doc.address}}</p>
|
<p class="b_6spaf">Адрес: {{doc.address}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.back_address %}
|
{% if doc.back_address %}
|
||||||
<p class="b_6spaf">Адрес для возврата: {{doc.back_address}}</p>
|
<p class="b_6spaf">Адрес для возврата: {{doc.back_address}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.delivery_type %}
|
{% if doc.delivery_type %}
|
||||||
<p class="b_6spaf">Способ доставки: {{doc.delivery_type}}</p>
|
<p class="b_6spaf">Способ доставки: {{doc.delivery_type}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.track %}
|
{% if doc.track %}
|
||||||
<p class="b_6spaf">Трэк-номер: {{doc.track}}</p>
|
<p class="b_6spaf">Трэк-номер: {{doc.track}}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if doc.sender %}
|
{% if doc.sender %}
|
||||||
<div class="b_xz6em">
|
<div class="b_xz6em">
|
||||||
<img src="/a/{{doc.sender._id}}" class="b_ob59y">
|
<img src="/a/{{doc.sender._id}}" class="b_ob59y">
|
||||||
<div class="c_9hjdk b_ffruz">
|
<div class="c_9hjdk b_ffruz">
|
||||||
<span class="b_qla2q">Отправитель</span>
|
<span class="b_qla2q">Отправитель</span>
|
||||||
<span class="c_zm0m4 b_09est">{{doc.sender.username}}</span>
|
<span class="c_zm0m4 b_09est">{{doc.sender.username}}</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if user._id != doc.sender._id%}
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{% if user._id != doc.sender._id%}
|
||||||
<summary>Показать контакты</summary>
|
{{ contacts.details(doc.sender) }}
|
||||||
<div class="menua">
|
{% endif %}
|
||||||
<a class="icona" href="/artists/{{doc.sender._id}}">
|
{% endif %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
|
||||||
</svg>
|
|
||||||
<span>Профиль</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="tel:{{doc.sender.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ doc.sender.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{doc.sender.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{doc.sender.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if doc.sender.vk_id %}https://vk.ru/im?sel={{doc.sender.vk_id}}{%else%}#{%endif%}"
|
{% if doc.receiver %}
|
||||||
{% if not doc.sender.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
<div class="b_xz6em">
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
||||||
</a>
|
<div class="c_9hjdk b_ffruz">
|
||||||
|
<span class="b_qla2q">Получатель</span>
|
||||||
<a class="icona" href="https://telegram.me/{{doc.sender.phone.split(',')[-1].strip()}}">
|
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
<span class="b_qla2q">+7 *** *** {{ doc.receiver.phone[-4:] }}</span>
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{doc.sender.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{doc.sender.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if doc.receiver %}
|
|
||||||
<div class="b_xz6em">
|
|
||||||
<img src="/a/{{doc.receiver._id}}" class="b_ob59y">
|
|
||||||
<div class="c_9hjdk b_ffruz">
|
|
||||||
<span class="b_qla2q">Получатель</span>
|
|
||||||
<span class="c_zm0m4 b_09est">{{doc.receiver.username}}</span>
|
|
||||||
<span class="b_qla2q">+7 *** *** {{ doc.receiver.phone[-4:] }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if user._id != doc.receiver._id%}
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{% if user._id != doc.receiver._id%}
|
||||||
<summary>Показать контакты</summary>
|
{{ contacts.details(doc.receiver) }}
|
||||||
<div class="menua">
|
{% endif %}
|
||||||
<a class="icona" href="/artists/{{doc.receiver._id}}">
|
{% endif %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
|
||||||
</svg>
|
|
||||||
<span>Профиль</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="tel:{{doc.receiver.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ doc.receiver.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{doc.receiver.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{doc.receiver.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if doc.receiver.vk_id %}https://vk.ru/im?sel={{doc.receiver.vk_id}}{%else%}#{%endif%}"
|
{# Checkbox instead of per-item button #}
|
||||||
{% if not doc.receiver.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
{% if doc.status in ['Ожидает отправки', 'Возврат художнику'] and user._id == doc.sender._id %}
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
<label class="offer-label delivery-checkbox-label">
|
||||||
</a>
|
<input type="checkbox" class="offer-checkbox delivery-checkbox send-checkbox" data-id="{{doc._id}}"
|
||||||
|
data-sender="{{doc.sender._id}}" data-receiver="{{doc.receiver._id}}">
|
||||||
|
<span>Выбрать для отправки</span>
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
{% if doc.status == 'Ожидает получения' and user._id == doc.receiver._id %}
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
<label class="offer-label delivery-checkbox-label">
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
<input type="checkbox" class="offer-checkbox delivery-checkbox accept-checkbox" data-id="{{doc._id}}">
|
||||||
</a>
|
<span>Выбрать для получения</span>
|
||||||
<a class="icona" href="https://max.ru/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
</label>
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
{% endif %}
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{doc.receiver.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{# Checkbox instead of per-item button #}
|
|
||||||
{% if doc.status in ['Ожидает отправки', 'Возврат художнику'] and user._id == doc.sender._id %}
|
|
||||||
<label class="offer-label delivery-checkbox-label">
|
|
||||||
<input type="checkbox"
|
|
||||||
class="offer-checkbox delivery-checkbox send-checkbox"
|
|
||||||
data-id="{{doc._id}}"
|
|
||||||
data-sender="{{doc.sender._id}}"
|
|
||||||
data-receiver="{{doc.receiver._id}}">
|
|
||||||
<span>Выбрать для отправки</span>
|
|
||||||
</label>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if doc.status == 'Ожидает получения' and user._id == doc.receiver._id %}
|
|
||||||
<label class="offer-label delivery-checkbox-label">
|
|
||||||
<input type="checkbox"
|
|
||||||
class="offer-checkbox delivery-checkbox accept-checkbox"
|
|
||||||
data-id="{{doc._id}}">
|
|
||||||
<span>Выбрать для получения</span>
|
|
||||||
</label>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p class="b_6spaf">
|
<p class="b_6spaf">
|
||||||
{{ (doc._id.generation_time.strftime('%d.%m.%Y')) if doc._id else ''}}
|
{{ (doc._id.generation_time.strftime('%d.%m.%Y')) if doc._id else ''}}
|
||||||
<b>{{ '%02d' % ((doc._id.generation_time.hour + 3) % 24) if doc._id else '' }}:{{ '%02d' % doc._id.generation_time.minute if doc._id else '' }}</b>
|
<b>{{ '%02d' % ((doc._id.generation_time.hour + 3) % 24) if doc._id else '' }}:{{ '%02d' %
|
||||||
|
doc._id.generation_time.minute if doc._id else '' }}</b>
|
||||||
</p>
|
</p>
|
||||||
</figcaption>
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
@ -362,6 +226,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function saledPaintings(postId) {
|
function saledPaintings(postId) {
|
||||||
fetch(`/api/post/${postId}/sale`, {
|
fetch(`/api/post/${postId}/sale`, {
|
||||||
method: 'PUT'
|
method: 'PUT'
|
||||||
@ -392,8 +257,10 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function selectAll(elem, send=true){
|
function selectAll(elem, send=true){
|
||||||
if (send){
|
if (send){
|
||||||
if (elem.checked){
|
if (elem.checked){
|
||||||
@ -420,8 +287,10 @@
|
|||||||
updateStickyButtons();
|
updateStickyButtons();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
// Helpers: collect selected IDs
|
// Helpers: collect selected IDs
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
@ -668,6 +537,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
function toggleTrackField() {
|
function toggleTrackField() {
|
||||||
@ -717,8 +587,10 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
document.getElementById('exhibition_id').value = exhibition_id;
|
document.getElementById('exhibition_id').value = exhibition_id;
|
||||||
}
|
}
|
||||||
filterFigure(exhibition_id);
|
filterFigure(exhibition_id);
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const deliveryType = document.getElementById('delivery_type');
|
const deliveryType = document.getElementById('delivery_type');
|
||||||
const track = document.getElementById('track');
|
const track = document.getElementById('track');
|
||||||
|
|
||||||
@ -734,6 +606,7 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
|
|
||||||
deliveryType.addEventListener('change', toggleTrack);
|
deliveryType.addEventListener('change', toggleTrack);
|
||||||
toggleTrack();
|
toggleTrack();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -748,17 +621,9 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
{{ competition.style() }}
|
{{ competition.style() }}
|
||||||
{{ profile_nav.style() }}
|
{{ profile_nav.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>
|
<style>
|
||||||
/* Base (common) styles */
|
/* Base (common) styles */
|
||||||
.menua{width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 7px;
|
|
||||||
margin: 10px 20px;}
|
|
||||||
.icona{display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: center;}
|
|
||||||
.icona>span{color: #5F1798;}
|
|
||||||
.c_aihm6{width: 100%;}
|
.c_aihm6{width: 100%;}
|
||||||
.mw{margin: 0 20px;
|
.mw{margin: 0 20px;
|
||||||
width: 100%;}
|
width: 100%;}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
{% import "components/profile_card.html" as profile_card %}
|
{% import "components/profile_card.html" as profile_card %}
|
||||||
{% import "components/profile_nav.html" as profile_nav %}
|
{% import "components/profile_nav.html" as profile_nav %}
|
||||||
{% import "competition/list.html" as competition %}
|
{% import "competition/list.html" as competition %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}Выставки{% endblock %}
|
{% block title %}Выставки{% endblock %}
|
||||||
|
|
||||||
@ -40,14 +41,17 @@
|
|||||||
<h3 class="c_hysjg b_8f3uh" id="preview_title">{{i.title}}</h3>
|
<h3 class="c_hysjg b_8f3uh" id="preview_title">{{i.title}}</h3>
|
||||||
</header>
|
</header>
|
||||||
<p class="c_2fr39 b_tfnz2" id="preview_topic">{{i.topic}}</p>
|
<p class="c_2fr39 b_tfnz2" id="preview_topic">{{i.topic}}</p>
|
||||||
|
</a>
|
||||||
|
{% if i.user %}
|
||||||
<div class="c_dbbe4 b_otttb">
|
<div class="c_dbbe4 b_otttb">
|
||||||
{% if i.user %}
|
|
||||||
<img crossorigin="anonymous" fetchpriority="high" loading="eager" class="c_pm80w b_a68fq" src="/a/{{i.user._id}}" alt="{{ i.user.username | e }}">
|
<img crossorigin="anonymous" fetchpriority="high" loading="eager" class="c_pm80w b_a68fq" src="/a/{{i.user._id}}" alt="{{ i.user.username | e }}">
|
||||||
<div class="c_4402p b_ntazj">
|
<div class="c_4402p b_ntazj">
|
||||||
<p class="c_kvah4 b_ghosy">{{ i.user.username }}</p>
|
<p class="c_kvah4 b_ghosy">{{ i.user.username }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{{ contacts.details(i.user) }}
|
||||||
|
{% endif %}
|
||||||
|
<a class="b_73p10" href="/exhibition/{{i._id}}">
|
||||||
<p class="c_2fr39 b_tfnz2">Подробнее</p>
|
<p class="c_2fr39 b_tfnz2">Подробнее</p>
|
||||||
</a>
|
</a>
|
||||||
<p class="c_drpqj b_mp1wb">{{ ( i._id.generation_time.strftime('%d.%m.%Y')) if i._id else ''}}</p>
|
<p class="c_drpqj b_mp1wb">{{ ( i._id.generation_time.strftime('%d.%m.%Y')) if i._id else ''}}</p>
|
||||||
@ -58,7 +62,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -66,28 +69,21 @@
|
|||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
{{ profile_nav.style() }}
|
{{ profile_nav.style() }}
|
||||||
{{ competition.style() }}
|
{{ competition.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
/* Mobile */
|
/* Mobile */
|
||||||
@media (max-width: 699px) {
|
@media (max-width: 699px) {
|
||||||
.c_mrl59 { align-items: center; background: #5F1798; border-radius: 25px; bottom: -15px; display: flex; height: 50px; justify-content: center; position: absolute; right: -15px; width: 50px; }
|
.c_mrl59 { align-items: center; background: #5F1798; border-radius: 25px; bottom: -15px; display: flex; height: 50px; justify-content: center; position: absolute; right: -15px; width: 50px; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tablet */
|
/* Tablet */
|
||||||
@media (min-width: 700px) and (max-width: 900px) {
|
@media (min-width: 700px) and (max-width: 900px) {
|
||||||
.c_iiehk { align-items: center; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 335px; }
|
.c_iiehk { align-items: center; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 335px; }
|
||||||
.c_nnsh6>a>img{display: none;}
|
.c_nnsh6>a>img{display: none;}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Desktop */
|
/* Desktop */
|
||||||
@media (min-width: 901px) {
|
@media (min-width: 901px) {
|
||||||
.c_iiehk { align-items: flex-end; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 310px; }
|
.c_iiehk { align-items: flex-end; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 310px; }
|
||||||
.c_nnsh6>a>img{display: none;}
|
.c_nnsh6>a>img{display: none;}
|
||||||
|
|
||||||
}</style>
|
}</style>
|
||||||
{{ footer.style() }}
|
{{ footer.style() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -217,6 +217,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.getElementById('female_name_lastname').value = `{% if user.get('female_name_lastname') is not none %}{{user.get('female_name_lastname','') }}{% endif %}`
|
document.getElementById('female_name_lastname').value = `{% if user.get('female_name_lastname') is not none %}{{user.get('female_name_lastname','') }}{% endif %}`
|
||||||
document.getElementById('birthday').value = `{% if user.get('birthday') is not none %}{{user.get('birthday','') }}{% endif %}`
|
document.getElementById('birthday').value = `{% if user.get('birthday') is not none %}{{user.get('birthday','') }}{% endif %}`
|
||||||
document.getElementById('living_place').value = `{% if user.get('living_place') is not none %}{{user.get('living_place','') }}{% endif %}`
|
document.getElementById('living_place').value = `{% if user.get('living_place') is not none %}{{user.get('living_place','') }}{% endif %}`
|
||||||
@ -248,12 +249,16 @@ document.getElementById('own_workshop').value = `{% if user.get('own_workshop')
|
|||||||
document.getElementById('workshop_tour').value = `{% if user.get('workshop_tour') is not none %}{{user.get('workshop_tour','') }}{% endif %}`
|
document.getElementById('workshop_tour').value = `{% if user.get('workshop_tour') is not none %}{{user.get('workshop_tour','') }}{% endif %}`
|
||||||
document.getElementById('biography').value = `{% if user.get('biography') is not none %}{{user.get('biography','') }}{% endif %}`
|
document.getElementById('biography').value = `{% if user.get('biography') is not none %}{{user.get('biography','') }}{% endif %}`
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("day"),t=document.getElementById("month"),l=document.getElementById("year"),n=document.getElementById("birthday"),a=new Date().getFullYear(),u=["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"];function i(t=31){e.innerHTML="";for(let l=1;l<=t;l++){let n=document.createElement("option");n.value=String(l),n.text=String(l),e.appendChild(n)}}function o(){t.innerHTML="",u.forEach((e,l)=>{let n=document.createElement("option");n.value=String(l+1),n.text=e,t.appendChild(n)})}function v(e=1900,t=a){l.innerHTML="";for(let n=t;n>=e;n--){let u=document.createElement("option");u.value=String(n),u.text=String(n),l.appendChild(u)}}let d=e=>String(e).padStart(2,"0");function p(e){if(!e)return;let n=e.split("-");if(3!==n.length)return;let[a,u,i]=n.map(Number);g(l,String(a)),g(t,String(u)),s(a,u,i)}function r(){let a=Number(l.value)||1900,u=Number(t.value)||1,o=Number(e.value)||1,v=new Date(a,u,0).getDate();e.options.length!==v&&i(v),o>v&&(o=v);let p=`${a}-${d(u)}-${d(o)}`;n.value=p,g(e,String(o))}function s(t,l,n){let a=new Date(Number(t),Number(l),0).getDate(),u=Number(e.value)||1;i(a),g(e,String(Math.min(n||u,a)))}function g(e,t){let l=Array.from(e.options).find(e=>e.value===t||e.text===t);if(l)e.value=l.value;else{let n=document.createElement("option");n.text=t,n.value=t,e.appendChild(n),e.value=t}}o(),v();let h=n.value?Number(n.value.split("-")[0]):l.options.length?Number(l.options[0].value):a,c=n.value?Number(n.value.split("-")[1]):1;n.value&&n.value.split("-")[2];let f=new Date(h,c,0).getDate();i(f),n.value?p(n.value):(!l.value&&l.options.length&&(l.value=l.options[0].value),!t.value&&t.options.length&&(t.value=t.options[0].value),!e.value&&e.options.length&&(e.value=e.options[0].value),r()),n.addEventListener("change",()=>{p(n.value)}),l.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),t.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),e.addEventListener("change",r)});
|
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("day"),t=document.getElementById("month"),l=document.getElementById("year"),n=document.getElementById("birthday"),a=new Date().getFullYear(),u=["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"];function i(t=31){e.innerHTML="";for(let l=1;l<=t;l++){let n=document.createElement("option");n.value=String(l),n.text=String(l),e.appendChild(n)}}function o(){t.innerHTML="",u.forEach((e,l)=>{let n=document.createElement("option");n.value=String(l+1),n.text=e,t.appendChild(n)})}function v(e=1900,t=a){l.innerHTML="";for(let n=t;n>=e;n--){let u=document.createElement("option");u.value=String(n),u.text=String(n),l.appendChild(u)}}let d=e=>String(e).padStart(2,"0");function p(e){if(!e)return;let n=e.split("-");if(3!==n.length)return;let[a,u,i]=n.map(Number);g(l,String(a)),g(t,String(u)),s(a,u,i)}function r(){let a=Number(l.value)||1900,u=Number(t.value)||1,o=Number(e.value)||1,v=new Date(a,u,0).getDate();e.options.length!==v&&i(v),o>v&&(o=v);let p=`${a}-${d(u)}-${d(o)}`;n.value=p,g(e,String(o))}function s(t,l,n){let a=new Date(Number(t),Number(l),0).getDate(),u=Number(e.value)||1;i(a),g(e,String(Math.min(n||u,a)))}function g(e,t){let l=Array.from(e.options).find(e=>e.value===t||e.text===t);if(l)e.value=l.value;else{let n=document.createElement("option");n.text=t,n.value=t,e.appendChild(n),e.value=t}}o(),v();let h=n.value?Number(n.value.split("-")[0]):l.options.length?Number(l.options[0].value):a,c=n.value?Number(n.value.split("-")[1]):1;n.value&&n.value.split("-")[2];let f=new Date(h,c,0).getDate();i(f),n.value?p(n.value):(!l.value&&l.options.length&&(l.value=l.options[0].value),!t.value&&t.options.length&&(t.value=t.options[0].value),!e.value&&e.options.length&&(e.value=e.options[0].value),r()),n.addEventListener("change",()=>{p(n.value)}),l.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),t.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),e.addEventListener("change",r)});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const createBtn = document.getElementById('createBtn');
|
const createBtn = document.getElementById('createBtn');
|
||||||
|
|
||||||
@ -328,6 +333,7 @@ window.location.reload();
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
{% import "/components/footer.html" as footer %}
|
{% import "/components/footer.html" as footer %}
|
||||||
{% import "components/profile_card.html" as profile_card %}
|
{% import "components/profile_card.html" as profile_card %}
|
||||||
{% import "components/profile_nav.html" as profile_nav %}
|
{% import "components/profile_nav.html" as profile_nav %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}Приглашения{% endblock %}
|
{% block title %}Приглашения{% endblock %}
|
||||||
|
|
||||||
@ -199,6 +200,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function selecteAll(elem){
|
function selecteAll(elem){
|
||||||
if (elem.checked){
|
if (elem.checked){
|
||||||
document.querySelectorAll('.yes').forEach(el=>{
|
document.querySelectorAll('.yes').forEach(el=>{
|
||||||
@ -215,6 +217,7 @@
|
|||||||
updateSelectedCount()
|
updateSelectedCount()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if doc.get('type_')=='paint' %}
|
{% if doc.get('type_')=='paint' %}
|
||||||
@ -253,6 +256,7 @@
|
|||||||
{# Sticky bottom action bar #}
|
{# Sticky bottom action bar #}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function toggleTrackField() {
|
function toggleTrackField() {
|
||||||
const deliveryType = document.getElementById('delivery_type');
|
const deliveryType = document.getElementById('delivery_type');
|
||||||
const trackGroup = document.getElementById('track-group');
|
const trackGroup = document.getElementById('track-group');
|
||||||
@ -275,8 +279,10 @@ document.addEventListener('DOMContentLoaded', toggleTrackField);
|
|||||||
|
|
||||||
// Run every time the select changes
|
// Run every time the select changes
|
||||||
document.getElementById('delivery_type')?.addEventListener('change', toggleTrackField);
|
document.getElementById('delivery_type')?.addEventListener('change', toggleTrackField);
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const query = window.location.href.split('?')[1] || '';
|
const query = window.location.href.split('?')[1] || '';
|
||||||
let exhibition_id = null;
|
let exhibition_id = null;
|
||||||
if (query) {
|
if (query) {
|
||||||
@ -302,8 +308,10 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
document.getElementById('exhibition_id').value = exhibition_id;
|
document.getElementById('exhibition_id').value = exhibition_id;
|
||||||
}
|
}
|
||||||
filterFigure(exhibition_id);
|
filterFigure(exhibition_id);
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const deliveryType = document.getElementById('delivery_type');
|
const deliveryType = document.getElementById('delivery_type');
|
||||||
const track = document.getElementById('track');
|
const track = document.getElementById('track');
|
||||||
|
|
||||||
@ -319,8 +327,10 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
|
|
||||||
deliveryType.addEventListener('change', toggleTrack);
|
deliveryType.addEventListener('change', toggleTrack);
|
||||||
toggleTrack();
|
toggleTrack();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
// Helpers: collect selected IDs
|
// Helpers: collect selected IDs
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
@ -561,6 +571,7 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@ -568,6 +579,7 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const LS_KEY = 'selected_posts_ids_{{doc._id}}';
|
const LS_KEY = 'selected_posts_ids_{{doc._id}}';
|
||||||
|
|
||||||
function safeParseArray(raw) {
|
function safeParseArray(raw) {
|
||||||
@ -728,6 +740,7 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
setAllCheckboxesFromStorage();
|
setAllCheckboxesFromStorage();
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -742,45 +755,7 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{{ contacts.details(user) }}
|
||||||
<summary>Показать контакты</summary>
|
|
||||||
<div class="menua">
|
|
||||||
<a class="icona" href="tel:{{user.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ user.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{user.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{user.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if user.social_vk %}https://vk.ru/im?sel={{user.social_vk.id}}{%else%}#{%endif%}">
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
{% macro render_links(doc) %}
|
{% macro render_links(doc) %}
|
||||||
{% if doc.get('exhibition')%}
|
{% if doc.get('exhibition')%}
|
||||||
@ -793,6 +768,7 @@ document.getElementById('delivery_type')?.addEventListener('change', toggleTrack
|
|||||||
{% block head %}
|
{% block head %}
|
||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
{{ profile_nav.style() }}
|
{{ profile_nav.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>
|
<style>
|
||||||
/* Base (common) styles */
|
/* Base (common) styles */
|
||||||
.c_aihm6{width: 100%;}
|
.c_aihm6{width: 100%;}
|
||||||
@ -929,15 +905,6 @@ picture>img{ width: 100%; object-fit: scale-down; }
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
.menua{width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 7px;
|
|
||||||
margin: 10px 20px;}
|
|
||||||
.icona{display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: center;}
|
|
||||||
.icona>span{color: #5F1798;}
|
|
||||||
.c_hysjg {
|
.c_hysjg {
|
||||||
color: #0ED646;
|
color: #0ED646;
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const deliveryType = document.getElementById('delivery_type');
|
const deliveryType = document.getElementById('delivery_type');
|
||||||
const trackWrap = document.getElementById('trackWrap');
|
const trackWrap = document.getElementById('trackWrap');
|
||||||
const track = document.getElementById('track');
|
const track = document.getElementById('track');
|
||||||
@ -74,8 +75,10 @@
|
|||||||
|
|
||||||
deliveryType.addEventListener('change', toggleTrack);
|
deliveryType.addEventListener('change', toggleTrack);
|
||||||
toggleTrack();
|
toggleTrack();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('click', async (e) => {
|
document.addEventListener('click', async (e) => {
|
||||||
const btn = e.target.closest('[data-id]');
|
const btn = e.target.closest('[data-id]');
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
@ -143,6 +146,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -3,11 +3,11 @@
|
|||||||
{% import "/components/footer.html" as footer %}
|
{% import "/components/footer.html" as footer %}
|
||||||
{% import "components/profile_card.html" as profile_card %}
|
{% import "components/profile_card.html" as profile_card %}
|
||||||
{% import "components/profile_nav.html" as profile_nav %}
|
{% import "components/profile_nav.html" as profile_nav %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}Приглашения{% endblock %}
|
{% block title %}Приглашения{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{{ header.section(user) }}
|
{{ header.section(user) }}
|
||||||
<section class="c_dg3k4">
|
<section class="c_dg3k4">
|
||||||
@ -76,6 +76,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function accept_inv(inv_id) {
|
async function accept_inv(inv_id) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/invitation/accept/${inv_id}`, {
|
const res = await fetch(`/api/invitation/accept/${inv_id}`, {
|
||||||
@ -95,63 +96,27 @@ async function accept_inv(inv_id) {
|
|||||||
showToast({ message: 'Ошибка сети/сервера', status: 'error' });
|
showToast({ message: 'Ошибка сети/сервера', status: 'error' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% macro render_user_contacts(user) %}
|
{% macro render_user_contacts(user) %}
|
||||||
|
{% if user %}
|
||||||
<div class="c_dbbe4 b_otttb">
|
<div class="c_dbbe4 b_otttb">
|
||||||
{% if user %}
|
|
||||||
<img class="c_pm80w b_a68fq" src="/a/{{user._id}}" alt="{{ user.username | e }}" crossorigin="anonymous"
|
<img class="c_pm80w b_a68fq" src="/a/{{user._id}}" alt="{{ user.username | e }}" crossorigin="anonymous"
|
||||||
fetchpriority="high" loading="eager">
|
fetchpriority="high" loading="eager">
|
||||||
<div class="c_4402p b_ntazj">
|
<div class="c_4402p b_ntazj">
|
||||||
<p class="c_kvah4 b_ghosy">{{ user.username | e }}</p>
|
<p class="c_kvah4 b_ghosy">{{ user.username | e }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{{ contacts.details(user) }}
|
||||||
<summary>Показать контакты</summary>
|
{% endif %}
|
||||||
<div class="menua">
|
|
||||||
<a class="icona" href="tel:{{user.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ user.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{user.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{user.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if user.social_vk %}https://vk.ru/im?sel={{user.social_vk.id}}{%else%}#{%endif%}">
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
{{ profile_nav.style() }}
|
{{ profile_nav.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>
|
<style>
|
||||||
/* Base (common) styles */
|
/* Base (common) styles */
|
||||||
.c_aq9et {
|
.c_aq9et {
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const competitionId = '{{competition._id}}';
|
const competitionId = '{{competition._id}}';
|
||||||
const stopBtn = document.getElementById('stop-btn');
|
const stopBtn = document.getElementById('stop-btn');
|
||||||
|
|
||||||
@ -56,11 +57,13 @@
|
|||||||
console.error('Ошибка при остановке приема заявок', e);
|
console.error('Ошибка при остановке приема заявок', e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
{% elif competition.status == 1 %}
|
{% elif competition.status == 1 %}
|
||||||
<div class="c_d4rhd b_wy3rt ba" id="stop-btn"><span class="c_4sl8i b_bvl0d">Завершить конкурс</span>
|
<div class="c_d4rhd b_wy3rt ba" id="stop-btn"><span class="c_4sl8i b_bvl0d">Завершить конкурс</span>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const competitionId = '{{competition._id}}';
|
const competitionId = '{{competition._id}}';
|
||||||
const stopBtn = document.getElementById('stop-btn');
|
const stopBtn = document.getElementById('stop-btn');
|
||||||
|
|
||||||
@ -85,7 +88,8 @@
|
|||||||
console.error('Ошибка при остановке приема заявок', e);
|
console.error('Ошибка при остановке приема заявок', e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
// @license-end
|
||||||
|
</script>
|
||||||
{% elif competition.status == 2 %}
|
{% elif competition.status == 2 %}
|
||||||
<div class="c_d4rhd b_wy3rt ba"><span class="c_4sl8i b_bvl0d">Конкурс завершен</span></div>
|
<div class="c_d4rhd b_wy3rt ba"><span class="c_4sl8i b_bvl0d">Конкурс завершен</span></div>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
@ -219,8 +223,10 @@ document.querySelectorAll('.c_6cezu.b_6spaf').forEach(toggle => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const competition_id = '{{competition._id}}';
|
const competition_id = '{{competition._id}}';
|
||||||
|
|
||||||
document.querySelectorAll('.b_k2cle button').forEach(button => {
|
document.querySelectorAll('.b_k2cle button').forEach(button => {
|
||||||
@ -270,6 +276,7 @@ document.querySelectorAll('.b_k2cle button').forEach(button => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -119,6 +119,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const competitionId = '{{competition._id}}';
|
const competitionId = '{{competition._id}}';
|
||||||
const memberId = '{{member._id}}';
|
const memberId = '{{member._id}}';
|
||||||
|
|
||||||
@ -164,6 +165,7 @@ async function selectMember(status) {
|
|||||||
|
|
||||||
passBtn.addEventListener('click', () => selectMember('pass'));
|
passBtn.addEventListener('click', () => selectMember('pass'));
|
||||||
failBtn.addEventListener('click', () => selectMember('fail'));
|
failBtn.addEventListener('click', () => selectMember('fail'));
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
@ -223,8 +225,10 @@ document.querySelectorAll('.c_6cezu.b_6spaf').forEach(toggle => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const competition_id = '{{competition._id}}';
|
const competition_id = '{{competition._id}}';
|
||||||
|
|
||||||
document.querySelectorAll('.b_k2cle button').forEach(button => {
|
document.querySelectorAll('.b_k2cle button').forEach(button => {
|
||||||
@ -271,6 +275,7 @@ document.querySelectorAll('.b_k2cle button').forEach(button => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.querySelectorAll('.c_2fr39.b_tfnz2#deleteBtn').forEach(btn => {
|
document.querySelectorAll('.c_2fr39.b_tfnz2#deleteBtn').forEach(btn => {
|
||||||
btn.addEventListener('click', async (e) => {
|
btn.addEventListener('click', async (e) => {
|
||||||
const article = btn.closest('article');
|
const article = btn.closest('article');
|
||||||
@ -87,6 +88,7 @@ document.querySelectorAll('#rePublishCompetition').forEach(btn => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -98,6 +98,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
];
|
];
|
||||||
document.getElementById('filter-galerists').dataset.list=JSON.stringify(galerists)
|
document.getElementById('filter-galerists').dataset.list=JSON.stringify(galerists)
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script defer>
|
<script defer>
|
||||||
const living_places = [
|
const living_places = [
|
||||||
@ -109,6 +110,7 @@ document.getElementById('filter-galerists').dataset.list=JSON.stringify(galerist
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
];
|
];
|
||||||
document.getElementById('filter-city').dataset.list=JSON.stringify(living_places)
|
document.getElementById('filter-city').dataset.list=JSON.stringify(living_places)
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script async>
|
<script async>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@ -242,8 +244,10 @@ genre = genres.map(g => {
|
|||||||
|
|
||||||
document.getElementById('filter-genre').dataset.list=JSON.stringify(genre)
|
document.getElementById('filter-genre').dataset.list=JSON.stringify(genre)
|
||||||
})
|
})
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const initialPostsData = [
|
const initialPostsData = [
|
||||||
{% for p in posts %}
|
{% for p in posts %}
|
||||||
{
|
{
|
||||||
@ -272,9 +276,11 @@ genre = genres.map(g => {
|
|||||||
title: "", posts: []
|
title: "", posts: []
|
||||||
{% endif %}
|
{% endif %}
|
||||||
};
|
};
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const selectedPostIds = new Set((exhibition?.posts || []).map(String));
|
const selectedPostIds = new Set((exhibition?.posts || []).map(String));
|
||||||
const container = document.querySelector('.c_tihtk');
|
const container = document.querySelector('.c_tihtk');
|
||||||
const showMoreBtn = document.getElementById('show-more-btn');
|
const showMoreBtn = document.getElementById('show-more-btn');
|
||||||
@ -491,6 +497,7 @@ genre = genres.map(g => {
|
|||||||
document.getElementById('apply-filters').addEventListener('click', applyFilters);
|
document.getElementById('apply-filters').addEventListener('click', applyFilters);
|
||||||
showMoreBtn.addEventListener('click', loadMore);
|
showMoreBtn.addEventListener('click', loadMore);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
{% import "components/profile_nav.html" as profile_nav %}
|
{% import "components/profile_nav.html" as profile_nav %}
|
||||||
{% import "competition/list.html" as competition %}
|
{% import "competition/list.html" as competition %}
|
||||||
{% import "components/label.html" as label %}
|
{% import "components/label.html" as label %}
|
||||||
|
{% import "/components/contacts.html" as contacts %}
|
||||||
|
|
||||||
{% block title %}Отобранные картины | Выставка {{exhibition.title}}{% endblock %}
|
{% block title %}Отобранные картины | Выставка {{exhibition.title}}{% endblock %}
|
||||||
|
|
||||||
@ -101,55 +102,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<details style="margin-bottom: 1.25rem;">
|
{{ contacts.details(post.user) }}
|
||||||
<summary>Показать контакты</summary>
|
|
||||||
<div class="menua">
|
|
||||||
<a class="icona" href="/artists/{{post.user._id}}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm146.5-204.5Q340-521 340-580t40.5-99.5Q421-720 480-720t99.5 40.5Q620-639 620-580t-40.5 99.5Q539-440 480-440t-99.5-40.5ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm100-95.5q47-15.5 86-44.5-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160q53 0 100-15.5ZM523-537q17-17 17-43t-17-43q-17-17-43-17t-43 17q-17 17-17 43t17 43q17 17 43 17t43-17Zm-43-43Zm0 360Z" />
|
|
||||||
</svg>
|
|
||||||
<span>Профиль</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="tel:{{post.user.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ post.user.phone.split(',')[-1].strip() }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="mailto:{{post.user.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
|
|
||||||
<path
|
|
||||||
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{post.user.email}}</span>
|
|
||||||
</a>
|
|
||||||
<div class="icona"><span>Написать</span></div>
|
|
||||||
<div class="icona">
|
|
||||||
|
|
||||||
<a class="icona" href="{% if post.user.vk_id %}https://vk.ru/im?sel={{post.user.vk_id}}{%else%}#{%endif%}"
|
|
||||||
{% if not post.user.vk_id %}onclick="showToast({message: 'У пользователя не привязан ВК'})"{%endif%}>
|
|
||||||
<img src="/static/icons/vk.svg" height="40">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="icona" href="https://telegram.me/{{post.user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/tg.svg" height="40">
|
|
||||||
<!-- <span>Написать в ТГ</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://max.ru/{{post.user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
|
|
||||||
<!-- <span>Написать в MAX</span> -->
|
|
||||||
</a>
|
|
||||||
<a class="icona" href="https://wa.me/{{post.user.phone.split(',')[-1].strip()}}">
|
|
||||||
<img src="/static/icons/wapp.svg" height="40">
|
|
||||||
<!-- <span>Написать в WA</span> -->
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
{% if post.status=='В каталоге' %}
|
{% if post.status=='В каталоге' %}
|
||||||
<button onclick="selectPost(this, '{{post._id}}')" class="c_ctfod b_289i1">
|
<button onclick="selectPost(this, '{{post._id}}')" class="c_ctfod b_289i1">
|
||||||
<span class="c_d2l0b b_al8e7">Убрать с выставки</span>
|
<span class="c_d2l0b b_al8e7">Убрать с выставки</span>
|
||||||
@ -174,6 +127,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function saledPaintings(postId) {
|
function saledPaintings(postId) {
|
||||||
fetch(`/api/post/${postId}/sale`, {
|
fetch(`/api/post/${postId}/sale`, {
|
||||||
method: 'PUT'
|
method: 'PUT'
|
||||||
@ -204,9 +158,11 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{#
|
{#
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function btnAccept(btn, itemId){
|
async function btnAccept(btn, itemId){
|
||||||
const figcaption = btn.parentElement;
|
const figcaption = btn.parentElement;
|
||||||
const statusDiv = figcaption.querySelectorAll('div')[0];
|
const statusDiv = figcaption.querySelectorAll('div')[0];
|
||||||
@ -245,9 +201,11 @@
|
|||||||
showToast({ message: 'Не удалось подключиться к серверу', duration: 2500 });
|
showToast({ message: 'Не удалось подключиться к серверу', duration: 2500 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
#}
|
#}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function sendInvitations(exhibition_id) {
|
async function sendInvitations(exhibition_id) {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.set('exhibition_id', exhibition_id);
|
data.set('exhibition_id', exhibition_id);
|
||||||
@ -296,6 +254,7 @@
|
|||||||
select.checked = false
|
select.checked = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -304,6 +263,7 @@
|
|||||||
{{ header.style() }}
|
{{ header.style() }}
|
||||||
{{ profile_nav.style() }}
|
{{ profile_nav.style() }}
|
||||||
{{ competition.style() }}
|
{{ competition.style() }}
|
||||||
|
{{ contacts.style() }}
|
||||||
<style>
|
<style>
|
||||||
.menua{width: 100%;
|
.menua{width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -41,14 +41,14 @@
|
|||||||
<h3 class="c_hysjg b_8f3uh" id="preview_title">{{i.title}}</h3>
|
<h3 class="c_hysjg b_8f3uh" id="preview_title">{{i.title}}</h3>
|
||||||
</header>
|
</header>
|
||||||
<p class="c_2fr39 b_tfnz2" id="preview_topic">{{i.topic}}</p>
|
<p class="c_2fr39 b_tfnz2" id="preview_topic">{{i.topic}}</p>
|
||||||
|
{% if i.user %}
|
||||||
<div class="c_dbbe4 b_otttb">
|
<div class="c_dbbe4 b_otttb">
|
||||||
{% if user %}
|
|
||||||
<img crossorigin="anonymous" fetchpriority="high" loading="eager" class="c_pm80w b_a68fq" src="/a/{{i.user._id}}" alt="{{ i.user.username | e }}">
|
<img crossorigin="anonymous" fetchpriority="high" loading="eager" class="c_pm80w b_a68fq" src="/a/{{i.user._id}}" alt="{{ i.user.username | e }}">
|
||||||
<div class="c_4402p b_ntazj">
|
<div class="c_4402p b_ntazj">
|
||||||
<p class="c_kvah4 b_ghosy">{{ i.user.username }}</p>
|
<p class="c_kvah4 b_ghosy">{{ i.user.username }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<p class="c_2fr39 b_tfnz2">Подробнее</p>
|
<p class="c_2fr39 b_tfnz2">Подробнее</p>
|
||||||
</a>
|
</a>
|
||||||
<div class="b_otttb"><a class="c_2fr39 b_tfnz2" href="/form/exhibition/{{i._id}}">Редактировать</a><span onclick="deleteExhibition(this, '{{i._id}}')" class="c_2fr39 b_tfnz2">Удалить</span></div>
|
<div class="b_otttb"><a class="c_2fr39 b_tfnz2" href="/form/exhibition/{{i._id}}">Редактировать</a><span onclick="deleteExhibition(this, '{{i._id}}')" class="c_2fr39 b_tfnz2">Удалить</span></div>
|
||||||
@ -61,6 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function deleteExhibition(btn, _id) {
|
async function deleteExhibition(btn, _id) {
|
||||||
const article = btn.closest('article');
|
const article = btn.closest('article');
|
||||||
try {
|
try {
|
||||||
@ -75,6 +76,7 @@ async function deleteExhibition(btn, _id) {
|
|||||||
console.error('Delete failed:', err);
|
console.error('Delete failed:', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -130,6 +130,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
async function postSetting(id, key, value) {
|
async function postSetting(id, key, value) {
|
||||||
const payload = {
|
const payload = {
|
||||||
id: id,
|
id: id,
|
||||||
@ -169,6 +170,7 @@ document.addEventListener('change', function (e) {
|
|||||||
postSetting(id, key, checked);
|
postSetting(id, key, checked);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -137,9 +137,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelector(".desc"),t=document.getElementById("preview"),l=document.getElementById("inpA"),d=document.getElementById("labelA"),a=document.getElementById("inpB"),r=document.getElementById("role"),s=document.getElementById("gradeC"),n=document.getElementById("gradeR"),i=e=>e.style.display="flex",o=e=>e.style.display="none";document.getElementById("wrap").addEventListener("click",y=>{document.querySelectorAll("#wrap > div").forEach(e=>e.classList.remove("selected"));let c=y.target.closest("#wrap > div");if(!c)return;c.classList.add("selected");let g=c.dataset.text||"";e.textContent=g;let m=c.dataset.img||"";m&&!m.startsWith("blob:")?t.src=m:m||t.removeAttribute("src");let v=c.id;if(o(l),o(a),i(s),o(n),"2"===v||"3"===v){i(l);let E=c.dataset.label;void 0!==E?d.textContent=E:d.textContent=""}"2"===v&&(r.value="user"),"2"===v&&(r.value="reporter",i(a),o(s),i(n)),"3"===v&&(r.value="galerist",o(s))})});
|
document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelector(".desc"),t=document.getElementById("preview"),l=document.getElementById("inpA"),d=document.getElementById("labelA"),a=document.getElementById("inpB"),r=document.getElementById("role"),s=document.getElementById("gradeC"),n=document.getElementById("gradeR"),i=e=>e.style.display="flex",o=e=>e.style.display="none";document.getElementById("wrap").addEventListener("click",y=>{document.querySelectorAll("#wrap > div").forEach(e=>e.classList.remove("selected"));let c=y.target.closest("#wrap > div");if(!c)return;c.classList.add("selected");let g=c.dataset.text||"";e.textContent=g;let m=c.dataset.img||"";m&&!m.startsWith("blob:")?t.src=m:m||t.removeAttribute("src");let v=c.id;if(o(l),o(a),i(s),o(n),"2"===v||"3"===v){i(l);let E=c.dataset.label;void 0!==E?d.textContent=E:d.textContent=""}"2"===v&&(r.value="user"),"2"===v&&(r.value="reporter",i(a),o(s),i(n)),"3"===v&&(r.value="galerist",o(s))})});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
function showOfferModal(offerHtml = '<p>Текст оферты...</p>') {
|
function showOfferModal(offerHtml = '<p>Текст оферты...</p>') {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const backdrop = document.createElement('div');
|
const backdrop = document.createElement('div');
|
||||||
@ -209,14 +212,20 @@ document.querySelectorAll('#openOffer').forEach(el => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("phone"),t=e=>(e||"").replace(/\D+/g,"");e.addEventListener("input",()=>{let a=t(e.value);a.length>10&&(a=a.slice(-10)),e.value=a}),e.addEventListener("paste",a=>{a.preventDefault();let n=(a.clipboardData||window.clipboardData).getData("text"),l=t(n);l.length>10&&(l=l.slice(-10)),e.value=l,e.dispatchEvent(new Event("input",{bubbles:!0}))})});
|
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("phone"),t=e=>(e||"").replace(/\D+/g,"");e.addEventListener("input",()=>{let a=t(e.value);a.length>10&&(a=a.slice(-10)),e.value=a}),e.addEventListener("paste",a=>{a.preventDefault();let n=(a.clipboardData||window.clipboardData).getData("text"),l=t(n);l.length>10&&(l=l.slice(-10)),e.value=l,e.dispatchEvent(new Event("input",{bubbles:!0}))})});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("day"),t=document.getElementById("month"),l=document.getElementById("year"),n=document.getElementById("birthday"),a=new Date().getFullYear(),u=["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"];function i(t=31){e.innerHTML="";for(let l=1;l<=t;l++){let n=document.createElement("option");n.value=String(l),n.text=String(l),e.appendChild(n)}}function o(){t.innerHTML="",u.forEach((e,l)=>{let n=document.createElement("option");n.value=String(l+1),n.text=e,t.appendChild(n)})}function v(e=1900,t=a){l.innerHTML="";for(let n=t;n>=e;n--){let u=document.createElement("option");u.value=String(n),u.text=String(n),l.appendChild(u)}}let d=e=>String(e).padStart(2,"0");function p(e){if(!e)return;let n=e.split("-");if(3!==n.length)return;let[a,u,i]=n.map(Number);g(l,String(a)),g(t,String(u)),s(a,u,i)}function r(){let a=Number(l.value)||1900,u=Number(t.value)||1,o=Number(e.value)||1,v=new Date(a,u,0).getDate();e.options.length!==v&&i(v),o>v&&(o=v);let p=`${a}-${d(u)}-${d(o)}`;n.value=p,g(e,String(o))}function s(t,l,n){let a=new Date(Number(t),Number(l),0).getDate(),u=Number(e.value)||1;i(a),g(e,String(Math.min(n||u,a)))}function g(e,t){let l=Array.from(e.options).find(e=>e.value===t||e.text===t);if(l)e.value=l.value;else{let n=document.createElement("option");n.text=t,n.value=t,e.appendChild(n),e.value=t}}o(),v();let h=n.value?Number(n.value.split("-")[0]):l.options.length?Number(l.options[0].value):a,c=n.value?Number(n.value.split("-")[1]):1;n.value&&n.value.split("-")[2];let f=new Date(h,c,0).getDate();i(f),n.value?p(n.value):(!l.value&&l.options.length&&(l.value=l.options[0].value),!t.value&&t.options.length&&(t.value=t.options[0].value),!e.value&&e.options.length&&(e.value=e.options[0].value),r()),n.addEventListener("change",()=>{p(n.value)}),l.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),t.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),e.addEventListener("change",r)});
|
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("day"),t=document.getElementById("month"),l=document.getElementById("year"),n=document.getElementById("birthday"),a=new Date().getFullYear(),u=["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"];function i(t=31){e.innerHTML="";for(let l=1;l<=t;l++){let n=document.createElement("option");n.value=String(l),n.text=String(l),e.appendChild(n)}}function o(){t.innerHTML="",u.forEach((e,l)=>{let n=document.createElement("option");n.value=String(l+1),n.text=e,t.appendChild(n)})}function v(e=1900,t=a){l.innerHTML="";for(let n=t;n>=e;n--){let u=document.createElement("option");u.value=String(n),u.text=String(n),l.appendChild(u)}}let d=e=>String(e).padStart(2,"0");function p(e){if(!e)return;let n=e.split("-");if(3!==n.length)return;let[a,u,i]=n.map(Number);g(l,String(a)),g(t,String(u)),s(a,u,i)}function r(){let a=Number(l.value)||1900,u=Number(t.value)||1,o=Number(e.value)||1,v=new Date(a,u,0).getDate();e.options.length!==v&&i(v),o>v&&(o=v);let p=`${a}-${d(u)}-${d(o)}`;n.value=p,g(e,String(o))}function s(t,l,n){let a=new Date(Number(t),Number(l),0).getDate(),u=Number(e.value)||1;i(a),g(e,String(Math.min(n||u,a)))}function g(e,t){let l=Array.from(e.options).find(e=>e.value===t||e.text===t);if(l)e.value=l.value;else{let n=document.createElement("option");n.text=t,n.value=t,e.appendChild(n),e.value=t}}o(),v();let h=n.value?Number(n.value.split("-")[0]):l.options.length?Number(l.options[0].value):a,c=n.value?Number(n.value.split("-")[1]):1;n.value&&n.value.split("-")[2];let f=new Date(h,c,0).getDate();i(f),n.value?p(n.value):(!l.value&&l.options.length&&(l.value=l.options[0].value),!t.value&&t.options.length&&(t.value=t.options[0].value),!e.value&&e.options.length&&(e.value=e.options[0].value),r()),n.addEventListener("change",()=>{p(n.value)}),l.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),t.addEventListener("change",()=>{let e=Number(l.value),n=Number(t.value);s(e,n),r()}),e.addEventListener("change",r)});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
// Основная логика
|
// Основная логика
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const emailInput = document.getElementById('email');
|
const emailInput = document.getElementById('email');
|
||||||
@ -375,9 +384,12 @@ document.addEventListener('click', (e) => {
|
|||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("avatar"),t=document.getElementById("preview");e.addEventListener("change",async()=>{if(0===e.files.length)return;let n=e.files[0];t.src=URL.createObjectURL(n);let a=new FormData;a.append("avatar",n)})});
|
document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("avatar"),t=document.getElementById("preview");e.addEventListener("change",async()=>{if(0===e.files.length)return;let n=e.files[0];t.src=URL.createObjectURL(n);let a=new FormData;a.append("avatar",n)})});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section(user) }}
|
{{ footer.section(user) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -26,117 +26,121 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('load', () => {
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const savedEmail = localStorage.getItem('restoreEmail');
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
|
window.addEventListener('load', () => {
|
||||||
if (savedEmail) {
|
const savedEmail = localStorage.getItem('restoreEmail');
|
||||||
document.getElementById('email').value = savedEmail;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const emailInput = document.getElementById('email');
|
|
||||||
const restoreBtn = document.getElementById('restoreBtn');
|
|
||||||
const nextUrl = "{{next or '/profile'}}";
|
|
||||||
restoreBtn.addEventListener('click', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const requiredInputs = document.querySelectorAll('input[required]');
|
if (savedEmail) {
|
||||||
const requiredTextareas = document.querySelectorAll('textarea[required]');
|
document.getElementById('email').value = savedEmail;
|
||||||
const requiredFields = [...requiredInputs, ...requiredTextareas];
|
|
||||||
|
|
||||||
let firstErrorField = null;
|
|
||||||
let hasError = false;
|
|
||||||
|
|
||||||
requiredFields.forEach(field => {
|
|
||||||
const group = field.closest('.floating-group');
|
|
||||||
if (!group) return; // skip if no group wrapper
|
|
||||||
|
|
||||||
let isEmpty = false;
|
|
||||||
if (field.type === 'file') {
|
|
||||||
isEmpty = !field.files || field.files.length === 0;
|
|
||||||
} else {
|
|
||||||
isEmpty = !field.value || !field.value.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEmpty) {
|
|
||||||
group.classList.add('error');
|
|
||||||
hasError = true;
|
|
||||||
|
|
||||||
if (!firstErrorField) firstErrorField = field;
|
|
||||||
} else {
|
|
||||||
group.classList.remove('error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasError && firstErrorField) {
|
|
||||||
firstErrorField.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
||||||
showToast({message: 'Введите Email', status: 'error'})
|
|
||||||
setTimeout(() => firstErrorField.focus(), 600);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No client-side validation errors — send request
|
|
||||||
try {
|
|
||||||
const payload = {
|
|
||||||
identifier: emailInput ? emailInput.value : '',
|
|
||||||
next: nextUrl
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = await fetch('/api/restore', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.ok) {
|
|
||||||
// success (HTTP 2xx). Redirect to /form
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
|
||||||
const next = params.get('next') || '/login';
|
|
||||||
window.location.href = next;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// non-2xx — mark all input groups as error
|
|
||||||
const allFields = document.querySelectorAll('.floating-group');
|
|
||||||
allFields.forEach(g => g.classList.add('error'));
|
|
||||||
|
|
||||||
// Optional: you can show server message if present
|
|
||||||
const errorText = await res.json();
|
|
||||||
// console.error('Server error:', errorText);
|
|
||||||
showToast({message: errorText.detail, status: 'error'})
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// Network or other unexpected error — mark fields as error
|
|
||||||
const allFields = document.querySelectorAll('.floating-group');
|
|
||||||
allFields.forEach(g => g.classList.add('error'));
|
|
||||||
console.error('Request failed', err);
|
|
||||||
showToast({message: err, status: 'error'})
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const emailInput = document.getElementById('email');
|
||||||
|
const restoreBtn = document.getElementById('restoreBtn');
|
||||||
|
const nextUrl = "{{next or '/profile'}}";
|
||||||
|
restoreBtn.addEventListener('click', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const requiredInputs = document.querySelectorAll('input[required]');
|
||||||
|
const requiredTextareas = document.querySelectorAll('textarea[required]');
|
||||||
|
const requiredFields = [...requiredInputs, ...requiredTextareas];
|
||||||
|
|
||||||
|
let firstErrorField = null;
|
||||||
|
let hasError = false;
|
||||||
|
|
||||||
|
requiredFields.forEach(field => {
|
||||||
|
const group = field.closest('.floating-group');
|
||||||
|
if (!group) return; // skip if no group wrapper
|
||||||
|
|
||||||
|
let isEmpty = false;
|
||||||
|
if (field.type === 'file') {
|
||||||
|
isEmpty = !field.files || field.files.length === 0;
|
||||||
|
} else {
|
||||||
|
isEmpty = !field.value || !field.value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
group.classList.add('error');
|
||||||
|
hasError = true;
|
||||||
|
|
||||||
|
if (!firstErrorField) firstErrorField = field;
|
||||||
|
} else {
|
||||||
|
group.classList.remove('error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasError && firstErrorField) {
|
||||||
|
firstErrorField.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
showToast({ message: 'Введите Email', status: 'error' })
|
||||||
|
setTimeout(() => firstErrorField.focus(), 600);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No client-side validation errors — send request
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
identifier: emailInput ? emailInput.value : '',
|
||||||
|
next: nextUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await fetch('/api/restore', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
// success (HTTP 2xx). Redirect to /form
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const next = params.get('next') || '/login';
|
||||||
|
window.location.href = next;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// non-2xx — mark all input groups as error
|
||||||
|
const allFields = document.querySelectorAll('.floating-group');
|
||||||
|
allFields.forEach(g => g.classList.add('error'));
|
||||||
|
|
||||||
|
// Optional: you can show server message if present
|
||||||
|
const errorText = await res.json();
|
||||||
|
// console.error('Server error:', errorText);
|
||||||
|
showToast({ message: errorText.detail, status: 'error' })
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Network or other unexpected error — mark fields as error
|
||||||
|
const allFields = document.querySelectorAll('.floating-group');
|
||||||
|
allFields.forEach(g => g.classList.add('error'));
|
||||||
|
console.error('Request failed', err);
|
||||||
|
showToast({ message: err, status: 'error' })
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Убираем красную подсветку сразу при исправлении пользователем
|
// Убираем красную подсветку сразу при исправлении пользователем
|
||||||
document.querySelectorAll('.floating-group input').forEach(input => {
|
document.querySelectorAll('.floating-group input').forEach(input => {
|
||||||
input.addEventListener('input', function() {
|
input.addEventListener('input', function () {
|
||||||
const group = this.closest('.floating-group');
|
const group = this.closest('.floating-group');
|
||||||
if (group) {
|
if (group) {
|
||||||
group.classList.remove('error');
|
group.classList.remove('error');
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Для файлов
|
|
||||||
if (input.type === 'file') {
|
|
||||||
input.addEventListener('change', function() {
|
|
||||||
const group = this.closest('.floating-group');
|
|
||||||
if (group && this.files.length > 0) {
|
|
||||||
group.classList.remove('error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Для файлов
|
||||||
|
if (input.type === 'file') {
|
||||||
|
input.addEventListener('change', function () {
|
||||||
|
const group = this.closest('.floating-group');
|
||||||
|
if (group && this.files.length > 0) {
|
||||||
|
group.classList.remove('error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section() }}
|
{{ footer.section() }}
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
fetch('/api/me')
|
fetch('/api/me')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@ -153,6 +157,7 @@ fetch('/api/me')
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('There was a problem with the fetch operation:', error);
|
console.error('There was a problem with the fetch operation:', error);
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -50,66 +50,68 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Password toggle functionality (same as login)
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.querySelectorAll('.password-toggle').forEach(toggle => {
|
// Password toggle functionality (same as login)
|
||||||
const input = toggle.parentElement.querySelector('input');
|
document.querySelectorAll('.password-toggle').forEach(toggle => {
|
||||||
const eyeOpen = toggle.querySelector('.eye-open');
|
const input = toggle.parentElement.querySelector('input');
|
||||||
const eyeClosed = toggle.querySelector('.eye-closed');
|
const eyeOpen = toggle.querySelector('.eye-open');
|
||||||
|
const eyeClosed = toggle.querySelector('.eye-closed');
|
||||||
|
|
||||||
toggle.addEventListener('click', () => {
|
toggle.addEventListener('click', () => {
|
||||||
if (input.type === 'password') {
|
if (input.type === 'password') {
|
||||||
input.type = 'text';
|
input.type = 'text';
|
||||||
eyeOpen.style.display = 'none';
|
eyeOpen.style.display = 'none';
|
||||||
eyeClosed.style.display = 'inline';
|
eyeClosed.style.display = 'inline';
|
||||||
} else {
|
} else {
|
||||||
input.type = 'password';
|
input.type = 'password';
|
||||||
eyeOpen.style.display = 'inline';
|
eyeOpen.style.display = 'inline';
|
||||||
eyeClosed.style.display = 'none';
|
eyeClosed.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Form submit
|
||||||
|
document.getElementById('resetBtn').addEventListener('click', async () => {
|
||||||
|
const newPass = document.getElementById('new_password').value;
|
||||||
|
const confirmPass = document.getElementById('confirm_password').value;
|
||||||
|
|
||||||
|
if (newPass.length < 6) {
|
||||||
|
showToast({ message: "Пароль должен быть не менее 6 символов", status: 'error' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPass !== confirmPass) {
|
||||||
|
showToast({ message: "Пароли не совпадают", status: 'error' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/reset-password', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: "{{ token }}",
|
||||||
|
new_password: newPass
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Form submit
|
const data = await res.json();
|
||||||
document.getElementById('resetBtn').addEventListener('click', async () => {
|
|
||||||
const newPass = document.getElementById('new_password').value;
|
|
||||||
const confirmPass = document.getElementById('confirm_password').value;
|
|
||||||
|
|
||||||
if (newPass.length < 6) {
|
if (res.ok) {
|
||||||
showToast({message: "Пароль должен быть не менее 6 символов", status: 'error'});
|
showToast({ message: "Пароль успешно изменён!", status: 'success' });
|
||||||
return;
|
setTimeout(() => {
|
||||||
|
window.location.href = `/login?next=${data.next}`;
|
||||||
|
}, 1500);
|
||||||
|
} else {
|
||||||
|
showToast({ message: data.detail || "Ошибка при смене пароля", status: 'error' });
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
if (newPass !== confirmPass) {
|
showToast({ message: "Ошибка соединения с сервером", status: 'error' });
|
||||||
showToast({message: "Пароли не совпадают", status: 'error'});
|
}
|
||||||
return;
|
});
|
||||||
}
|
// @license-end
|
||||||
|
</script>
|
||||||
try {
|
|
||||||
const res = await fetch('/api/reset-password', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {'Content-Type': 'application/json'},
|
|
||||||
body: JSON.stringify({
|
|
||||||
token: "{{ token }}",
|
|
||||||
new_password: newPass
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
if (res.ok) {
|
|
||||||
showToast({message: "Пароль успешно изменён!", status: 'success'});
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.href = `/login?next=${data.next}`;
|
|
||||||
}, 1500);
|
|
||||||
} else {
|
|
||||||
showToast({message: data.detail || "Ошибка при смене пароля", status: 'error'});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
showToast({message: "Ошибка соединения с сервером", status: 'error'});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ footer.section() }}
|
{{ footer.section() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -65,6 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
(function(){
|
(function(){
|
||||||
const input = document.getElementById('memberSearch');
|
const input = document.getElementById('memberSearch');
|
||||||
const container = document.querySelectorAll('.c_lt3gk')[1];
|
const container = document.querySelectorAll('.c_lt3gk')[1];
|
||||||
@ -92,6 +93,7 @@
|
|||||||
|
|
||||||
filter();
|
filter();
|
||||||
})();
|
})();
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section() }}
|
{{ footer.section() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
const userId = '{{find._id}}';
|
const userId = '{{find._id}}';
|
||||||
|
|
||||||
document.getElementById('switch-user').addEventListener('click', async () => {
|
document.getElementById('switch-user').addEventListener('click', async () => {
|
||||||
@ -47,6 +48,7 @@ document.getElementById('switch-user').addEventListener('click', async () => {
|
|||||||
showToast({message: 'Не удалось переключиться на пользователя.', status: 'error'});
|
showToast({message: 'Не удалось переключиться на пользователя.', status: 'error'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if 'admin' in user.get('roles', []) %}
|
{% if 'admin' in user.get('roles', []) %}
|
||||||
@ -76,6 +78,7 @@ document.getElementById('switch-user').addEventListener('click', async () => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
|
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
const avatarInput = document.getElementById('avatar');
|
const avatarInput = document.getElementById('avatar');
|
||||||
@ -90,6 +93,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
{{ footer.section() }}
|
{{ footer.section() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
185
vk.ipynb
185
vk.ipynb
@ -53,7 +53,8 @@
|
|||||||
" load_env('env_example')\n",
|
" load_env('env_example')\n",
|
||||||
" except Exception:\n",
|
" except Exception:\n",
|
||||||
" pass"
|
" pass"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
@ -85,7 +86,8 @@
|
|||||||
"from fastapi import APIRouter, Depends, Request, Response\n",
|
"from fastapi import APIRouter, Depends, Request, Response\n",
|
||||||
"from fastapi.responses import RedirectResponse\n",
|
"from fastapi.responses import RedirectResponse\n",
|
||||||
"from images import insert_logo\n"
|
"from images import insert_logo\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
@ -103,7 +105,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"celery_app_vk = Celery('vk', broker=f'{redis_uri}1', backend=f'{redis_uri}1', task_track_started=True )\n"
|
"celery_app_vk = Celery('vk', broker=f'{redis_uri}1', backend=f'{redis_uri}1', task_track_started=True )\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -113,7 +116,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"token_manager = TokenManager()\n"
|
"token_manager = TokenManager()\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -154,7 +158,8 @@
|
|||||||
"\n",
|
"\n",
|
||||||
" # Привязка соцсети к уже залогиненному пользователю\n",
|
" # Привязка соцсети к уже залогиненному пользователю\n",
|
||||||
" return RedirectResponse(url='/profile/social', status_code=status.HTTP_303_SEE_OTHER)"
|
" return RedirectResponse(url='/profile/social', status_code=status.HTTP_303_SEE_OTHER)"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -184,7 +189,8 @@
|
|||||||
" images[_id] = (\"photo\", (name, background, \"image/jpeg\"))\n",
|
" images[_id] = (\"photo\", (name, background, \"image/jpeg\"))\n",
|
||||||
" \n",
|
" \n",
|
||||||
" return images\n"
|
" return images\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -193,6 +199,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
|
"# TODO: function call like send_tg from tg.py (without router)\n",
|
||||||
"@router.post(\"/send\")\n",
|
"@router.post(\"/send\")\n",
|
||||||
"async def send_vk(data:dict, request: Request):\n",
|
"async def send_vk(data:dict, request: Request):\n",
|
||||||
" auth = request.headers.get(\"Authorization\")\n",
|
" auth = request.headers.get(\"Authorization\")\n",
|
||||||
@ -208,20 +215,19 @@
|
|||||||
" \n",
|
" \n",
|
||||||
" sign_avatar = data['sign_avatar']\n",
|
" sign_avatar = data['sign_avatar']\n",
|
||||||
" db_name = item.get('db')\n",
|
" db_name = item.get('db')\n",
|
||||||
" # if db_name == 'competitions':\n",
|
" if db_name in ['competitions', 'exhibition']:\n",
|
||||||
" # social = await social_collection.find_one({'service': True, 'type':'vk'})\n",
|
" social = await social_collection.find_one({'service': True, 'type':'vk'})\n",
|
||||||
" # else:\n",
|
" else:\n",
|
||||||
" social = doc\n",
|
" social = doc\n",
|
||||||
" logging.info(doc)\n",
|
" logging.info(doc)\n",
|
||||||
" logging.info(social)\n",
|
" logging.info(social)\n",
|
||||||
" images = await get_images(db_name, file_ids, sign_avatar)\n",
|
" images = await get_images(db_name, file_ids, sign_avatar)\n",
|
||||||
" async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
" async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
||||||
" attachments = []\n",
|
" attachments = []\n",
|
||||||
" for _id, img in images.items():\n",
|
" for _id, img in images.items():\n",
|
||||||
" # doc_photo = await mongo_client['vk']['photos'].find_one({'id':f\"{_id}:{social.get('_id')}\"})\n",
|
" if (doc_photo:=await mongo_client['vk']['photos'].find_one({'id':f\"{_id}:{social.get('_id')}\"},{'attachment': 1})):\n",
|
||||||
" # if doc_photo:\n",
|
" attachments.append(doc_photo['attachment'])\n",
|
||||||
" # attachments.append(doc_photo['attachment'])\n",
|
" continue\n",
|
||||||
" # continue\n",
|
|
||||||
" payload = {\"v\": \"5.199\"}\n",
|
" payload = {\"v\": \"5.199\"}\n",
|
||||||
" if 'group' in social:\n",
|
" if 'group' in social:\n",
|
||||||
" payload['group_id'] = social['id']\n",
|
" payload['group_id'] = social['id']\n",
|
||||||
@ -237,7 +243,7 @@
|
|||||||
" attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
" attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
||||||
" if not attachment:\n",
|
" if not attachment:\n",
|
||||||
" return {'ok': False}\n",
|
" return {'ok': False}\n",
|
||||||
" # await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f\"{_id}:{social.get('_id')}\"})\n",
|
" await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f\"{_id}:{social.get('_id')}\"})\n",
|
||||||
" attachments.append(attachment)\n",
|
" attachments.append(attachment)\n",
|
||||||
" logging.info(attachments)\n",
|
" logging.info(attachments)\n",
|
||||||
" \n",
|
" \n",
|
||||||
@ -257,7 +263,8 @@
|
|||||||
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
||||||
" return {\"ok\": True}\n",
|
" return {\"ok\": True}\n",
|
||||||
"\n"
|
"\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -266,6 +273,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
|
"# TODO: function call like send_tg from tg.py (without router)\n",
|
||||||
"@router.post(\"/edit\")\n",
|
"@router.post(\"/edit\")\n",
|
||||||
"async def edit_vk(data:dict, request: Request):\n",
|
"async def edit_vk(data:dict, request: Request):\n",
|
||||||
" auth = request.headers.get(\"Authorization\")\n",
|
" auth = request.headers.get(\"Authorization\")\n",
|
||||||
@ -333,7 +341,8 @@
|
|||||||
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
||||||
" return {\"ok\": True}\n",
|
" return {\"ok\": True}\n",
|
||||||
"\n"
|
"\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -342,6 +351,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
|
"# TODO: function call like send_tg from tg.py (without router)\n",
|
||||||
"@router.post(\"/delete\")\n",
|
"@router.post(\"/delete\")\n",
|
||||||
"async def wall_delete(data: dict, request: Request):\n",
|
"async def wall_delete(data: dict, request: Request):\n",
|
||||||
" # ---- auth ----\n",
|
" # ---- auth ----\n",
|
||||||
@ -386,7 +396,8 @@
|
|||||||
" )\n",
|
" )\n",
|
||||||
"\n",
|
"\n",
|
||||||
" return {\"ok\": True}\n"
|
" return {\"ok\": True}\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -410,7 +421,7 @@
|
|||||||
" try:\n",
|
" try:\n",
|
||||||
" logging.info(f\"VK начало edit {item} {file_ids}\")\n",
|
" logging.info(f\"VK начало edit {item} {file_ids}\")\n",
|
||||||
" res = httpx.post(\n",
|
" res = httpx.post(\n",
|
||||||
" 'http://127.0.0.1:30080/api/v1/social/vk/edit', \n",
|
" 'http://127.0.0.1:30081/api/v1/social/vk/edit', \n",
|
||||||
" headers={\"Authorization\": f\"bearer {ATOKEN}\"}, \n",
|
" headers={\"Authorization\": f\"bearer {ATOKEN}\"}, \n",
|
||||||
" json={'post_id': post_id, 'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},\n",
|
" json={'post_id': post_id, 'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},\n",
|
||||||
" timeout=100\n",
|
" timeout=100\n",
|
||||||
@ -421,7 +432,8 @@
|
|||||||
" \n",
|
" \n",
|
||||||
" except Exception as exc:\n",
|
" except Exception as exc:\n",
|
||||||
" raise self.retry(exc=exc)\n"
|
" raise self.retry(exc=exc)\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -445,7 +457,7 @@
|
|||||||
" try:\n",
|
" try:\n",
|
||||||
" logging.info(f\"VK удаления публикации {doc} {post_id}\")\n",
|
" logging.info(f\"VK удаления публикации {doc} {post_id}\")\n",
|
||||||
" res = httpx.post(\n",
|
" res = httpx.post(\n",
|
||||||
" 'http://127.0.0.1:30080/api/v1/social/vk/delete',\n",
|
" 'http://127.0.0.1:30081/api/v1/social/vk/delete',\n",
|
||||||
" headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
" headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
||||||
" json={'item': item, 'post_id': post_id, \"doc\": doc},\n",
|
" json={'item': item, 'post_id': post_id, \"doc\": doc},\n",
|
||||||
" timeout=100\n",
|
" timeout=100\n",
|
||||||
@ -456,7 +468,8 @@
|
|||||||
" \n",
|
" \n",
|
||||||
" except Exception as exc:\n",
|
" except Exception as exc:\n",
|
||||||
" raise self.retry(exc=exc)\n"
|
" raise self.retry(exc=exc)\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -480,7 +493,7 @@
|
|||||||
" try:\n",
|
" try:\n",
|
||||||
" logging.info(f\"VK начало публикации {item} {file_ids}\")\n",
|
" logging.info(f\"VK начало публикации {item} {file_ids}\")\n",
|
||||||
" res = httpx.post(\n",
|
" res = httpx.post(\n",
|
||||||
" 'http://127.0.0.1:30080/api/v1/social/vk/send',\n",
|
" 'http://127.0.0.1:30081/api/v1/social/vk/send',\n",
|
||||||
" headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
" headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
||||||
" json={'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},\n",
|
" json={'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},\n",
|
||||||
" timeout=100\n",
|
" timeout=100\n",
|
||||||
@ -491,7 +504,8 @@
|
|||||||
" \n",
|
" \n",
|
||||||
" except Exception as exc:\n",
|
" except Exception as exc:\n",
|
||||||
" raise self.retry(exc=exc)\n"
|
" raise self.retry(exc=exc)\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
@ -522,7 +536,8 @@
|
|||||||
"# timeout=100\n",
|
"# timeout=100\n",
|
||||||
"# ).json()\n",
|
"# ).json()\n",
|
||||||
"# await asyncio.sleep(1)\n"
|
"# await asyncio.sleep(1)\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -553,7 +568,8 @@
|
|||||||
"\n",
|
"\n",
|
||||||
" with open(f'{filename_without_extension}.py', 'w') as f:\n",
|
" with open(f'{filename_without_extension}.py', 'w') as f:\n",
|
||||||
" f.write('\\n\\n'.join(app))\n"
|
" f.write('\\n\\n'.join(app))\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -567,7 +583,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!celery -A vk.celery_app_vk worker --loglevel=info"
|
"!celery -A vk.celery_app_vk worker --loglevel=info"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -581,7 +598,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!docker build -t registry.spiritofweb.ru/avtopost-api:latest ."
|
"!docker build -t registry.spiritofweb.ru/avtopost-api:latest ."
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -595,7 +613,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!sudo docker image push registry.spiritofweb.ru/avtopost-api:latest"
|
"!sudo docker image push registry.spiritofweb.ru/avtopost-api:latest"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -609,7 +628,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!kubectl rollout restart deployments/vk-celery -n kultmost"
|
"!kubectl rollout restart deployments/vk-celery -n kultmost"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -623,7 +643,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"!echo $REGISTRY_HOST"
|
"!echo $REGISTRY_HOST"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
@ -641,7 +662,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"stop"
|
"stop"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -651,7 +673,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"user_id = '681684390000000000000000'"
|
"user_id = '681684390000000000000000'"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -662,7 +685,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"await redis_client.delete(f\"access_token:{user_id}\")\n",
|
"await redis_client.delete(f\"access_token:{user_id}\")\n",
|
||||||
"await redis_client.delete(f\"tokens:{user_id}\")"
|
"await redis_client.delete(f\"tokens:{user_id}\")"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -686,7 +710,8 @@
|
|||||||
" },\n",
|
" },\n",
|
||||||
" upsert=True,\n",
|
" upsert=True,\n",
|
||||||
")\n"
|
")\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -696,7 +721,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"import token_manager as tm"
|
"import token_manager as tm"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -707,7 +733,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"from token_manager import TokenManager\n",
|
"from token_manager import TokenManager\n",
|
||||||
"token_manager = TokenManager()"
|
"token_manager = TokenManager()"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -719,7 +746,8 @@
|
|||||||
"token_manager = TokenManager()\n",
|
"token_manager = TokenManager()\n",
|
||||||
"access_token = await token_manager.get_access_token('644fa8bb0000000000000000')\n",
|
"access_token = await token_manager.get_access_token('644fa8bb0000000000000000')\n",
|
||||||
"access_token"
|
"access_token"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -730,7 +758,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"item ={'_id': '6a21559cca3ad8a73b652bcb', 'db': 'competitions', 'col': 'competitions'} \n",
|
"item ={'_id': '6a21559cca3ad8a73b652bcb', 'db': 'competitions', 'col': 'competitions'} \n",
|
||||||
"file_ids = ['681684390000000000000000', '6a21559cca3ad8a73b652bc6']"
|
"file_ids = ['681684390000000000000000', '6a21559cca3ad8a73b652bc6']"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -741,7 +770,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"docs =[ doc async for doc in mongo_client['social']['social'].find({'user_id':'681684390000000000000000'})]\n",
|
"docs =[ doc async for doc in mongo_client['social']['social'].find({'user_id':'681684390000000000000000'})]\n",
|
||||||
"doc = docs[1]"
|
"doc = docs[1]"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -751,7 +781,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"competition = await competitions_col.find_one({'_id':ObjectId('6a21559cca3ad8a73b652bcb')})"
|
"competition = await competitions_col.find_one({'_id':ObjectId('6a21559cca3ad8a73b652bcb')})"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -761,7 +792,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"images = await get_images(db_name, file_ids, sign_avatar)"
|
"images = await get_images(db_name, file_ids, sign_avatar)"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -803,7 +835,8 @@
|
|||||||
" })\n",
|
" })\n",
|
||||||
" res = resp.json()\n",
|
" res = resp.json()\n",
|
||||||
" res.update({'doc': doc})"
|
" res.update({'doc': doc})"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -813,7 +846,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"res"
|
"res"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -880,7 +914,8 @@
|
|||||||
" update_spec = {\"$push\": {\"vk\": res}}\n",
|
" update_spec = {\"$push\": {\"vk\": res}}\n",
|
||||||
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
||||||
" return {\"ok\": True}\n"
|
" return {\"ok\": True}\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -919,7 +954,8 @@
|
|||||||
" })\n",
|
" })\n",
|
||||||
" print(resp_wall.json())\n",
|
" print(resp_wall.json())\n",
|
||||||
" \n"
|
" \n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -929,7 +965,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"await competitions_col.find_one({'_id': competition['_id']})"
|
"await competitions_col.find_one({'_id': competition['_id']})"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -944,7 +981,8 @@
|
|||||||
" \"$push\": {\"vk\": resp_wall.json()}\n",
|
" \"$push\": {\"vk\": resp_wall.json()}\n",
|
||||||
" },\n",
|
" },\n",
|
||||||
" )"
|
" )"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -959,7 +997,8 @@
|
|||||||
" \"v\": \"5.199\",\n",
|
" \"v\": \"5.199\",\n",
|
||||||
" })\n",
|
" })\n",
|
||||||
"resp.json()['response'][0]"
|
"resp.json()['response'][0]"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -969,7 +1008,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"[doc async for doc in mongo_client['social']['social'].find({'user_id':competition['user']['id']})]"
|
"[doc async for doc in mongo_client['social']['social'].find({'user_id':competition['user']['id']})]"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -987,7 +1027,8 @@
|
|||||||
"})\n",
|
"})\n",
|
||||||
"\n",
|
"\n",
|
||||||
"z.json()['response']"
|
"z.json()['response']"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -997,7 +1038,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"#!pip freeze > requirements.txt"
|
"#!pip freeze > requirements.txt"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1017,7 +1059,8 @@
|
|||||||
" \"body\": \"group_id=191599084&user_id=392892935&role=moderator&is_contact=0&contact_position=&contact_phone=&contact_email=&permissions=&access_token=vk1.a.-kG07OUZgX5FrxtsQrU5QJh8HaP_suYXkqcg\",\n",
|
" \"body\": \"group_id=191599084&user_id=392892935&role=moderator&is_contact=0&contact_position=&contact_phone=&contact_email=&permissions=&access_token=vk1.a.-kG07OUZgX5FrxtsQrU5QJh8HaP_suYXkqcg\",\n",
|
||||||
" \"method\": \"POST\",\n",
|
" \"method\": \"POST\",\n",
|
||||||
"});"
|
"});"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1035,7 +1078,8 @@
|
|||||||
"VK_CLIENT_ID = 51852444\n",
|
"VK_CLIENT_ID = 51852444\n",
|
||||||
"SCOPES = 'offline,wall,photos,groups'\n",
|
"SCOPES = 'offline,wall,photos,groups'\n",
|
||||||
"redirect_uri = 'https://oauth.vk.ru/blank.html'"
|
"redirect_uri = 'https://oauth.vk.ru/blank.html'"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1066,7 +1110,8 @@
|
|||||||
"url = f'{AUTHORIZE_URL}?responsetype_item=code&client_id={VK_CLIENT_ID}&scope={SCOPES}&redirect_uri={redirect_uri}&state={state}&code_challenge={code_challenge}&code_challenge_method=S256'\n",
|
"url = f'{AUTHORIZE_URL}?responsetype_item=code&client_id={VK_CLIENT_ID}&scope={SCOPES}&redirect_uri={redirect_uri}&state={state}&code_challenge={code_challenge}&code_challenge_method=S256'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f\"\\n\\n{url}\\n\\n\")"
|
"print(f\"\\n\\n{url}\\n\\n\")"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1078,7 +1123,8 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"code='vk2.a.---'\n",
|
"code='vk2.a.---'\n",
|
||||||
"device_id=''"
|
"device_id=''"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1089,7 +1135,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"refresh_token = \"vk2.a.-----\"\n",
|
"refresh_token = \"vk2.a.-----\"\n",
|
||||||
"device_id = \"-\"\n"
|
"device_id = \"-\"\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1108,7 +1155,8 @@
|
|||||||
" 'state': os.urandom(32).hex(),\n",
|
" 'state': os.urandom(32).hex(),\n",
|
||||||
"})\n",
|
"})\n",
|
||||||
"z.json()"
|
"z.json()"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1119,7 +1167,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"CLIENT_ID = 51852444\n",
|
"CLIENT_ID = 51852444\n",
|
||||||
"OAUTH_URL = 'https://id.vk.com/oauth2/auth'"
|
"OAUTH_URL = 'https://id.vk.com/oauth2/auth'"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1140,7 +1189,8 @@
|
|||||||
" 'redirect_uri': 'https://oauth.vk.com/blank.html'\n",
|
" 'redirect_uri': 'https://oauth.vk.com/blank.html'\n",
|
||||||
"})\n",
|
"})\n",
|
||||||
"r.json()\n"
|
"r.json()\n"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1161,7 +1211,8 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"z=T()\n",
|
"z=T()\n",
|
||||||
"z.json()"
|
"z.json()"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1172,7 +1223,8 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"refresh_token=r.json()['refresh_token']\n",
|
"refresh_token=r.json()['refresh_token']\n",
|
||||||
"refresh_token"
|
"refresh_token"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1191,7 +1243,8 @@
|
|||||||
" 'state': os.urandom(32).hex(),\n",
|
" 'state': os.urandom(32).hex(),\n",
|
||||||
"})\n",
|
"})\n",
|
||||||
"z.json()"
|
"z.json()"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1201,7 +1254,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"print(f'\\n\\n{z.json()['refresh_token']}\\n\\n')"
|
"print(f'\\n\\n{z.json()['refresh_token']}\\n\\n')"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
@ -1211,7 +1265,8 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"users.search"
|
"users.search"
|
||||||
]
|
],
|
||||||
|
"display_name": ".venv"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
|
|||||||
28
vk.py
28
vk.py
@ -123,6 +123,7 @@ async def get_images(db_name: str, file_ids: list, sign_avatar: bool = True):
|
|||||||
return images
|
return images
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: function call like send_tg from tg.py (without router)
|
||||||
@router.post("/send")
|
@router.post("/send")
|
||||||
async def send_vk(data:dict, request: Request):
|
async def send_vk(data:dict, request: Request):
|
||||||
auth = request.headers.get("Authorization")
|
auth = request.headers.get("Authorization")
|
||||||
@ -138,20 +139,19 @@ async def send_vk(data:dict, request: Request):
|
|||||||
|
|
||||||
sign_avatar = data['sign_avatar']
|
sign_avatar = data['sign_avatar']
|
||||||
db_name = item.get('db')
|
db_name = item.get('db')
|
||||||
# if db_name == 'competitions':
|
if db_name in ['competitions', 'exhibition']:
|
||||||
# social = await social_collection.find_one({'service': True, 'type':'vk'})
|
social = await social_collection.find_one({'service': True, 'type':'vk'})
|
||||||
# else:
|
else:
|
||||||
social = doc
|
social = doc
|
||||||
logging.info(doc)
|
logging.info(doc)
|
||||||
logging.info(social)
|
logging.info(social)
|
||||||
images = await get_images(db_name, file_ids, sign_avatar)
|
images = await get_images(db_name, file_ids, sign_avatar)
|
||||||
async with httpx.AsyncClient(http2=True, verify=ctx) as client:
|
async with httpx.AsyncClient(http2=True, verify=ctx) as client:
|
||||||
attachments = []
|
attachments = []
|
||||||
for _id, img in images.items():
|
for _id, img in images.items():
|
||||||
# doc_photo = await mongo_client['vk']['photos'].find_one({'id':f"{_id}:{social.get('_id')}"})
|
if (doc_photo:=await mongo_client['vk']['photos'].find_one({'id':f"{_id}:{social.get('_id')}"},{'attachment': 1})):
|
||||||
# if doc_photo:
|
attachments.append(doc_photo['attachment'])
|
||||||
# attachments.append(doc_photo['attachment'])
|
continue
|
||||||
# continue
|
|
||||||
payload = {"v": "5.199"}
|
payload = {"v": "5.199"}
|
||||||
if 'group' in social:
|
if 'group' in social:
|
||||||
payload['group_id'] = social['id']
|
payload['group_id'] = social['id']
|
||||||
@ -167,7 +167,7 @@ async def send_vk(data:dict, request: Request):
|
|||||||
attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])
|
attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])
|
||||||
if not attachment:
|
if not attachment:
|
||||||
return {'ok': False}
|
return {'ok': False}
|
||||||
# await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f"{_id}:{social.get('_id')}"})
|
await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f"{_id}:{social.get('_id')}"})
|
||||||
attachments.append(attachment)
|
attachments.append(attachment)
|
||||||
logging.info(attachments)
|
logging.info(attachments)
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ async def send_vk(data:dict, request: Request):
|
|||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: function call like send_tg from tg.py (without router)
|
||||||
@router.post("/edit")
|
@router.post("/edit")
|
||||||
async def edit_vk(data:dict, request: Request):
|
async def edit_vk(data:dict, request: Request):
|
||||||
auth = request.headers.get("Authorization")
|
auth = request.headers.get("Authorization")
|
||||||
@ -257,7 +257,7 @@ async def edit_vk(data:dict, request: Request):
|
|||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: function call like send_tg from tg.py (without router)
|
||||||
@router.post("/delete")
|
@router.post("/delete")
|
||||||
async def wall_delete(data: dict, request: Request):
|
async def wall_delete(data: dict, request: Request):
|
||||||
# ---- auth ----
|
# ---- auth ----
|
||||||
@ -319,7 +319,7 @@ def edit(self, post_id: int, item: dict, text: str, file_ids: list, social: dict
|
|||||||
try:
|
try:
|
||||||
logging.info(f"VK начало edit {item} {file_ids}")
|
logging.info(f"VK начало edit {item} {file_ids}")
|
||||||
res = httpx.post(
|
res = httpx.post(
|
||||||
'http://127.0.0.1:30080/api/v1/social/vk/edit',
|
'http://127.0.0.1:30081/api/v1/social/vk/edit',
|
||||||
headers={"Authorization": f"bearer {ATOKEN}"},
|
headers={"Authorization": f"bearer {ATOKEN}"},
|
||||||
json={'post_id': post_id, 'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},
|
json={'post_id': post_id, 'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},
|
||||||
timeout=100
|
timeout=100
|
||||||
@ -347,7 +347,7 @@ def delete_wall(self, post_id: int, doc: dict, item: dict|None = None):
|
|||||||
try:
|
try:
|
||||||
logging.info(f"VK удаления публикации {doc} {post_id}")
|
logging.info(f"VK удаления публикации {doc} {post_id}")
|
||||||
res = httpx.post(
|
res = httpx.post(
|
||||||
'http://127.0.0.1:30080/api/v1/social/vk/delete',
|
'http://127.0.0.1:30081/api/v1/social/vk/delete',
|
||||||
headers={"Authorization": f"bearer {ATOKEN}"},
|
headers={"Authorization": f"bearer {ATOKEN}"},
|
||||||
json={'item': item, 'post_id': post_id, "doc": doc},
|
json={'item': item, 'post_id': post_id, "doc": doc},
|
||||||
timeout=100
|
timeout=100
|
||||||
@ -375,7 +375,7 @@ def notify(self, item: dict, text: str, file_ids: list, social: dict, sign_avata
|
|||||||
try:
|
try:
|
||||||
logging.info(f"VK начало публикации {item} {file_ids}")
|
logging.info(f"VK начало публикации {item} {file_ids}")
|
||||||
res = httpx.post(
|
res = httpx.post(
|
||||||
'http://127.0.0.1:30080/api/v1/social/vk/send',
|
'http://127.0.0.1:30081/api/v1/social/vk/send',
|
||||||
headers={"Authorization": f"bearer {ATOKEN}"},
|
headers={"Authorization": f"bearer {ATOKEN}"},
|
||||||
json={'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},
|
json={'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},
|
||||||
timeout=100
|
timeout=100
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user