вывела список курсов из бека

This commit is contained in:
Tatyana 2025-08-22 16:10:30 +03:00
parent bbffbd1fdb
commit 4b38fa67b0
8 changed files with 453 additions and 80 deletions

18
SSL/localhost.crt Normal file
View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC1zCCAb+gAwIBAgIUPHdL8t6goPcrwjyu1bR0S+Ts7O8wDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJMTI3LjAuMC4xMB4XDTI1MDgyMTA4NTUzMFoXDTI2MDgy
MTA4NTUzMFowFDESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAmsutLy1yUE1TCvs475LV0UwGrSvuW818ccxh5LEKUiad
iWuv0NL5/OxaG+dWJvVzOz9uBafcxbBYwJ65XqOTXM44FKCKuDtYG/7E2TDc5KPH
/7f/GCFla+2k/aep2VagtTK+AFRiTFcmm9C34mFu34O/2fiAiNROiRBE+SxajPdQ
DEd71yyCypnJWMdvxODToaRSwBNPMCOd/QceHgWUxFuC3813ewASuqKMP+M9ZNEU
QfFPypkgqGvDMUun6olXHs34qYAlu8w1Fk9fu6+9JAEKONtvXaGQcBkF0LBwTicZ
LgDheKc2ZG0wHyrFSs8rMee4zd/gvcgaw7G1bxgcbQIDAQABoyEwHzAdBgNVHQ4E
FgQU9PnSNORZygTvdFeXfjbeYsxbbs8wDQYJKoZIhvcNAQELBQADggEBABo5fok7
NeeX/0UL01HEy/BwGNxZnscl3tAfTsLTCwhGC4ADd4ppGROTfv+R68eMSM8ZFtR7
wLO6zK/VE0bidyw9jXN1Tp9etv25IjfkQB4LqNcs6b7LgoeXWklVW9Ap4K2h6A6q
C1lBs8nVW6YtTHE2BPF2dNFMuuqnYiquw3bEikjrZ3waEYnxYP+l9eAFgcAEqyQB
5RKgqq6fv4q7PxyXmvKy18OFxalVogoUFNiyZOoNpgj8ZbqIKru20oU/Xi821yAU
xhGrQn/aY5IshTpNsjzxcP9LYQjOFUId/ISxA9tPucHctkMm/dnbcJmoPZlStIaK
j3xnOy8TLQLoNG4=
-----END CERTIFICATE-----

28
SSL/localhost.key Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCay60vLXJQTVMK
+zjvktXRTAatK+5bzXxxzGHksQpSJp2Ja6/Q0vn87Fob51Ym9XM7P24Fp9zFsFjA
nrleo5NczjgUoIq4O1gb/sTZMNzko8f/t/8YIWVr7aT9p6nZVqC1Mr4AVGJMVyab
0LfiYW7fg7/Z+ICI1E6JEET5LFqM91AMR3vXLILKmclYx2/E4NOhpFLAE08wI539
Bx4eBZTEW4LfzXd7ABK6oow/4z1k0RRB8U/KmSCoa8MxS6fqiVcezfipgCW7zDUW
T1+7r70kAQo4229doZBwGQXQsHBOJxkuAOF4pzZkbTAfKsVKzysx57jN3+C9yBrD
sbVvGBxtAgMBAAECggEAHe4dW5aiOIgm8yPdn6cIzDnyvYeVxC7gbcF6uSUJLZa1
VbWablpox0Bs8OHDTO+fGvjZ/WJ2Y8wD8SSPi469xs9B1S0wfUxOLkWNyr/xqgzH
9jgdrQ0CBwMRaJFDXFhtZPO9fKNUSVX9i1mpQG6d6T5YeV0c/zfrwoFAkNxEWuaG
hmp+F7OW3QcvZhLm3jJo2PnWpVfhbcMyw2MDVfSVzcZrZS1qFp0AvalcOI3z1QWd
1CsJYVASc7adyfev0qJ64EmgdI6sIBbI1cxb7gDLDX48f2rSwznEvgQ1gKUdZ5a5
FBI/hSV8XkDDYNzaniFeQavHZ8BjrU66UxCd0x3JoQKBgQDaW54nommnUQYzOmYB
0tdAHBDrxjSQt5aUf+XngWMykpIYEYA0rtS5Q1i4CUVK+F4bKfCiURf4PSyp9vOs
4DLOC+e3O+ZGbXbIgmi9SuU6//T+wJY/NHppo1rIZldTMNNCdltW4nroO0ROSebW
Ot8I0JDLexwS6wedfGsnirggIQKBgQC1evu21yor0pZe6laPzsnnArX7NSdPiA8L
TidODrGXO9PzB2CifaQENBFe4SHKTVk5FtqUd5I0EJ32yUBDHbnqfVIXV7/juZxA
Ez98NyD70wT4FmiHVAG2SrN96NfaRASBaWlGk8oAA1P4pOQao6IVpE4ICQua1qXZ
jVa6gSIizQKBgHzKS1J/YT478f0o7M8x/c4nvAvi1Hu4UBhCF9P8gAKQ/Wk/5zM0
j2HpeTSEJ9O2qaGAkINTMQ2veG0SMySjZKWY7C4tz2aEfJQO42j6+pKDYTKOQc+R
YDwrHWDWDCYBC1s6ZOz8th0ucdUEKyZXsstI1tdTXjH5m/qG9n48qwnBAoGBAIqC
UclL0QjfUhshGW3qsthYjlIrUFR4EJtdS8xclJhLdkmfUNbTs7Htl3BlvWdsv3M+
CReVZwXLxPRMx3oyHupkOZpNQ8xnpmSVDDgez1LDzKAYYjEfIatiujmX097nWNT4
gfv24g4+fAFiwCHAz/1aiJ/DX5MOzkgLgq0Xz9jlAoGBAL521PPgAWdNngZh/3IZ
bcC88v3bgreZfw3FL6FEMiPD/lO4h021LqkwvicL9TlgsFxsdpZfEX01jMF4J23o
Ll0JQ4r6zPl0kO0dmeEN3vt/YWToekUfE9fOXjuXIPSgMU+8+xREO8PBtgE9q8WR
Nk49oeSsHE4dDm/hMnWUgRcp
-----END PRIVATE KEY-----

105
SSL/ssl Normal file
View File

@ -0,0 +1,105 @@
самоподписанный сертификат. проблема в том, что не полуается его в доверенные добавть
1. Запустить эмулятор, потом добавить сертификат в sdcard/Download
adb push "/home/tatyana/Рабочий стол/ssl_test/localhost.crt" /sdcard/Download/
tatyana@fedora:~/Рабочий стол/ssl_test$ adb push "/home/tatyana/Рабочий стол/ssl_test/localhost.crt"
/sdcard/Download/
/home/tatyana/Рабочий стол/...pped. 12.2 MB/s (1046 bytes in 0.000s)
tatyana@fedora:~/Рабочий стол/ssl_test$
2. Сверзу нажать груг = хоум, Зайти в настройки устройства в самом эмуляторе
3. Найти "Encryption and Credentials /«Шифрование и учетные данные
4. Выбираем установка (второй пункт vpn ....)
5. сертификат будет в загрузках (пункт 1) на карте
6. Объединить ключ и сертификат
openssl pkcs12 -export -inkey localhost.key -in localhost.crt -out localhost.p12
7. перенести на устройство
adb push /home/tatyana/Рабочий\ стол/ssl_test/localhost.p12 /sdcard/Download/
/////////////////////////////////////////
2 способ поместить в доверенные в ручную
app/
src/
main/
res/
raw/
your_cert.der
Конечно! Ниже я подробно объясню, как доверять самоподписанному сертификату в эмуляторе Android для разработки, используя network_security_config.xml. Это наиболее безопасный и удобный способ для тестирования в приложениях без необходимости рутировать устройство или эмулятор.
Подробная инструкция: доверие к самоподписанному сертификату в Android через network_security_config.xml
Шаг 1. Подготовьте ваш сертификат
1.1. Экспортируйте сертификат в нужном формате
Если у вас есть .p12 или .crt, убедитесь, что он в формате .der или .pem.
Для этого используйте команду OpenSSL:
bash
# Извлечь сертификат из p12 в PEM
openssl pkcs12 -in localhost.p12 -clcerts -nokeys -out localhost.pem
или
bash
# Конвертировать PEM в DER (бинарный формат)
openssl x509 -in localhost.pem -outform DER -out localhost.der
Важно: Назовите файл, например, your_cert.der.
1.2. Поместите сертификат в проект
В вашем проекте Android создайте папку res/raw/ (если ее еще нет).
Поместите туда файл your_cert.der.
Шаг 2. Создайте файл конфигурации network_security_config.xml
Этот файл укажет вашему приложению доверять вашему сертификату.
2.1. Создайте папку и файл
В вашем проекте перейдите по пути: app/src/main/res/xml/
Если папки xml нет, создайте ее.
Внутри создайте файл network_security_config.xml.
2.2. Напишите содержимое файла
xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain>your.server.domain</domain> <!-- замените на ваш домен или IP -->
<trust-anchors>
<certificates src="@raw/your_cert" />
</trust-anchors>
</domain-config>
</network-security-config>
Обратите внимание:
Замените your.server.domain на ваш реальный сервер или IP, к которому вы подключаетесь.
Если вы хотите доверять всему трафику (не рекомендуется), можно оставить <domain>, а не указывать конкретный.
Шаг 3. Обновите AndroidManifest.xml
Добавьте ссылку на конфигурацию безопасности в ваш манифест:
xml
<application
android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>

View File

@ -4,9 +4,9 @@ import Welcome from "./pages/Welcome";
import Login from "./pages/Login";
import Home from "./pages/Home";
import ForgotPasword from "./pages/ForgotPassword";
import Courses from "./pages/Courses";
import { Courses } from "./pages/Courses";
import CourseExercises from "./pages/CourseExercises";
import Exercise from "./pages/Exercise";
import { Exercise } from "./pages/Exercise";
import Settings from "./pages/Settings";
import CourseComplete from "./pages/CourseComplete";

133
src/pages/Courses old.tsx Normal file
View File

@ -0,0 +1,133 @@
"use client"
import { useState, useEffect } from 'react';
import BottomNavigation from "../components/BottomNavigation"
import { useHistory } from "react-router-dom"
import HeaderNav from "../components/HeaderNav"
import { getRouteCourseExercises } from "../shared/consts/router"
// Типизация Exercise
interface Exercise {
id: number;
title: string;
desc: string;
url_file_img: string;
}
const ProgressLine = () => {
return (
<div
className="h-full bg-gradient-to-r from-orange-300 to-orange-500 transition-all duration-500 absolute left-0 top-0 rounded-l-xl"
style={{ width: '85%' }}
/>
);
}
const AnalitcsCards = () => {
return (
<div className="px-6 mb-8" >
<div className="text-center relative ">
<div className="w-full h-10 bg-gray-500 rounded-xl relative flex items-center justify-center mb-4 shadow-xl">
{/* Прогрессная часть */}
<ProgressLine />
{/* Текст поверх линии */}
<div className="absolute text-white font-semibold text-base">Вы прошли реабилитацию на {85}%</div>
</div>
</div>
</div>
)
}
export const Courses = () => {
const history = useHistory()
// Внутренний компонент для загрузки упражнений
const Exercises = () => {
const [exercises, setExercises] = useState<Exercise[]>([]);
useEffect(() => {
fetch('/pacient/exercises')
.then(res => {
if (!res.ok) throw new Error('Ошибка при загрузке упражнений');
return res.json();
})
.then((data: Exercise[]) => {
console.log('test');
setExercises(data);
})
.catch(err => {
setError(err.message);
});
}, []);
return (
<div>
{/* Можно добавить заголовок или обертку */}
<ul>
{exercises.map(ex => (
<li key={ex.id} className="mb-4 p-4 bg-white/20 rounded-lg shadow-md hover:bg-white/30 transition">
<h3 className="font-semibold text-[#5F5C5C] mb-2">{ex.title}</h3>
<p className="text-sm text-[#5F5C5C]/70 mb-2">{ex.desc}</p>
{/* Вставка изображения */}
<img src={ex.url_file_img} alt={ex.title} className="w-full rounded" />
</li>
))}
</ul>
</div>
);
};
return (
<div className="my-36 min-h-screen max-w-4xl mx-auto">
<HeaderNav item='Курсы' text='все назначенные' />
<AnalitcsCards />
{/* Внедрение компонента упражнений */}
<Exercises />
{/* Можно оставить закомментированный блок или убрать его */}
{/*
<div className="px-6 mb-8">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-black text-[#5F5C5C]">Мои курсы</h2>
<button onClick={() => history.push("/courses")} className="text-[#2BACBE] text-sm font-bold hover:underline">
Все курсы
</button>
</div>
<div className="space-y-4">
{courses.map((course) => (
<div
key={course.id}
onClick={() => history.push(getRouteCourseExercises(':id'))}
className="bg-white/30 backdrop-blur-2xl rounded-3xl p-6 border border-white/20 shadow-xl cursor-pointer hover:shadow-2xl transition-all duration-300 transform hover:scale-[1.02]"
>
<div className="flex items-center space-x-5">
<div className="flex-1">
<h3 className="font-semibold text-[#5F5C5C] text-lg mb-2">{course.name}</h3>
<div className="bg-white/50 rounded-full h-3 mb-2 overflow-hidden">
<div
className={`bg-gradient-to-r ${course.color} h-3 rounded-full transition-all duration-700 shadow-sm`}
style={{ width: `${course.progress}%` }}
></div>
</div>
<p className="text-sm text-[#5F5C5C]/70 font-semibold">{course.progress}% завершено</p>
</div>
<div className="text-[#2BACBE] transform transition-transform duration-300 hover:translate-x-1">
{/* Иконка стрелки */}
{/*<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>*/}
{/*</div>
</div>
</div>
))}
</div>
</div> */}
<BottomNavigation />
</div>
)
}

View File

@ -1,93 +1,100 @@
"use client"
import type React from "react"
import { useState, useEffect } from 'react';
import BottomNavigation from "../components/BottomNavigation"
import { useHistory } from "react-router-dom"
import { useHistory } from "react-router-dom" // для v5
import HeaderNav from "../components/HeaderNav"
import { getRouteCourseExercises } from "../shared/consts/router"
import { connect } from '../confconnect';
const ProgressLine = () => {
return (<div
className="h-full bg-gradient-to-r from-orange-300 to-orange-500 transition-all duration-500 absolute left-0 top-0 rounded-l-xl"
style={{ width: '85%' }}
/>
);
interface Course {
ID: number;
title: string;
desc: string;
url_file_img: string;
}
const AnalitcsCards = () => {
export const Courses = () => {
const history = useHistory();
{/* Analytics Cards */ }
return (
<div className="px-6 mb-8" >
<div className="text-center relative ">
<div className="w-full h-10 bg-gray-500 rounded-xl relative flex items-center justify-center mb-4 shadow-xl">
{/* Прогрессная часть */}
<ProgressLine/>
const [courses, setCourses] = useState<Course[]>([]);
const [error, setError] = useState<string>('');
const token = localStorage.getItem('authToken');
{/* Текст поверх линии */}
<div className="absolute text-white font-semibold text-base">Вы прошли реабилитацию на {85}%</div>
</div>
</div>
</div>
)
useEffect(() => {
if (!token) {
setError('Токен не найден');
return;
}
const Home: React.FC = () => {
const history = useHistory()
connect.get('/pacient/courses', {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then(response => {
console.log('Response status:', response.status);
const courses = [
{ id: 1, name: "Восстановление колена", progress: 75, color: "from-[#2BACBE] to-[#2BACBE]/80" },
{ id: 2, name: "Укрепление спины", progress: 45, color: "from-[#5F5C5C] to-[#5F5C5C]/80" },
{ id: 3, name: "Реабилитация плеча", progress: 90, color: "from-[#2BACBE]/80 to-[#5F5C5C]" },
];
// Предполагаемая структура:
// response.data.courses — массив пользователей
const users = response.data.courses || [];
// Собираем все курсы из всех пользователей
const allCourses: Course[] = [];
users.forEach(user => {
if (user.Courses && Array.isArray(user.Courses)) {
user.Courses.forEach(course => {
// Можно добавить проверку или преобразование
allCourses.push({
ID: course.id, // или course.ID, зависит от структуры
title: course.title,
desc: course.desc,
url_file_img: course.url_file_img,
});
});
}
});
setCourses(allCourses);
})
.catch(error => {
if (error.response) {
console.error('Ошибка ответа сервера:', error.response.status, error.response.data);
setError(`Ошибка сервера: ${error.response.status}`);
} else if (error.request) {
console.error('Нет ответа от сервера:', error.request);
setError('Нет ответа от сервера');
} else {
console.error('Ошибка при настройке запроса:', error.message);
setError(`Ошибка: ${error.message}`);
}
});
}, [token]);
return (
<div className="my-36 min-h-screen max-w-4xl mx-auto">
<HeaderNav item='Курсы' text='все назначенные' />
<AnalitcsCards />
{error && <p className="text-red-500">{error}</p>}
{/* Courses */}
<div className="px-6 mb-8">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-black text-[#5F5C5C]">Мои курсы</h2>
{/* <button onClick={() => history.push("/courses")} className="text-[#2BACBE] text-sm font-bold hover:underline">
Все курсы
</button> */}
</div>
<div className="space-y-4">
{courses.map((course) => (
<div
key={course.id}
onClick={() => history.push(getRouteCourseExercises(':id'))}
className="bg-white/30 backdrop-blur-2xl rounded-3xl p-6 border border-white/20 shadow-xl cursor-pointer hover:shadow-2xl transition-all duration-300 transform hover:scale-[1.02]"
>
<div className="flex items-center space-x-5">
<div className="flex-1">
<h3 className="font-semibold text-[#5F5C5C] text-lg mb-2">{course.name}</h3>
<div className="bg-white/50 rounded-full h-3 mb-2 overflow-hidden">
<div
className={`bg-gradient-to-r ${course.color} h-3 rounded-full transition-all duration-700 shadow-sm`}
style={{ width: `${course.progress}%` }}
></div>
</div>
<p className="text-sm text-[#5F5C5C]/70 font-semibold">{course.progress}% завершено</p>
</div>
<div className="text-[#2BACBE] transform transition-transform duration-300 hover:translate-x-1">
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
</div>
</div>
</div>
))}
{/* Выводим список курсов */}
<div>
{courses.length > 0 ? (
courses.map(course => (
<div key={course.ID} className="border p-4 mb-4 rounded shadow">
<h2 className="text-xl font-bold">{course.title}</h2>
<p>{course.desc}</p>
{course.url_file_img && (
<img src={course.url_file_img} alt={course.title} className="mt-2 w-full h-auto" />
)}
</div>
))
) : (
!error && <p>Нет назначенных курсов</p>
)}
</div>
<BottomNavigation />
</div>
)
}
export default Home
);
};

View File

@ -1,5 +1,5 @@
"use client"
import type React from "react"
import { useState, useEffect } from "react"
import { useHistory } from "react-router-dom"
@ -9,7 +9,19 @@ import HeaderNav from "../components/HeaderNav"
import video from "../assets/img/video.mov"
const Exercise: React.FC = () => {
export interface Exercise {
id: number;
title: string;
desc: string;
url_file: string;
url_file_img: string;
}
export const Exercise = () => {
const history = useHistory()
// const { id } = useParams<{ id: string }>()
const [isPlaying, setIsPlaying] = useState(false)
@ -104,7 +116,7 @@ const Exercise: React.FC = () => {
<HeaderNav item='Надо разобраться?' text='упражнение' />
{/* Video/Image Section */}
<div className="px-4 sm:px-6 mt-10 mb-6">
<div className="glass-morphism rounded-3xl overflow-hidden shadow-2xl border border-white/20 backdrop-blur-2xl">
<div className="relative">
@ -129,7 +141,7 @@ const Exercise: React.FC = () => {
{isPlaying ? <PauseIcon /> : <PlayIcon />}
</button>
</div>
{/* Live indicators */}
{isPlaying && (
<div className="absolute top-4 left-4 flex items-center space-x-2">
<div className="w-3 h-3 bg-orange-500 rounded-full animate-pulse "></div>
@ -138,14 +150,14 @@ const Exercise: React.FC = () => {
</span>
</div>
)}
{/* Timer Display */}
<div className="absolute top-4 right-4 bg-cyan-50 backdrop-blur-sm px-3 py-1 rounded-xl">
<span className="text-gray-800 text-sm font-bold">{formatTime(currentTime)}</span>
</div>
</div>
</div>
</div>
{/* Exercise Steps - Vertical Scroll */}
<div className="px-4 sm:px-6 space-y-4 mb-6">
{exerciseSteps.map((step, index) => (
<div
@ -225,4 +237,4 @@ const Exercise: React.FC = () => {
)
}
export default Exercise

View File

@ -0,0 +1,70 @@
curl -i -X OPTIONS http://localhost:8093/auth/api/login -H "Origin: http://localhost" -H "Access-Control-Request-Method: POST"
tatyana@fedora:~/Рабочий стол/RehabMobileApp/RehabMobileApp/android$ curl -i -X OPTIONS http://localhost:8093/auth/api/login -H "Origin: http://localhost" -H "Access-Control-Request-Method: POST"
HTTP/1.1 204 No Content
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Accept-Language,Access-Control-Allow-Origin,Authorization,Content-Language,X-Csrf-Token,X-Xsrf-Token,Origin,X-Requested-With,Content-Type,Accept
Access-Control-Allow-Methods: PUT,GET,POST,PATCH,OPTIONS,DELETE
Access-Control-Allow-Origin: http://localhost
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Date: Fri, 22 Aug 2025 08:09:40 GMT
tatyana@fedora:~/Рабочий стол/RehabMobileApp/RehabMobileApp/android$ curl -i -X POST http://localhost:8093/auth/api/login \
-H "Origin: http://localhost" \
-H "Content-Type: application/json" \
-d '{"Email": "krasnova@mail.ru", "Password": "Tatyana1"}'
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8093/pacient/courses
"courses": [
{
"CreatedAt": "2025-08-19T10:50:04.454157+03:00",
"UpdatedAt": "2025-08-19T10:50:04.454157+03:00",
"DeletedAt": null,
"ID": 25,
"Name": "krasnova@mail.ru",
"Email": "krasnova@mail.ru",
"Password": "$2a$10$ryI/OSON56IlmDL0sAHhmOk9vhFkuTRieFlj32p/cKYCrPWGOJZKC",
"Role": "",
"UserDoctorID": 0,
"ExerciseCourses": null,
"Courses": [
{
"ID": 0,
"CreatedAt": "2025-08-15T11:46:58.879953+03:00",
"UpdatedAt": "2025-08-15T11:46:58.879953+03:00",
"DeletedAt": null,
"id": 1,
"title": "Восстановление",
"desc": "Восстановиться",
"time_course": "",
"day_course": 0,
"url_file_img": "https://vivasport.ru/assets/images/news/12555/spine-training-1.webp",
"users": null,
"exercises": null
}
]
},
{
"CreatedAt": "2025-08-20T14:19:19.754239+03:00",
"UpdatedAt": "2025-08-20T14:19:19.754239+03:00",
"DeletedAt": null,
"ID": 26,
"Name": "krasnova5@mail.ru",
"Email": "krasnova5@mail.ru",
"Password": "$2a$10$sdcCn51708LV5y6wsmOho.dLtpDGf43muXobIcvGYQ1.TtB1WxFju",
"Role": "",
"UserDoctorID": 0,
"ExerciseCourses": null,
"Courses": []
}
],
"sessionname": "krasnova@mail.ru"