mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
make checkInvite check only one invite, invite daemon
checkInvite no longer loops over all invites and checks for expiry, that functionality has moved to checkInvites. Couple more rogue print statements removed aswell.
This commit is contained in:
parent
dba20bd3ea
commit
4e16f6fd48
84
api.go
84
api.go
@ -76,12 +76,11 @@ func timeDiff(a, b time.Time) (year, month, day, hour, min, sec int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *appContext) checkInvite(code string, used bool, username string) bool {
|
func (ctx *appContext) checkInvites() {
|
||||||
current_time := time.Now()
|
current_time := time.Now()
|
||||||
ctx.storage.loadInvites()
|
ctx.storage.loadInvites()
|
||||||
match := false
|
|
||||||
changed := false
|
changed := false
|
||||||
for invCode, data := range ctx.storage.invites {
|
for code, data := range ctx.storage.invites {
|
||||||
expiry := data.ValidTill
|
expiry := data.ValidTill
|
||||||
if current_time.After(expiry) {
|
if current_time.After(expiry) {
|
||||||
ctx.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
ctx.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
||||||
@ -90,7 +89,7 @@ func (ctx *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
ctx.debug.Printf("%s: Expiry notification", code)
|
ctx.debug.Printf("%s: Expiry notification", code)
|
||||||
for address, settings := range notify {
|
for address, settings := range notify {
|
||||||
if settings["notify-expiry"] {
|
if settings["notify-expiry"] {
|
||||||
if ctx.email.constructExpiry(invCode, data, ctx) != nil {
|
if ctx.email.constructExpiry(code, data, ctx) != nil {
|
||||||
ctx.err.Printf("%s: Failed to construct expiry notification", code)
|
ctx.err.Printf("%s: Failed to construct expiry notification", code)
|
||||||
} else if ctx.email.send(address, ctx) != nil {
|
} else if ctx.email.send(address, ctx) != nil {
|
||||||
ctx.err.Printf("%s: Failed to send expiry notification", code)
|
ctx.err.Printf("%s: Failed to send expiry notification", code)
|
||||||
@ -101,31 +100,62 @@ func (ctx *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
changed = true
|
changed = true
|
||||||
delete(ctx.storage.invites, invCode)
|
delete(ctx.storage.invites, code)
|
||||||
} else if invCode == code {
|
|
||||||
match = true
|
|
||||||
if used {
|
|
||||||
changed = true
|
|
||||||
del := false
|
|
||||||
newInv := data
|
|
||||||
if newInv.RemainingUses == 1 {
|
|
||||||
del = true
|
|
||||||
delete(ctx.storage.invites, invCode)
|
|
||||||
} else if newInv.RemainingUses != 0 {
|
|
||||||
// 0 means infinite i guess?
|
|
||||||
newInv.RemainingUses -= 1
|
|
||||||
}
|
|
||||||
newInv.UsedBy = append(newInv.UsedBy, []string{username, ctx.formatDatetime(current_time)})
|
|
||||||
if !del {
|
|
||||||
ctx.storage.invites[invCode] = newInv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changed {
|
if changed {
|
||||||
ctx.storage.storeInvites()
|
ctx.storage.storeInvites()
|
||||||
}
|
}
|
||||||
return match
|
}
|
||||||
|
|
||||||
|
func (ctx *appContext) checkInvite(code string, used bool, username string) bool {
|
||||||
|
current_time := time.Now()
|
||||||
|
ctx.storage.loadInvites()
|
||||||
|
changed := false
|
||||||
|
if inv, match := ctx.storage.invites[code]; match {
|
||||||
|
expiry := inv.ValidTill
|
||||||
|
if current_time.After(expiry) {
|
||||||
|
ctx.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
||||||
|
notify := inv.Notify
|
||||||
|
if ctx.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
||||||
|
ctx.debug.Printf("%s: Expiry notification", code)
|
||||||
|
for address, settings := range notify {
|
||||||
|
if settings["notify-expiry"] {
|
||||||
|
if ctx.email.constructExpiry(code, inv, ctx) != nil {
|
||||||
|
ctx.err.Printf("%s: Failed to construct expiry notification", code)
|
||||||
|
} else if ctx.email.send(address, ctx) != nil {
|
||||||
|
ctx.err.Printf("%s: Failed to send expiry notification", code)
|
||||||
|
} else {
|
||||||
|
ctx.info.Printf("Sent expiry notification to %s", address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = true
|
||||||
|
match = false
|
||||||
|
delete(ctx.storage.invites, code)
|
||||||
|
} else if used {
|
||||||
|
changed = true
|
||||||
|
del := false
|
||||||
|
newInv := inv
|
||||||
|
if newInv.RemainingUses == 1 {
|
||||||
|
del = true
|
||||||
|
delete(ctx.storage.invites, code)
|
||||||
|
} else if newInv.RemainingUses != 0 {
|
||||||
|
// 0 means infinite i guess?
|
||||||
|
newInv.RemainingUses -= 1
|
||||||
|
}
|
||||||
|
newInv.UsedBy = append(newInv.UsedBy, []string{username, ctx.formatDatetime(current_time)})
|
||||||
|
if !del {
|
||||||
|
ctx.storage.invites[code] = newInv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if changed {
|
||||||
|
ctx.storage.storeInvites()
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routes from now on!
|
// Routes from now on!
|
||||||
@ -270,12 +300,8 @@ func (ctx *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
func (ctx *appContext) GetInvites(gc *gin.Context) {
|
func (ctx *appContext) GetInvites(gc *gin.Context) {
|
||||||
ctx.debug.Println("Invites requested")
|
ctx.debug.Println("Invites requested")
|
||||||
current_time := time.Now()
|
current_time := time.Now()
|
||||||
// checking one checks all of them
|
|
||||||
ctx.storage.loadInvites()
|
ctx.storage.loadInvites()
|
||||||
for key := range ctx.storage.invites {
|
ctx.checkInvites()
|
||||||
ctx.checkInvite(key, false, "")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
var invites []map[string]interface{}
|
var invites []map[string]interface{}
|
||||||
for code, inv := range ctx.storage.invites {
|
for code, inv := range ctx.storage.invites {
|
||||||
_, _, days, hours, minutes, _ := timeDiff(inv.ValidTill, current_time)
|
_, _, days, hours, minutes, _ := timeDiff(inv.ValidTill, current_time)
|
||||||
|
3
auth.go
3
auth.go
@ -16,9 +16,6 @@ func (ctx *appContext) webAuth() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *appContext) authenticate(gc *gin.Context) {
|
func (ctx *appContext) authenticate(gc *gin.Context) {
|
||||||
for _, val := range ctx.users {
|
|
||||||
fmt.Println("userid", val.UserID)
|
|
||||||
}
|
|
||||||
header := strings.SplitN(gc.Request.Header.Get("Authorization"), " ", 2)
|
header := strings.SplitN(gc.Request.Header.Get("Authorization"), " ", 2)
|
||||||
if header[0] != "Basic" {
|
if header[0] != "Basic" {
|
||||||
ctx.debug.Println("Invalid authentication header")
|
ctx.debug.Println("Invalid authentication header")
|
||||||
|
50
daemon.go
Normal file
50
daemon.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// https://bbengfort.github.io/snippets/2016/06/26/background-work-goroutines-timer.html THANKS
|
||||||
|
|
||||||
|
type Repeater struct {
|
||||||
|
Stopped bool
|
||||||
|
ShutdownChannel chan string
|
||||||
|
Interval time.Duration
|
||||||
|
period time.Duration
|
||||||
|
ctx *appContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRepeater(interval time.Duration, ctx *appContext) *Repeater {
|
||||||
|
return &Repeater{
|
||||||
|
Stopped: false,
|
||||||
|
ShutdownChannel: make(chan string),
|
||||||
|
Interval: interval,
|
||||||
|
period: interval,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Repeater) Run() {
|
||||||
|
rt.ctx.info.Println("Invite daemon started")
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-rt.ShutdownChannel:
|
||||||
|
rt.ShutdownChannel <- "Down"
|
||||||
|
return
|
||||||
|
case <-time.After(rt.period):
|
||||||
|
break
|
||||||
|
}
|
||||||
|
started := time.Now()
|
||||||
|
rt.ctx.storage.loadInvites()
|
||||||
|
rt.ctx.debug.Println("Daemon: Checking invites")
|
||||||
|
rt.ctx.checkInvites()
|
||||||
|
finished := time.Now()
|
||||||
|
duration := finished.Sub(started)
|
||||||
|
rt.period = rt.Interval - duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Repeater) Shutdown() {
|
||||||
|
rt.Stopped = true
|
||||||
|
rt.ShutdownChannel <- "Down"
|
||||||
|
<-rt.ShutdownChannel
|
||||||
|
close(rt.ShutdownChannel)
|
||||||
|
}
|
40
email.go
40
email.go
@ -73,7 +73,6 @@ func (email *Emailer) constructInvite(code string, invite Invite, ctx *appContex
|
|||||||
fpath := ctx.config.Section("invite_emails").Key("email_" + key).String()
|
fpath := ctx.config.Section("invite_emails").Key("email_" + key).String()
|
||||||
tpl, err := template.ParseFiles(fpath)
|
tpl, err := template.ParseFiles(fpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("failed email", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var tplData bytes.Buffer
|
var tplData bytes.Buffer
|
||||||
@ -85,7 +84,6 @@ func (email *Emailer) constructInvite(code string, invite Invite, ctx *appContex
|
|||||||
"message": message,
|
"message": message,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("failed email", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if key == "html" {
|
if key == "html" {
|
||||||
@ -105,7 +103,6 @@ func (email *Emailer) constructExpiry(code string, invite Invite, ctx *appContex
|
|||||||
fpath := ctx.config.Section("notifications").Key("expiry_" + key).String()
|
fpath := ctx.config.Section("notifications").Key("expiry_" + key).String()
|
||||||
tpl, err := template.ParseFiles(fpath)
|
tpl, err := template.ParseFiles(fpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("failed email", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var tplData bytes.Buffer
|
var tplData bytes.Buffer
|
||||||
@ -114,7 +111,6 @@ func (email *Emailer) constructExpiry(code string, invite Invite, ctx *appContex
|
|||||||
"expiry": expiry,
|
"expiry": expiry,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("failed email", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if key == "html" {
|
if key == "html" {
|
||||||
@ -140,7 +136,6 @@ func (email *Emailer) constructCreated(code, username, address string, invite In
|
|||||||
fpath := ctx.config.Section("notifications").Key("created_" + key).String()
|
fpath := ctx.config.Section("notifications").Key("created_" + key).String()
|
||||||
tpl, err := template.ParseFiles(fpath)
|
tpl, err := template.ParseFiles(fpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("failed email", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var tplData bytes.Buffer
|
var tplData bytes.Buffer
|
||||||
@ -151,7 +146,6 @@ func (email *Emailer) constructCreated(code, username, address string, invite In
|
|||||||
"time": created,
|
"time": created,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("failed email", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if key == "html" {
|
if key == "html" {
|
||||||
@ -166,33 +160,6 @@ func (email *Emailer) constructCreated(code, username, address string, invite In
|
|||||||
|
|
||||||
func (email *Emailer) send(address string, ctx *appContext) error {
|
func (email *Emailer) send(address string, ctx *appContext) error {
|
||||||
if email.sendMethod == "mailgun" {
|
if email.sendMethod == "mailgun" {
|
||||||
// reqData := map[string]string{
|
|
||||||
// "to": fmt.Sprintf("%s <%s>", "test", email.to),
|
|
||||||
// "from": email.fromAddr,
|
|
||||||
// "subject": email.subject,
|
|
||||||
// }
|
|
||||||
// if email.sendType == "invite" {
|
|
||||||
// reqData["text"] = email.invite.text
|
|
||||||
// reqData["html"] = email.invite.html
|
|
||||||
// }
|
|
||||||
// data := &bytes.Buffer{}
|
|
||||||
// encoder := json.NewEncoder(data)
|
|
||||||
// encoder.SetEscapeHTML(false)
|
|
||||||
// err := encoder.Encode(reqData)
|
|
||||||
// fmt.Println("marshaled:", data)
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Println("Failed marshal:", err, ">", data)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// var req *http.Request
|
|
||||||
// req, err = http.NewRequest("POST", ctx.config.Section("mailgun").Key("api_url").String(), data)
|
|
||||||
// req.SetBasicAuth("api", ctx.config.Section("mailgun").Key("api_key").String())
|
|
||||||
// var resp *http.Response
|
|
||||||
// resp, err = email.httpClient.Do(req)
|
|
||||||
// if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 204) {
|
|
||||||
// fmt.Println("failed send:", err, resp.StatusCode)
|
|
||||||
// fmt.Println("resp:", resp.Header.Get("Content-Encoding"), resp.Body)
|
|
||||||
// }
|
|
||||||
message := email.mg.NewMessage(
|
message := email.mg.NewMessage(
|
||||||
fmt.Sprintf("%s <%s>", email.fromName, email.fromAddr),
|
fmt.Sprintf("%s <%s>", email.fromName, email.fromAddr),
|
||||||
email.content.subject,
|
email.content.subject,
|
||||||
@ -201,9 +168,10 @@ func (email *Emailer) send(address string, ctx *appContext) error {
|
|||||||
message.SetHtml(email.content.html)
|
message.SetHtml(email.content.html)
|
||||||
mgctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
mgctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
_, id, err := email.mg.Send(mgctx, message)
|
_, _, err := email.mg.Send(mgctx, message)
|
||||||
fmt.Println("mailgun:", id, err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
4
main.go
4
main.go
@ -13,6 +13,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Username is JWT!
|
// Username is JWT!
|
||||||
@ -193,6 +194,9 @@ func main() {
|
|||||||
|
|
||||||
ctx.email.init(ctx)
|
ctx.email.init(ctx)
|
||||||
|
|
||||||
|
inviteDaemon := NewRepeater(time.Duration(60*time.Second), ctx)
|
||||||
|
go inviteDaemon.Run()
|
||||||
|
|
||||||
ctx.info.Println("Loading routes")
|
ctx.info.Println("Loading routes")
|
||||||
router := gin.New()
|
router := gin.New()
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -78,8 +77,6 @@ func loadJSON(path string, obj interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func storeJSON(path string, obj interface{}) error {
|
func storeJSON(path string, obj interface{}) error {
|
||||||
test := json.NewEncoder(os.Stdout)
|
|
||||||
test.Encode(obj)
|
|
||||||
data, err := json.Marshal(obj)
|
data, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user