diff --git a/cmd/review/email.go b/cmd/review/email.go index 70412e9..d0b304a 100644 --- a/cmd/review/email.go +++ b/cmd/review/email.go @@ -1,8 +1,67 @@ package main -// TODO function for reading smtp.pw from /town/docs +import ( + "errors" + "fmt" + "os" -func sendInviteEmail() error { - // TODO - return nil + "git.tilde.town/tildetown/town/email" + "git.tilde.town/tildetown/town/invites" +) + +const emailText = `hello! + +You applied to https://tilde.town at some point and your application has been approved ^_^ + +Your invite code is: %s + +To redeem your code, please open a terminal and run: + +ssh welcome@tilde.town + +You'll fill in details like your desired username and SSH public key. + +If you're brand new to SSH or have never heard of it that is okay! + +This page has information on what SSH is and how to use it, including how to create an ssh key pair which you'll need to access your town account: https://tilde.town/wiki/getting-started/ssh.html + +If you run into confusion or problems creating a key pair on your computer, this page can generate one for you: https://tilde.town/keymachine . However you'll still need to save the generated key files to your computer in order to use them. + +If you end up stuck, e-mail root@tilde.town with any questions. + +See you on the server, +~vilmibm` + +func loadPassword() (string, error) { + f, err := os.Open("/town/docs/smtp.pw") + if err != nil { + return "", err + } + + pw := make([]byte, 100) + + n, err := f.Read(pw) + if err != nil { + return "", err + } + if n == 0 { + return "", errors.New("read nothing") + } + + return string(pw[0:n]), nil +} + +func sendInviteEmail(invite invites.Invite) error { + pw, err := loadPassword() + if err != nil { + return fmt.Errorf("could not read password: %w", err) + } + + body := fmt.Sprintf(emailText, invite.Code) + + mailer := email.NewExternalMailer(pw) + return mailer.Send( + invite.Email, + "your tilde.town application was accepted", + body) } diff --git a/cmd/review/main.go b/cmd/review/main.go index 5025719..ec62955 100644 --- a/cmd/review/main.go +++ b/cmd/review/main.go @@ -263,15 +263,16 @@ func _main() error { updateCount() render() if decision == models.SignupAccepted { - if err = invites.InsertInvite(inviteDB, currSignup.CleanEmail); err != nil { + invite := &invites.Invite{ + Email: currSignup.CleanEmail, + } + + if err = invite.Insert(inviteDB); err != nil { errorModal.SetText(fmt.Sprintf("error! failed to create invite: %s", err.Error())) pages.SwitchToPage("error") } - // TODO need to get an invite back from InsertInvite so we can send it to - // the clean email using sendInviteEmail - - if err = sendInviteEmail(); err != nil { + if err = sendInviteEmail(*invite); err != nil { errorModal.SetText(fmt.Sprintf("error! failed to send welcome email: %s", err.Error())) pages.SwitchToPage("error") } diff --git a/cmd/signup/main.go b/cmd/signup/main.go index 6c355dc..0165ded 100644 --- a/cmd/signup/main.go +++ b/cmd/signup/main.go @@ -262,7 +262,8 @@ func _main(l *log.Logger, db *sql.DB) error { newScene("done", heredoc.Doc(` thank you for applying to tilde.town! - please be on the look out for an email from [-:-:b]root@tilde.town[-:-:-] + please be on the look out for an email from [-:-:b]root@tilde.town[-:-:-]. + it's almost certain that it will end up in your spam filter, unfortunately. you can [-:-:b]/quit[-:-:-] now diff --git a/email/email.go b/email/email.go index 1a96684..fff69dd 100644 --- a/email/email.go +++ b/email/email.go @@ -9,9 +9,9 @@ import ( ) const ( - SMTPlogin = "root@tilde.town" - SMTPHost = "smtp.zoho.com" - SMTPPort = 465 + from = "root@tilde.town" + SMTPHost = "smtp.zoho.com" + SMTPPort = 465 ) func SendLocalEmail(username, subject, body string) error { @@ -39,8 +39,19 @@ func NewExternalMailer(pw string) *ExternalMailer { } func (m *ExternalMailer) Send(address, subject, body string) error { - // TODO need to add headers to prepare message - auth := smtp.PlainAuth("", SMTPlogin, m.Password, SMTPHost) + headers := map[string]string{ + "From": from, + "To": address, + "Subject": subject, + } + + message := "" + for k, v := range headers { + message += fmt.Sprintf("%s: %s\r\n", k, v) + } + message += "\r\n" + body + + auth := smtp.PlainAuth("", from, m.Password, SMTPHost) server := fmt.Sprintf("%s:%d", SMTPHost, SMTPPort) diff --git a/invites/invites.go b/invites/invites.go index 2cd9f6d..16d79c2 100644 --- a/invites/invites.go +++ b/invites/invites.go @@ -24,6 +24,23 @@ type Invite struct { Used bool } +func (i *Invite) Insert(db *sql.DB) error { + stmt, err := db.Prepare(` + INSERT INTO invites (code, email) VALUES (?, ?) + `) + if err != nil { + return err + } + + _, err = stmt.Exec(generateCode(i.Email), i.Email) + if err != nil { + return err + } + defer stmt.Close() + + return nil +} + func ConnectDB() (*sql.DB, error) { db, err := sql.Open("sqlite3", dsn) if err != nil { @@ -66,23 +83,6 @@ func Decode(code string) ([]string, error) { return strings.Split(string(decoded), " "), nil } -func InsertInvite(db *sql.DB, email string) error { - stmt, err := db.Prepare(` - INSERT INTO invites (code, email) VALUES (?, ?) - `) - if err != nil { - return err - } - - _, err = stmt.Exec(generateCode(email), email) - if err != nil { - return err - } - defer stmt.Close() - - return nil -} - func Get(db *sql.DB, code string) (*Invite, error) { inv := &Invite{ Code: code,