feat: переделал все клиентские запросы на другие endpoint для безопастности
Backend CI / build-and-test (push) Successful in 48s
Frontend CI / build-and-check (push) Failing after 5m13s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 15s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 1m9s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 26s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 14s

This commit is contained in:
2026-05-18 03:27:16 +03:00
parent 6eeacd80cc
commit 19ea303782
19 changed files with 660 additions and 96 deletions
+26
View File
@@ -59,6 +59,32 @@ export const lecturesApi = {
}
export const usersApi = {
me: () => apiRequest<CurrentUserDto>('/users/me'),
updateMe: (payload: { displayName?: string | null; avatarUrl?: string | null }) =>
apiRequest<CurrentUserDto>('/users/me', {
method: 'PUT',
body: JSON.stringify(payload),
}),
myStats: () => apiRequest<UserStatsDto>('/users/me/stats'),
async myEnrollments() {
const payload = await apiRequest<PagedResult<LectureDto> | LectureDto[] | undefined>(
'/users/me/enrollments',
)
return extractItems(payload)
},
async myAchievements() {
const payload = await apiRequest<
PagedResult<UserAchievementDto> | UserAchievementDto[] | AchievementDto[]
>('/users/me/achievements')
if (Array.isArray(payload)) return payload
return payload.items ?? []
},
async myTransactions() {
const payload = await apiRequest<PagedResult<CoinTransactionDto> | CoinTransactionDto[]>(
'/users/me/transactions',
)
return extractItems(payload)
},
get: (id: string | number) => apiRequest<UserDto>(`/users/${id}`),
async list(query: UserQuery = {}) {
const payload = await apiRequest<PagedResult<UserDto> | UserDto[]>('/users', {
-1
View File
@@ -33,7 +33,6 @@ function getDefaultActiveRole(roles: UserRole[]): UserRole {
export function mapApiUser(user: UserAuthDto | UserDto | CurrentUserDto, stats?: UserStatsDto): User {
const roles = mapApiRoles(user.roles)
return {
id: String(user.id),
name: user.displayName || user.email || 'Пользователь UniVerse',
email: user.email || '',
roles,
+1 -1
View File
@@ -29,13 +29,13 @@ export interface LoginMicrosoftRequest {
}
export interface UserAuthDto {
id: number
email: string
displayName?: string | null
roles: ApiUserRole[]
}
export interface UserDto extends UserAuthDto {
id: number
avatarUrl?: string | null
isActive: boolean
xp: number
+4 -4
View File
@@ -46,17 +46,17 @@ export const useLecturesStore = defineStore('lectures', () => {
}
}
async function fetchRegisteredForUser(userId: string) {
async function fetchRegisteredForCurrentUser() {
try {
const enrollments = await usersApi.enrollments(userId)
const enrollments = await usersApi.myEnrollments()
const mapped = enrollments.map(mapApiLecture)
registered.value = mapped.map(lecture => lecture.id)
if (mapped.length) {
mapped.forEach(lecture => {
const index = lectures.value.findIndex(item => item.id === lecture.id)
if (index >= 0) lectures.value[index] = { ...lectures.value[index], ...lecture, registered: true }
else lectures.value.push({ ...lecture, registered: true })
})
registered.value = mapped.map(lecture => lecture.id)
}
} catch {
// Some backend builds return an empty 200 for this endpoint; catalog detail still carries isEnrolled.
@@ -108,7 +108,7 @@ export const useLecturesStore = defineStore('lectures', () => {
registeredLectures,
fetchLectures,
fetchLecture,
fetchRegisteredForUser,
fetchRegisteredForCurrentUser,
fetchReviews,
register,
unregister,
+5 -6
View File
@@ -12,18 +12,17 @@ export const useUserStore = defineStore('user', () => {
const loading = ref(false)
const error = ref<string | null>(null)
async function fetchStudentData(userId?: string) {
async function fetchStudentData() {
const auth = useAuthStore()
const id = userId ?? auth.user?.id
if (!id) return
if (!auth.user) return
loading.value = true
error.value = null
try {
const [stats, achievementPayload, transactions] = await Promise.all([
usersApi.stats(id),
usersApi.achievements(id),
usersApi.transactions(id),
usersApi.myStats(),
usersApi.myAchievements(),
usersApi.myTransactions(),
])
const [achievementCatalog, notificationPayload] = await Promise.all([
achievementsApi.list(),
-1
View File
@@ -1,7 +1,6 @@
export type UserRole = 'student' | 'teacher' | 'admin'
export interface User {
id: string
name: string
email: string
roles: UserRole[]
@@ -11,7 +11,7 @@ const unlocked = computed(() => userStore.achievements.filter(a => a.unlocked))
const locked = computed(() => userStore.achievements.filter(a => !a.unlocked))
onMounted(() => {
if (auth.user) void userStore.fetchStudentData(auth.user.id)
if (auth.user) void userStore.fetchStudentData()
})
</script>
+2 -2
View File
@@ -56,9 +56,9 @@ const levelProgressText = computed(() =>
onMounted(async () => {
await Promise.all([
lectures.all.length ? Promise.resolve() : lectures.fetchLectures(),
userStore.fetchStudentData(user.value.id),
userStore.fetchStudentData(),
])
await lectures.fetchRegisteredForUser(user.value.id)
await lectures.fetchRegisteredForCurrentUser()
})
</script>
@@ -23,7 +23,7 @@ const history = computed(() => lecturesStore.all.filter(l => l.status === 'compl
onMounted(async () => {
if (!lecturesStore.all.length) await lecturesStore.fetchLectures()
if (auth.user) await lecturesStore.fetchRegisteredForUser(auth.user.id)
if (auth.user) await lecturesStore.fetchRegisteredForCurrentUser()
})
function openCancel(id: string) {
+1 -1
View File
@@ -53,7 +53,7 @@ const interestTags = ref([
const notificationSettings = ref({ email: true })
onMounted(() => {
void userStore.fetchStudentData(user.value.id)
void userStore.fetchStudentData()
})
</script>