v2
This commit is contained in:
337
backend/public/index.html
Normal file
337
backend/public/index.html
Normal file
@@ -0,0 +1,337 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="MobileOptimized" content="176" />
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<script src="https://telegram.org/js/telegram-web-app.js?56"></script>
|
||||
<title></title>
|
||||
<style>
|
||||
*[hidden] {display: none;}
|
||||
.block {border: 1px black solid; padding:10px; margin-bottom: 10px;}
|
||||
#settings input {width: 45%;}
|
||||
#delete {color:red; cursor: pointer; margin-left: 10px;}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id = "adminapp" hidden>
|
||||
<b>Админка</b>
|
||||
<div id = "settings" class = "block">
|
||||
<b>Настройки</b><br>
|
||||
<input id = "name" type = "text" placeholder = "Name">
|
||||
<div>
|
||||
<button id = "upload-group" href = "">Не задано</button>
|
||||
<button id = "upload-group-selector" href = "" admin>Задать</button>
|
||||
</div>
|
||||
<b>Company</b>
|
||||
<div id = "company">
|
||||
<input id = "company-name" type = "text" placeholder = "Name">
|
||||
<input id = "company-phone" type = "text" placeholder = "Phone">
|
||||
<input id = "company-site" type = "text" placeholder = "Site">
|
||||
<input id = "company-description" type = "text" placeholder = "Description">
|
||||
</div>
|
||||
|
||||
<button id = "update-profile">Update</button>
|
||||
</div>
|
||||
|
||||
<div id = "projects" class = "block">
|
||||
<b>Список проектов</b><button id = "add-project">Добавить/Обновить</button>
|
||||
<br>
|
||||
<input id = "project-id" placeholder = "Id">
|
||||
<input id = "project-name" placeholder = "Name">
|
||||
<input id = "project-description" placeholder = "Description">
|
||||
<br>
|
||||
<div id = "project-list">Loading...</div>
|
||||
</div>
|
||||
|
||||
<div id = "groups" class = "block">
|
||||
<b>Список групп</b><button id = "add-group" href="" admin>Добавить</button>
|
||||
<br>
|
||||
<div id = "group-list">Проект не выбран</div>
|
||||
<button id = "share" href = "">Отправить ключ подключения</button>
|
||||
</div>
|
||||
|
||||
<div id = "users" class = "block">
|
||||
<b>Список пользователей</b>
|
||||
<br>
|
||||
<div id = "user-list">Проект не выбран</div>
|
||||
</div>
|
||||
|
||||
<div id = "companies" class = "block">
|
||||
<b>Список компаний</b><button id = "add-company">Добавить/Обновить</button>
|
||||
<br>
|
||||
<input id = "company-id" placeholder = "Id">
|
||||
<input id = "company-name" placeholder = "Name">
|
||||
<input id = "company-description" placeholder = "Description">
|
||||
<br>
|
||||
<div id = "company-list">Проект не выбран</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id = "miniapp" style = "min-height: 20px; border: 1px black solid; padding:10px; word-break: break-all;" hidden>
|
||||
Пользов
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
const $miniapp = document.getElementById('miniapp')
|
||||
const $adminapp = document.getElementById('adminapp')
|
||||
|
||||
$adminapp.querySelector('#settings #update-profile').addEventListener('click', async function (event) {
|
||||
const $e = this.parentNode
|
||||
const data = {
|
||||
name: $e.querySelector('#name').value,
|
||||
company: {
|
||||
name: $e.querySelector('#company-name').value,
|
||||
phone: $e.querySelector('#company-phone').value,
|
||||
site: $e.querySelector('#company-site').value,
|
||||
description: $e.querySelector('#company-description').value
|
||||
}
|
||||
}
|
||||
|
||||
const res = await fetch('/api/admin/customer/profile', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(res => res.json())
|
||||
console.log(res)
|
||||
})
|
||||
|
||||
$adminapp.querySelector('#projects #project-list').addEventListener('click', async function (event) {
|
||||
const $e = event.target
|
||||
if ($e.id != 'delete')
|
||||
return
|
||||
|
||||
const id = $e.parentNode.id
|
||||
|
||||
const res = await fetch('/api/admin/project/' + id, {
|
||||
method: 'DELETE'
|
||||
}).then(res => res.json())
|
||||
.then(res => $e.parentNode.remove())
|
||||
.catch(alert)
|
||||
})
|
||||
|
||||
$adminapp.querySelector('#projects #project-list').addEventListener('click', async function (event) {
|
||||
const $e = event.target
|
||||
if ($e.parentNode.id != 'project-list')
|
||||
return
|
||||
|
||||
$adminapp.querySelector('#projects #project-id').value = $e.id
|
||||
$adminapp.querySelector('#projects #project-name').value = $e.getAttribute('name')
|
||||
$adminapp.querySelector('#projects #project-description').value = $e.getAttribute('title')
|
||||
|
||||
$adminapp.querySelector('#groups #add-group').setAttribute('href', 'https://t.me/ready_or_not_2025_bot?startgroup=' + $e.id)
|
||||
|
||||
reloadGroups($e.id)
|
||||
reloadUsers($e.id)
|
||||
reloadCompanies($e.id)
|
||||
|
||||
const reqKey = await fetch('/api/admin/project/' + $e.id + '/token').then(res => res.json())
|
||||
const url = 'https://t.me/share/url?url=' + reqKey.data
|
||||
$adminapp.querySelector('#groups #share').setAttribute('href', url)
|
||||
})
|
||||
|
||||
$adminapp.querySelector('#companies #company-list').addEventListener('click', async function (event) {
|
||||
const $e = event.target
|
||||
if ($e.id != 'delete')
|
||||
return
|
||||
|
||||
const id = $e.parentNode.id
|
||||
const project_id = $adminapp.querySelector('#groups #group-list').getAttribute('project-id')
|
||||
|
||||
const res = await fetch(`/api/admin/project/${project_id}/company/${id}`, {
|
||||
method: 'DELETE'
|
||||
}).then(res => res.json())
|
||||
.then(res => $e.parentNode.remove())
|
||||
.catch(alert)
|
||||
})
|
||||
|
||||
$adminapp.querySelector('#companies #company-list').addEventListener('click', async function (event) {
|
||||
const $e = event.target
|
||||
if ($e.parentNode.id != 'company-list')
|
||||
return
|
||||
|
||||
$adminapp.querySelector('#companies #company-id').value = $e.id
|
||||
$adminapp.querySelector('#companies #company-name').value = $e.getAttribute('name')
|
||||
$adminapp.querySelector('#companies #company-description').value = $e.getAttribute('title')
|
||||
})
|
||||
|
||||
$adminapp.querySelector('#groups #group-list').addEventListener('click', async function (event) {
|
||||
const $e = event.target
|
||||
if ($e.id != 'delete')
|
||||
return
|
||||
|
||||
const id = $e.parentNode.id
|
||||
const project_id = $adminapp.querySelector('#groups #group-list').getAttribute('project-id')
|
||||
|
||||
const res = await fetch(`/api/admin/project/${project_id}/group/${id}`, {
|
||||
method: 'DELETE'
|
||||
}).then(res => res.json())
|
||||
.then(res => $e.parentNode.remove())
|
||||
.catch(alert)
|
||||
})
|
||||
|
||||
$adminapp.querySelectorAll('button[href]')
|
||||
.forEach($e => {
|
||||
$e.addEventListener('click', async function (event) {
|
||||
// &admin=change_info+delete_messages+restrict_members+invite_users+pin_messages+promote_members
|
||||
let url = this.getAttribute('href')
|
||||
if ($e.hasAttribute('admin'))
|
||||
url += '&admin=change_info+pin_messages'
|
||||
window.Telegram.WebApp.openTelegramLink(url)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
async function reloadProjects() {
|
||||
const reqProjects = await fetch('/api/admin/project').then(res => res.json())
|
||||
|
||||
const projects = reqProjects.data
|
||||
const $projectList = $adminapp.querySelector('#projects #project-list')
|
||||
$projectList.innerHTML = projects.map(e => `<div id = "${e.id}" title = "${e.description}" name = "${e.name}">${e.name}<span id = "delete">x</div></div>`).join('') || 'Пусто'
|
||||
}
|
||||
|
||||
async function reloadGroups(projectId) {
|
||||
const req = await fetch('/api/admin/project/' + projectId + '/group').then(res => res.json())
|
||||
|
||||
const groups = req.data
|
||||
const $groupList = $adminapp.querySelector('#groups #group-list')
|
||||
$groupList.setAttribute('project-id', projectId)
|
||||
$groupList.innerHTML = groups.map(e => `<div id = "${e.id}" name = "${e.name}">${e.name}<span id = "delete">x</div></div>`).join('') || 'Пусто'
|
||||
}
|
||||
|
||||
async function reloadCompanies(projectId) {
|
||||
const req = await fetch('/api/admin/project/' + projectId + '/company').then(res => res.json())
|
||||
|
||||
const companies = req.data
|
||||
const $companyList = $adminapp.querySelector('#companies #company-list')
|
||||
$companyList.setAttribute('project-id', projectId)
|
||||
$companyList.innerHTML = companies.map(e => `<div id = "${e.id}" name = "${e.name}" title = "${e.description}">${e.name}<span id = "delete">x</div></div>`).join('') || 'Пусто'
|
||||
}
|
||||
|
||||
async function reloadUsers(projectId) {
|
||||
const req = await fetch('/api/admin/project/' + projectId + '/user').then(res => res.json())
|
||||
|
||||
const users = req.data
|
||||
const $userList = $adminapp.querySelector('#users #user-list')
|
||||
$userList.setAttribute('user-id', projectId)
|
||||
$userList.innerHTML = users.map(e => `<div id = "${e.id}">${e.firstname} ${e.lastname}</div>`).join('') || 'Пусто'
|
||||
}
|
||||
|
||||
$adminapp.querySelector('#projects #add-project').addEventListener('click', async function (event) {
|
||||
const $e = this.parentNode
|
||||
const id = +$e.querySelector('#project-id').value
|
||||
|
||||
const data = {
|
||||
name: $e.querySelector('#project-name').value,
|
||||
description: $e.querySelector('#project-description').value
|
||||
}
|
||||
|
||||
const url = id ? '/api/admin/project/' + id : '/api/admin/project'
|
||||
const method = id ? 'PUT' : 'POST'
|
||||
|
||||
|
||||
await fetch(url, {
|
||||
method,
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(res => res.json()).then(() => {
|
||||
reloadProjects()
|
||||
$e.querySelector('#project-id').value = ''
|
||||
$e.querySelector('#project-name').value = ''
|
||||
$e.querySelector('#project-description').value = ''
|
||||
}).catch(alert)
|
||||
})
|
||||
|
||||
$adminapp.querySelector('#companies #add-company').addEventListener('click', async function (event) {
|
||||
const $e = this.parentNode
|
||||
const project_id = +$adminapp.querySelector('#groups #group-list').getAttribute('project-id')
|
||||
const id = +$e.querySelector('#company-id').value
|
||||
|
||||
const data = {
|
||||
name: $e.querySelector('#company-name').value,
|
||||
description: $e.querySelector('#company-description').value
|
||||
}
|
||||
|
||||
const url = '/api/admin/project/' + project_id + '/company' + (id ? '/' + id : '')
|
||||
const method = id ? 'PUT' : 'POST'
|
||||
|
||||
|
||||
await fetch(url, {
|
||||
method,
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(res => res.json()).then(() => {
|
||||
reloadCompanies(project_id)
|
||||
$e.querySelector('#company-id').value = ''
|
||||
$e.querySelector('#company-name').value = ''
|
||||
$e.querySelector('#company-description').value = ''
|
||||
}).catch(alert)
|
||||
})
|
||||
|
||||
try {
|
||||
|
||||
|
||||
|
||||
|
||||
(async () => {
|
||||
const startParams = (Telegram.WebApp.initDataUnsafe.start_param || '').split('_')
|
||||
const isAdmin = startParams[0] == 'admin'
|
||||
const $app = isAdmin ? $adminapp : $miniapp
|
||||
$app.hidden = false
|
||||
|
||||
const login_url = isAdmin ? '/api/admin/customer/login?' : '/api/miniapp/user/login?'
|
||||
const login = await fetch(login_url + Telegram.WebApp.initData, {method: 'POST'}).then(res => res.json())
|
||||
console.log(login)
|
||||
|
||||
|
||||
if (isAdmin) {
|
||||
const reqProfile = await fetch('/api/admin/customer/profile').then(res => res.json())
|
||||
const profile = reqProfile.data
|
||||
|
||||
$adminapp.querySelector('#settings #name').value = profile.name || ''
|
||||
$adminapp.querySelector('#settings #company-name').value = profile.company?.name || ''
|
||||
$adminapp.querySelector('#settings #company-phone').value = profile.company?.phone || ''
|
||||
$adminapp.querySelector('#settings #company-site').value = profile.company?.site || ''
|
||||
$adminapp.querySelector('#settings #company-description').value = profile.company?.description || ''
|
||||
$adminapp.querySelector('#settings #upload-group-selector').setAttribute('href', 'https://t.me/ready_or_not_2025_bot?startgroup=-' + profile.id)
|
||||
|
||||
const $uploadGroup = $adminapp.querySelector('#settings #upload-group')
|
||||
if (profile.upload_group) {
|
||||
$uploadGroup.innerHTML = profile.upload_group.name || 'Ошибка'
|
||||
$uploadGroup.setAttribute('href', 'https://t.me/c/' + profile.upload_group.telegram_id)
|
||||
} else {
|
||||
$uploadGroup.innerHTML = 'Не задано'
|
||||
$uploadGroup.setAttribute('href', '')
|
||||
}
|
||||
|
||||
await reloadProjects()
|
||||
} else {
|
||||
// Пользовательский
|
||||
if (startParams[1])
|
||||
alert('Группа на проекте ' + startParams[1])
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
} catch (err) {
|
||||
alert(err)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
65
backend/public/miniapp.html
Normal file
65
backend/public/miniapp.html
Normal file
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<style>
|
||||
.block {margin-bottom: 10px}
|
||||
#projects > div {cursor: pointer}
|
||||
</style>
|
||||
<div class = "block">
|
||||
<label for = "user">USER</label>
|
||||
<select id = "user"></select>
|
||||
</div>
|
||||
|
||||
<div class = "block">
|
||||
<div id = "project-title">ПРОЕКТЫ</div>
|
||||
<div id = "projects">EMPTY</div>
|
||||
</div>
|
||||
|
||||
<div class = "block">
|
||||
<div id = "member-title">УЧАСТНИКИ</div>
|
||||
<div id = "members"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
(async function () {
|
||||
try {
|
||||
const $user = document.getElementById('user')
|
||||
const $projects = document.getElementById('projects')
|
||||
const $members = document.getElementById('members')
|
||||
|
||||
let members = {}
|
||||
|
||||
$user.addEventListener('change', async () => {
|
||||
const user_id = $user.value
|
||||
const projects = await fetch('/api/miniapp/project?user_id=' + user_id).then(res => res.json())
|
||||
$projects.innerHTML = projects.data.map(e =>
|
||||
`<div id = "${e.id}" title = '${JSON.stringify(e)}'>${e.name} - ${e.description}</div>`
|
||||
).join('')
|
||||
$members.innerHTML = ''
|
||||
})
|
||||
|
||||
$projects.addEventListener('click', async (evt) => {
|
||||
if (evt.target.parentNode != $projects)
|
||||
return
|
||||
|
||||
const _members = await fetch('/api/miniapp/project/' + evt.target.id + '/member?user_id=' + $user.value).then(res => res.json())
|
||||
members = _members.data
|
||||
$members.innerHTML = members.map(e =>
|
||||
`<div id = "${e.id}" title = '${JSON.stringify(e)}' is-blocked = '${e.is_blocked}'>${e.id} - ${e.telegram_name}</div>`
|
||||
).join('')
|
||||
})
|
||||
|
||||
|
||||
const user_ids = await fetch('/api/miniapp/user').then(res => res.json())
|
||||
$user.innerHTML = user_ids.data.map(id => `<option value = '${id}'>${id}</option>`).join('')
|
||||
$user.dispatchEvent(new Event('change'))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
alert(err.message)
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user