1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-22 17:10:10 +00:00

expiry: add option to delete after n days

Much like activities, you can have an expired account disabled, then
deleted after n days (unless the admin intervenes and re-enables the
account).

For #341.
This commit is contained in:
Harvey Tindall 2024-08-05 13:56:34 +01:00
parent 3c3297c8e7
commit 86c37fb423
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
3 changed files with 83 additions and 66 deletions

View File

@ -1797,6 +1797,15 @@
"value": "disable_user", "value": "disable_user",
"description": "Whether to delete or disable users on expiry." "description": "Whether to delete or disable users on expiry."
}, },
"delete_expired_after_days": {
"name": "Delete expired accounts after (days)",
"required": false,
"requires_restart": false,
"type": "number",
"value": 0,
"depends_true": "behaviour",
"description": "When set, user accounts will be deleted this many days after expiring (if \"Behaviour\" is \"Disable user\"). Set to 0 to disable."
},
"send_email": { "send_email": {
"name": "Send email", "name": "Send email",
"required": false, "required": false,

View File

@ -65,6 +65,7 @@ type Activity struct {
type UserExpiry struct { type UserExpiry struct {
JellyfinID string `badgerhold:"key"` JellyfinID string `badgerhold:"key"`
Expiry time.Time Expiry time.Time
DeleteAfterPeriod bool // Whether or not to further disable the user later on
} }
type DebugLogAction int type DebugLogAction int

View File

@ -22,6 +22,7 @@ func (app *appContext) checkUsers() {
if len(app.storage.GetUserExpiries()) == 0 { if len(app.storage.GetUserExpiries()) == 0 {
return return
} }
app.info.Println(lm.CheckUserExpiries) app.info.Println(lm.CheckUserExpiries)
users, status, err := app.jf.GetUsers(false) users, status, err := app.jf.GetUsers(false)
if err != nil || status != 200 { if err != nil || status != 200 {
@ -29,40 +30,36 @@ func (app *appContext) checkUsers() {
return return
} }
mode := "disable" mode := "disable"
phrase := lm.DisableExpiredUser
if app.config.Section("user_expiry").Key("behaviour").MustString("disable_user") == "delete_user" { if app.config.Section("user_expiry").Key("behaviour").MustString("disable_user") == "delete_user" {
mode = "delete" mode = "delete"
phrase = lm.DeleteExpiredUser
} }
deleteAfterPeriod := app.config.Section("user_expiry").Key("delete_expired_after_days").MustInt(0)
if mode == "delete" {
deleteAfterPeriod = 0
}
contact := false contact := false
if messagesEnabled && app.config.Section("user_expiry").Key("send_email").MustBool(true) { if messagesEnabled && app.config.Section("user_expiry").Key("send_email").MustBool(true) {
contact = true contact = true
} }
// Use a map to speed up checking for deleted users later // Use a map to speed up checking for deleted users later
userExists := map[string]bool{} userExists := map[string]mediabrowser.User{}
for _, user := range users { for _, user := range users {
userExists[user.ID] = true userExists[user.ID] = user
} }
for _, expiry := range app.storage.GetUserExpiries() { for _, expiry := range app.storage.GetUserExpiries() {
id := expiry.JellyfinID id := expiry.JellyfinID
if _, ok := userExists[id]; !ok { user, ok := userExists[id]
if !ok {
app.info.Printf(lm.DeleteExpiryForOldUser, id) app.info.Printf(lm.DeleteExpiryForOldUser, id)
app.storage.DeleteUserExpiryKey(expiry.JellyfinID) 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.storage.DeleteUserExpiryKey(expiry.JellyfinID)
continue continue
} }
app.info.Printf(phrase, user.Name) if !time.Now().After(expiry.Expiry) {
continue
}
deleteUserLater := deleteAfterPeriod != 0 && expiry.DeleteAfterPeriod
// Record activity // Record activity
activity := Activity{ activity := Activity{
@ -71,7 +68,10 @@ func (app *appContext) checkUsers() {
Time: time.Now(), Time: time.Now(),
} }
if mode == "delete" { deleteUserNow := deleteUserLater && time.Now().After(expiry.Expiry.AddDate(0, 0, deleteAfterPeriod))
if mode == "delete" || deleteUserNow {
app.info.Printf(lm.DeleteExpiredUser, user.Name)
deleted := false deleted := false
err, deleted = app.DeleteUser(user) err, deleted = app.DeleteUser(user)
// Silence unimportant errors // Silence unimportant errors
@ -81,7 +81,8 @@ func (app *appContext) checkUsers() {
activity.Type = ActivityDeletion activity.Type = ActivityDeletion
// Store the user name, since there's no longer a user ID to reference back to // Store the user name, since there's no longer a user ID to reference back to
activity.Value = user.Name activity.Value = user.Name
} else if mode == "disable" { } else if mode == "disable" && !deleteUserLater {
app.info.Printf(lm.DisableExpiredUser, user.Name)
// Admins can't be disabled // Admins can't be disabled
// so they're not an admin anymore, sorry // so they're not an admin anymore, sorry
user.Policy.IsAdministrator = false user.Policy.IsAdministrator = false
@ -95,7 +96,14 @@ func (app *appContext) checkUsers() {
app.storage.SetActivityKey(shortuuid.New(), activity, nil, false) app.storage.SetActivityKey(shortuuid.New(), activity, nil, false)
app.storage.DeleteUserExpiryKey(expiry.JellyfinID) // If the we're not gonna be deleting the user later, we don't need this.
// also, if the admin re-enabled the user, we should get rid of the countdown.
if deleteAfterPeriod <= 0 || mode == "delete" || deleteUserNow || (deleteUserLater && !user.Policy.IsDisabled) {
app.storage.DeleteUserExpiryKey(user.ID)
} else if deleteAfterPeriod > 0 && !deleteUserLater {
expiry.DeleteAfterPeriod = true
app.storage.SetUserExpiryKey(user.ID, expiry)
}
app.jf.CacheExpiry = time.Now() app.jf.CacheExpiry = time.Now()
if contact { if contact {
if !ok { if !ok {
@ -106,11 +114,10 @@ func (app *appContext) checkUsers() {
if err != nil { if err != nil {
app.err.Printf(lm.FailedConstructExpiryMessage, user.ID, err) app.err.Printf(lm.FailedConstructExpiryMessage, user.ID, err)
} else if err := app.sendByID(msg, user.ID); err != nil { } else if err := app.sendByID(msg, user.ID); err != nil {
app.err.Printf(lm.FailedConstructExpiryMessage, user.ID, name, err) app.err.Printf(lm.FailedSendExpiryMessage, user.ID, name, err)
} else { } else {
app.err.Printf(lm.SentExpiryMessage, user.ID, name) app.err.Printf(lm.SentExpiryMessage, user.ID, name)
} }
} }
} }
}
} }