Skip to content

feat: add "dormant" user state #8644

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

Merged
merged 80 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
30b71d0
WIP
mtojek Jul 21, 2023
0091738
generated
mtojek Jul 21, 2023
6771255
make gen
mtojek Jul 21, 2023
57547ae
Dormant API
mtojek Jul 21, 2023
f699e6f
WIP
mtojek Jul 21, 2023
3376a0f
make gen
mtojek Jul 21, 2023
4fbc5d9
userauth
mtojek Jul 21, 2023
67c4e96
fix: lint
mtojek Jul 21, 2023
daa025f
UsersFilter.tsx
mtojek Jul 21, 2023
b86f636
Site UI changes
mtojek Jul 21, 2023
05cd577
make fmt
mtojek Jul 21, 2023
7d4ad5c
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 24, 2023
738441b
CLI changes
mtojek Jul 24, 2023
3ff2962
CLI fix
mtojek Jul 25, 2023
08b9cbb
UI fixes
mtojek Jul 25, 2023
a3b3f65
FIXME pubsub
mtojek Jul 25, 2023
e63f7a8
Add learn more link2
mtojek Jul 25, 2023
d6d9dac
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 25, 2023
1454cb0
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 25, 2023
b7a870e
Fix: migrations
mtojek Jul 25, 2023
d90ea27
dump.sql
mtojek Jul 26, 2023
83b8f63
FIXME
mtojek Jul 26, 2023
1553871
CLI tests
mtojek Jul 26, 2023
6a959d6
oss
mtojek Jul 26, 2023
f7d3061
next fixes
mtojek Jul 26, 2023
4a530ae
Unit test: dormant to active after login
mtojek Jul 26, 2023
c359d9f
More tests
mtojek Jul 26, 2023
5b4e76f
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 26, 2023
972c807
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 27, 2023
a771d35
More tests fixed
mtojek Jul 27, 2023
5694c08
Fix migrations
mtojek Jul 27, 2023
157b6bf
Fix: OIDC callback
mtojek Jul 27, 2023
41ac4d5
Fix: refresh account status
mtojek Jul 27, 2023
bd87560
Another fix
mtojek Jul 27, 2023
9b7c40e
More fixes
mtojek Jul 27, 2023
09b7a18
docs
mtojek Jul 27, 2023
ac43fcf
make gen
mtojek Jul 27, 2023
7b02cee
Fix: dbgen
mtojek Jul 27, 2023
c3dc08d
More fixes
mtojek Jul 27, 2023
4997479
Fix: entitlements tests
mtojek Jul 27, 2023
8f1ef7b
Fix
mtojek Jul 27, 2023
ec6e294
Users Table
mtojek Jul 27, 2023
d04c6f2
TS tests
mtojek Jul 27, 2023
4f2cdc3
Docs
mtojek Jul 27, 2023
87645cb
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 28, 2023
63eadcb
Fix: apikey
mtojek Jul 28, 2023
699ff5a
lint
mtojek Jul 28, 2023
e0b33b3
fix?
mtojek Jul 28, 2023
db9769f
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Jul 31, 2023
0eb910a
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Aug 1, 2023
eb1aaa0
fix
mtojek Aug 1, 2023
6fcec6c
Rip: update user status to dormant
mtojek Aug 1, 2023
2b20a26
More trimming
mtojek Aug 1, 2023
adaecab
More trimming
mtojek Aug 1, 2023
e0a6b2f
User story
mtojek Aug 1, 2023
8765449
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Aug 1, 2023
74c70a1
make update-golden-files
mtojek Aug 1, 2023
b010271
cleanup
mtojek Aug 1, 2023
8add519
bring back coder.env
mtojek Aug 1, 2023
37f9e8f
fix: migration down: update dormant users to active
mtojek Aug 1, 2023
d9da865
fix
mtojek Aug 1, 2023
2749c91
Fix: migration
mtojek Aug 1, 2023
cdbc50e
Implement job
mtojek Aug 1, 2023
916d807
fix
mtojek Aug 1, 2023
32723cf
WIP
mtojek Aug 2, 2023
f9ae3c9
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Aug 2, 2023
e145b74
Write unit test for job
mtojek Aug 2, 2023
187e866
Fix
mtojek Aug 2, 2023
82b791a
info
mtojek Aug 2, 2023
4545cb6
Address PR feedback
mtojek Aug 2, 2023
85d6fae
t.Helper
mtojek Aug 2, 2023
d71ba7f
Address PR comments
mtojek Aug 2, 2023
f7ab39d
Fix: populate UpdatedAt
mtojek Aug 2, 2023
76d24c7
Update interval
mtojek Aug 2, 2023
f6890db
or dormant
mtojek Aug 2, 2023
811c637
Merge branch 'main' into 8128-new-user-state-dormant
mtojek Aug 2, 2023
d34e06c
update docs
mtojek Aug 2, 2023
67f3b17
docs fix
mtojek Aug 2, 2023
67c5500
fix
mtojek Aug 2, 2023
11143ca
docs rephrase
mtojek Aug 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import (
"github.com/coder/coder/coderd/database/migrations"
"github.com/coder/coder/coderd/database/pubsub"
"github.com/coder/coder/coderd/devtunnel"
"github.com/coder/coder/coderd/dormancy"
"github.com/coder/coder/coderd/gitauth"
"github.com/coder/coder/coderd/gitsshkey"
"github.com/coder/coder/coderd/httpapi"
Expand Down Expand Up @@ -812,6 +813,9 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
options.SwaggerEndpoint = cfg.Swagger.Enable.Value()
}

closeCheckInactiveUsersFunc := dormancy.CheckInactiveUsers(ctx, logger, options.Database)
defer closeCheckInactiveUsersFunc()

// We use a separate coderAPICloser so the Enterprise API
// can have it's own close functions. This is cleaner
// than abstracting the Coder API itself.
Expand Down
16 changes: 0 additions & 16 deletions cli/testdata/coder_scaletest_--help.golden

This file was deleted.

19 changes: 0 additions & 19 deletions cli/testdata/coder_scaletest_cleanup_--help.golden

This file was deleted.

114 changes: 0 additions & 114 deletions cli/testdata/coder_scaletest_create-workspaces_--help.golden

This file was deleted.

62 changes: 0 additions & 62 deletions cli/testdata/coder_scaletest_workspace-traffic_--help.golden

This file was deleted.

2 changes: 1 addition & 1 deletion cli/testdata/coder_users_list_--output_json.golden
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"email": "testuser2@coder.com",
"created_at": "[timestamp]",
"last_seen_at": "[timestamp]",
"status": "active",
"status": "dormant",
"organization_ids": [
"[first org ID]"
],
Expand Down
18 changes: 11 additions & 7 deletions cli/userstatus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import (

func TestUserStatus(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
admin := coderdtest.CreateFirstUser(t, client)
other, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
otherUser, err := other.User(context.Background(), codersdk.Me)
require.NoError(t, err, "fetch user")

t.Run("StatusSelf", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)

inv, root := clitest.New(t, "users", "suspend", "me")
clitest.SetupConfig(t, client, root)
// Yes to the prompt
Expand All @@ -34,13 +33,18 @@ func TestUserStatus(t *testing.T) {

t.Run("StatusOther", func(t *testing.T) {
t.Parallel()
require.Equal(t, codersdk.UserStatusActive, otherUser.Status, "start as active")

client := coderdtest.New(t, nil)
admin := coderdtest.CreateFirstUser(t, client)
other, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
otherUser, err := other.User(context.Background(), codersdk.Me)
require.NoError(t, err, "fetch user")

inv, root := clitest.New(t, "users", "suspend", otherUser.Username)
clitest.SetupConfig(t, client, root)
// Yes to the prompt
inv.Stdin = bytes.NewReader([]byte("yes\n"))
err := inv.Run()
err = inv.Run()
require.NoError(t, err, "suspend user")

// Check the user status
Expand Down
2 changes: 2 additions & 0 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions coderd/coderdtest/coderdtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,14 @@ func createAnotherUserRetry(t *testing.T, client *codersdk.Client, organizationI
sessionToken = token.Key
}

if user.Status == codersdk.UserStatusDormant {
// Use admin client so that user's LastSeenAt is not updated.
// In general we need to refresh the user status, which should
// transition from "dormant" to "active".
user, err = client.User(context.Background(), user.Username)
require.NoError(t, err)
}

other := codersdk.New(client.URL)
other.SetSessionToken(sessionToken)
t.Cleanup(func() {
Expand Down
7 changes: 7 additions & 0 deletions coderd/database/dbauthz/dbauthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -2099,6 +2099,13 @@ func (q *querier) UpdateGroupByID(ctx context.Context, arg database.UpdateGroupB
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateGroupByID)(ctx, arg)
}

func (q *querier) UpdateInactiveUsersToDormant(ctx context.Context, lastSeenAfter database.UpdateInactiveUsersToDormantParams) ([]database.UpdateInactiveUsersToDormantRow, error) {
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
return nil, err
}
return q.db.UpdateInactiveUsersToDormant(ctx, lastSeenAfter)
}

func (q *querier) UpdateMemberRoles(ctx context.Context, arg database.UpdateMemberRolesParams) (database.OrganizationMember, error) {
// Authorized fetch will check that the actor has read access to the org member since the org member is returned.
member, err := q.GetOrganizationMemberByUserID(ctx, database.GetOrganizationMemberByUserIDParams{
Expand Down
25 changes: 24 additions & 1 deletion coderd/database/dbfake/dbfake.go
Original file line number Diff line number Diff line change
Expand Up @@ -3862,7 +3862,7 @@ func (q *FakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParam
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
Username: arg.Username,
Status: database.UserStatusActive,
Status: database.UserStatusDormant,
RBACRoles: arg.RBACRoles,
LoginType: arg.LoginType,
}
Expand Down Expand Up @@ -4337,6 +4337,29 @@ func (q *FakeQuerier) UpdateGroupByID(_ context.Context, arg database.UpdateGrou
return database.Group{}, sql.ErrNoRows
}

func (q *FakeQuerier) UpdateInactiveUsersToDormant(_ context.Context, params database.UpdateInactiveUsersToDormantParams) ([]database.UpdateInactiveUsersToDormantRow, error) {
q.mutex.Lock()
defer q.mutex.Unlock()

var updated []database.UpdateInactiveUsersToDormantRow
for index, user := range q.users {
if user.Status == database.UserStatusActive && user.LastSeenAt.Before(params.LastSeenAfter) {
q.users[index].Status = database.UserStatusDormant
q.users[index].UpdatedAt = params.UpdatedAt
updated = append(updated, database.UpdateInactiveUsersToDormantRow{
ID: user.ID,
Email: user.Email,
LastSeenAt: user.LastSeenAt,
})
}
}

if len(updated) == 0 {
return nil, sql.ErrNoRows
}
return updated, nil
}

func (q *FakeQuerier) UpdateMemberRoles(_ context.Context, arg database.UpdateMemberRolesParams) (database.OrganizationMember, error) {
if err := validateDatabaseType(arg); err != nil {
return database.OrganizationMember{}, err
Expand Down
7 changes: 7 additions & 0 deletions coderd/database/dbgen/dbgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ func User(t testing.TB, db database.Store, orig database.User) database.User {
})
require.NoError(t, err, "insert user")

user, err = db.UpdateUserStatus(genCtx, database.UpdateUserStatusParams{
ID: user.ID,
Status: database.UserStatusActive,
UpdatedAt: database.Now(),
})
require.NoError(t, err, "insert user")

if !orig.LastSeenAt.IsZero() {
user, err = db.UpdateUserLastSeenAt(genCtx, database.UpdateUserLastSeenAtParams{
ID: user.ID,
Expand Down
Loading