mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
Audit date filter/kira pilot (#4845)
* sql query * added time_to * added validation error * documentation * attempt to add test * removed whiitespace * fix: ensure date_from and date_to are applied correct audit logs * added more tests * ran make gen * PR feedback Co-authored-by: Dean Sheather <dean@deansheather.com>
This commit is contained in:
@ -50,6 +50,8 @@ func (api *API) auditLogs(rw http.ResponseWriter, r *http.Request) {
|
||||
Action: filter.Action,
|
||||
Username: filter.Username,
|
||||
Email: filter.Email,
|
||||
DateFrom: filter.DateFrom,
|
||||
DateTo: filter.DateTo,
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
@ -84,6 +86,8 @@ func (api *API) auditLogCount(rw http.ResponseWriter, r *http.Request) {
|
||||
Action: filter.Action,
|
||||
Username: filter.Username,
|
||||
Email: filter.Email,
|
||||
DateFrom: filter.DateFrom,
|
||||
DateTo: filter.DateTo,
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
@ -142,10 +146,13 @@ func (api *API) generateFakeAuditLog(rw http.ResponseWriter, r *http.Request) {
|
||||
if params.ResourceID == uuid.Nil {
|
||||
params.ResourceID = uuid.New()
|
||||
}
|
||||
if params.Time.IsZero() {
|
||||
params.Time = time.Now()
|
||||
}
|
||||
|
||||
_, err = api.Database.InsertAuditLog(ctx, database.InsertAuditLogParams{
|
||||
ID: uuid.New(),
|
||||
Time: time.Now(),
|
||||
Time: params.Time,
|
||||
UserID: user.ID,
|
||||
Ip: ipNet,
|
||||
UserAgent: r.UserAgent(),
|
||||
@ -273,12 +280,33 @@ func auditSearchQuery(query string) (database.GetAuditLogsOffsetParams, []coders
|
||||
// Using the query param parser here just returns consistent errors with
|
||||
// other parsing.
|
||||
parser := httpapi.NewQueryParamParser()
|
||||
const layout = "2006-01-02"
|
||||
|
||||
var (
|
||||
dateFromString = parser.String(searchParams, "", "date_from")
|
||||
dateToString = parser.String(searchParams, "", "date_to")
|
||||
parsedDateFrom, _ = time.Parse(layout, dateFromString)
|
||||
parsedDateTo, _ = time.Parse(layout, dateToString)
|
||||
)
|
||||
|
||||
if dateToString != "" {
|
||||
parsedDateTo = parsedDateTo.Add(23*time.Hour + 59*time.Minute + 59*time.Second) // parsedDateTo goes to 23:59
|
||||
}
|
||||
|
||||
if dateToString != "" && parsedDateTo.Before(parsedDateFrom) {
|
||||
return database.GetAuditLogsOffsetParams{}, []codersdk.ValidationError{
|
||||
{Field: "q", Detail: fmt.Sprintf("DateTo value %q cannot be before than DateFrom", parsedDateTo)},
|
||||
}
|
||||
}
|
||||
|
||||
filter := database.GetAuditLogsOffsetParams{
|
||||
ResourceType: resourceTypeFromString(parser.String(searchParams, "", "resource_type")),
|
||||
ResourceID: parser.UUID(searchParams, uuid.Nil, "resource_id"),
|
||||
Action: actionFromString(parser.String(searchParams, "", "action")),
|
||||
Username: parser.String(searchParams, "", "username"),
|
||||
Email: parser.String(searchParams, "", "email"),
|
||||
DateFrom: parsedDateFrom,
|
||||
DateTo: parsedDateTo,
|
||||
}
|
||||
|
||||
return filter, parser.Errors
|
||||
|
@ -3,6 +3,7 @@ package coderd_test
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -54,12 +55,14 @@ func TestAuditLogsFilter(t *testing.T) {
|
||||
err := client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
|
||||
Action: codersdk.AuditActionCreate,
|
||||
ResourceType: codersdk.ResourceTypeTemplate,
|
||||
Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
|
||||
Action: codersdk.AuditActionCreate,
|
||||
ResourceType: codersdk.ResourceTypeUser,
|
||||
ResourceID: userResourceID,
|
||||
Time: time.Date(2022, 8, 16, 14, 30, 45, 100, time.UTC), // 2022-8-16 14:30:45
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -68,6 +71,7 @@ func TestAuditLogsFilter(t *testing.T) {
|
||||
Action: codersdk.AuditActionDelete,
|
||||
ResourceType: codersdk.ResourceTypeUser,
|
||||
ResourceID: userResourceID,
|
||||
Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -127,6 +131,21 @@ func TestAuditLogsFilter(t *testing.T) {
|
||||
SearchQuery: "action:invalid",
|
||||
ExpectedResult: 3,
|
||||
},
|
||||
{
|
||||
Name: "FilterOnCreateSingleDay",
|
||||
SearchQuery: "action:create date_from:2022-08-15 date_to:2022-08-15",
|
||||
ExpectedResult: 1,
|
||||
},
|
||||
{
|
||||
Name: "FilterOnCreateDateFrom",
|
||||
SearchQuery: "action:create date_from:2022-08-15",
|
||||
ExpectedResult: 2,
|
||||
},
|
||||
{
|
||||
Name: "FilterOnCreateDateTo",
|
||||
SearchQuery: "action:create date_to:2022-08-15",
|
||||
ExpectedResult: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
@ -2995,6 +2995,16 @@ func (q *fakeQuerier) GetAuditLogsOffset(ctx context.Context, arg database.GetAu
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !arg.DateFrom.IsZero() {
|
||||
if alog.Time.Before(arg.DateFrom) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !arg.DateTo.IsZero() {
|
||||
if alog.Time.After(arg.DateTo) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
user, err := q.GetUserByID(ctx, alog.UserID)
|
||||
userValid := err == nil
|
||||
@ -3057,6 +3067,16 @@ func (q *fakeQuerier) GetAuditLogCount(_ context.Context, arg database.GetAuditL
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !arg.DateFrom.IsZero() {
|
||||
if alog.Time.Before(arg.DateFrom) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !arg.DateTo.IsZero() {
|
||||
if alog.Time.After(arg.DateTo) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
logs = append(logs, alog)
|
||||
}
|
||||
|
@ -405,6 +405,18 @@ WHERE
|
||||
user_id = (SELECT id from users WHERE users.email = $6 )
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_from
|
||||
AND CASE
|
||||
WHEN $7 :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" >= $7
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_to
|
||||
AND CASE
|
||||
WHEN $8 :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" <= $8
|
||||
ELSE true
|
||||
END
|
||||
`
|
||||
|
||||
type GetAuditLogCountParams struct {
|
||||
@ -414,6 +426,8 @@ type GetAuditLogCountParams struct {
|
||||
Action string `db:"action" json:"action"`
|
||||
Username string `db:"username" json:"username"`
|
||||
Email string `db:"email" json:"email"`
|
||||
DateFrom time.Time `db:"date_from" json:"date_from"`
|
||||
DateTo time.Time `db:"date_to" json:"date_to"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetAuditLogCount(ctx context.Context, arg GetAuditLogCountParams) (int64, error) {
|
||||
@ -424,6 +438,8 @@ func (q *sqlQuerier) GetAuditLogCount(ctx context.Context, arg GetAuditLogCountP
|
||||
arg.Action,
|
||||
arg.Username,
|
||||
arg.Email,
|
||||
arg.DateFrom,
|
||||
arg.DateTo,
|
||||
)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
@ -480,6 +496,18 @@ WHERE
|
||||
users.email = $8
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_from
|
||||
AND CASE
|
||||
WHEN $9 :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" >= $9
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_to
|
||||
AND CASE
|
||||
WHEN $10 :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" <= $10
|
||||
ELSE true
|
||||
END
|
||||
ORDER BY
|
||||
"time" DESC
|
||||
LIMIT
|
||||
@ -497,6 +525,8 @@ type GetAuditLogsOffsetParams struct {
|
||||
Action string `db:"action" json:"action"`
|
||||
Username string `db:"username" json:"username"`
|
||||
Email string `db:"email" json:"email"`
|
||||
DateFrom time.Time `db:"date_from" json:"date_from"`
|
||||
DateTo time.Time `db:"date_to" json:"date_to"`
|
||||
}
|
||||
|
||||
type GetAuditLogsOffsetRow struct {
|
||||
@ -535,6 +565,8 @@ func (q *sqlQuerier) GetAuditLogsOffset(ctx context.Context, arg GetAuditLogsOff
|
||||
arg.Action,
|
||||
arg.Username,
|
||||
arg.Email,
|
||||
arg.DateFrom,
|
||||
arg.DateTo,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -50,6 +50,18 @@ WHERE
|
||||
users.email = @email
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_from
|
||||
AND CASE
|
||||
WHEN @date_from :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" >= @date_from
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_to
|
||||
AND CASE
|
||||
WHEN @date_to :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" <= @date_to
|
||||
ELSE true
|
||||
END
|
||||
ORDER BY
|
||||
"time" DESC
|
||||
LIMIT
|
||||
@ -98,6 +110,18 @@ WHERE
|
||||
WHEN @email :: text != '' THEN
|
||||
user_id = (SELECT id from users WHERE users.email = @email )
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_from
|
||||
AND CASE
|
||||
WHEN @date_from :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" >= @date_from
|
||||
ELSE true
|
||||
END
|
||||
-- Filter by date_to
|
||||
AND CASE
|
||||
WHEN @date_to :: timestamp with time zone != '0001-01-01 00:00:00' THEN
|
||||
"time" <= @date_to
|
||||
ELSE true
|
||||
END;
|
||||
|
||||
-- name: InsertAuditLog :one
|
||||
|
Reference in New Issue
Block a user