-
Notifications
You must be signed in to change notification settings - Fork 3
Refactor/hooks #630
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor/hooks #630
Changes from 4 commits
10c2049
c237f0b
01e21dc
7502bb2
21f6fd7
b44693c
c9f3b04
2990035
3e8582a
e7e0267
1fe4e8b
30e0e03
6f7de9b
c9834b8
ec9dcf1
904fe1f
3cea8dc
6f7bcc7
e621dc1
6c66f9f
7898f41
e84a208
fb911d6
db6e5cc
70f6c91
b1982f1
0eb3a3c
c770992
74c5f96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,19 +74,39 @@ func (repo *gormRepository) GetAllRooms(start, end time.Time, excludeEventID uui | |
|
|
||
| func createRoom(db *gorm.DB, args domain.CreateRoomArgs) (*Room, error) { | ||
| room := ConvCreateRoomParamsToRoom(args) | ||
| err := db.Create(&room).Error | ||
| var err error | ||
| // IDを新規発行 | ||
| room.ID ,err = uuid.NewV4() | ||
| if err != nil { | ||
| return nil,err | ||
| } | ||
| // 時間整合性は service で確認済み | ||
| err = db.Create(&room).Error | ||
| return &room, err | ||
|
Comment on lines
87
to
112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Room 本体と Admin 差し替えを 1 トランザクションにまとめてください。
Also applies to: 118-142 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| func updateRoom(db *gorm.DB, roomID uuid.UUID, args domain.UpdateRoomArgs) (*Room, error) { | ||
| room := ConvUpdateRoomParamsToRoom(args) | ||
| room.ID = roomID | ||
| err := db.Session(&gorm.Session{FullSaveAssociations: true}). | ||
| Omit("verified", "CreatedAt").Save(&room).Error | ||
| if room.ID == uuid.Nil { | ||
| return nil,ErrRoomUndefined | ||
| } | ||
|
|
||
| // BeforeSave, BeforeUpdate が発火 | ||
iChemy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| err := db.Where("room_id", room.ID).Delete(&RoomAdmin{}).Error | ||
| if err!=nil{ | ||
| return nil,err | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // 時間整合性は service で確認済み | ||
| err = db.Omit("verified", "CreatedAt").Save(&room).Error | ||
|
||
|
|
||
| // err := db.Session(&gorm.Session{FullSaveAssociations: true}). | ||
| // Omit("verified", "CreatedAt").Save(&room).Error | ||
| return &room, err | ||
| } | ||
|
|
||
| func updateRoomVerified(db *gorm.DB, roomID uuid.UUID, verified bool) error { | ||
| // hooksは発火しない | ||
| return db.Model(&Room{}).Where("id = ?", roomID).UpdateColumn("verified", verified).Error | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -118,7 +118,18 @@ func saveUser(db *gorm.DB, user *User) (*User, error) { | |||||||||||||||||||||||||||||||||||||||||
| err := db.Transaction(func(tx *gorm.DB) error { | ||||||||||||||||||||||||||||||||||||||||||
| existingUser, err := getUser(tx.Preload("Provider").Preload("Token"), user.ID) | ||||||||||||||||||||||||||||||||||||||||||
| if errors.Is(err, gorm.ErrRecordNotFound) { | ||||||||||||||||||||||||||||||||||||||||||
| return tx.Create(&user).Error | ||||||||||||||||||||||||||||||||||||||||||
| // BeforeCreate が呼ばれる | ||||||||||||||||||||||||||||||||||||||||||
| if user.ID != uuid.Nil { | ||||||||||||||||||||||||||||||||||||||||||
| // 単純にIDが違う場合 | ||||||||||||||||||||||||||||||||||||||||||
| return ErrRecordNotFound | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| // IDなしで新たに作成する場合 | ||||||||||||||||||||||||||||||||||||||||||
| user.ID ,err = uuid.NewV4() | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| return tx.Create(&user).Error | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| // BeforeCreate が呼ばれる | |
| if user.ID != uuid.Nil { | |
| // 単純にIDが違う場合 | |
| return ErrRecordNotFound | |
| } else { | |
| // IDなしで新たに作成する場合 | |
| user.ID ,err = uuid.NewV4() | |
| if err != nil { | |
| return err | |
| } | |
| return tx.Create(&user).Error | |
| } | |
| // BeforeCreate が呼ばれる | |
| if user.ID == uuid.Nil { | |
| user.ID, err = uuid.NewV4() | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return tx.Create(&user).Error |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@infra/db/user.go` around lines 121 - 132, The BeforeCreate hook currently
returns ErrRecordNotFound whenever user.ID != uuid.Nil which prevents creating
new users that supply an ID; instead, change BeforeCreate so it only generates a
new UUID when user.ID == uuid.Nil (use uuid.NewV4) and in all other cases
attempt tx.Create(&user).Error rather than returning ErrRecordNotFound;
reference the BeforeCreate function, the user.ID check, uuid.NewV4 call,
tx.Create(&user).Error and ErrRecordNotFound and remove the early
ErrRecordNotFound branch so provided IDs are allowed and creation is attempted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,15 @@ import ( | |
| "github.com/traPtitech/knoQ/infra/traq" | ||
| ) | ||
|
|
||
| var ( | ||
| ErrInvalidArgs = errors.New("invalid args") | ||
| ErrTimeConsistency = errors.New("inconsistent time") | ||
| ErrExpression = errors.New("invalid expression") | ||
| ErrRoomUndefined = errors.New("invalid room or args") | ||
| ErrNoAdmins = errors.New("no admins") | ||
| ErrDuplicateEntry = errors.New("duplicate entry") | ||
| ) | ||
|
Comment on lines
+12
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check service/errors.go and trace error handling flow
echo "=== service/errors.go content ==="
cat -n service/errors.go
echo ""
echo "=== ErrTimeConsistency usage locations ==="
rg -n "ErrTimeConsistency" --type=go -B1 -A1
echo ""
echo "=== handleDBError implementation ==="
rg -n "func.*handleDBError" --type=go -A20
echo ""
echo "=== defaultErrorHandling implementation ==="
rg -n "func.*defaultErrorHandling" --type=go -A20
echo ""
echo "=== Check room_impl.go for ErrTimeConsistency usage ==="
rg -n "ErrTimeConsistency" service/room_impl.go -B2 -A2Repository: traPtitech/knoQ Length of output: 7130 🏁 Script executed: #!/bin/bash
# Check HTTP handler code that uses service methods and how errors are handled
echo "=== Find HTTP handlers ==="
fd -e go -path "*/infra/api*" -o -path "*/handler*" | head -20
echo ""
echo "=== Search for service calls in handlers ==="
rg -n "\.CreateRoom\(|\.UpdateRoom\(" --type=go -B2 -A5 | head -50
echo ""
echo "=== Check if service.ErrTimeConsistency is handled in handlers ==="
rg -n "service\.Err" --type=go | grep -i handle
echo ""
echo "=== Check how errors from service are handled ==="
rg -n "s\..*Room\(" --type=go -A10 | grep -A5 "if err"Repository: traPtitech/knoQ Length of output: 2308 🏁 Script executed: #!/bin/bash
# Check all service.Err* direct returns vs wrapped returns
echo "=== All service.Err* returns without defaultErrorHandling wrapping ==="
rg -n "return.*service\.Err|return nil.*Err(Time|Invalid|Expression|Room|NoAdmins|Duplicate)" service/ --type=go
echo ""
echo "=== Count returns with defaultErrorHandling ==="
rg -n "return.*defaultErrorHandling" service/ --type=go | wc -l
echo ""
echo "=== Check all Err* constants usage in service layer ==="
rg -n "Err(TimeConsistency|InvalidArgs|Expression|RoomUndefined|NoAdmins|DuplicateEntry)" service/ --type=go -c | sortRepository: traPtitech/knoQ Length of output: 591 サービス層の検証エラーがエラーハンドリングマッピングをバイパスしている
修正案:
🤖 Prompt for AI Agents |
||
|
|
||
| func handleTraQError(err error) error { | ||
| if errors.Is(err, traq.ErrUnAuthorized) { | ||
| return domain.ErrInvalidToken | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,27 @@ func (s *service) UpdateEvent(ctx context.Context, reqID uuid.UUID, eventID uuid | |
| WriteEventParams: params, | ||
| CreatedBy: reqID, | ||
| } | ||
| // RoomIDの存在を確認 RoomがなくPlaceがあれば新たに作成 | ||
|
|
||
| // if params.RoomID == uuid.Nil { | ||
| // if params.Place == "" { | ||
| // roomParams := domain.WriteRoomParams { | ||
| // Place: params.Place, | ||
| // TimeStart: params.TimeStart, | ||
| // TimeEnd: params.TimeEnd, | ||
| // Admins: params.Admins, | ||
| // } | ||
| // // UnVerifiedを仮定 | ||
| // _,err = s.CreateUnVerifiedRoom(ctx,reqID,roomParams) | ||
| // if err != nil { | ||
| // return nil,err | ||
| // } | ||
| // } else{ | ||
| // return nil, ErrRoomUndefined | ||
| // } | ||
| // } | ||
|
||
|
|
||
| // Event Save を使っている | ||
Nzt3-gh marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| event, err := s.GormRepo.UpdateEvent(eventID, p) | ||
| if err != nil { | ||
| return nil, defaultErrorHandling(err) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,10 @@ import ( | |
| ) | ||
|
|
||
| func (s *service) CreateUnVerifiedRoom(ctx context.Context, reqID uuid.UUID, params domain.WriteRoomParams) (*domain.Room, error) { | ||
| // 時間整合性の確認 | ||
| if(!params.TimeStart.Before(params.TimeEnd)){ | ||
| return nil,ErrTimeConsistency | ||
| } | ||
| p := domain.CreateRoomArgs{ | ||
| WriteRoomParams: params, | ||
| Verified: false, | ||
|
|
@@ -23,6 +27,10 @@ func (s *service) CreateVerifiedRoom(ctx context.Context, reqID uuid.UUID, param | |
| if !s.IsPrivilege(ctx, reqID) { | ||
| return nil, domain.ErrForbidden | ||
| } | ||
| // 時間整合性の確認 | ||
| if(!params.TimeStart.Before(params.TimeEnd)){ | ||
| return nil,ErrTimeConsistency | ||
| } | ||
| p := domain.CreateRoomArgs{ | ||
| WriteRoomParams: params, | ||
| Verified: true, | ||
|
|
@@ -36,12 +44,20 @@ func (s *service) UpdateRoom(ctx context.Context, reqID uuid.UUID, roomID uuid.U | |
| if !s.IsRoomAdmins(ctx, reqID, roomID) { | ||
| return nil, domain.ErrForbidden | ||
| } | ||
| // そもそもNilだとIsRoomAdminsで弾かれるはず | ||
| // if roomID == uuid.Nil { | ||
| // return nil,ErrRoomUndefined | ||
| // } | ||
|
||
|
|
||
| p := domain.UpdateRoomArgs{ | ||
| WriteRoomParams: params, | ||
| CreatedBy: reqID, | ||
| } | ||
|
|
||
| // 時間整合性の確認 | ||
| if(!params.TimeStart.Before(params.TimeEnd)){ | ||
| return nil,ErrTimeConsistency | ||
| } | ||
| r, err := s.GormRepo.UpdateRoom(roomID, p) | ||
| return r, defaultErrorHandling(err) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UpdateGroupを transaction で包まないと、中途半端な状態が永続化されます。ここは
GroupMember削除 →GroupAdmin削除 →groups更新 → 関連再作成が別々の書き込みです。service/group_impl.go:28-42 側でも transaction を張っていないので、途中で 1 本でも失敗するとメンバー/管理者だけ消えたグループが残ります。🤖 Prompt for AI Agents