Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit266af06

Browse files
committed
add API endpoints and test (currently fails)
1 parent804f4a1 commit266af06

File tree

8 files changed

+359
-0
lines changed

8 files changed

+359
-0
lines changed

‎coderd/apidoc/docs.go

Lines changed: 62 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/audit/diff.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Auditable interface {
1313
database.TemplateVersion|
1414
database.User|
1515
database.Workspace|
16+
database.UserPinnedWorkspace|
1617
database.GitSSHKey|
1718
database.WorkspaceBuild|
1819
database.AuditableGroup|

‎coderd/coderd.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,8 @@ func New(options *Options) *API {
950950
r.Get("/watch",api.watchWorkspace)
951951
r.Put("/extend",api.putExtendWorkspace)
952952
r.Put("/dormant",api.putWorkspaceDormant)
953+
r.Put("/pin",api.putWorkspacePin)
954+
r.Delete("/pin",api.deleteWorkspacePin)
953955
r.Put("/autoupdates",api.putWorkspaceAutoupdates)
954956
r.Get("/resolve-autostart",api.resolveAutostart)
955957
})

‎coderd/workspaces.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,93 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
10211021
httpapi.Write(ctx,rw,code,resp)
10221022
}
10231023

1024+
// @Summary Pin workspace by ID.
1025+
// @ID pin-workspace-by-id
1026+
// @Security CoderSessionToken
1027+
// @Accept json
1028+
// @Tags Workspaces
1029+
// @Param workspace path string true "Workspace ID" format(uuid)
1030+
// @Success 204
1031+
// @Router /workspaces/{workspace}/pin [put]
1032+
func (api*API)putWorkspacePin(rw http.ResponseWriter,r*http.Request) {
1033+
var (
1034+
ctx=r.Context()
1035+
apiKey=httpmw.APIKey(r)
1036+
workspace=httpmw.WorkspaceParam(r)
1037+
auditor=api.Auditor.Load()
1038+
aReq,commitAudit=audit.InitRequest[database.UserPinnedWorkspace](rw,&audit.RequestParams{
1039+
Audit:*auditor,
1040+
Log:api.Logger,
1041+
Request:r,
1042+
Action:database.AuditActionCreate,
1043+
})
1044+
)
1045+
defercommitAudit()
1046+
aReq.Old= database.UserPinnedWorkspace{}
1047+
1048+
err:=api.Database.PinWorkspace(ctx, database.PinWorkspaceParams{
1049+
UserID:apiKey.UserID,
1050+
WorkspaceID:workspace.ID,
1051+
})
1052+
iferr!=nil {
1053+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
1054+
Message:"Internal error pinning workspace",
1055+
Detail:err.Error(),
1056+
})
1057+
return
1058+
}
1059+
1060+
aReq.New= database.UserPinnedWorkspace{
1061+
UserID:apiKey.UserID,
1062+
WorkspaceID:workspace.ID,
1063+
}
1064+
1065+
rw.WriteHeader(http.StatusNoContent)
1066+
}
1067+
1068+
// @Summary Unpin workspace by ID.
1069+
// @ID unpin-workspace-by-id
1070+
// @Security CoderSessionToken
1071+
// @Accept json
1072+
// @Tags Workspaces
1073+
// @Param workspace path string true "Workspace ID" format(uuid)
1074+
// @Success 204
1075+
// @Router /workspaces/{workspace}/pin [delete]
1076+
func (api*API)deleteWorkspacePin(rw http.ResponseWriter,r*http.Request) {
1077+
var (
1078+
ctx=r.Context()
1079+
apiKey=httpmw.APIKey(r)
1080+
workspace=httpmw.WorkspaceParam(r)
1081+
auditor=api.Auditor.Load()
1082+
aReq,commitAudit=audit.InitRequest[database.UserPinnedWorkspace](rw,&audit.RequestParams{
1083+
Audit:*auditor,
1084+
Log:api.Logger,
1085+
Request:r,
1086+
Action:database.AuditActionCreate,
1087+
})
1088+
)
1089+
defercommitAudit()
1090+
aReq.Old= database.UserPinnedWorkspace{
1091+
UserID:apiKey.UserID,
1092+
WorkspaceID:workspace.ID,
1093+
}
1094+
1095+
err:=api.Database.UnpinWorkspace(ctx, database.UnpinWorkspaceParams{
1096+
UserID:apiKey.UserID,
1097+
WorkspaceID:workspace.ID,
1098+
})
1099+
iferr!=nil {
1100+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
1101+
Message:"Internal error unpinning workspace",
1102+
Detail:err.Error(),
1103+
})
1104+
return
1105+
}
1106+
aReq.New= database.UserPinnedWorkspace{}
1107+
1108+
rw.WriteHeader(http.StatusNoContent)
1109+
}
1110+
10241111
// @Summary Update workspace automatic updates by ID
10251112
// @ID update-workspace-automatic-updates-by-id
10261113
// @Security CoderSessionToken
@@ -1472,6 +1559,7 @@ func convertWorkspace(
14721559
},
14731560
AutomaticUpdates:codersdk.AutomaticUpdates(workspace.AutomaticUpdates),
14741561
AllowRenames:allowRenames,
1562+
// Pinned: pinned, // TODO
14751563
}
14761564
}
14771565

‎coderd/workspaces_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2927,4 +2927,79 @@ func TestWorkspaceDormant(t *testing.T) {
29272927
require.NoError(t,err)
29282928
coderdtest.MustTransitionWorkspace(t,client,workspace.ID,database.WorkspaceTransitionStop,database.WorkspaceTransitionStart)
29292929
})
2930+
2931+
t.Run("PinUnpin",func(t*testing.T) {
2932+
t.Parallel()
2933+
// Given:
2934+
var (
2935+
auditRecorder=audit.NewMock()
2936+
client=coderdtest.New(t,&coderdtest.Options{
2937+
IncludeProvisionerDaemon:true,
2938+
Auditor:auditRecorder,
2939+
})
2940+
owner=coderdtest.CreateFirstUser(t,client)
2941+
version=coderdtest.CreateTemplateVersion(t,client,owner.OrganizationID,nil)
2942+
_=coderdtest.AwaitTemplateVersionJobCompleted(t,client,version.ID)
2943+
template=coderdtest.CreateTemplate(t,client,owner.OrganizationID,version.ID)
2944+
memberClient,_=coderdtest.CreateAnotherUser(t,client,owner.OrganizationID)
2945+
workspace=coderdtest.CreateWorkspace(t,memberClient,owner.OrganizationID,template.ID)
2946+
_=coderdtest.AwaitWorkspaceBuildJobCompleted(t,client,workspace.LatestBuild.ID)
2947+
)
2948+
2949+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
2950+
defercancel()
2951+
2952+
// Initially, workspace should not be pinned.
2953+
workspaces,err:=memberClient.Workspaces(ctx, codersdk.WorkspaceFilter{})
2954+
require.NoError(t,err)
2955+
require.Len(t,workspaces.Workspaces,1)
2956+
require.False(t,workspaces.Workspaces[0].Pinned)
2957+
ws,err:=memberClient.Workspace(ctx,workspace.ID)
2958+
require.NoError(t,err)
2959+
require.False(t,ws.Pinned)
2960+
2961+
// When member pins workspace
2962+
err=memberClient.PinWorkspace(ctx,workspace.ID)
2963+
require.NoError(t,err)
2964+
2965+
// Then it should be pinned for them
2966+
workspaces,err=memberClient.Workspaces(ctx, codersdk.WorkspaceFilter{})
2967+
require.NoError(t,err)
2968+
require.Len(t,workspaces.Workspaces,1)
2969+
require.True(t,workspaces.Workspaces[0].Pinned)
2970+
ws,err=memberClient.Workspace(ctx,workspace.ID)
2971+
require.NoError(t,err)
2972+
require.True(t,ws.Pinned)
2973+
2974+
// But not for someone else
2975+
workspaces,err=client.Workspaces(ctx, codersdk.WorkspaceFilter{})
2976+
require.NoError(t,err)
2977+
require.Len(t,workspaces.Workspaces,1)
2978+
require.False(t,workspaces.Workspaces[0].Pinned)
2979+
ws,err=client.Workspace(ctx,workspace.ID)
2980+
require.NoError(t,err)
2981+
require.False(t,ws.Pinned)
2982+
2983+
// When member unpins workspace
2984+
err=memberClient.UnpinWorkspace(ctx,workspace.ID)
2985+
require.NoError(t,err)
2986+
2987+
// Then it should no longer be pinned for them
2988+
workspaces,err=memberClient.Workspaces(ctx, codersdk.WorkspaceFilter{})
2989+
require.NoError(t,err)
2990+
require.Len(t,workspaces.Workspaces,1)
2991+
require.False(t,workspaces.Workspaces[0].Pinned)
2992+
ws,err=memberClient.Workspace(ctx,workspace.ID)
2993+
require.NoError(t,err)
2994+
require.False(t,ws.Pinned)
2995+
2996+
// Assert invariant: workspace should remain unpinned for a different user
2997+
workspaces,err=client.Workspaces(ctx, codersdk.WorkspaceFilter{})
2998+
require.NoError(t,err)
2999+
require.Len(t,workspaces.Workspaces,1)
3000+
require.False(t,workspaces.Workspaces[0].Pinned)
3001+
ws,err=client.Workspace(ctx,workspace.ID)
3002+
require.NoError(t,err)
3003+
require.False(t,ws.Pinned)
3004+
})
29303005
}

‎codersdk/workspaces.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type Workspace struct {
5858
HealthWorkspaceHealth`json:"health"`
5959
AutomaticUpdatesAutomaticUpdates`json:"automatic_updates" enums:"always,never"`
6060
AllowRenamesbool`json:"allow_renames"`
61+
Pinnedbool`json:"pinned"`
6162
}
6263

6364
func (wWorkspace)FullName()string {
@@ -471,6 +472,30 @@ func (c *Client) ResolveAutostart(ctx context.Context, workspaceID string) (Reso
471472
returnresponse,json.NewDecoder(res.Body).Decode(&response)
472473
}
473474

475+
func (c*Client)PinWorkspace(ctx context.Context,workspaceID uuid.UUID)error {
476+
res,err:=c.Request(ctx,http.MethodPut,fmt.Sprintf("/api/v2/workspaces/%s/pin",workspaceID),nil)
477+
iferr!=nil {
478+
returnerr
479+
}
480+
deferres.Body.Close()
481+
ifres.StatusCode!=http.StatusNoContent {
482+
returnerr
483+
}
484+
returnnil
485+
}
486+
487+
func (c*Client)UnpinWorkspace(ctx context.Context,workspaceID uuid.UUID)error {
488+
res,err:=c.Request(ctx,http.MethodDelete,fmt.Sprintf("/api/v2/workspaces/%s/pin",workspaceID),nil)
489+
iferr!=nil {
490+
returnerr
491+
}
492+
deferres.Body.Close()
493+
ifres.StatusCode!=http.StatusNoContent {
494+
returnerr
495+
}
496+
returnnil
497+
}
498+
474499
// WorkspaceNotifyChannel is the PostgreSQL NOTIFY
475500
// channel to listen for updates on. The payload is empty,
476501
// because the size of a workspace payload can be very large.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp