2024-11-05 21:12:17 +02:00
package apis
import (
"database/sql"
"errors"
"fmt"
"os"
"os/exec"
"runtime"
2024-11-06 18:20:48 +02:00
"strings"
2024-11-05 21:12:17 +02:00
"time"
"github.com/fatih/color"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/security"
)
2024-11-06 18:20:48 +02:00
// @todo consider combining with the installer specific hooks after refactoring cmd
func loadInstaller ( app core . App , dashboardURL string ) error {
2024-11-05 21:12:17 +02:00
if ! needInstallerSuperuser ( app ) {
return nil
}
installerRecord , err := findOrCreateInstallerSuperuser ( app )
if err != nil {
return err
}
token , err := installerRecord . NewStaticAuthToken ( 30 * time . Minute )
if err != nil {
return err
}
// launch url (ignore errors and always print a help text as fallback)
2024-11-06 18:20:48 +02:00
url := fmt . Sprintf ( "%s/#/pbinstal/%s" , strings . TrimRight ( dashboardURL , "/" ) , token )
2024-11-05 21:12:17 +02:00
_ = launchURL ( url )
color . Magenta ( "\n(!) Launch the URL below in the browser if it hasn't been open already to create your first superuser account:" )
color . New ( color . Bold ) . Add ( color . FgCyan ) . Println ( url )
2024-11-06 18:20:48 +02:00
color . New ( color . FgHiBlack , color . Italic ) . Printf ( "(you can also create your first superuser account by running '%s superuser upsert test@example.com yourpass')\n" , os . Args [ 0 ] )
2024-11-05 21:12:17 +02:00
return nil
}
func needInstallerSuperuser ( app core . App ) bool {
total , err := app . CountRecords ( core . CollectionNameSuperusers , dbx . Not ( dbx . HashExp {
2024-11-06 14:22:57 +02:00
"email" : core . DefaultInstallerEmail ,
2024-11-05 21:12:17 +02:00
} ) )
2024-11-06 18:20:48 +02:00
2024-11-05 21:12:17 +02:00
return err == nil && total == 0
}
func findOrCreateInstallerSuperuser ( app core . App ) ( * core . Record , error ) {
col , err := app . FindCachedCollectionByNameOrId ( core . CollectionNameSuperusers )
if err != nil {
return nil , err
}
2024-11-06 14:22:57 +02:00
record , err := app . FindAuthRecordByEmail ( col , core . DefaultInstallerEmail )
2024-11-05 21:12:17 +02:00
if err != nil {
if ! errors . Is ( err , sql . ErrNoRows ) {
return nil , err
}
record = core . NewRecord ( col )
2024-11-06 14:22:57 +02:00
record . SetEmail ( core . DefaultInstallerEmail )
2024-11-05 21:12:17 +02:00
record . SetPassword ( security . RandomString ( 30 ) )
err = app . Save ( record )
if err != nil {
return nil , err
}
}
return record , nil
}
func launchURL ( url string ) error {
if err := is . URL . Validate ( url ) ; err != nil {
return err
}
switch runtime . GOOS {
case "darwin" :
return exec . Command ( "open" , url ) . Start ( )
case "windows" :
// not sure if this is the best command but seems to be the most reliable based on the comments in
// https://stackoverflow.com/questions/3739327/launching-a-website-via-the-windows-commandline#answer-49115945
return exec . Command ( "rundll32" , "url.dll,FileProtocolHandler" , url ) . Start ( )
default : // linux, freebsd, etc.
return exec . Command ( "xdg-open" , url ) . Start ( )
}
}