Skip to content

Commit a89dee9

Browse files
committed
Write tests
1 parent 841a99c commit a89dee9

File tree

5 files changed

+65
-4
lines changed

5 files changed

+65
-4
lines changed

coderd/database/databasefake/databasefake.go

+16
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,22 @@ func (q *fakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUse
19561956
return database.User{}, sql.ErrNoRows
19571957
}
19581958

1959+
func (q *fakeQuerier) UpdateUserLastSeenAt(_ context.Context, arg database.UpdateUserLastSeenAtParams) (database.User, error) {
1960+
q.mutex.Lock()
1961+
defer q.mutex.Unlock()
1962+
1963+
for index, user := range q.users {
1964+
if user.ID != arg.ID {
1965+
continue
1966+
}
1967+
user.LastSeenAt = arg.LastSeenAt
1968+
user.UpdatedAt = arg.UpdatedAt
1969+
q.users[index] = user
1970+
return user, nil
1971+
}
1972+
return database.User{}, sql.ErrNoRows
1973+
}
1974+
19591975
func (q *fakeQuerier) UpdateUserHashedPassword(_ context.Context, arg database.UpdateUserHashedPasswordParams) error {
19601976
q.mutex.Lock()
19611977
defer q.mutex.Unlock()

coderd/httpmw/apikey.go

+13
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,19 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
317317
return
318318
}
319319
}
320+
321+
_, err = cfg.DB.UpdateUserLastSeenAt(ctx, database.UpdateUserLastSeenAtParams{
322+
ID: key.UserID,
323+
LastSeenAt: database.Now(),
324+
UpdatedAt: database.Now(),
325+
})
326+
if err != nil {
327+
write(http.StatusInternalServerError, codersdk.Response{
328+
Message: internalErrorMessage,
329+
Detail: fmt.Sprintf("update user last_seen_at: %s", err.Error()),
330+
})
331+
return
332+
}
320333
}
321334

322335
// If the key is valid, we also fetch the user roles and status.

coderd/users.go

+1
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,7 @@ func convertUser(user database.User, organizationIDs []uuid.UUID) codersdk.User
12101210
ID: user.ID,
12111211
Email: user.Email,
12121212
CreatedAt: user.CreatedAt,
1213+
LastSeenAt: user.LastSeenAt,
12131214
Username: user.Username,
12141215
Status: codersdk.UserStatus(user.Status),
12151216
OrganizationIDs: organizationIDs,

coderd/users_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,35 @@ func TestFirstUser(t *testing.T) {
6565
_ = coderdtest.CreateFirstUser(t, client)
6666
})
6767

68+
t.Run("LastSeenAt", func(t *testing.T) {
69+
t.Parallel()
70+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
71+
defer cancel()
72+
73+
client := coderdtest.New(t, nil)
74+
firstUserResp := coderdtest.CreateFirstUser(t, client)
75+
76+
firstUser, err := client.User(ctx, firstUserResp.UserID.String())
77+
require.NoError(t, err)
78+
79+
_ = coderdtest.CreateAnotherUser(t, client, firstUserResp.OrganizationID)
80+
81+
allUsers, err := client.Users(ctx, codersdk.UsersRequest{})
82+
require.NoError(t, err)
83+
84+
require.Len(t, allUsers, 2)
85+
86+
// We sent the "GET Users" request with the first user, but the second user
87+
// should be Never since they haven't performed a request.
88+
for _, user := range allUsers {
89+
if user.ID == firstUser.ID {
90+
require.WithinDuration(t, firstUser.LastSeenAt, database.Now(), testutil.WaitShort)
91+
} else {
92+
require.Zero(t, user.LastSeenAt)
93+
}
94+
}
95+
})
96+
6897
t.Run("AutoImportsTemplates", func(t *testing.T) {
6998
t.Parallel()
7099

codersdk/users.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ type UsersRequest struct {
4343

4444
// User represents a user in Coder.
4545
type User struct {
46-
ID uuid.UUID `json:"id" validate:"required" table:"id"`
47-
Username string `json:"username" validate:"required" table:"username"`
48-
Email string `json:"email" validate:"required" table:"email"`
49-
CreatedAt time.Time `json:"created_at" validate:"required" table:"created at"`
46+
ID uuid.UUID `json:"id" validate:"required" table:"id"`
47+
Username string `json:"username" validate:"required" table:"username"`
48+
Email string `json:"email" validate:"required" table:"email"`
49+
CreatedAt time.Time `json:"created_at" validate:"required" table:"created at"`
50+
LastSeenAt time.Time `json:"last_seen_at"`
51+
5052
Status UserStatus `json:"status" table:"status"`
5153
OrganizationIDs []uuid.UUID `json:"organization_ids"`
5254
Roles []Role `json:"roles"`

0 commit comments

Comments
 (0)