axe/internal/handlers/types.go
2026-10-18 22:07:25 +03:00

145 lines
6.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handlers
import (
"time"
"building-mgmt/internal/models"
)
// Формы ответов API. Нужны дважды: как фактический JSON в хендлерах
// и как схема в Swagger — чтобы документация не разъезжалась с кодом.
// ErrorResponse — единая форма ошибки. Текст фиксированный и короткий,
// детали БД в него не попадают (они только в логе).
type ErrorResponse struct {
Error string `json:"error"`
}
// TokenResponse — ответ login, register и refresh.
type TokenResponse struct {
// Access-токен: JWT на auth.AccessTTL.
Token string `json:"token"`
// Срок жизни access-токена в секундах.
ExpiresIn int `json:"expires_in"`
User *models.Profile `json:"user"`
// Refresh-токен в JSON не отдаётся: он живёт только в httpOnly-куке
// (см. AuthHandler.setRefreshCookie) — из JavaScript ему не достаться.
}
// OKResponse — ответ для действий без сущности на выходе (logout).
type OKResponse struct {
OK bool `json:"ok"`
// Revoked — сколько сессий закрыто; заполняется только в logout-all.
Revoked int64 `json:"revoked,omitempty"`
}
// Формы списков. Список — это всегда страница (items + метаданные),
// а не голый массив: total считается COUNT(*) OVER() до обрезки,
// limit/offset отражают то, что реально применено.
// TicketListResponse — страница GET /tickets.
type TicketListResponse struct {
Items []models.Ticket `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// ProjectListResponse — страница GET /projects.
type ProjectListResponse struct {
Items []models.Project `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// ObjectListResponse — страница GET /projects/{id}/objects.
type ObjectListResponse struct {
Items []models.Object `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// ProfileListResponse — страница пользователей: GET /users.
type ProfileListResponse struct {
Items []models.Profile `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// ProjectWorkerListResponse — страница состава проекта
// (GET /projects/{id}/workers): профили плюс статус членства.
type ProjectWorkerListResponse struct {
Items []models.ProjectWorker `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// InvitationListResponse — страница приглашений мастера (GET /invitations).
type InvitationListResponse struct {
Items []models.ProjectInvitation `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// TicketEventListResponse — страница журнала заявки (GET /tickets/{id}/events).
type TicketEventListResponse struct {
Items []models.TicketEvent `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// PhotoListResponse — страница списка фото (GET /tickets/{id}/photos).
type PhotoListResponse struct {
Items []models.TicketPhoto `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
// MaxPerTicket — лимит файлов на заявку (PHOTO_MAX_PER_TICKET):
// UI рисует «n / N», не зная настройки окружения.
MaxPerTicket int `json:"max_per_ticket"`
}
// RecurringRuleListResponse — страница правил повторения (GET /recurring).
type RecurringRuleListResponse struct {
Items []models.RecurringRule `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// RecurringRunListResponse — страница истории срабатываний правила
// (GET /recurring/{id}/runs).
type RecurringRunListResponse struct {
Items []models.RecurringRun `json:"items"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// InvitationResponse — ответ на POST /projects/{id}/workers: с 0005 это
// приглашение, а не готовое членство, поэтому в ответе его статус и срок.
type InvitationResponse struct {
OK bool `json:"ok"`
// Всегда "invited": стать участником мастер может только сам, через
// POST /projects/{id}/invitation/accept.
Status string `json:"status"`
// До какого срока мастер может ответить (см. repository.InvitationTTL).
ExpiresAt time.Time `json:"expires_at"`
}
// PasswordResetResponse — ответ на POST /users/{id}/password-reset.
// Сам токен живёт только в этом ответе: в БД — лишь sha256, поэтому
// выпущенный токен нельзя подсмотреть даже с доступом к базе.
type PasswordResetResponse struct {
OK bool `json:"ok"`
Token string `json:"token"`
// См. repository.ResetTTL (24 часа).
ExpiresAt time.Time `json:"expires_at"`
}