diff --git a/mapg b/mapg
old mode 100755
new mode 100644
index 8acfda2..684c7b4
--- a/mapg
+++ b/mapg
@@ -8,5 +8,6 @@ $app = new Symfony\Component\Console\Application('MapGuesser Console', '');
$app->add(new MapGuesser\Cli\DatabaseMigration());
$app->add(new MapGuesser\Cli\AddUserCommand());
$app->add(new MapGuesser\Cli\LinkViewCommand());
+$app->add(new \MapGuesser\Cli\MaintainDatabaseCommand());
$app->run();
diff --git a/src/Cli/MaintainDatabaseCommand.php b/src/Cli/MaintainDatabaseCommand.php
new file mode 100644
index 0000000..f2afc70
--- /dev/null
+++ b/src/Cli/MaintainDatabaseCommand.php
@@ -0,0 +1,107 @@
+persistentDataManager = new PersistentDataManager();
+ $this->userRepository = new UserRepository();
+ $this->userConfirmationRepository = new UserConfirmationRepository();
+ $this->userPasswordResetterRepository = new UserPasswordResetterRepository();
+ }
+
+ public function configure()
+ {
+ $this->setName('db:maintain')
+ ->setDescription('Maintain database.');
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output): int
+ {
+ try {
+ $this->deleteInactiveExpiredUsers();
+ $this->deleteExpiredPasswordResetters();
+ $this->deleteExpiredSessions();
+ } catch (\Exception $e) {
+ $output->writeln('Maintenance failed!');
+ $output->writeln('');
+
+ $output->writeln((string) $e);
+ $output->writeln('');
+
+ return 1;
+ }
+
+ $output->writeln('Maintenance was successful!');
+ $output->writeln('');
+
+ return 0;
+ }
+
+ private function deleteInactiveExpiredUsers(): void
+ {
+ \Container::$dbConnection->startTransaction();
+
+ foreach ($this->userRepository->getAllInactiveExpired() as $user) {
+ //TODO: these can be in some wrapper class
+ $userConfirmation = $this->userConfirmationRepository->getByUser($user);
+ if ($userConfirmation !== null) {
+ $this->pdm->deleteFromDb($userConfirmation);
+ }
+
+ $userPasswordResetter = $this->userPasswordResetterRepository->getByUser($user);
+ if ($userPasswordResetter !== null) {
+ $this->pdm->deleteFromDb($userPasswordResetter);
+ }
+
+ $this->persistentDataManager->deleteFromDb($user);
+ }
+
+ \Container::$dbConnection->commit();
+ }
+
+ private function deleteExpiredPasswordResetters(): void
+ {
+ foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) {
+ $this->persistentDataManager->deleteFromDb($passwordResetter);
+ }
+ }
+
+ private function deleteExpiredSessions(): void
+ {
+ //TODO: model may be used for sessions too
+ $select = new Select(\Container::$dbConnection, 'sessions');
+ $select->columns(['id']);
+ $select->where('updated', '<', (new DateTime('-7 days'))->format('Y-m-d H:i:s'));
+
+ $result = $select->execute();
+
+ while ($session = $result->fetch(IResultSet::FETCH_ASSOC)) {
+ $modify = new Modify(\Container::$dbConnection, 'sessions');
+ $modify->setId($session['id']);
+ $modify->delete();
+ }
+ }
+}