finish form part, next make user account

pull/1/head
vilmibm 2023-03-03 21:14:22 +00:00
parent f28da14d98
commit 28ac63f256
2 changed files with 89 additions and 31 deletions

View File

@ -44,13 +44,58 @@ func promptCode() (code string, err error) {
return return
} }
func promptUsername(townData stats.TildeData) (un string, err error) { func confirmContinue() (conf bool, err error) {
err = survey.AskOne(
&survey.Confirm{
Message: "Does the above look ok?",
}, &conf,
survey.WithValidator(survey.Required),
survey.WithIcons(surveyIconSet))
return
}
type asker struct {
UserData *newUserData
Style lipgloss.Style
Invite invites.Invite
TownData stats.TildeData
}
func (a *asker) Ask() (err error) {
// TODO somehow un and email getting set to "" but pubkey works fine?
if err = a.promptUsername(); err != nil {
return err
}
if err = a.promptEmail(); err != nil {
return err
}
if err = a.promptKey(); err != nil {
return err
}
s := a.Style.SetString(
fmt.Sprintf(`ok! your account is about to be created with the following details:
username: %s
email: %s
pubkey: %s`, a.UserData.Username, a.UserData.Email, a.UserData.PubKey)).Bold(true).MaxWidth(80)
fmt.Println(s)
return nil
}
func (a *asker) promptUsername() (err error) {
// copied from /etc/adduser.conf // copied from /etc/adduser.conf
usernameRE := regexp.MustCompile(`^[a-z][-a-z0-9_]*$`) usernameRE := regexp.MustCompile(`^[a-z][-a-z0-9_]*$`)
err = survey.AskOne( err = survey.AskOne(
&survey.Input{ &survey.Input{
Message: "desired username?", Message: "desired username?",
}, &un, Default: a.UserData.Username,
}, &a.UserData.Username,
survey.WithValidator(survey.Required), survey.WithValidator(survey.Required),
survey.WithIcons(surveyIconSet), survey.WithIcons(surveyIconSet),
survey.WithValidator(func(val interface{}) error { survey.WithValidator(func(val interface{}) error {
@ -58,7 +103,6 @@ func promptUsername(townData stats.TildeData) (un string, err error) {
if len(un) > 32 { if len(un) > 32 {
return fmt.Errorf("username '%s' is too long", un) return fmt.Errorf("username '%s' is too long", un)
} }
return nil return nil
}), }),
survey.WithValidator(func(val interface{}) error { survey.WithValidator(func(val interface{}) error {
@ -66,12 +110,11 @@ func promptUsername(townData stats.TildeData) (un string, err error) {
if !usernameRE.MatchString(un) { if !usernameRE.MatchString(un) {
return errors.New("usernames must start with a letter and only contain letters, nubers, - or _") return errors.New("usernames must start with a letter and only contain letters, nubers, - or _")
} }
return nil return nil
}), }),
survey.WithValidator(func(val interface{}) error { survey.WithValidator(func(val interface{}) error {
un := val.(string) un := val.(string)
for _, v := range townData.Users { for _, v := range a.TownData.Users {
if v.Username == un { if v.Username == un {
return fmt.Errorf("username '%s' is already in use", un) return fmt.Errorf("username '%s' is already in use", un)
} }
@ -79,15 +122,15 @@ func promptUsername(townData stats.TildeData) (un string, err error) {
return nil return nil
})) }))
return "", nil return
} }
func promptEmail(defaultEmail string) (email string, err error) { func (a *asker) promptEmail() (err error) {
err = survey.AskOne( err = survey.AskOne(
&survey.Input{ &survey.Input{
Message: "e-mail (for account recovery only)?", Message: "e-mail (for account recovery only)?",
Default: defaultEmail, Default: a.UserData.Email,
}, &email, }, &a.UserData.Email,
survey.WithValidator(survey.Required), survey.WithValidator(survey.Required),
survey.WithIcons(surveyIconSet), survey.WithIcons(surveyIconSet),
survey.WithValidator(func(val interface{}) error { survey.WithValidator(func(val interface{}) error {
@ -104,14 +147,15 @@ func promptEmail(defaultEmail string) (email string, err error) {
return nil return nil
})) }))
return "", nil return
} }
func promptKey() (key string, err error) { func (a *asker) promptKey() (err error) {
err = survey.AskOne( err = survey.AskOne(
&survey.Input{ &survey.Input{
Message: "SSH public key?", Message: "SSH public key?",
}, &key, Default: a.UserData.PubKey,
}, &a.UserData.PubKey,
survey.WithValidator(survey.Required), survey.WithValidator(survey.Required),
survey.WithIcons(surveyIconSet), survey.WithIcons(surveyIconSet),
survey.WithValidator(func(v interface{}) error { survey.WithValidator(func(v interface{}) error {
@ -120,11 +164,9 @@ func promptKey() (key string, err error) {
if err != nil { if err != nil {
return fmt.Errorf("failed to validate key: %w", err) return fmt.Errorf("failed to validate key: %w", err)
} }
if !valid { if !valid {
return errors.New("that doesn't seem like a valid SSH key. try another public key?") return errors.New("that doesn't seem like a valid SSH key. try another public key?")
} }
return nil return nil
})) }))
@ -132,18 +174,11 @@ func promptKey() (key string, err error) {
} }
func _main() error { func _main() error {
townData, err := stats.Stats()
if err != nil {
return err
}
inviteDB, err := invites.ConnectDB() inviteDB, err := invites.ConnectDB()
if err != nil { if err != nil {
return err return err
} }
data := &newUserData{}
s := lipgloss.NewStyle(). s := lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{ Foreground(lipgloss.AdaptiveColor{
Light: "#7D19BD", Light: "#7D19BD",
@ -171,22 +206,43 @@ func _main() error {
fmt.Println(s) fmt.Println(s)
data.Username, err = promptUsername(townData) townData, err := stats.Stats()
if err != nil {
return err
}
data := &newUserData{
Email: invite.Email,
}
a := &asker{
UserData: data,
Invite: *invite,
TownData: townData,
Style: s,
}
if err = a.Ask(); err != nil {
return err
}
conf, err := confirmContinue()
if err != nil { if err != nil {
return err return err
} }
data.Email, err = promptEmail(invite.Email) if !conf {
if err != nil { for !conf {
if err = a.Ask(); err != nil {
return err return err
} }
if conf, err = confirmContinue(); err != nil {
data.PubKey, err = promptKey()
if err != nil {
return err return err
} }
}
}
// TODO should I allow a review+edit step? s = s.SetString("cool, awesome, going to make your account now...")
fmt.Println(s)
// TODO have enough to make account; can now do that // TODO have enough to make account; can now do that
// TODO assuming account creation succeeded, mark invite as used // TODO assuming account creation succeeded, mark invite as used

View File

@ -16,6 +16,8 @@ import (
"time" "time"
) )
// TODO FIX LOGGING TO STDOUT (move this to the cmd)
const defaultIndexPath = "/etc/skel/public_html/index.html" const defaultIndexPath = "/etc/skel/public_html/index.html"
const description = `an intentional digital community for creating and sharing const description = `an intentional digital community for creating and sharing
works of art, peer education, and technological anachronism. we are works of art, peer education, and technological anachronism. we are