Skip to content

Commit

Permalink
Allow to disable users instead of deleting them.
Browse files Browse the repository at this point in the history
Add new config parameters for disabling normal and guest users and
allow to configure them in the settings UI.

Fixes: #31

Signed-off-by: Jonas <jonas@freesources.org>
  • Loading branch information
mejo- authored and nickvergessen committed Mar 20, 2023
1 parent e5a3a1b commit 83d9794
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
43 changes: 42 additions & 1 deletion lib/Service/RetentionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ class RetentionService {
protected IFactory $l10nFactory;
protected LoggerInterface $logger;

protected int $userDaysDisable = 0;
protected int $userDisableMaxLastLogin = 0;
protected int $userDays = 0;
protected int $userMaxLastLogin = 0;
protected int $guestDaysDisable = 0;
protected int $guestDisableMaxLastLogin = 0;
protected int $guestDays = 0;
protected int $guestMaxLastLogin = 0;
protected array $excludedGroups = [];
Expand Down Expand Up @@ -84,6 +88,15 @@ public function __construct(

public function runCron(): void {
$now = new \DateTimeImmutable();
$this->userDaysDisable = (int) $this->config->getAppValue('user_retention', 'user_days_disable', '0');
if ($this->userDaysDisable > 0) {
$userDisableMaxLastLogin = $now->sub(new \DateInterval('P' . $this->userDaysDisable . 'D'));
$this->userDisableMaxLastLogin = $userDisableMaxLastLogin->getTimestamp();
$this->logger->debug('Account disabling with last login before ' . $userDisableMaxLastLogin->format(\DateTimeInterface::ATOM));
} else {
$this->logger->debug('Account disabling is disabled');
}

$this->userDays = (int) $this->config->getAppValue('user_retention', 'user_days', '0');
if ($this->userDays > 0) {
$userMaxLastLogin = $now->sub(new \DateInterval('P' . $this->userDays . 'D'));
Expand All @@ -93,6 +106,15 @@ public function runCron(): void {
$this->logger->debug('Account retention is disabled');
}

$this->guestDaysDisable = (int) $this->config->getAppValue('user_retention', 'guest_days_disable', '0');
if ($this->guestDaysDisable > 0) {
$guestDisableMaxLastLogin = $now->sub(new \DateInterval('P' . $this->guestDaysDisable . 'D'));
$this->guestDisableMaxLastLogin = $guestDisableMaxLastLogin->getTimestamp();
$this->logger->debug('Guest account disabling with last login before ' . $guestDisableMaxLastLogin->format(\DateTimeInterface::ATOM));
} else {
$this->logger->debug('Guest account disabling is disabled');
}

$this->guestDays = (int) $this->config->getAppValue('user_retention', 'guest_days', '0');
if ($this->guestDays > 0) {
$guestMaxLastLogin = $now->sub(new \DateInterval('P' . $this->guestDays . 'D'));
Expand Down Expand Up @@ -130,14 +152,19 @@ public function runCron(): void {
}

public function executeRetentionPolicy(IUser $user): ?bool {
$skipDisableIfNewerThan = $this->userDisableMaxLastLogin;
if ($user->getBackend() instanceof GuestUserBackend) {
$skipDisableIfNewerThan = $this->guestDisableMaxLastLogin;
}

$skipIfNewerThan = $this->userMaxLastLogin;
$policyDays = $this->userDays;
if ($user->getBackend() instanceof GuestUserBackend) {
$skipIfNewerThan = $this->guestMaxLastLogin;
$policyDays = $this->guestDays;
}

if (!$skipIfNewerThan) {
if (!$skipDisableIfNewerThan && !$skipIfNewerThan) {
$this->logger->debug('Skipping retention because not defined for user backend: {user}', [
'user' => $user->getUID(),
]);
Expand All @@ -152,6 +179,20 @@ public function executeRetentionPolicy(IUser $user): ?bool {
return true;
}

// Check if we disable the user
try {
$this->shouldPerformActionOnUser($user, $skipDisableIfNewerThan);

if ($user->isEnabled()) {
$user->setEnabled(false);
$this->logger->info('Account disabled: ' . $user->getUID());
return true;
}
$this->logger->debug('Account already disabled, continuing with potential deletion: ' . $user->getUID());
} catch (SkipUserException $e) {
// Not disabling yet, continue with checking deletion
}

// Check if we delete the user
try {
$this->shouldPerformActionOnUser($user, $skipIfNewerThan);
Expand Down
4 changes: 4 additions & 0 deletions lib/Settings/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ public function __construct(IConfig $config,
public function getForm(): TemplateResponse {
$keepUsersWithoutLogin = $this->config->getAppValue('user_retention', 'keep_users_without_login', 'yes') === 'yes';
$this->initialStateService->provideInitialState('keep_users_without_login', $keepUsersWithoutLogin);
$userDaysDisable = (int) $this->config->getAppValue('user_retention', 'user_days_disable', 0);
$this->initialStateService->provideInitialState('user_days_disable', $userDaysDisable);
$userDays = (int) $this->config->getAppValue('user_retention', 'user_days', 0);
$this->initialStateService->provideInitialState('user_days', $userDays);
$guestDaysDisable = (int) $this->config->getAppValue('user_retention', 'guest_days_disable', 0);
$this->initialStateService->provideInitialState('guest_days_disable', $guestDaysDisable);
$guestDays = (int) $this->config->getAppValue('user_retention', 'guest_days', 0);
$this->initialStateService->provideInitialState('guest_days', $guestDays);

Expand Down
50 changes: 50 additions & 0 deletions src/views/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@
</label>
</div>

<div>
<label>
<span>{{ t('user_retention', 'Account disabling:') }}</span>
<input id="user_days_disable"
v-model="userDaysDisable"
type="number"
placeholder="180"
@change="saveUserDaysDisable"> {{ t('user_retention', 'days') }}
<em>{{ t('user_retention', '(0 to disable)') }}</em>
</label>
</div>

<div>
<label>
<span>{{ t('user_retention', 'Account expiration:') }}</span>
Expand All @@ -53,6 +65,18 @@
</label>
</div>

<div v-if="guestsAppInstalled">
<label>
<span>{{ t('user_retention', 'Guest account disabling:') }}</span>
<input id="guest_days_disable"
v-model="guestDaysDisable"
type="number"
placeholder="180"
@change="saveGuestDaysDisable"> {{ t('user_retention', 'days') }}
<em>{{ t('user_retention', '(0 to disable)') }}</em>
</label>
</div>

<div v-if="guestsAppInstalled">
<label>
<span>{{ t('user_retention', 'Guest account expiration:') }}</span>
Expand Down Expand Up @@ -118,7 +142,9 @@ export default {
groups: [],
excludedGroups: [],
keepUsersWithoutLogin: true,
userDaysDisable: 0,
userDays: 0,
guestDaysDisable: 0,
guestDays: 0,
}
},
Expand All @@ -127,7 +153,9 @@ export default {
this.loading = true

this.keepUsersWithoutLogin = loadState('user_retention', 'keep_users_without_login')
this.userDaysDisable = loadState('user_retention', 'user_days_disable')
this.userDays = loadState('user_retention', 'user_days')
this.guestDaysDisable = loadState('user_retention', 'guest_days_disable')
this.guestDays = loadState('user_retention', 'guest_days')
this.excludedGroups = loadState('user_retention', 'excluded_groups').sort(function(a, b) {
return a.displayname.localeCompare(b.displayname)
Expand Down Expand Up @@ -171,6 +199,17 @@ export default {
})
},

saveUserDaysDisable() {
OCP.AppConfig.setValue('user_retention', 'user_days_disable', this.userDaysDisable, {
success: () => {
showSuccess(t('user_retention', 'Setting saved'))
},
error: () => {
showError(t('user_retention', 'Could not save the setting'))
},
})
},

saveUserDays() {
OCP.AppConfig.setValue('user_retention', 'user_days', this.userDays, {
success: () => {
Expand All @@ -182,6 +221,17 @@ export default {
})
},

saveGuestDaysDisable() {
OCP.AppConfig.setValue('user_retention', 'guest_days_disable', this.guestDaysDisable, {
success: () => {
showSuccess(t('user_retention', 'Setting saved'))
},
error: () => {
showError(t('user_retention', 'Could not save the setting'))
},
})
},

saveGuestDays() {
OCP.AppConfig.setValue('user_retention', 'guest_days', this.guestDays, {
success: () => {
Expand Down

0 comments on commit 83d9794

Please sign in to comment.