Added activities module

This commit is contained in:
2026-04-11 11:51:18 +03:00
parent 8e074db55f
commit 2dc8ff01b7
13 changed files with 694 additions and 4 deletions
+60
View File
@@ -0,0 +1,60 @@
package routers
import (
"FamilyHub/src/api/dto"
"FamilyHub/src/api/services"
"FamilyHub/src/domain"
"net/http"
"github.com/gin-gonic/gin"
)
type ActivitiesRouter struct {
service services.ActivityService
}
func NewActivitiesRouter(s services.ActivityService) *ActivitiesRouter {
return &ActivitiesRouter{service: s}
}
func (router *ActivitiesRouter) RegisterRoutes(r *gin.RouterGroup) {
activities := r.Group("/activities")
{
activities.GET("", router.List)
}
}
// List GoDoc
// @Summary Получить активность пользователей
// @Description Возвращает список действий пользователей с пагинацией
// @Tags Activities
// @Accept json
// @Produce json
// @Param family_id query int false "Family ID"
// @Param user_id query int false "User ID"
// @Param limit query int false "Limit, default 10"
// @Param offset query int false "Offset"
// @Success 200 {object} dto.ActivityListResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /activities [get]
func (router *ActivitiesRouter) List(c *gin.Context) {
var query dto.ActivityListQuery
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()})
return
}
activities, filter, err := router.service.List(c.Request.Context(), domain.ActivityLogListFilter{
FamilyID: query.FamilyID,
UserID: query.UserID,
Limit: query.Limit,
Offset: query.Offset,
})
if err != nil {
c.JSON(http.StatusInternalServerError, dto.ErrorResponse{Message: "internal server error"})
return
}
c.JSON(http.StatusOK, dto.ActivitiesToListResponse(activities, filter.Limit, filter.Offset))
}
@@ -0,0 +1,65 @@
package routers
import (
"FamilyHub/src/api/services"
"FamilyHub/src/domain"
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type activityServiceMock struct {
listFn func(ctx context.Context, filter domain.ActivityLogListFilter) ([]*domain.ActivityLog, domain.ActivityLogListFilter, error)
}
func (m *activityServiceMock) List(ctx context.Context, filter domain.ActivityLogListFilter) ([]*domain.ActivityLog, domain.ActivityLogListFilter, error) {
if m.listFn != nil {
return m.listFn(ctx, filter)
}
return nil, filter, errors.New("mock list is not configured")
}
func setupActivitiesRouter(mock services.ActivityService) *gin.Engine {
gin.SetMode(gin.TestMode)
r := gin.New()
apiV1 := r.Group("/api/v1")
router := NewActivitiesRouter(mock)
router.RegisterRoutes(apiV1)
return r
}
func TestActivitiesRouter_List(t *testing.T) {
t.Run("uses default pagination", func(t *testing.T) {
r := setupActivitiesRouter(&activityServiceMock{listFn: func(ctx context.Context, filter domain.ActivityLogListFilter) ([]*domain.ActivityLog, domain.ActivityLogListFilter, error) {
assert.Equal(t, 0, filter.Limit)
assert.Equal(t, 0, filter.Offset)
activity := &domain.ActivityLog{
ID: 1,
UserID: 2,
Action: "create",
EntityType: "transaction",
Description: "Created transaction 1",
CreatedAt: time.Date(2026, time.April, 11, 12, 0, 0, 0, time.UTC),
}
filter.Limit = 10
return []*domain.ActivityLog{activity}, filter, nil
}})
req := httptest.NewRequest(http.MethodGet, "/api/v1/activities", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "\"limit\":10")
assert.Contains(t, w.Body.String(), "Created transaction 1")
})
}