email accepted users

trunk
vilmibm 2023-03-09 06:33:31 +00:00
parent cee8b75bad
commit c43adc49fb
5 changed files with 104 additions and 32 deletions

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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

View File

@ -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)

View File

@ -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,