wip 15
This commit is contained in:
@@ -280,6 +280,13 @@ type ImportResultsResponse struct {
|
||||
// ImportType defines model for ImportType.
|
||||
type ImportType string
|
||||
|
||||
// InfoResponse defines model for InfoResponse.
|
||||
type InfoResponse struct {
|
||||
RegistrationEnabled bool `json:"registration_enabled"`
|
||||
SearchEnabled bool `json:"search_enabled"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// LeaderboardData defines model for LeaderboardData.
|
||||
type LeaderboardData struct {
|
||||
All []LeaderboardEntry `json:"all"`
|
||||
@@ -290,8 +297,8 @@ type LeaderboardData struct {
|
||||
|
||||
// LeaderboardEntry defines model for LeaderboardEntry.
|
||||
type LeaderboardEntry struct {
|
||||
UserId string `json:"user_id"`
|
||||
Value int64 `json:"value"`
|
||||
UserId string `json:"user_id"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
// LogEntry defines model for LogEntry.
|
||||
@@ -598,6 +605,9 @@ type ServerInterface interface {
|
||||
// Get user streaks
|
||||
// (GET /home/streaks)
|
||||
GetStreaks(w http.ResponseWriter, r *http.Request)
|
||||
// Get server information
|
||||
// (GET /info)
|
||||
GetInfo(w http.ResponseWriter, r *http.Request)
|
||||
// List progress records
|
||||
// (GET /progress)
|
||||
GetProgressList(w http.ResponseWriter, r *http.Request, params GetProgressListParams)
|
||||
@@ -1174,6 +1184,20 @@ func (siw *ServerInterfaceWrapper) GetStreaks(w http.ResponseWriter, r *http.Req
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetInfo operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetInfo(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetInfo(w, r)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetProgressList operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetProgressList(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -1510,6 +1534,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
|
||||
m.HandleFunc("GET "+options.BaseURL+"/home/graph", wrapper.GetGraphData)
|
||||
m.HandleFunc("GET "+options.BaseURL+"/home/statistics", wrapper.GetUserStatistics)
|
||||
m.HandleFunc("GET "+options.BaseURL+"/home/streaks", wrapper.GetStreaks)
|
||||
m.HandleFunc("GET "+options.BaseURL+"/info", wrapper.GetInfo)
|
||||
m.HandleFunc("GET "+options.BaseURL+"/progress", wrapper.GetProgressList)
|
||||
m.HandleFunc("GET "+options.BaseURL+"/progress/{id}", wrapper.GetProgress)
|
||||
m.HandleFunc("GET "+options.BaseURL+"/search", wrapper.GetSearch)
|
||||
@@ -2350,6 +2375,31 @@ func (response GetStreaks500JSONResponse) VisitGetStreaksResponse(w http.Respons
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type GetInfoRequestObject struct {
|
||||
}
|
||||
|
||||
type GetInfoResponseObject interface {
|
||||
VisitGetInfoResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type GetInfo200JSONResponse InfoResponse
|
||||
|
||||
func (response GetInfo200JSONResponse) VisitGetInfoResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type GetInfo500JSONResponse ErrorResponse
|
||||
|
||||
func (response GetInfo500JSONResponse) VisitGetInfoResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(500)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type GetProgressListRequestObject struct {
|
||||
Params GetProgressListParams
|
||||
}
|
||||
@@ -2650,6 +2700,9 @@ type StrictServerInterface interface {
|
||||
// Get user streaks
|
||||
// (GET /home/streaks)
|
||||
GetStreaks(ctx context.Context, request GetStreaksRequestObject) (GetStreaksResponseObject, error)
|
||||
// Get server information
|
||||
// (GET /info)
|
||||
GetInfo(ctx context.Context, request GetInfoRequestObject) (GetInfoResponseObject, error)
|
||||
// List progress records
|
||||
// (GET /progress)
|
||||
GetProgressList(ctx context.Context, request GetProgressListRequestObject) (GetProgressListResponseObject, error)
|
||||
@@ -3260,6 +3313,30 @@ func (sh *strictHandler) GetStreaks(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetInfo operation middleware
|
||||
func (sh *strictHandler) GetInfo(w http.ResponseWriter, r *http.Request) {
|
||||
var request GetInfoRequestObject
|
||||
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.GetInfo(ctx, request.(GetInfoRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "GetInfo")
|
||||
}
|
||||
|
||||
response, err := handler(r.Context(), w, r, request)
|
||||
|
||||
if err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
} else if validResponse, ok := response.(GetInfoResponseObject); ok {
|
||||
if err := validResponse.VisitGetInfoResponse(w); err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
}
|
||||
} else if response != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
|
||||
}
|
||||
}
|
||||
|
||||
// GetProgressList operation middleware
|
||||
func (sh *strictHandler) GetProgressList(w http.ResponseWriter, r *http.Request, params GetProgressListParams) {
|
||||
var request GetProgressListRequestObject
|
||||
|
||||
@@ -174,66 +174,66 @@ func convertGraphData(graphData []database.GetDailyReadStatsRow) []GraphDataPoin
|
||||
}
|
||||
|
||||
func arrangeUserStatistics(userStatistics []database.GetUserStatisticsRow) UserStatisticsResponse {
|
||||
// Sort helper - sort by WPM
|
||||
sortByWPM := func(stats []database.GetUserStatisticsRow) []LeaderboardEntry {
|
||||
// Sort by WPM for each period
|
||||
sortByWPM := func(stats []database.GetUserStatisticsRow, getter func(database.GetUserStatisticsRow) float64) []LeaderboardEntry {
|
||||
sorted := append([]database.GetUserStatisticsRow(nil), stats...)
|
||||
sort.SliceStable(sorted, func(i, j int) bool {
|
||||
return sorted[i].TotalWpm > sorted[j].TotalWpm
|
||||
return getter(sorted[i]) > getter(sorted[j])
|
||||
})
|
||||
|
||||
result := make([]LeaderboardEntry, len(sorted))
|
||||
for i, item := range sorted {
|
||||
result[i] = LeaderboardEntry{UserId: item.UserID, Value: int64(item.TotalWpm)}
|
||||
result[i] = LeaderboardEntry{UserId: item.UserID, Value: getter(item)}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Sort by duration (seconds)
|
||||
sortByDuration := func(stats []database.GetUserStatisticsRow) []LeaderboardEntry {
|
||||
// Sort by duration (seconds) for each period
|
||||
sortByDuration := func(stats []database.GetUserStatisticsRow, getter func(database.GetUserStatisticsRow) int64) []LeaderboardEntry {
|
||||
sorted := append([]database.GetUserStatisticsRow(nil), stats...)
|
||||
sort.SliceStable(sorted, func(i, j int) bool {
|
||||
return sorted[i].TotalSeconds > sorted[j].TotalSeconds
|
||||
return getter(sorted[i]) > getter(sorted[j])
|
||||
})
|
||||
|
||||
result := make([]LeaderboardEntry, len(sorted))
|
||||
for i, item := range sorted {
|
||||
result[i] = LeaderboardEntry{UserId: item.UserID, Value: item.TotalSeconds}
|
||||
result[i] = LeaderboardEntry{UserId: item.UserID, Value: float64(getter(item))}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Sort by words
|
||||
sortByWords := func(stats []database.GetUserStatisticsRow) []LeaderboardEntry {
|
||||
// Sort by words for each period
|
||||
sortByWords := func(stats []database.GetUserStatisticsRow, getter func(database.GetUserStatisticsRow) int64) []LeaderboardEntry {
|
||||
sorted := append([]database.GetUserStatisticsRow(nil), stats...)
|
||||
sort.SliceStable(sorted, func(i, j int) bool {
|
||||
return sorted[i].TotalWordsRead > sorted[j].TotalWordsRead
|
||||
return getter(sorted[i]) > getter(sorted[j])
|
||||
})
|
||||
|
||||
result := make([]LeaderboardEntry, len(sorted))
|
||||
for i, item := range sorted {
|
||||
result[i] = LeaderboardEntry{UserId: item.UserID, Value: item.TotalWordsRead}
|
||||
result[i] = LeaderboardEntry{UserId: item.UserID, Value: float64(getter(item))}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
return UserStatisticsResponse{
|
||||
Wpm: LeaderboardData{
|
||||
All: sortByWPM(userStatistics),
|
||||
Year: sortByWPM(userStatistics),
|
||||
Month: sortByWPM(userStatistics),
|
||||
Week: sortByWPM(userStatistics),
|
||||
All: sortByWPM(userStatistics, func(s database.GetUserStatisticsRow) float64 { return s.TotalWpm }),
|
||||
Year: sortByWPM(userStatistics, func(s database.GetUserStatisticsRow) float64 { return s.YearlyWpm }),
|
||||
Month: sortByWPM(userStatistics, func(s database.GetUserStatisticsRow) float64 { return s.MonthlyWpm }),
|
||||
Week: sortByWPM(userStatistics, func(s database.GetUserStatisticsRow) float64 { return s.WeeklyWpm }),
|
||||
},
|
||||
Duration: LeaderboardData{
|
||||
All: sortByDuration(userStatistics),
|
||||
Year: sortByDuration(userStatistics),
|
||||
Month: sortByDuration(userStatistics),
|
||||
Week: sortByDuration(userStatistics),
|
||||
All: sortByDuration(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.TotalSeconds }),
|
||||
Year: sortByDuration(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.YearlySeconds }),
|
||||
Month: sortByDuration(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.MonthlySeconds }),
|
||||
Week: sortByDuration(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.WeeklySeconds }),
|
||||
},
|
||||
Words: LeaderboardData{
|
||||
All: sortByWords(userStatistics),
|
||||
Year: sortByWords(userStatistics),
|
||||
Month: sortByWords(userStatistics),
|
||||
Week: sortByWords(userStatistics),
|
||||
All: sortByWords(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.TotalWordsRead }),
|
||||
Year: sortByWords(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.YearlyWordsRead }),
|
||||
Month: sortByWords(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.MonthlyWordsRead }),
|
||||
Week: sortByWords(userStatistics, func(s database.GetUserStatisticsRow) int64 { return s.WeeklyWordsRead }),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,8 +460,8 @@ components:
|
||||
user_id:
|
||||
type: string
|
||||
value:
|
||||
type: integer
|
||||
format: int64
|
||||
type: number
|
||||
format: double
|
||||
required:
|
||||
- user_id
|
||||
- value
|
||||
@@ -617,6 +617,20 @@ components:
|
||||
filter:
|
||||
type: string
|
||||
|
||||
InfoResponse:
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
search_enabled:
|
||||
type: boolean
|
||||
registration_enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- version
|
||||
- search_enabled
|
||||
- registration_enabled
|
||||
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
@@ -1111,6 +1125,26 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/info:
|
||||
get:
|
||||
summary: Get server information
|
||||
operationId: getInfo
|
||||
tags:
|
||||
- Info
|
||||
responses:
|
||||
200:
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/InfoResponse'
|
||||
500:
|
||||
description: Internal server error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/home:
|
||||
get:
|
||||
summary: Get home page data
|
||||
|
||||
@@ -46,8 +46,8 @@ func (s *Server) authMiddleware(handler StrictHandlerFunc, operationID string) S
|
||||
ctx = context.WithValue(ctx, "request", r)
|
||||
ctx = context.WithValue(ctx, "response", w)
|
||||
|
||||
// Skip auth for login endpoint only - cover and file require auth via cookies
|
||||
if operationID == "Login" {
|
||||
// Skip auth for login and info endpoints - cover and file require auth via cookies
|
||||
if operationID == "Login" || operationID == "GetInfo" {
|
||||
return handler(ctx, w, r, request)
|
||||
}
|
||||
|
||||
@@ -67,3 +67,13 @@ func (s *Server) authMiddleware(handler StrictHandlerFunc, operationID string) S
|
||||
}
|
||||
}
|
||||
|
||||
// GetInfo returns server information
|
||||
func (s *Server) GetInfo(ctx context.Context, request GetInfoRequestObject) (GetInfoResponseObject, error) {
|
||||
return GetInfo200JSONResponse{
|
||||
Version: s.cfg.Version,
|
||||
SearchEnabled: s.cfg.SearchEnabled,
|
||||
RegistrationEnabled: s.cfg.RegistrationEnabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user