1032e4e747
fixed some missing data (being stored and being shown), improved layout, also usernames are now injected by the route.
143 lines
3.6 KiB
Go
143 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/hrfee/mediabrowser"
|
|
"github.com/lithammer/shortuuid/v3"
|
|
)
|
|
|
|
type userDaemon struct {
|
|
Stopped bool
|
|
ShutdownChannel chan string
|
|
Interval time.Duration
|
|
period time.Duration
|
|
app *appContext
|
|
}
|
|
|
|
func newUserDaemon(interval time.Duration, app *appContext) *userDaemon {
|
|
return &userDaemon{
|
|
Stopped: false,
|
|
ShutdownChannel: make(chan string),
|
|
Interval: interval,
|
|
period: interval,
|
|
app: app,
|
|
}
|
|
}
|
|
|
|
func (rt *userDaemon) run() {
|
|
rt.app.info.Println("User daemon started")
|
|
for {
|
|
select {
|
|
case <-rt.ShutdownChannel:
|
|
rt.ShutdownChannel <- "Down"
|
|
return
|
|
case <-time.After(rt.period):
|
|
break
|
|
}
|
|
started := time.Now()
|
|
rt.app.checkUsers()
|
|
finished := time.Now()
|
|
duration := finished.Sub(started)
|
|
rt.period = rt.Interval - duration
|
|
}
|
|
}
|
|
|
|
func (rt *userDaemon) shutdown() {
|
|
rt.Stopped = true
|
|
rt.ShutdownChannel <- "Down"
|
|
<-rt.ShutdownChannel
|
|
close(rt.ShutdownChannel)
|
|
}
|
|
|
|
func (app *appContext) checkUsers() {
|
|
if len(app.storage.GetUserExpiries()) == 0 {
|
|
return
|
|
}
|
|
app.info.Println("Daemon: Checking for user expiry")
|
|
users, status, err := app.jf.GetUsers(false)
|
|
if err != nil || status != 200 {
|
|
app.err.Printf("Failed to get users (%d): %s", status, err)
|
|
return
|
|
}
|
|
mode := "disable"
|
|
term := "Disabling"
|
|
if app.config.Section("user_expiry").Key("behaviour").MustString("disable_user") == "delete_user" {
|
|
mode = "delete"
|
|
term = "Deleting"
|
|
}
|
|
contact := false
|
|
if messagesEnabled && app.config.Section("user_expiry").Key("send_email").MustBool(true) {
|
|
contact = true
|
|
}
|
|
// Use a map to speed up checking for deleted users later
|
|
userExists := map[string]bool{}
|
|
for _, user := range users {
|
|
userExists[user.ID] = true
|
|
}
|
|
for _, expiry := range app.storage.GetUserExpiries() {
|
|
id := expiry.JellyfinID
|
|
if _, ok := userExists[id]; !ok {
|
|
app.info.Printf("Deleting expiry for non-existent user \"%s\"", id)
|
|
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
|
|
} else if time.Now().After(expiry.Expiry) {
|
|
found := false
|
|
var user mediabrowser.User
|
|
for _, u := range users {
|
|
if u.ID == id {
|
|
found = true
|
|
user = u
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
app.info.Printf("Expired user already deleted, ignoring.")
|
|
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
|
|
continue
|
|
}
|
|
app.info.Printf("%s expired user \"%s\"", term, user.Name)
|
|
|
|
// Record activity
|
|
activity := Activity{
|
|
UserID: id,
|
|
SourceType: ActivityDaemon,
|
|
Time: time.Now(),
|
|
}
|
|
|
|
if mode == "delete" {
|
|
status, err = app.jf.DeleteUser(id)
|
|
activity.Type = ActivityDeletion
|
|
} else if mode == "disable" {
|
|
user.Policy.IsDisabled = true
|
|
// Admins can't be disabled
|
|
user.Policy.IsAdministrator = false
|
|
status, err = app.jf.SetPolicy(id, user.Policy)
|
|
activity.Type = ActivityDisabled
|
|
}
|
|
if !(status == 200 || status == 204) || err != nil {
|
|
app.err.Printf("Failed to %s \"%s\" (%d): %s", mode, user.Name, status, err)
|
|
continue
|
|
}
|
|
|
|
app.storage.SetActivityKey(shortuuid.New(), activity)
|
|
|
|
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
|
|
app.jf.CacheExpiry = time.Now()
|
|
if contact {
|
|
if !ok {
|
|
continue
|
|
}
|
|
name := app.getAddressOrName(user.ID)
|
|
msg, err := app.email.constructUserExpired(app, false)
|
|
if err != nil {
|
|
app.err.Printf("Failed to construct expiry message for \"%s\": %s", user.Name, err)
|
|
} else if err := app.sendByID(msg, user.ID); err != nil {
|
|
app.err.Printf("Failed to send expiry message to \"%s\": %s", name, err)
|
|
} else {
|
|
app.info.Printf("Sent expiry notification to \"%s\"", name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|