Skip to content

Commit

Permalink
synced with master
Browse files Browse the repository at this point in the history
  • Loading branch information
ganigeorgiev committed Feb 7, 2024
2 parents 722a749 + 368af1f commit b7447f3
Show file tree
Hide file tree
Showing 36 changed files with 167 additions and 136 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
- Other minor improvements (updated the `ghupdate` plugin to use the configured executable name when printing to the console, increased with +1 the `thumbGenSem` limit, fixed the error reporting of `admin update/delete` commands, etc.).


## v0.21.2

- Fixed `@request.auth.*` initialization side-effect which caused the current authenticated user email to not being returned in the user auth response ([#2173](https://github.com/pocketbase/pocketbase/issues/2173#issuecomment-1932332038)).
_The current authenticated user email should be accessible always no matter of the `emailVisibility` state._

- Fixed `RecordUpsert.RemoveFiles` godoc example.

- Bumped to `NumCPU()+2` the `thumbGenSem` limit as some users reported that it was too restrictive.


## v0.21.1

- Small fix for the Admin UI related to the _Settings > Sync_ menu not being visible even when the "Hide controls" toggle is off.
Expand Down
110 changes: 61 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,64 +32,76 @@ The easiest way to interact with the API is to use one of the official SDK clien

## Overview

PocketBase could be [downloaded directly as a standalone app](https://github.com/pocketbase/pocketbase/releases) or it could be used as a Go framework/toolkit which allows you to build
### Use as standalone app

You could download the prebuilt executable for your platform from the [Releases page](https://github.com/pocketbase/pocketbase/releases).
Once downloaded, extract the archive and run `./pocketbase serve` in the extracted directory.

The prebuilt executables are based on the [`examples/base/main.go` file](https://github.com/pocketbase/pocketbase/blob/master/examples/base/main.go) and comes with the JS VM plugin enabled by default which allows to extend PocketBase with JavaScript (_for more details please refer to [Extend with JavaScript](https://pocketbase.io/docs/js-overview/)_).

### Use as a Go framework/toolkit

PocketBase as distributed as a regular Go library package which allows you to build
your own custom app specific business logic and still have a single portable executable at the end.

### Installation
Here is a minimal example:

```sh
# go 1.21+
go get github.com/pocketbase/pocketbase
```
0. [Install Go 1.21+](https://go.dev/doc/install) (_if you haven't already_)

### Example

```go
package main

import (
"log"
"net/http"

"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)

func main() {
app := pocketbase.New()

app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// add new "GET /hello" route to the app router (echo)
e.Router.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/hello",
Handler: func(c echo.Context) error {
return c.String(200, "Hello world!")
},
Middlewares: []echo.MiddlewareFunc{
apis.ActivityLogger(app),
},
1. Create a new project directory with the following `main.go` file inside it:
```go
package main

import (
"log"
"net/http"

"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)

func main() {
app := pocketbase.New()

app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// add new "GET /hello" route to the app router (echo)
e.Router.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/hello",
Handler: func(c echo.Context) error {
return c.String(200, "Hello world!")
},
Middlewares: []echo.MiddlewareFunc{
apis.ActivityLogger(app),
},
})

return nil
})

return nil
})

if err := app.Start(); err != nil {
log.Fatal(err)
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
}
```
```

2. To init the dependencies, run `go mod init myapp && go mod tidy`.

3. To start the application, run `go run main.go serve`.

### Running and building
4. To build a statically linked executable, you can run `CGO_ENABLED=0 go build` and then start the created executable with `./myapp serve`.

Running/building the application is the same as for any other Go program, aka. just `go run` and `go build`.
> [!NOTE]
> PocketBase embeds SQLite, but doesn't require CGO.
>
> If CGO is enabled (aka. `CGO_ENABLED=1`), it will use [mattn/go-sqlite3](https://pkg.go.dev/github.com/mattn/go-sqlite3) driver, otherwise - [modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite).
> Enable CGO only if you really need to squeeze the read/write query performance at the expense of complicating cross compilation.
**PocketBase embeds SQLite, but doesn't require CGO.**
_For more details please refer to [Extend with Go](https://pocketbase.io/docs/go-overview/)._

If CGO is enabled (aka. `CGO_ENABLED=1`), it will use [mattn/go-sqlite3](https://pkg.go.dev/github.com/mattn/go-sqlite3) driver, otherwise - [modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite).
Enable CGO only if you really need to squeeze the read/write query performance at the expense of complicating cross compilation.
### Building and running the repo main.go example

To build the minimal standalone executable, like the prebuilt ones in the releases page, you can simply run `go build` inside the `examples/base` directory:

Expand All @@ -100,7 +112,7 @@ To build the minimal standalone executable, like the prebuilt ones in the releas
(_https://go.dev/doc/install/source#environment_)
4. Start the created executable by running `./base serve`.

The supported build targets by the non-cgo driver at the moment are:
Note that the supported build targets by the pure Go SQLite driver at the moment are:

```
darwin amd64
Expand All @@ -121,7 +133,7 @@ windows arm64
### Testing

PocketBase comes with mixed bag of unit and integration tests.
To run them, use the default `go test` command:
To run them, use the standard `go test` command:

```sh
go test ./...
Expand Down
7 changes: 4 additions & 3 deletions resolvers/record_field_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ func NewRecordFieldResolver(
r.staticRequestInfo["data"] = r.requestInfo.Data
r.staticRequestInfo["auth"] = nil
if r.requestInfo.AuthRecord != nil {
r.requestInfo.AuthRecord.IgnoreEmailVisibility(true)
r.staticRequestInfo["auth"] = r.requestInfo.AuthRecord.PublicExport()
r.requestInfo.AuthRecord.IgnoreEmailVisibility(false)
authData := r.requestInfo.AuthRecord.PublicExport()
// always add the record email no matter of the emailVisibility field
authData[schema.FieldNameEmail] = r.requestInfo.AuthRecord.Email()
r.staticRequestInfo["auth"] = authData
}
}

Expand Down
94 changes: 51 additions & 43 deletions resolvers/record_field_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,56 +501,64 @@ func TestRecordFieldResolverResolveStaticRequestInfoFields(t *testing.T) {
{"@request.data.c", false, `"{\"sub\":1}"`},
{"@request.auth", true, ""},
{"@request.auth.id", false, `"4q1xlclmfloku33"`},
{"@request.auth.email", false, `"test@example.com"`},
{"@request.auth.username", false, `"users75657"`},
{"@request.auth.verified", false, `false`},
{"@request.auth.emailVisibility", false, `false`},
{"@request.auth.email", false, `"test@example.com"`}, // should always be returned no matter of the emailVisibility state
{"@request.auth.missing", false, `NULL`},
}

for i, s := range scenarios {
r, err := r.Resolve(s.fieldName)

hasErr := err != nil
if hasErr != s.expectError {
t.Errorf("(%d) Expected hasErr %v, got %v (%v)", i, s.expectError, hasErr, err)
continue
}

if hasErr {
continue
}

// missing key
// ---
if len(r.Params) == 0 {
if r.Identifier != "NULL" {
t.Errorf("(%d) Expected 0 placeholder parameters for %v, got %v", i, r.Identifier, r.Params)
t.Run(s.fieldName, func(t *testing.T) {
r, err := r.Resolve(s.fieldName)

hasErr := err != nil
if hasErr != s.expectError {
t.Fatalf("(%d) Expected hasErr %v, got %v (%v)", i, s.expectError, hasErr, err)
}

if hasErr {
return
}

// missing key
// ---
if len(r.Params) == 0 {
if r.Identifier != "NULL" {
t.Fatalf("(%d) Expected 0 placeholder parameters for %v, got %v", i, r.Identifier, r.Params)
}
return
}
continue
}

// existing key
// ---
if len(r.Params) != 1 {
t.Errorf("(%d) Expected 1 placeholder parameter for %v, got %v", i, r.Identifier, r.Params)
continue
}

var paramName string
var paramValue any
for k, v := range r.Params {
paramName = k
paramValue = v
}

if r.Identifier != ("{:" + paramName + "}") {
t.Errorf("(%d) Expected parameter r.Identifier %q, got %q", i, paramName, r.Identifier)
}

encodedParamValue, _ := json.Marshal(paramValue)
if string(encodedParamValue) != s.expectParamValue {
t.Errorf("(%d) Expected r.Params %v for %v, got %v", i, s.expectParamValue, r.Identifier, string(encodedParamValue))
}

// existing key
// ---
if len(r.Params) != 1 {
t.Fatalf("(%d) Expected 1 placeholder parameter for %v, got %v", i, r.Identifier, r.Params)
}

var paramName string
var paramValue any
for k, v := range r.Params {
paramName = k
paramValue = v
}

if r.Identifier != ("{:" + paramName + "}") {
t.Fatalf("(%d) Expected parameter r.Identifier %q, got %q", i, paramName, r.Identifier)
}

encodedParamValue, _ := json.Marshal(paramValue)
if string(encodedParamValue) != s.expectParamValue {
t.Fatalf("(%d) Expected r.Params %v for %v, got %v", i, s.expectParamValue, r.Identifier, string(encodedParamValue))
}
})
}

// ensure that the original email visibility was restored
if authRecord.EmailVisibility() {
t.Fatal("Expected the original authRecord emailVisibility to remain unchanged")
}
if v, ok := authRecord.PublicExport()["email"]; ok {
t.Fatalf("Expected the original authRecord email to not be exported, got %q", v)
}
}
2 changes: 1 addition & 1 deletion ui/.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ PB_DOCS_URL = "https://pocketbase.io/docs/"
PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk"
PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk"
PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases"
PB_VERSION = "v0.21.1"
PB_VERSION = "v0.21.2"

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

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import{S as je,i as xe,s as Je,N as Ue,O as J,e as s,v as k,b as p,c as K,f as b,g as d,h as o,m as I,w as de,P as Ee,Q as Ke,k as Ie,R as We,n as Ge,t as N,a as V,o as u,d as W,C as Le,A as Xe,q as G,r as Ye}from"./index-MkGUixqr.js";import{S as Ze}from"./SdkTabs-7yshYvVF.js";import{F as et}from"./FieldsQueryParam-N-1EL4Av.js";function Ne(r,l,a){const n=r.slice();return n[5]=l[a],n}function Ve(r,l,a){const n=r.slice();return n[5]=l[a],n}function ze(r,l){let a,n=l[5].code+"",m,_,i,h;function g(){return l[4](l[5])}return{key:r,first:null,c(){a=s("button"),m=k(n),_=p(),b(a,"class","tab-item"),G(a,"active",l[1]===l[5].code),this.first=a},m(v,w){d(v,a,w),o(a,m),o(a,_),i||(h=Ye(a,"click",g),i=!0)},p(v,w){l=v,w&4&&n!==(n=l[5].code+"")&&de(m,n),w&6&&G(a,"active",l[1]===l[5].code)},d(v){v&&u(a),i=!1,h()}}}function Qe(r,l){let a,n,m,_;return n=new Ue({props:{content:l[5].body}}),{key:r,first:null,c(){a=s("div"),K(n.$$.fragment),m=p(),b(a,"class","tab-item"),G(a,"active",l[1]===l[5].code),this.first=a},m(i,h){d(i,a,h),I(n,a,null),o(a,m),_=!0},p(i,h){l=i;const g={};h&4&&(g.content=l[5].body),n.$set(g),(!_||h&6)&&G(a,"active",l[1]===l[5].code)},i(i){_||(N(n.$$.fragment,i),_=!0)},o(i){V(n.$$.fragment,i),_=!1},d(i){i&&u(a),W(n)}}}function tt(r){var De,Fe;let l,a,n=r[0].name+"",m,_,i,h,g,v,w,B,X,S,z,ue,Q,M,pe,Y,U=r[0].name+"",Z,he,fe,j,ee,D,te,T,oe,be,F,C,le,me,ae,_e,f,ke,R,ge,ve,$e,se,ye,ne,Se,we,Te,re,Ce,Pe,A,ie,O,ce,P,H,y=[],Re=new Map,Ae,E,$=[],qe=new Map,q;v=new Ze({props:{js:`
import{S as je,i as xe,s as Je,N as Ue,O as J,e as s,v as k,b as p,c as K,f as b,g as d,h as o,m as I,w as de,P as Ee,Q as Ke,k as Ie,R as We,n as Ge,t as N,a as V,o as u,d as W,C as Le,A as Xe,q as G,r as Ye}from"./index-1jExaXyd.js";import{S as Ze}from"./SdkTabs-AHniCgYQ.js";import{F as et}from"./FieldsQueryParam-0vrvP0gl.js";function Ne(r,l,a){const n=r.slice();return n[5]=l[a],n}function Ve(r,l,a){const n=r.slice();return n[5]=l[a],n}function ze(r,l){let a,n=l[5].code+"",m,_,i,h;function g(){return l[4](l[5])}return{key:r,first:null,c(){a=s("button"),m=k(n),_=p(),b(a,"class","tab-item"),G(a,"active",l[1]===l[5].code),this.first=a},m(v,w){d(v,a,w),o(a,m),o(a,_),i||(h=Ye(a,"click",g),i=!0)},p(v,w){l=v,w&4&&n!==(n=l[5].code+"")&&de(m,n),w&6&&G(a,"active",l[1]===l[5].code)},d(v){v&&u(a),i=!1,h()}}}function Qe(r,l){let a,n,m,_;return n=new Ue({props:{content:l[5].body}}),{key:r,first:null,c(){a=s("div"),K(n.$$.fragment),m=p(),b(a,"class","tab-item"),G(a,"active",l[1]===l[5].code),this.first=a},m(i,h){d(i,a,h),I(n,a,null),o(a,m),_=!0},p(i,h){l=i;const g={};h&4&&(g.content=l[5].body),n.$set(g),(!_||h&6)&&G(a,"active",l[1]===l[5].code)},i(i){_||(N(n.$$.fragment,i),_=!0)},o(i){V(n.$$.fragment,i),_=!1},d(i){i&&u(a),W(n)}}}function tt(r){var De,Fe;let l,a,n=r[0].name+"",m,_,i,h,g,v,w,B,X,S,z,ue,Q,M,pe,Y,U=r[0].name+"",Z,he,fe,j,ee,D,te,T,oe,be,F,C,le,me,ae,_e,f,ke,R,ge,ve,$e,se,ye,ne,Se,we,Te,re,Ce,Pe,A,ie,O,ce,P,H,y=[],Re=new Map,Ae,E,$=[],qe=new Map,q;v=new Ze({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${r[3]}');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import{S as Ee,i as Je,s as Ne,N as Le,O as z,e as o,v as k,b as h,c as I,f as p,g as r,h as a,m as K,w as pe,P as Ue,Q as Qe,k as xe,R as ze,n as Ie,t as L,a as E,o as c,d as G,C as Be,A as Ke,q as X,r as Ge}from"./index-MkGUixqr.js";import{S as Xe}from"./SdkTabs-7yshYvVF.js";import{F as Ye}from"./FieldsQueryParam-N-1EL4Av.js";function Fe(s,l,n){const i=s.slice();return i[5]=l[n],i}function He(s,l,n){const i=s.slice();return i[5]=l[n],i}function je(s,l){let n,i=l[5].code+"",f,g,d,m;function _(){return l[4](l[5])}return{key:s,first:null,c(){n=o("button"),f=k(i),g=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(v,O){r(v,n,O),a(n,f),a(n,g),d||(m=Ge(n,"click",_),d=!0)},p(v,O){l=v,O&4&&i!==(i=l[5].code+"")&&pe(f,i),O&6&&X(n,"active",l[1]===l[5].code)},d(v){v&&c(n),d=!1,m()}}}function Ve(s,l){let n,i,f,g;return i=new Le({props:{content:l[5].body}}),{key:s,first:null,c(){n=o("div"),I(i.$$.fragment),f=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(d,m){r(d,n,m),K(i,n,null),a(n,f),g=!0},p(d,m){l=d;const _={};m&4&&(_.content=l[5].body),i.$set(_),(!g||m&6)&&X(n,"active",l[1]===l[5].code)},i(d){g||(L(i.$$.fragment,d),g=!0)},o(d){E(i.$$.fragment,d),g=!1},d(d){d&&c(n),G(i)}}}function Ze(s){let l,n,i=s[0].name+"",f,g,d,m,_,v,O,P,Y,A,J,me,N,R,be,Z,Q=s[0].name+"",ee,fe,te,M,ae,W,le,U,ne,S,oe,ge,B,y,se,ke,ie,_e,b,ve,C,we,$e,Oe,re,Ae,ce,Se,ye,Te,de,Ce,qe,q,ue,F,he,T,H,$=[],De=new Map,Pe,j,w=[],Re=new Map,D;v=new Xe({props:{js:`
import{S as Ee,i as Je,s as Ne,N as Le,O as z,e as o,v as k,b as h,c as I,f as p,g as r,h as a,m as K,w as pe,P as Ue,Q as Qe,k as xe,R as ze,n as Ie,t as L,a as E,o as c,d as G,C as Be,A as Ke,q as X,r as Ge}from"./index-1jExaXyd.js";import{S as Xe}from"./SdkTabs-AHniCgYQ.js";import{F as Ye}from"./FieldsQueryParam-0vrvP0gl.js";function Fe(s,l,n){const i=s.slice();return i[5]=l[n],i}function He(s,l,n){const i=s.slice();return i[5]=l[n],i}function je(s,l){let n,i=l[5].code+"",f,g,d,m;function _(){return l[4](l[5])}return{key:s,first:null,c(){n=o("button"),f=k(i),g=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(v,O){r(v,n,O),a(n,f),a(n,g),d||(m=Ge(n,"click",_),d=!0)},p(v,O){l=v,O&4&&i!==(i=l[5].code+"")&&pe(f,i),O&6&&X(n,"active",l[1]===l[5].code)},d(v){v&&c(n),d=!1,m()}}}function Ve(s,l){let n,i,f,g;return i=new Le({props:{content:l[5].body}}),{key:s,first:null,c(){n=o("div"),I(i.$$.fragment),f=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(d,m){r(d,n,m),K(i,n,null),a(n,f),g=!0},p(d,m){l=d;const _={};m&4&&(_.content=l[5].body),i.$set(_),(!g||m&6)&&X(n,"active",l[1]===l[5].code)},i(d){g||(L(i.$$.fragment,d),g=!0)},o(d){E(i.$$.fragment,d),g=!1},d(d){d&&c(n),G(i)}}}function Ze(s){let l,n,i=s[0].name+"",f,g,d,m,_,v,O,P,Y,A,J,me,N,R,be,Z,Q=s[0].name+"",ee,fe,te,M,ae,W,le,U,ne,S,oe,ge,B,y,se,ke,ie,_e,b,ve,C,we,$e,Oe,re,Ae,ce,Se,ye,Te,de,Ce,qe,q,ue,F,he,T,H,$=[],De=new Map,Pe,j,w=[],Re=new Map,D;v=new Xe({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${s[3]}');
Expand Down

0 comments on commit b7447f3

Please sign in to comment.