Skip to content

Commit 76c47f5

Browse files
authored
Merge pull request #17 from su-its/feat/backend/api/v1
Feat/backend/api/v1
2 parents 540ce5f + 39a9744 commit 76c47f5

File tree

30 files changed

+1538
-284
lines changed

30 files changed

+1538
-284
lines changed

typing-server/api/cmd/main.go

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"time"
1515

1616
"github.com/go-sql-driver/mysql"
17+
"github.com/su-its/typing/typing-server/api/handler"
18+
"github.com/su-its/typing/typing-server/api/router"
1719
"github.com/su-its/typing/typing-server/domain/repository/ent"
1820
"github.com/su-its/typing/typing-server/domain/repository/ent/user"
1921
)
@@ -54,6 +56,7 @@ func main() {
5456
return
5557
}
5658
defer entClient.Close()
59+
handler.SetEntClient(entClient)
5760
logger.Info("ent client is opened")
5861

5962
// スキーマの作成
@@ -65,7 +68,7 @@ func main() {
6568

6669
// シードデータの挿入
6770
if *seedFlag {
68-
if err := seedData(context.Background(), entClient); err != nil {
71+
if err := seedData(context.Background(), entClient, logger); err != nil {
6972
logger.Error("failed to seed data: %v", err)
7073
return
7174
}
@@ -86,7 +89,14 @@ func main() {
8689
go func() {
8790
defer wg.Done() // 関数終了時にWaitGroupをデクリメント
8891
// サーバーの設定
89-
server := &http.Server{Addr: ":8080"}
92+
// ルーティングの設定
93+
r := router.SetupRouter()
94+
95+
// サーバーの設定
96+
server := &http.Server{
97+
Addr: ":8080",
98+
Handler: r,
99+
}
90100
// 非同期でサーバーを開始
91101
go func() {
92102
logger.Info("server is running at Addr :8080")
@@ -115,42 +125,77 @@ func main() {
115125
logger.Info("server exited")
116126
}
117127

118-
// TODO: 本番環境では削除する
119-
func seedData(ctx context.Context, client *ent.Client) error {
128+
func seedData(ctx context.Context, client *ent.Client, logger *slog.Logger) error {
120129
// シードデータの作成
121130
for i := 0; i < 10; i++ {
122-
isAlreadySeeded, err := client.User.Query().Where(user.StudentNumber(fmt.Sprintf("user%d", i+1))).Exist(ctx)
131+
studentNumber := fmt.Sprintf("user%d", i+1)
132+
handleName := fmt.Sprintf("handle%d", i+1)
133+
134+
isAlreadySeeded, err := client.User.Query().Where(user.StudentNumber(studentNumber)).Exist(ctx)
123135
if err != nil {
124136
return err
125137
}
126138
if isAlreadySeeded {
139+
logger.Info("User with student number already seeded, skipping", slog.String("studentNumber", studentNumber))
127140
continue
128141
}
129142

130143
u, err := client.User.Create().
131-
SetStudentNumber(fmt.Sprintf("user%d", i+1)).
132-
SetHandleName(fmt.Sprintf("handle%d", i+1)).
144+
SetStudentNumber(studentNumber).
145+
SetHandleName(handleName).
133146
Save(ctx)
134147
if err != nil {
135148
panic(err)
136149
}
137150

151+
logger.Info("Created user", slog.String("studentNumber", studentNumber), slog.String("handleName", handleName))
152+
153+
var maxKeystrokesScore, maxAccuracyScore *ent.Score
154+
138155
for j := 0; j < 5; j++ {
139-
score, err := client.Score.Create().
140-
SetKeystrokes(rand.Intn(200)).
141-
SetAccuracy(rand.Float64()).
156+
keystrokes := rand.Intn(200) + 100
157+
accuracy := rand.Float64()
158+
159+
s, err := client.Score.Create().
160+
SetKeystrokes(keystrokes).
161+
SetAccuracy(accuracy).
142162
SetCreatedAt(time.Now()).
163+
SetUser(u).
143164
Save(ctx)
144165
if err != nil {
145166
panic(err)
146167
}
147168

148-
_, err = client.User.UpdateOne(u).
149-
AddScores(score).Save(ctx)
169+
logger.Info("Created score", slog.Int("keystrokes", keystrokes), slog.Float64("accuracy", accuracy), slog.String("studentNumber", studentNumber))
170+
171+
if s.Keystrokes < 120 || s.Accuracy < 0.95 {
172+
continue
173+
}
174+
175+
if maxKeystrokesScore == nil || s.Keystrokes > maxKeystrokesScore.Keystrokes {
176+
maxKeystrokesScore = s
177+
}
178+
if maxAccuracyScore == nil || s.Accuracy > maxAccuracyScore.Accuracy {
179+
maxAccuracyScore = s
180+
}
181+
}
182+
183+
// 最大のKeystrokesスコアと最大のAccuracyスコアのフラグを設定
184+
if maxKeystrokesScore != nil {
185+
err = maxKeystrokesScore.Update().SetIsMaxKeystrokes(true).Exec(ctx)
150186
if err != nil {
151-
panic(err)
187+
return err
152188
}
189+
logger.Info("Set is_max_keystrokes flag", slog.Int("keystrokes", maxKeystrokesScore.Keystrokes), slog.String("studentNumber", studentNumber))
190+
}
191+
if maxAccuracyScore != nil {
192+
err = maxAccuracyScore.Update().SetIsMaxAccuracy(true).Exec(ctx)
193+
if err != nil {
194+
return err
195+
}
196+
logger.Info("Set is_max_accuracy flag", slog.Float64("accuracy", maxAccuracyScore.Accuracy), slog.String("studentNumber", studentNumber))
153197
}
154198
}
199+
155200
return nil
156201
}

typing-server/api/controller/system/health.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

typing-server/api/handler/health.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package handler
2+
3+
import (
4+
"log/slog"
5+
"net/http"
6+
)
7+
8+
func HealthCheck(w http.ResponseWriter, r *http.Request) {
9+
w.WriteHeader(http.StatusOK)
10+
_, err := w.Write([]byte("API is running"))
11+
if err != nil {
12+
slog.Error("failed to write response: %v", err)
13+
}
14+
}

typing-server/api/handler/options.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package handler
2+
3+
import "github.com/su-its/typing/typing-server/domain/repository/ent"
4+
5+
var entClient *ent.Client
6+
7+
func SetEntClient(client *ent.Client) {
8+
entClient = client
9+
}

typing-server/api/handler/score.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package handler
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"strconv"
7+
8+
"github.com/google/uuid"
9+
"github.com/su-its/typing/typing-server/api/service"
10+
)
11+
12+
func GetScoresRanking(w http.ResponseWriter, r *http.Request) {
13+
ctx := r.Context()
14+
15+
sortBy := r.URL.Query().Get("sort_by")
16+
if sortBy == "" {
17+
sortBy = "keystrokes"
18+
}
19+
20+
startStr := r.URL.Query().Get("start")
21+
start, err := strconv.Atoi(startStr)
22+
if err != nil {
23+
start = 1
24+
}
25+
26+
limitStr := r.URL.Query().Get("limit")
27+
limit, err := strconv.Atoi(limitStr)
28+
if err != nil {
29+
limit = 10
30+
}
31+
32+
rankings, err := service.GetScoresRanking(ctx, entClient, sortBy, start, limit)
33+
if err != nil {
34+
http.Error(w, err.Error(), http.StatusInternalServerError)
35+
return
36+
}
37+
38+
w.Header().Set("Content-Type", "application/json")
39+
err = json.NewEncoder(w).Encode(rankings)
40+
if err != nil {
41+
http.Error(w, err.Error(), http.StatusInternalServerError)
42+
return
43+
}
44+
}
45+
46+
func PostScore(w http.ResponseWriter, r *http.Request) {
47+
ctx := r.Context()
48+
49+
userIDStr := r.URL.Query().Get("user_id")
50+
userID, err := uuid.Parse(userIDStr)
51+
if err != nil {
52+
http.Error(w, "Invalid user_id", http.StatusBadRequest)
53+
return
54+
}
55+
56+
keystrokesStr := r.URL.Query().Get("keystrokes")
57+
keystrokes, err := strconv.Atoi(keystrokesStr)
58+
if err != nil {
59+
http.Error(w, "Invalid keystrokes", http.StatusBadRequest)
60+
return
61+
}
62+
63+
accuracyStr := r.URL.Query().Get("accuracy")
64+
accuracy, err := strconv.ParseFloat(accuracyStr, 64)
65+
if err != nil {
66+
http.Error(w, "Invalid accuracy", http.StatusBadRequest)
67+
return
68+
}
69+
70+
if err := service.CreateScore(ctx, entClient, userID, keystrokes, accuracy); err != nil {
71+
http.Error(w, err.Error(), http.StatusInternalServerError)
72+
return
73+
}
74+
75+
w.WriteHeader(http.StatusCreated)
76+
}

typing-server/api/handler/user.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package handler
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
7+
"github.com/su-its/typing/typing-server/api/service"
8+
)
9+
10+
func GetUser(w http.ResponseWriter, r *http.Request) {
11+
ctx := r.Context()
12+
13+
studentNumber := r.URL.Query().Get("student_number")
14+
if studentNumber == "" {
15+
http.Error(w, "student_number is required", http.StatusBadRequest)
16+
return
17+
}
18+
19+
user, err := service.GetUserByStudentNumber(ctx, entClient, studentNumber)
20+
if err != nil {
21+
http.Error(w, err.Error(), http.StatusInternalServerError)
22+
return
23+
}
24+
25+
w.Header().Set("Content-Type", "application/json")
26+
err = json.NewEncoder(w).Encode(user)
27+
if err != nil {
28+
http.Error(w, err.Error(), http.StatusInternalServerError)
29+
return
30+
}
31+
}

typing-server/api/presenter/server.go

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)