mirror of https://github.com/coder/coder.git
bep
This commit is contained in:
parent
215dd7b152
commit
f432099664
|
@ -8280,6 +8280,9 @@ const docTemplate = `{
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/codersdk.LinkConfig"
|
"$ref": "#/definitions/codersdk.LinkConfig"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"terms_of_service": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -11896,6 +11899,9 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"service_banner": {
|
"service_banner": {
|
||||||
"$ref": "#/definitions/codersdk.ServiceBannerConfig"
|
"$ref": "#/definitions/codersdk.ServiceBannerConfig"
|
||||||
|
},
|
||||||
|
"terms_of_service": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -7349,6 +7349,9 @@
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/codersdk.LinkConfig"
|
"$ref": "#/definitions/codersdk.LinkConfig"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"terms_of_service": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -10755,6 +10758,9 @@
|
||||||
},
|
},
|
||||||
"service_banner": {
|
"service_banner": {
|
||||||
"$ref": "#/definitions/codersdk.ServiceBannerConfig"
|
"$ref": "#/definitions/codersdk.ServiceBannerConfig"
|
||||||
|
},
|
||||||
|
"terms_of_service": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1793,6 +1793,11 @@ func (q *querier) GetTemplatesWithFilter(ctx context.Context, arg database.GetTe
|
||||||
return q.db.GetAuthorizedTemplates(ctx, arg, prep)
|
return q.db.GetAuthorizedTemplates(ctx, arg, prep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *querier) GetTermsOfService(ctx context.Context) (string, error) {
|
||||||
|
// No authz checks
|
||||||
|
return q.db.GetTermsOfService(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *querier) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
|
func (q *querier) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
|
||||||
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceSystem); err != nil {
|
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceSystem); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -3438,6 +3443,13 @@ func (q *querier) UpsertTemplateUsageStats(ctx context.Context) error {
|
||||||
return q.db.UpsertTemplateUsageStats(ctx)
|
return q.db.UpsertTemplateUsageStats(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *querier) UpsertTermsOfService(ctx context.Context, value string) error {
|
||||||
|
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceDeploymentValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return q.db.UpsertTermsOfService(ctx, value)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *querier) UpsertWorkspaceAgentPortShare(ctx context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
func (q *querier) UpsertWorkspaceAgentPortShare(ctx context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
||||||
workspace, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
|
workspace, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4213,6 +4213,10 @@ func (q *FakeQuerier) GetTemplatesWithFilter(ctx context.Context, arg database.G
|
||||||
return q.GetAuthorizedTemplates(ctx, arg, nil)
|
return q.GetAuthorizedTemplates(ctx, arg, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *FakeQuerier) GetTermsOfService(ctx context.Context) (string, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (q *FakeQuerier) GetUnexpiredLicenses(_ context.Context) ([]database.License, error) {
|
func (q *FakeQuerier) GetUnexpiredLicenses(_ context.Context) ([]database.License, error) {
|
||||||
q.mutex.RLock()
|
q.mutex.RLock()
|
||||||
defer q.mutex.RUnlock()
|
defer q.mutex.RUnlock()
|
||||||
|
@ -8932,6 +8936,10 @@ TemplateUsageStatsInsertLoop:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *FakeQuerier) UpsertTermsOfService(ctx context.Context, value string) error {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (q *FakeQuerier) UpsertWorkspaceAgentPortShare(_ context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
func (q *FakeQuerier) UpsertWorkspaceAgentPortShare(_ context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
||||||
err := validateDatabaseType(arg)
|
err := validateDatabaseType(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1038,6 +1038,13 @@ func (m metricsStore) GetTemplatesWithFilter(ctx context.Context, arg database.G
|
||||||
return templates, err
|
return templates, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m metricsStore) GetTermsOfService(ctx context.Context) (string, error) {
|
||||||
|
start := time.Now()
|
||||||
|
r0, r1 := m.s.GetTermsOfService(ctx)
|
||||||
|
m.queryLatencies.WithLabelValues("GetTermsOfService").Observe(time.Since(start).Seconds())
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
func (m metricsStore) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
|
func (m metricsStore) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
licenses, err := m.s.GetUnexpiredLicenses(ctx)
|
licenses, err := m.s.GetUnexpiredLicenses(ctx)
|
||||||
|
@ -2256,6 +2263,13 @@ func (m metricsStore) UpsertTemplateUsageStats(ctx context.Context) error {
|
||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m metricsStore) UpsertTermsOfService(ctx context.Context, value string) error {
|
||||||
|
start := time.Now()
|
||||||
|
r0 := m.s.UpsertTermsOfService(ctx, value)
|
||||||
|
m.queryLatencies.WithLabelValues("UpsertTermsOfService").Observe(time.Since(start).Seconds())
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
func (m metricsStore) UpsertWorkspaceAgentPortShare(ctx context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
func (m metricsStore) UpsertWorkspaceAgentPortShare(ctx context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
r0, r1 := m.s.UpsertWorkspaceAgentPortShare(ctx, arg)
|
r0, r1 := m.s.UpsertWorkspaceAgentPortShare(ctx, arg)
|
||||||
|
|
|
@ -2145,6 +2145,21 @@ func (mr *MockStoreMockRecorder) GetTemplatesWithFilter(arg0, arg1 any) *gomock.
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplatesWithFilter", reflect.TypeOf((*MockStore)(nil).GetTemplatesWithFilter), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplatesWithFilter", reflect.TypeOf((*MockStore)(nil).GetTemplatesWithFilter), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTermsOfService mocks base method.
|
||||||
|
func (m *MockStore) GetTermsOfService(arg0 context.Context) (string, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetTermsOfService", arg0)
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTermsOfService indicates an expected call of GetTermsOfService.
|
||||||
|
func (mr *MockStoreMockRecorder) GetTermsOfService(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTermsOfService", reflect.TypeOf((*MockStore)(nil).GetTermsOfService), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// GetUnexpiredLicenses mocks base method.
|
// GetUnexpiredLicenses mocks base method.
|
||||||
func (m *MockStore) GetUnexpiredLicenses(arg0 context.Context) ([]database.License, error) {
|
func (m *MockStore) GetUnexpiredLicenses(arg0 context.Context) ([]database.License, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -4723,6 +4738,20 @@ func (mr *MockStoreMockRecorder) UpsertTemplateUsageStats(arg0 any) *gomock.Call
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertTemplateUsageStats", reflect.TypeOf((*MockStore)(nil).UpsertTemplateUsageStats), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertTemplateUsageStats", reflect.TypeOf((*MockStore)(nil).UpsertTemplateUsageStats), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpsertTermsOfService mocks base method.
|
||||||
|
func (m *MockStore) UpsertTermsOfService(arg0 context.Context, arg1 string) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "UpsertTermsOfService", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpsertTermsOfService indicates an expected call of UpsertTermsOfService.
|
||||||
|
func (mr *MockStoreMockRecorder) UpsertTermsOfService(arg0, arg1 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertTermsOfService", reflect.TypeOf((*MockStore)(nil).UpsertTermsOfService), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// UpsertWorkspaceAgentPortShare mocks base method.
|
// UpsertWorkspaceAgentPortShare mocks base method.
|
||||||
func (m *MockStore) UpsertWorkspaceAgentPortShare(arg0 context.Context, arg1 database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
func (m *MockStore) UpsertWorkspaceAgentPortShare(arg0 context.Context, arg1 database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -215,6 +215,7 @@ type sqlcQuerier interface {
|
||||||
GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error)
|
GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error)
|
||||||
GetTemplates(ctx context.Context) ([]Template, error)
|
GetTemplates(ctx context.Context) ([]Template, error)
|
||||||
GetTemplatesWithFilter(ctx context.Context, arg GetTemplatesWithFilterParams) ([]Template, error)
|
GetTemplatesWithFilter(ctx context.Context, arg GetTemplatesWithFilterParams) ([]Template, error)
|
||||||
|
GetTermsOfService(ctx context.Context) (string, error)
|
||||||
GetUnexpiredLicenses(ctx context.Context) ([]License, error)
|
GetUnexpiredLicenses(ctx context.Context) ([]License, error)
|
||||||
// GetUserActivityInsights returns the ranking with top active users.
|
// GetUserActivityInsights returns the ranking with top active users.
|
||||||
// The result can be filtered on template_ids, meaning only user data
|
// The result can be filtered on template_ids, meaning only user data
|
||||||
|
@ -435,6 +436,7 @@ type sqlcQuerier interface {
|
||||||
// used to store the data, and the minutes are summed for each user and template
|
// used to store the data, and the minutes are summed for each user and template
|
||||||
// combination. The result is stored in the template_usage_stats table.
|
// combination. The result is stored in the template_usage_stats table.
|
||||||
UpsertTemplateUsageStats(ctx context.Context) error
|
UpsertTemplateUsageStats(ctx context.Context) error
|
||||||
|
UpsertTermsOfService(ctx context.Context, value string) error
|
||||||
UpsertWorkspaceAgentPortShare(ctx context.Context, arg UpsertWorkspaceAgentPortShareParams) (WorkspaceAgentPortShare, error)
|
UpsertWorkspaceAgentPortShare(ctx context.Context, arg UpsertWorkspaceAgentPortShareParams) (WorkspaceAgentPortShare, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5637,6 +5637,17 @@ func (q *sqlQuerier) GetServiceBanner(ctx context.Context) (string, error) {
|
||||||
return value, err
|
return value, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getTermsOfService = `-- name: GetTermsOfService :one
|
||||||
|
SELECT value FROM site_configs WHERE key = 'terms_of_service'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *sqlQuerier) GetTermsOfService(ctx context.Context) (string, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getTermsOfService)
|
||||||
|
var value string
|
||||||
|
err := row.Scan(&value)
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
|
||||||
const insertDERPMeshKey = `-- name: InsertDERPMeshKey :exec
|
const insertDERPMeshKey = `-- name: InsertDERPMeshKey :exec
|
||||||
INSERT INTO site_configs (key, value) VALUES ('derp_mesh_key', $1)
|
INSERT INTO site_configs (key, value) VALUES ('derp_mesh_key', $1)
|
||||||
`
|
`
|
||||||
|
@ -5748,6 +5759,16 @@ func (q *sqlQuerier) UpsertServiceBanner(ctx context.Context, value string) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const upsertTermsOfService = `-- name: UpsertTermsOfService :exec
|
||||||
|
INSERT INTO site_configs (key, value) VALUES ('terms_of_service', $1)
|
||||||
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'terms_of_service'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *sqlQuerier) UpsertTermsOfService(ctx context.Context, value string) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, upsertTermsOfService, value)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const cleanTailnetCoordinators = `-- name: CleanTailnetCoordinators :exec
|
const cleanTailnetCoordinators = `-- name: CleanTailnetCoordinators :exec
|
||||||
DELETE
|
DELETE
|
||||||
FROM tailnet_coordinators
|
FROM tailnet_coordinators
|
||||||
|
|
|
@ -57,6 +57,13 @@ ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'application
|
||||||
-- name: GetApplicationName :one
|
-- name: GetApplicationName :one
|
||||||
SELECT value FROM site_configs WHERE key = 'application_name';
|
SELECT value FROM site_configs WHERE key = 'application_name';
|
||||||
|
|
||||||
|
-- name: UpsertTermsOfService :exec
|
||||||
|
INSERT INTO site_configs (key, value) VALUES ('terms_of_service', $1)
|
||||||
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'terms_of_service';
|
||||||
|
|
||||||
|
-- name: GetTermsOfService :one
|
||||||
|
SELECT value FROM site_configs WHERE key = 'terms_of_service';
|
||||||
|
|
||||||
-- name: GetAppSecurityKey :one
|
-- name: GetAppSecurityKey :one
|
||||||
SELECT value FROM site_configs WHERE key = 'app_signing_key';
|
SELECT value FROM site_configs WHERE key = 'app_signing_key';
|
||||||
|
|
||||||
|
|
|
@ -2078,6 +2078,7 @@ type AppearanceConfig struct {
|
||||||
ApplicationName string `json:"application_name"`
|
ApplicationName string `json:"application_name"`
|
||||||
LogoURL string `json:"logo_url"`
|
LogoURL string `json:"logo_url"`
|
||||||
ServiceBanner ServiceBannerConfig `json:"service_banner"`
|
ServiceBanner ServiceBannerConfig `json:"service_banner"`
|
||||||
|
TermsOfService string `json:"terms_of_service"`
|
||||||
SupportLinks []LinkConfig `json:"support_links,omitempty"`
|
SupportLinks []LinkConfig `json:"support_links,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2085,6 +2086,7 @@ type UpdateAppearanceConfig struct {
|
||||||
ApplicationName string `json:"application_name"`
|
ApplicationName string `json:"application_name"`
|
||||||
LogoURL string `json:"logo_url"`
|
LogoURL string `json:"logo_url"`
|
||||||
ServiceBanner ServiceBannerConfig `json:"service_banner"`
|
ServiceBanner ServiceBannerConfig `json:"service_banner"`
|
||||||
|
TermsOfService string `json:"terms_of_service"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceBannerConfig struct {
|
type ServiceBannerConfig struct {
|
||||||
|
|
|
@ -32,7 +32,8 @@ curl -X GET http://coder-server:8080/api/v2/appearance \
|
||||||
"name": "string",
|
"name": "string",
|
||||||
"target": "string"
|
"target": "string"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"terms_of_service": "string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -68,7 +69,8 @@ curl -X PUT http://coder-server:8080/api/v2/appearance \
|
||||||
"background_color": "string",
|
"background_color": "string",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"message": "string"
|
"message": "string"
|
||||||
}
|
},
|
||||||
|
"terms_of_service": "string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -90,7 +92,8 @@ curl -X PUT http://coder-server:8080/api/v2/appearance \
|
||||||
"background_color": "string",
|
"background_color": "string",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"message": "string"
|
"message": "string"
|
||||||
}
|
},
|
||||||
|
"terms_of_service": "string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -762,7 +762,8 @@
|
||||||
"name": "string",
|
"name": "string",
|
||||||
"target": "string"
|
"target": "string"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"terms_of_service": "string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -774,6 +775,7 @@
|
||||||
| `logo_url` | string | false | | |
|
| `logo_url` | string | false | | |
|
||||||
| `service_banner` | [codersdk.ServiceBannerConfig](#codersdkservicebannerconfig) | false | | |
|
| `service_banner` | [codersdk.ServiceBannerConfig](#codersdkservicebannerconfig) | false | | |
|
||||||
| `support_links` | array of [codersdk.LinkConfig](#codersdklinkconfig) | false | | |
|
| `support_links` | array of [codersdk.LinkConfig](#codersdklinkconfig) | false | | |
|
||||||
|
| `terms_of_service` | string | false | | |
|
||||||
|
|
||||||
## codersdk.ArchiveTemplateVersionsRequest
|
## codersdk.ArchiveTemplateVersionsRequest
|
||||||
|
|
||||||
|
@ -5172,7 +5174,8 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||||
"background_color": "string",
|
"background_color": "string",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"message": "string"
|
"message": "string"
|
||||||
}
|
},
|
||||||
|
"terms_of_service": "string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -5183,6 +5186,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||||
| `application_name` | string | false | | |
|
| `application_name` | string | false | | |
|
||||||
| `logo_url` | string | false | | |
|
| `logo_url` | string | false | | |
|
||||||
| `service_banner` | [codersdk.ServiceBannerConfig](#codersdkservicebannerconfig) | false | | |
|
| `service_banner` | [codersdk.ServiceBannerConfig](#codersdkservicebannerconfig) | false | | |
|
||||||
|
| `terms_of_service` | string | false | | |
|
||||||
|
|
||||||
## codersdk.UpdateCheckResponse
|
## codersdk.UpdateCheckResponse
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi
|
||||||
var applicationName string
|
var applicationName string
|
||||||
var logoURL string
|
var logoURL string
|
||||||
var serviceBannerJSON string
|
var serviceBannerJSON string
|
||||||
|
var termsOfService string
|
||||||
eg.Go(func() (err error) {
|
eg.Go(func() (err error) {
|
||||||
applicationName, err = f.database.GetApplicationName(ctx)
|
applicationName, err = f.database.GetApplicationName(ctx)
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
@ -77,6 +78,13 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
eg.Go(func() (err error) {
|
||||||
|
termsOfService, err = f.database.GetTermsOfService(ctx)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return xerrors.Errorf("get terms of service: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
err := eg.Wait()
|
err := eg.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return codersdk.AppearanceConfig{}, err
|
return codersdk.AppearanceConfig{}, err
|
||||||
|
@ -85,6 +93,7 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi
|
||||||
cfg := codersdk.AppearanceConfig{
|
cfg := codersdk.AppearanceConfig{
|
||||||
ApplicationName: applicationName,
|
ApplicationName: applicationName,
|
||||||
LogoURL: logoURL,
|
LogoURL: logoURL,
|
||||||
|
TermsOfService: termsOfService,
|
||||||
}
|
}
|
||||||
if serviceBannerJSON != "" {
|
if serviceBannerJSON != "" {
|
||||||
err = json.Unmarshal([]byte(serviceBannerJSON), &cfg.ServiceBanner)
|
err = json.Unmarshal([]byte(serviceBannerJSON), &cfg.ServiceBanner)
|
||||||
|
@ -176,6 +185,15 @@ func (api *API) putAppearance(rw http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = api.Database.UpsertTermsOfService(ctx, appearance.TermsOfService)
|
||||||
|
if err != nil {
|
||||||
|
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||||
|
Message: "Unable to set terms of service",
|
||||||
|
Detail: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = api.Database.UpsertLogoURL(ctx, appearance.LogoURL)
|
err = api.Database.UpsertLogoURL(ctx, appearance.LogoURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||||
|
|
|
@ -1282,6 +1282,8 @@ export const getAppearance = async (): Promise<TypesGen.AppearanceConfig> => {
|
||||||
const response = await axios.get(`/api/v2/appearance`);
|
const response = await axios.get(`/api/v2/appearance`);
|
||||||
return response.data || {};
|
return response.data || {};
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
// This endpoint is only available on enterprise binaries. A 404 is expected
|
||||||
|
// from AGPL builds, and should be be treated as a "successful" response.
|
||||||
if (axios.isAxiosError(ex) && ex.response?.status === 404) {
|
if (axios.isAxiosError(ex) && ex.response?.status === 404) {
|
||||||
return {
|
return {
|
||||||
application_name: "",
|
application_name: "",
|
||||||
|
@ -1289,6 +1291,7 @@ export const getAppearance = async (): Promise<TypesGen.AppearanceConfig> => {
|
||||||
service_banner: {
|
service_banner: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
terms_of_service: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
|
|
|
@ -49,6 +49,7 @@ export interface AppearanceConfig {
|
||||||
readonly application_name: string;
|
readonly application_name: string;
|
||||||
readonly logo_url: string;
|
readonly logo_url: string;
|
||||||
readonly service_banner: ServiceBannerConfig;
|
readonly service_banner: ServiceBannerConfig;
|
||||||
|
readonly terms_of_service: string;
|
||||||
readonly support_links?: readonly LinkConfig[];
|
readonly support_links?: readonly LinkConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1279,6 +1280,7 @@ export interface UpdateAppearanceConfig {
|
||||||
readonly application_name: string;
|
readonly application_name: string;
|
||||||
readonly logo_url: string;
|
readonly logo_url: string;
|
||||||
readonly service_banner: ServiceBannerConfig;
|
readonly service_banner: ServiceBannerConfig;
|
||||||
|
readonly terms_of_service: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/updatecheck.go
|
// From codersdk/updatecheck.go
|
||||||
|
|
|
@ -22,6 +22,7 @@ const AppearanceSettingsPage: FC = () => {
|
||||||
newConfig: Partial<UpdateAppearanceConfig>,
|
newConfig: Partial<UpdateAppearanceConfig>,
|
||||||
preview: boolean,
|
preview: boolean,
|
||||||
) => {
|
) => {
|
||||||
|
console.log(newConfig);
|
||||||
const newAppearance = { ...appearance.config, ...newConfig };
|
const newAppearance = { ...appearance.config, ...newConfig };
|
||||||
if (preview) {
|
if (preview) {
|
||||||
appearance.setPreview(newAppearance);
|
appearance.setPreview(newAppearance);
|
||||||
|
|
|
@ -13,6 +13,7 @@ const meta: Meta<typeof AppearanceSettingsPageView> = {
|
||||||
message: "hello world",
|
message: "hello world",
|
||||||
background_color: "white",
|
background_color: "white",
|
||||||
},
|
},
|
||||||
|
terms_of_service: "",
|
||||||
},
|
},
|
||||||
isEntitled: false,
|
isEntitled: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -80,6 +80,16 @@ export const AppearanceSettingsPageView: FC<
|
||||||
serviceBannerForm.values.background_color,
|
serviceBannerForm.values.background_color,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const termsOfServiceForm = useFormik<{
|
||||||
|
terms_of_service: string;
|
||||||
|
}>({
|
||||||
|
initialValues: {
|
||||||
|
terms_of_service: appearance.terms_of_service,
|
||||||
|
},
|
||||||
|
onSubmit: (values) => onSaveAppearance(values, false),
|
||||||
|
});
|
||||||
|
const termsOfServiceFieldHelpers = getFormHelpers(termsOfServiceForm);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header
|
<Header
|
||||||
|
@ -276,6 +286,30 @@ export const AppearanceSettingsPageView: FC<
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
|
|
||||||
|
<Fieldset
|
||||||
|
title="Terms of Service"
|
||||||
|
subtitle="Add a custom Terms of Service that must be accepted before using Coder."
|
||||||
|
validation={!isEntitled ? "This is an Enterprise only feature." : ""}
|
||||||
|
onSubmit={termsOfServiceForm.handleSubmit}
|
||||||
|
button={!isEntitled && <Button disabled>Submit</Button>}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
{...termsOfServiceFieldHelpers("terms_of_service", {
|
||||||
|
helperText: "Markdown is supported.",
|
||||||
|
})}
|
||||||
|
defaultValue={appearance.terms_of_service}
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
label="Terms of Service"
|
||||||
|
placeholder="Leave empty to disable."
|
||||||
|
disabled={!isEntitled}
|
||||||
|
inputProps={{
|
||||||
|
"aria-label": "Terms of Service. Leave empty to disable.",
|
||||||
|
style: { height: 100, resize: "vertical" },
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Fieldset>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { useAuthContext } from "contexts/auth/AuthProvider";
|
||||||
import { getApplicationName } from "utils/appearance";
|
import { getApplicationName } from "utils/appearance";
|
||||||
import { retrieveRedirect } from "utils/redirect";
|
import { retrieveRedirect } from "utils/redirect";
|
||||||
import { LoginPageView } from "./LoginPageView";
|
import { LoginPageView } from "./LoginPageView";
|
||||||
|
import { appearance } from "api/queries/appearance";
|
||||||
|
|
||||||
export const LoginPage: FC = () => {
|
export const LoginPage: FC = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
@ -24,6 +25,7 @@ export const LoginPage: FC = () => {
|
||||||
const applicationName = getApplicationName();
|
const applicationName = getApplicationName();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const buildInfoQuery = useQuery(buildInfo());
|
const buildInfoQuery = useQuery(buildInfo());
|
||||||
|
const siteConfigQuery = useQuery(appearance());
|
||||||
|
|
||||||
if (isSignedIn) {
|
if (isSignedIn) {
|
||||||
// If the redirect is going to a workspace application, and we
|
// If the redirect is going to a workspace application, and we
|
||||||
|
@ -68,6 +70,7 @@ export const LoginPage: FC = () => {
|
||||||
error={signInError}
|
error={signInError}
|
||||||
isLoading={isLoading || authMethodsQuery.isLoading}
|
isLoading={isLoading || authMethodsQuery.isLoading}
|
||||||
buildInfo={buildInfoQuery.data}
|
buildInfo={buildInfoQuery.data}
|
||||||
|
termsOfService={siteConfigQuery.data?.terms_of_service}
|
||||||
isSigningIn={isSigningIn}
|
isSigningIn={isSigningIn}
|
||||||
onSignIn={async ({ email, password }) => {
|
onSignIn={async ({ email, password }) => {
|
||||||
await signIn(email, password);
|
await signIn(email, password);
|
||||||
|
|
|
@ -13,6 +13,7 @@ export interface LoginPageViewProps {
|
||||||
error: unknown;
|
error: unknown;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
buildInfo?: BuildInfoResponse;
|
buildInfo?: BuildInfoResponse;
|
||||||
|
termsOfService?: string;
|
||||||
isSigningIn: boolean;
|
isSigningIn: boolean;
|
||||||
onSignIn: (credentials: { email: string; password: string }) => void;
|
onSignIn: (credentials: { email: string; password: string }) => void;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +23,7 @@ export const LoginPageView: FC<LoginPageViewProps> = ({
|
||||||
error,
|
error,
|
||||||
isLoading,
|
isLoading,
|
||||||
buildInfo,
|
buildInfo,
|
||||||
|
termsOfService,
|
||||||
isSigningIn,
|
isSigningIn,
|
||||||
onSignIn,
|
onSignIn,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -49,6 +51,10 @@ export const LoginPageView: FC<LoginPageViewProps> = ({
|
||||||
<CoderIcon fill="white" opacity={1} css={styles.icon} />
|
<CoderIcon fill="white" opacity={1} css={styles.icon} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (termsOfService) {
|
||||||
|
return <>{termsOfService}</>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={styles.root}>
|
<div css={styles.root}>
|
||||||
<div css={styles.container}>
|
<div css={styles.container}>
|
||||||
|
|
|
@ -2347,6 +2347,7 @@ export const MockAppearanceConfig: TypesGen.AppearanceConfig = {
|
||||||
service_banner: {
|
service_banner: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
terms_of_service: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MockWorkspaceBuildParameter1: TypesGen.WorkspaceBuildParameter = {
|
export const MockWorkspaceBuildParameter1: TypesGen.WorkspaceBuildParameter = {
|
||||||
|
|
Loading…
Reference in New Issue