feat(integrations): align notion authorization

This commit is contained in:
2026-06-06 18:00:19 +08:00
parent 5ed9952b7e
commit 0f2d64c8f6
9 changed files with 154 additions and 9 deletions
@@ -20,6 +20,23 @@ func NewNotionIntegrationHandler(svc *service.NotionIntegrationService) *NotionI
return &NotionIntegrationHandler{svc: svc}
}
// Authorization creates a Notion OAuth authorization URL.
// POST /api/v1/accounts/:account_id/notion/authorization
func (h *NotionIntegrationHandler) Authorization(c *gin.Context) {
accountID, err := parseUintParam(c, "account_id")
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id")
return
}
result, svcErr := h.svc.BuildAuthorizationURL(accountID)
if svcErr != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"success": false})
return
}
c.JSON(http.StatusOK, result)
}
// Delete removes a Notion integration for an account.
// DELETE /api/v1/accounts/:account_id/integrations/notion
func (h *NotionIntegrationHandler) Delete(c *gin.Context) {
@@ -35,7 +35,9 @@ func setupNotionIntegrationRouter(t *testing.T) (*gin.Engine, *gorm.DB) {
handler := NewNotionIntegrationHandler(service.NewNotionIntegrationService(repository.NewIntegrationHookRepo(db)))
integrations := r.Group("/api/v1/accounts/:account_id/integrations")
account := r.Group("/api/v1/accounts/:account_id")
account.POST("/notion/authorization", handler.Authorization)
integrations := account.Group("/integrations")
RegisterNotionIntegrationRoutes(integrations, handler)
return r, db
@@ -60,6 +62,41 @@ func TestNotionIntegration_Delete_BadAccountID(t *testing.T) {
assert.Contains(t, errBody["message"], "invalid account_id")
}
func TestNotionIntegration_Authorization_BadAccountID(t *testing.T) {
r, _ := setupNotionIntegrationRouter(t)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/accounts/abc/notion/authorization", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
var resp map[string]interface{}
json.Unmarshal(w.Body.Bytes(), &resp)
errBody := resp["error"].(map[string]interface{})
assert.Contains(t, errBody["message"], "invalid account_id")
}
func TestNotionIntegration_Authorization_ReturnsChatwootPayload(t *testing.T) {
t.Setenv("NOTION_CLIENT_ID", "notion-client")
t.Setenv("NOTION_CLIENT_SECRET", "notion-secret")
t.Setenv("FRONTEND_URL", "https://app.example.test/")
r, db := setupNotionIntegrationRouter(t)
account := &model.Account{Name: "Test Account"}
require.NoError(t, db.Create(account).Error)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", fmt.Sprintf("/api/v1/accounts/%d/notion/authorization", account.ID), nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, true, resp["success"])
assert.Contains(t, resp["url"], "https://api.notion.com/v1/oauth/authorize")
assert.Contains(t, resp["url"], "redirect_uri=https%3A%2F%2Fapp.example.test%2Fnotion%2Fcallback")
}
func TestNotionIntegration_Delete_NoTrailingSlashReturnsEmptyOK(t *testing.T) {
r, db := setupNotionIntegrationRouter(t)
account := &model.Account{Name: "Test Account"}