mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-19 18:15:08 +00:00
Let a client account expire on a date
Staff can give a client an expiry date on the create and edit screens, and through /api/v1/clients. When the date passes, the client is refused at sign-in and on their next request, and their API access ends too. Files and history stay, and a later date (or none) brings them back. Access is checked through one predicate, User::maySignIn(), at every door: sign-in, the web session, API tokens and the two-factor challenge. An hourly sweep also switches `active` off, so the list, its filter and seat counts agree. The sweep is not what enforces it, so a scheduler that is not running cannot keep an account open. An account cannot be active with a date that has passed. Reactivating an expired client needs a new date in the same save. The day-means-end-of-day-where-you-are rule moved out of FileExpiry into a shared DateInput, so file and account expiry read dates the same way. Requested by @Drardollan in #1310.
This commit is contained in:
@@ -808,6 +808,14 @@
|
||||
],
|
||||
"minimum": 0
|
||||
},
|
||||
"expires_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time",
|
||||
"description": "When the account stops working; omit or send null for never.\nA bare date (`2026-12-31`) means the end of that day in the\ntoken owner's timezone; a full timestamp is used as given.\nMust be in the future."
|
||||
},
|
||||
"custom_field_values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -945,6 +953,14 @@
|
||||
],
|
||||
"minimum": 0
|
||||
},
|
||||
"expires_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time",
|
||||
"description": "Send null to remove the expiry. Read the same way as on\ncreate. An account cannot be active with a date that has\npassed, so reactivating an expired client needs a new date\n(or null) in the same request."
|
||||
},
|
||||
"custom_field_values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -3534,6 +3550,7 @@
|
||||
"client.invitation_redeemed",
|
||||
"client.invitation_revoked",
|
||||
"client.invitation_resent",
|
||||
"client.expired",
|
||||
"file.uploaded",
|
||||
"file.updated",
|
||||
"file.deleted",
|
||||
@@ -3730,6 +3747,13 @@
|
||||
"type": "boolean",
|
||||
"description": "Whether, not what: the state of the second factor is what a\ncaller needs to see before removing it. The secret and the\nrecovery codes stay where they are."
|
||||
},
|
||||
"expires_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Null when the account never expires. Once this passes the\nclient can no longer sign in, and `active` turns false within\nthe hour."
|
||||
},
|
||||
"created_at": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -3810,6 +3834,7 @@
|
||||
"active",
|
||||
"account_requested",
|
||||
"two_factor_enabled",
|
||||
"expires_at",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"storage",
|
||||
|
||||
Reference in New Issue
Block a user