From 07727dbde6b3e2a6d827b9995e72c032a06ad3d9 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Thu, 2 Mar 2023 15:15:00 +0200 Subject: [PATCH 1/8] [#1956] normalized _requests.method to UPPERCASE --- CHANGELOG.md | 5 +++++ apis/middlewares.go | 2 +- .../logs/1677760279_uppsercase_method.go | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 migrations/logs/1677760279_uppsercase_method.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 99844924..39b5a4b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## (WIP) v0.14.0 + +- Normalized the request logs `method` value to UPPERCASE, eg. "get" => "GET" ([#1956](https://github.com/pocketbase/pocketbase/discussions/1956)). + + ## v0.13.0 - Added new "View" collection type allowing you to create a read-only collection from a custom SQL `SELECT` statement. It supports: diff --git a/apis/middlewares.go b/apis/middlewares.go index b0561dca..a1c0a51d 100644 --- a/apis/middlewares.go +++ b/apis/middlewares.go @@ -321,7 +321,7 @@ func ActivityLogger(app core.App) echo.MiddlewareFunc { model := &models.Request{ Url: httpRequest.URL.RequestURI(), - Method: strings.ToLower(httpRequest.Method), + Method: strings.ToUpper(httpRequest.Method), Status: status, Auth: requestAuth, UserIp: realUserIp(httpRequest, ip), diff --git a/migrations/logs/1677760279_uppsercase_method.go b/migrations/logs/1677760279_uppsercase_method.go new file mode 100644 index 00000000..459b4bff --- /dev/null +++ b/migrations/logs/1677760279_uppsercase_method.go @@ -0,0 +1,18 @@ +package logs + +import ( + "github.com/pocketbase/dbx" +) + +// This migrations converts all logs "method" valus to all UPPERCASE (eg. "get" => "GET"). +func init() { + LogsMigrations.Register(func(db dbx.Builder) error { + _, err := db.NewQuery("UPDATE {{_requests}} SET method=UPPER(method)").Execute() + + return err + }, func(db dbx.Builder) error { + _, err := db.NewQuery("UPDATE {{_requests}} SET method=LOWER(method)").Execute() + + return err + }) +} From 56a77fd5ff54ac11ee143e8e2a36574e65c65cfb Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Thu, 2 Mar 2023 15:16:47 +0200 Subject: [PATCH 2/8] updated migrations comment --- migrations/logs/1677760279_uppsercase_method.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/logs/1677760279_uppsercase_method.go b/migrations/logs/1677760279_uppsercase_method.go index 459b4bff..cef96960 100644 --- a/migrations/logs/1677760279_uppsercase_method.go +++ b/migrations/logs/1677760279_uppsercase_method.go @@ -4,7 +4,7 @@ import ( "github.com/pocketbase/dbx" ) -// This migrations converts all logs "method" valus to all UPPERCASE (eg. "get" => "GET"). +// This migration normalizes the request logs method to UPPERCASE (eg. "get" => "GET"). func init() { LogsMigrations.Register(func(db dbx.Builder) error { _, err := db.NewQuery("UPDATE {{_requests}} SET method=UPPER(method)").Execute() From 19faa0d8e73505f728a5a17366119999ef7b4f86 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Thu, 2 Mar 2023 16:10:56 +0200 Subject: [PATCH 3/8] updated calendar styles --- ui/src/scss/_flatpickr.scss | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/ui/src/scss/_flatpickr.scss b/ui/src/scss/_flatpickr.scss index 5a38e84a..e9a671a5 100644 --- a/ui/src/scss/_flatpickr.scss +++ b/ui/src/scss/_flatpickr.scss @@ -21,7 +21,9 @@ input, select { box-shadow: none; min-height: 0; - height: var(--inputHeight); + height: var(--smBtnHeight); + padding-top: 3px; + padding-bottom: 3px; background: none; border-radius: var(--baseRadius); border: 1px solid var(--baseAlt1Color); @@ -143,13 +145,16 @@ } .flatpickr-months { display: flex; - margin: 0 0 4px; + align-items: center; + padding: 5px 0; } .flatpickr-months .flatpickr-month { + display: flex; + align-items: center; + justify-content: center; background: transparent; color: var(--txtPrimaryColor); fill: var(--txtPrimaryColor); - height: 34px; line-height: 1; text-align: center; position: relative; @@ -164,12 +169,12 @@ } .flatpickr-months .flatpickr-prev-month, .flatpickr-months .flatpickr-next-month { + display: flex; + align-items: center; text-decoration: none; cursor: pointer; - position: absolute; - top: 0; height: 34px; - padding: 10px; + padding: 5px 12px; z-index: 3; color: var(--txtPrimaryColor); fill: var(--txtPrimaryColor); @@ -210,6 +215,7 @@ .numInputWrapper { position: relative; height: auto; + border-radius: var(--baseRadius); } .numInputWrapper input, .numInputWrapper span { @@ -276,7 +282,7 @@ fill: rgba(0,0,0,0.5); } .numInputWrapper:hover { - background: var(--baseAlt2Color); + background: var(--baseAlt1Color); } .numInputWrapper:hover span { opacity: 1; @@ -284,12 +290,11 @@ .flatpickr-current-month { line-height: inherit; color: inherit; - position: absolute; - width: 75%; - left: 12.5%; + width: 85%; padding: 1px 0; line-height: 1; display: flex; + gap: 10px; align-items: center; justify-content: center; text-align: center; @@ -303,14 +308,13 @@ padding: 0; } .flatpickr-current-month span.cur-month:hover { - background: var(--baseAlt2Color); + background: var(--baseAlt1Color); } .flatpickr-current-month .numInputWrapper { display: inline-flex; align-items: center; justify-content: center; - width: 63px; - margin: 0 5px; + width: 62px; } .flatpickr-current-month .numInputWrapper span.arrowUp:after { border-bottom-color: var(--txtPrimaryColor); @@ -362,7 +366,7 @@ outline: none; } .flatpickr-current-month .flatpickr-monthDropdown-months:hover { - background: var(--baseAlt2Color); + background: var(--baseAlt1Color); } .flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month { background-color: transparent; From a67c14c3688f145fce48a2ba2f3da3f3140cd290 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Thu, 2 Mar 2023 18:56:18 +0200 Subject: [PATCH 4/8] added support for @request.headers.* --- apis/record_helpers.go | 15 ++++++++++++--- apis/record_helpers_test.go | 7 +++++++ models/request_data.go | 11 ++++++----- resolvers/record_field_resolver.go | 3 +++ resolvers/record_field_resolver_test.go | 11 +++++++++++ .../base/FilterAutocompleteInput.svelte | 1 + .../collections/CollectionRulesTab.svelte | 2 +- 7 files changed, 41 insertions(+), 9 deletions(-) diff --git a/apis/record_helpers.go b/apis/record_helpers.go index 96e7de31..d8e9ad75 100644 --- a/apis/record_helpers.go +++ b/apis/record_helpers.go @@ -30,9 +30,18 @@ func RequestData(c echo.Context) *models.RequestData { } result := &models.RequestData{ - Method: c.Request().Method, - Query: map[string]any{}, - Data: map[string]any{}, + Method: c.Request().Method, + Query: map[string]any{}, + Data: map[string]any{}, + Headers: map[string]string{}, + } + + // extract the first value of all headers and normalizes the keys + // ("X-Token" is converted to "x_token") + for k, v := range c.Request().Header { + if len(v) > 0 { + result.Headers[strings.ToLower(strings.ReplaceAll(k, "-", "_"))] = v[0] + } } result.AuthRecord, _ = c.Get(ContextAuthRecordKey).(*models.Record) diff --git a/apis/record_helpers_test.go b/apis/record_helpers_test.go index 7f96c2ff..765182ce 100644 --- a/apis/record_helpers_test.go +++ b/apis/record_helpers_test.go @@ -17,6 +17,7 @@ func TestRequestData(t *testing.T) { e := echo.New() req := httptest.NewRequest(http.MethodPost, "/?test=123", strings.NewReader(`{"test":456}`)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + req.Header.Set("X-Token-Test", "123") rec := httptest.NewRecorder() c := e.NewContext(req, rec) @@ -38,6 +39,12 @@ func TestRequestData(t *testing.T) { t.Fatalf("Expected Method %v, got %v", http.MethodPost, result.Method) } + rawHeaders, _ := json.Marshal(result.Headers) + expectedHeaders := `{"content_type":"application/json","x_token_test":"123"}` + if v := string(rawHeaders); v != expectedHeaders { + t.Fatalf("Expected Query %v, got %v", expectedHeaders, v) + } + rawQuery, _ := json.Marshal(result.Query) expectedQuery := `{"test":"123"}` if v := string(rawQuery); v != expectedQuery { diff --git a/models/request_data.go b/models/request_data.go index 693795c3..e574c0c7 100644 --- a/models/request_data.go +++ b/models/request_data.go @@ -9,11 +9,12 @@ import ( // RequestData defines a HTTP request data struct, usually used // as part of the `@request.*` filter resolver. type RequestData struct { - Method string `json:"method"` - Query map[string]any `json:"query"` - Data map[string]any `json:"data"` - AuthRecord *Record `json:"authRecord"` - Admin *Admin `json:"admin"` + Method string `json:"method"` + Query map[string]any `json:"query"` + Data map[string]any `json:"data"` + Headers map[string]string `json:"headers"` + AuthRecord *Record `json:"authRecord"` + Admin *Admin `json:"admin"` } // HasModifierDataKeys loosely checks if the current struct has any modifier Data keys. diff --git a/resolvers/record_field_resolver.go b/resolvers/record_field_resolver.go index 220abbfe..9bd18af2 100644 --- a/resolvers/record_field_resolver.go +++ b/resolvers/record_field_resolver.go @@ -84,6 +84,7 @@ func NewRecordFieldResolver( `^\@request\.auth\.[\w\.\:]*\w+$`, `^\@request\.data\.[\w\.\:]*\w+$`, `^\@request\.query\.[\w\.\:]*\w+$`, + `^\@request\.headers\.\w+$`, `^\@collection\.\w+\.[\w\.\:]*\w+$`, }, } @@ -92,6 +93,7 @@ func NewRecordFieldResolver( if r.requestData != nil { r.staticRequestData["method"] = r.requestData.Method r.staticRequestData["query"] = r.requestData.Query + r.staticRequestData["headers"] = r.requestData.Headers r.staticRequestData["data"] = r.requestData.Data r.staticRequestData["auth"] = nil if r.requestData.AuthRecord != nil { @@ -132,6 +134,7 @@ func (r *RecordFieldResolver) UpdateQuery(query *dbx.SelectQuery) error { // project.screen.status // @request.status // @request.query.filter +// @request.headers.x_token // @request.auth.someRelation.name // @request.data.someRelation.name // @request.data.someField diff --git a/resolvers/record_field_resolver_test.go b/resolvers/record_field_resolver_test.go index 206e32c4..28d6d34c 100644 --- a/resolvers/record_field_resolver_test.go +++ b/resolvers/record_field_resolver_test.go @@ -23,6 +23,10 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) { } requestData := &models.RequestData{ + Headers: map[string]string{ + "a": "123", + "b": "456", + }, Query: map[string]any{ "a": nil, "b": 123, @@ -438,6 +442,9 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) { "b": 456, "c": map[string]int{"sub": 1}, }, + Headers: map[string]string{ + "d": "789", + }, AuthRecord: authRecord, } @@ -456,6 +463,10 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) { {"@request.query", true, ``}, {"@request.query.a", false, `123`}, {"@request.query.a.missing", false, ``}, + {"@request.headers", true, ``}, + {"@request.headers.missing", false, ``}, + {"@request.headers.d", false, `456`}, + {"@request.headers.d.sub", true, ``}, {"@request.data", true, ``}, {"@request.data.b", false, `456`}, {"@request.data.number", false, `10`}, // number field normalization diff --git a/ui/src/components/base/FilterAutocompleteInput.svelte b/ui/src/components/base/FilterAutocompleteInput.svelte index 4e8e6c0d..152979ee 100644 --- a/ui/src/components/base/FilterAutocompleteInput.svelte +++ b/ui/src/components/base/FilterAutocompleteInput.svelte @@ -256,6 +256,7 @@ result.push("@request.method"); result.push("@request.query."); result.push("@request.data."); + result.push("@request.headers."); result.push("@request.auth.id"); result.push("@request.auth.collectionId"); result.push("@request.auth.collectionName"); diff --git a/ui/src/components/collections/CollectionRulesTab.svelte b/ui/src/components/collections/CollectionRulesTab.svelte index 6fcfed3c..74ece011 100644 --- a/ui/src/components/collections/CollectionRulesTab.svelte +++ b/ui/src/components/collections/CollectionRulesTab.svelte @@ -45,7 +45,7 @@ The request fields could be accessed with the special @request filter:

- @request.method + @request.headers.* @request.query.* @request.data.* @request.auth.* From e8d61e7b45e734d2c4c42d6c645d187796eec3bd Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sat, 4 Mar 2023 13:05:55 +0200 Subject: [PATCH 5/8] simplified rules ui --- .../collections/CollectionRulesTab.svelte | 5 ----- ui/src/components/collections/RuleField.svelte | 15 +++------------ 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/ui/src/components/collections/CollectionRulesTab.svelte b/ui/src/components/collections/CollectionRulesTab.svelte index 74ece011..eb5f0a0d 100644 --- a/ui/src/components/collections/CollectionRulesTab.svelte +++ b/ui/src/components/collections/CollectionRulesTab.svelte @@ -77,22 +77,17 @@ -
{#if !collection?.isView} -
-
-
{/if} {#if collection?.isAuth} -
{:else} @@ -93,20 +93,11 @@ bind:value={rule} baseCollection={collection} disabled={isAdminOnly} + placeholder={!isAdminOnly ? "Leave empty to grant everyone access..." : ""} />
- -

- {#if isAdminOnly} - Only admins will be able to perform this action ( - - ). - {:else} - Leave empty to grant everyone access. - {/if} -

-
+
{/if} From 01f0af7af634c52535528e975856a2595f0645de Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sat, 4 Mar 2023 13:06:15 +0200 Subject: [PATCH 6/8] added errors slide transition --- ui/src/components/base/Field.svelte | 3 ++- ui/src/scss/_alert.scss | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/src/components/base/Field.svelte b/ui/src/components/base/Field.svelte index 122ef0ef..a9b8c033 100644 --- a/ui/src/components/base/Field.svelte +++ b/ui/src/components/base/Field.svelte @@ -1,5 +1,6 @@ - +