diff --git a/beat/web/accounts/management/commands/block_rejected_users.py b/beat/web/accounts/management/commands/block_rejected_users.py
index 05d9f4bb2227c2150103aae2527107ac1f5698b4..e9ad65b4a7564da73977e97001ac4e758b26898c 100644
--- a/beat/web/accounts/management/commands/block_rejected_users.py
+++ b/beat/web/accounts/management/commands/block_rejected_users.py
@@ -30,27 +30,16 @@
 import datetime
 import sys
 
-from django.core.management.base import BaseCommand
-
+from ....common.management.commands.base import InteractiveCommand
 from ...models import Profile
 from ...models import SupervisionTrack
 
 
-class Command(BaseCommand):
+class Command(InteractiveCommand):
 
     help = "Block rejected users after rejection date with no valid supervisor"
 
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--noinput",
-            action="store_false",
-            dest="interactive",
-            default=False,
-            help=("Tells Django to NOT prompt the user for input of any kind."),
-        )
-
     def handle(self, *args, **options):
-        block = True
 
         if options["interactive"]:
             try:
@@ -64,46 +53,33 @@ class Command(BaseCommand):
 
             if answer != "y":
                 self.stdout.write("Block users operation canceled")
-                sys.exit(1)
-
-        if block:
-            rejected_profiles = Profile.objects.filter(status=Profile.REJECTED)
-            count = 0
-            for rejected_profile in rejected_profiles:
-                user = rejected_profile.user
-                if user.profile.rejection_date < datetime.datetime.now():
-                    count += 1
-                    user.profile.status = Profile.BLOCKED
-                    user.profile.rejection_date = None
-                    user.is_active = False
-
-                    if user.profile.supervision_key is not None:
-                        supervisiontrack = SupervisionTrack.objects.get(
-                            supervision_key=rejected_profile.supervision_key
-                        )
-                        if (
-                            not supervisiontrack.is_valid
-                            and supervisiontrack.start_date is None
-                        ):
-                            user.profile.supervision_key = None
-                            supervisiontrack.delete()
-
-                    user.profile.save()
-                    user.save()
-
-            self.stdout.write(
-                "{} Rejected user(s) successfully blocked/".format(count)
-                + "{} Total user(s) checked".format(rejected_profiles.count())
-            )
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = input(message)
-
-        if default and raw_value == "":
-            raw_value = default
-
-        return raw_value
+                sys.exit(0)
+
+        rejected_profiles = Profile.objects.filter(status=Profile.REJECTED)
+        count = 0
+        for rejected_profile in rejected_profiles:
+            user = rejected_profile.user
+            if user.profile.rejection_date < datetime.datetime.now():
+                count += 1
+                user.profile.status = Profile.BLOCKED
+                user.profile.rejection_date = None
+                user.is_active = False
+
+                if user.profile.supervision_key is not None:
+                    supervisiontrack = SupervisionTrack.objects.get(
+                        supervision_key=rejected_profile.supervision_key
+                    )
+                    if (
+                        not supervisiontrack.is_valid
+                        and supervisiontrack.start_date is None
+                    ):
+                        user.profile.supervision_key = None
+                        supervisiontrack.delete()
+
+                user.profile.save()
+                user.save()
+
+        self.stdout.write(
+            "{} Rejected user(s) successfully blocked/".format(count)
+            + "{} Total user(s) checked".format(rejected_profiles.count())
+        )
diff --git a/beat/web/accounts/management/commands/clean_blocked_users_expired_requests.py b/beat/web/accounts/management/commands/clean_blocked_users_expired_requests.py
index a321e4f4e2806959d3a90fc475b2349281b6fd77..fa792fa88c7e74d0303ba116a62772be357eb38a 100644
--- a/beat/web/accounts/management/commands/clean_blocked_users_expired_requests.py
+++ b/beat/web/accounts/management/commands/clean_blocked_users_expired_requests.py
@@ -29,26 +29,17 @@
 
 import datetime
 import sys
-from django.core.management.base import BaseCommand
+
+from ....common.management.commands.base import InteractiveCommand
 from ...models import Profile
 from ...models import SupervisionTrack
 
 
-class Command(BaseCommand):
+class Command(InteractiveCommand):
 
     help = "Clean blocked users expired requests for supervisor validation"
 
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--noinput",
-            action="store_false",
-            dest="interactive",
-            default=False,
-            help=("Tells Django to NOT prompt the user for input of any kind."),
-        )
-
     def handle(self, *args, **options):
-        block = True
 
         if options["interactive"]:
             try:
@@ -62,49 +53,36 @@ class Command(BaseCommand):
 
             if answer != "y":
                 self.stdout.write("Clean blocked users operation canceled")
-                sys.exit(1)
-
-        if block:
-            blocked_profiles = Profile.objects.filter(status=Profile.BLOCKED)
-            count = 0
-            for blocked_profile in blocked_profiles:
-                user = blocked_profile.user
-                if user.profile.rejection_date is not None:
-                    if user.profile.rejection_date < datetime.datetime.now():
-                        count += 1
-                        user.profile.status = Profile.BLOCKED
-                        user.profile.rejection_date = None
-                        user.is_active = False
-
-                        if user.profile.supervision_key is not None:
-                            supervisiontrack = SupervisionTrack.objects.get(
-                                supervision_key=blocked_profile.supervision_key
-                            )
-                            if (
-                                not supervisiontrack.is_valid
-                                and supervisiontrack.start_date is None
-                            ):
-                                user.profile.supervision_key = None
-                                supervisiontrack.delete()
-
-                        user.profile.save()
-                        user.save()
-
-            self.stdout.write(
-                "{} Blocked user(s) successfully cleaned from expired supervision/".format(
-                    count
-                )
-                + "{} Total user(s) checked".format(blocked_profiles.count())
+                sys.exit(0)
+
+        blocked_profiles = Profile.objects.filter(status=Profile.BLOCKED)
+        count = 0
+        for blocked_profile in blocked_profiles:
+            user = blocked_profile.user
+            if user.profile.rejection_date is not None:
+                if user.profile.rejection_date < datetime.datetime.now():
+                    count += 1
+                    user.profile.status = Profile.BLOCKED
+                    user.profile.rejection_date = None
+                    user.is_active = False
+
+                    if user.profile.supervision_key is not None:
+                        supervisiontrack = SupervisionTrack.objects.get(
+                            supervision_key=blocked_profile.supervision_key
+                        )
+                        if (
+                            not supervisiontrack.is_valid
+                            and supervisiontrack.start_date is None
+                        ):
+                            user.profile.supervision_key = None
+                            supervisiontrack.delete()
+
+                    user.profile.save()
+                    user.save()
+
+        self.stdout.write(
+            "{} Blocked user(s) successfully cleaned from expired supervision/".format(
+                count
             )
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = input(message)
-
-        if default and raw_value == "":
-            raw_value = default
-
-        return raw_value
+            + "{} Total user(s) checked".format(blocked_profiles.count())
+        )
diff --git a/beat/web/accounts/management/commands/clean_expired_temporary_urls.py b/beat/web/accounts/management/commands/clean_expired_temporary_urls.py
index 2b7db73dace09852178a461a8556c79ea051bcd3..ce831d81728bcc5ed3ef7ca4a7176f2f2582dec0 100644
--- a/beat/web/accounts/management/commands/clean_expired_temporary_urls.py
+++ b/beat/web/accounts/management/commands/clean_expired_temporary_urls.py
@@ -30,24 +30,14 @@
 import datetime
 import sys
 
-from django.core.management.base import BaseCommand
-
+from ....common.management.commands.base import InteractiveCommand
 from ...models import TemporaryUrl
 
 
-class Command(BaseCommand):
+class Command(InteractiveCommand):
 
     help = "Clean expired temporary urls"
 
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--noinput",
-            action="store_false",
-            dest="interactive",
-            default=False,
-            help=("Tells Django to NOT prompt the user for input of any kind."),
-        )
-
     def handle(self, *args, **options):
 
         if options["interactive"]:
@@ -62,7 +52,7 @@ class Command(BaseCommand):
 
             if answer != "y":
                 self.stdout.write("Clean expired temporary urls operation canceled")
-                sys.exit(1)
+                sys.exit(0)
 
         temporary_urls_count = TemporaryUrl.objects.all().count()
         now = datetime.datetime.now()
@@ -71,15 +61,3 @@ class Command(BaseCommand):
             "{} Expired temporary url(s) successfully cleaned/".format(count)
             + "{} Total temporary url(s) checked".format(temporary_urls_count)
         )
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = input(message)
-
-        if default and raw_value == "":
-            raw_value = default
-
-        return raw_value
diff --git a/beat/web/accounts/management/commands/clean_invalid_users.py b/beat/web/accounts/management/commands/clean_invalid_users.py
index ec56088cd18c8118751e74f54007ae02c246e2ee..228e593aa3c2e50734da108b8c2fdbc904926a1b 100644
--- a/beat/web/accounts/management/commands/clean_invalid_users.py
+++ b/beat/web/accounts/management/commands/clean_invalid_users.py
@@ -31,26 +31,17 @@ import datetime
 import sys
 
 from django.conf import settings
-from django.core.management.base import BaseCommand
 
+from ....common.management.commands.base import InteractiveCommand
 from ....ui.registration.models import RegistrationProfile
 from ...models import Profile
 from ...models import SupervisionTrack
 
 
-class Command(BaseCommand):
+class Command(InteractiveCommand):
 
     help = "Cleanup outdated invalid users"
 
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--noinput",
-            action="store_false",
-            dest="interactive",
-            default=False,
-            help=("Tells Django to NOT prompt the user for input of any kind."),
-        )
-
     def handle(self, *args, **options):
 
         if options["interactive"]:
@@ -120,15 +111,3 @@ class Command(BaseCommand):
                 registration_profile.delete()
 
         return count_updated_users
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = input(message)
-
-        if default and raw_value == "":
-            raw_value = default
-
-        return raw_value
diff --git a/beat/web/accounts/management/commands/postpone_users_validation.py b/beat/web/accounts/management/commands/postpone_users_validation.py
index 91db6e4717b7830be965a0b5ceea1f3693128ade..1fe0721737c52cb3b7005a942311b6c426872d30 100644
--- a/beat/web/accounts/management/commands/postpone_users_validation.py
+++ b/beat/web/accounts/management/commands/postpone_users_validation.py
@@ -31,26 +31,17 @@ import datetime
 import sys
 
 from django.conf import settings
-from django.core.management.base import BaseCommand
 
+from ....common.management.commands.base import InteractiveCommand
 from ....ui.registration.models import RegistrationProfile
 from ...models import Profile
 from ...models import SupervisionTrack
 
 
-class Command(BaseCommand):
+class Command(InteractiveCommand):
 
     help = "Postpone user(s) validation process"
 
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--noinput",
-            action="store_false",
-            dest="interactive",
-            default=False,
-            help=("Tells Django to NOT prompt the user for input of any kind."),
-        )
-
     def handle(self, *args, **options):
 
         if options["interactive"]:
@@ -146,15 +137,3 @@ class Command(BaseCommand):
                 RegistrationProfile.objects.filter(user=invalid_profile.user).delete()
 
         return count_updated_users
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = input(message)
-
-        if default and raw_value == "":
-            raw_value = default
-
-        return raw_value
diff --git a/beat/web/accounts/management/commands/year_revalidation_users.py b/beat/web/accounts/management/commands/year_revalidation_users.py
index e701e823a0bd0e7fa573744c9c78f739503a4ecf..67f3ef89a3128edc3453c50e064634e28cb17e62 100644
--- a/beat/web/accounts/management/commands/year_revalidation_users.py
+++ b/beat/web/accounts/management/commands/year_revalidation_users.py
@@ -31,10 +31,10 @@ import datetime
 import sys
 
 from django.conf import settings
-from django.core.management.base import BaseCommand
 from django.db import models
 from django.db.models import Q
 
+from ....common.management.commands.base import InteractiveCommand
 from ....ui.registration.models import RegistrationProfile
 from ....utils import mail
 from ...models import Profile
@@ -47,21 +47,11 @@ except ImportError:
     from urllib.parse import urlparse
 
 
-class Command(BaseCommand):
+class Command(InteractiveCommand):
 
     help = "Check users for yearly revalidation"
 
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--noinput",
-            action="store_false",
-            dest="interactive",
-            default=False,
-            help=("Tells Django to NOT prompt the user for input of any kind."),
-        )
-
     def handle(self, *args, **options):
-        yearrevalidate = True
 
         if options["interactive"]:
             try:
@@ -75,178 +65,138 @@ class Command(BaseCommand):
 
             if answer != "y":
                 self.stdout.write("Check users yearly revalidation operation canceled")
-                sys.exit(1)
+                sys.exit(0)
 
-        if yearrevalidate:
-            specialusers = ["AnonymousUser", "plot", "system", "scheduler"]
-            torevalidate_profiles = (
-                Profile.objects.filter(
-                    Q(status=Profile.ACCEPTED) | Q(status=Profile.YEARREVALIDATION)
-                )
-                .exclude(user__is_superuser=True)
-                .exclude(user__username__in=specialusers)
+        specialusers = ["AnonymousUser", "plot", "system", "scheduler"]
+        torevalidate_profiles = (
+            Profile.objects.filter(
+                Q(status=Profile.ACCEPTED) | Q(status=Profile.YEARREVALIDATION)
             )
+            .exclude(user__is_superuser=True)
+            .exclude(user__username__in=specialusers)
+        )
 
-            now = datetime.datetime.now()
-            blocked_count = 0
-            warned_count = 0
+        now = datetime.datetime.now()
+        blocked_count = 0
+        warned_count = 0
 
-            parsed_url = urlparse(settings.URL_PREFIX)
-            server_address = "%s://%s" % (parsed_url.scheme, parsed_url.hostname)
+        parsed_url = urlparse(settings.URL_PREFIX)
+        server_address = "%s://%s" % (parsed_url.scheme, parsed_url.hostname)
 
-            for torevalidate_profile in torevalidate_profiles:
-                user = torevalidate_profile.user
-                if user.profile.supervision_key is not None:
-                    supervisiontrack = SupervisionTrack.objects.get(
-                        supervision_key=torevalidate_profile.supervision_key
+        for torevalidate_profile in torevalidate_profiles:
+            user = torevalidate_profile.user
+            if user.profile.supervision_key is not None:
+                supervisiontrack = SupervisionTrack.objects.get(
+                    supervision_key=torevalidate_profile.supervision_key
+                )
+                if supervisiontrack.is_valid:
+                    # Check expiration date
+                    expiration_date_delta = datetime.timedelta(
+                        days=settings.ACCOUNT_BLOCKAGE_AFTER_FIRST_REJECTION_DAYS
                     )
-                    if supervisiontrack.is_valid:
-                        # Check expiration date
-                        expiration_date_delta = datetime.timedelta(
-                            days=settings.ACCOUNT_BLOCKAGE_AFTER_FIRST_REJECTION_DAYS
-                        )
-                        if (
-                            supervisiontrack.expiration_date
-                            < now + expiration_date_delta
-                        ):
-                            # check if need to block account
-                            if now > supervisiontrack.expiration_date:
-                                # if supervisor account reject all supervisees and inform them
-                                if user.profile.is_supervisor:
-                                    context = {
-                                        "supervisor": user,
-                                        "supervisee": user,
-                                        "prefix": server_address,
-                                    }
-
-                                    # Transform supervisor account to normal account and inform by email
-                                    user.profile.is_supervisor = False
-                                    user.profile.save()
-                                    user.save()
-
-                                    mail.send_email(
-                                        "registration/mail.beatadmin_supervisor_rejected.subject.txt",
-                                        "registration/mail.beatadmin_supervisor_rejected_blocked.message.txt",
-                                        context,
-                                        [user.email],
-                                    )
+                    if supervisiontrack.expiration_date < now + expiration_date_delta:
+                        # check if need to block account
+                        if now > supervisiontrack.expiration_date:
+                            # if supervisor account reject all supervisees and inform them
+                            if user.profile.is_supervisor:
+                                context = {
+                                    "supervisor": user,
+                                    "supervisee": user,
+                                    "prefix": server_address,
+                                }
+
+                                # Transform supervisor account to normal account and inform by email
+                                user.profile.is_supervisor = False
+                                user.profile.save()
+                                user.save()
 
-                                    # Reject all his supervisees and inform by email
-                                    # Make sure all supervision tracks are invalid for rejected supervisor
-                                    supervisiontracks = (
-                                        SupervisionTrack.objects.filter(supervisor=user)
-                                        .filter(
-                                            Q(
-                                                supervisee__profile__status=Profile.REJECTED
-                                            )
-                                            | Q(
-                                                supervisee__profile__status=Profile.YEARREVALIDATION
-                                            )
-                                            | Q(
-                                                supervisee__profile__status=Profile.ACCEPTED
-                                            )
-                                            | Q(
-                                                supervisee__profile__status=Profile.BLOCKED
-                                            )
+                                mail.send_email(
+                                    "registration/mail.beatadmin_supervisor_rejected.subject.txt",
+                                    "registration/mail.beatadmin_supervisor_rejected_blocked.message.txt",
+                                    context,
+                                    [user.email],
+                                )
+
+                                # Reject all his supervisees and inform by email
+                                # Make sure all supervision tracks are invalid for rejected supervisor
+                                supervisiontracks = (
+                                    SupervisionTrack.objects.filter(supervisor=user)
+                                    .filter(
+                                        Q(supervisee__profile__status=Profile.REJECTED)
+                                        | Q(
+                                            supervisee__profile__status=Profile.YEARREVALIDATION
                                         )
-                                        .filter(
-                                            Q(
-                                                supervisee__profile__supervision_key=models.F(
-                                                    "supervision_key"
-                                                )
-                                            )
+                                        | Q(
+                                            supervisee__profile__status=Profile.ACCEPTED
                                         )
+                                        | Q(supervisee__profile__status=Profile.BLOCKED)
                                     )
-                                    supervisiontracks_new_users = SupervisionTrack.objects.filter(
-                                        supervisor=user
-                                    ).filter(
-                                        Q(supervisee__profile__status=Profile.NEWUSER)
-                                        | Q(
-                                            supervisee__profile__status=Profile.WAITINGVALIDATION
+                                    .filter(
+                                        Q(
+                                            supervisee__profile__supervision_key=models.F(
+                                                "supervision_key"
+                                            )
                                         )
                                     )
-
-                                    if supervisiontracks.count() > 0:
-                                        for track in supervisiontracks:
-                                            track.expiration_date = now
-                                            track.is_valid = False
-
-                                            track_supervisee = track.supervisee
-                                            track_supervisor = track.supervisor
+                                )
+                                supervisiontracks_new_users = SupervisionTrack.objects.filter(
+                                    supervisor=user
+                                ).filter(
+                                    Q(supervisee__profile__status=Profile.NEWUSER)
+                                    | Q(
+                                        supervisee__profile__status=Profile.WAITINGVALIDATION
+                                    )
+                                )
+
+                                if supervisiontracks.count() > 0:
+                                    for track in supervisiontracks:
+                                        track.expiration_date = now
+                                        track.is_valid = False
+
+                                        track_supervisee = track.supervisee
+                                        track_supervisor = track.supervisor
+                                        if (
+                                            track_supervisee.profile.status
+                                            != Profile.BLOCKED
+                                        ):
+                                            track_supervisee.profile.status = (
+                                                Profile.REJECTED
+                                            )
                                             if (
-                                                track_supervisee.profile.status
-                                                != Profile.BLOCKED
+                                                track_supervisee.profile.rejection_date
+                                                is None
                                             ):
-                                                track_supervisee.profile.status = (
-                                                    Profile.REJECTED
-                                                )
-                                                if (
-                                                    track_supervisee.profile.rejection_date
-                                                    is None
-                                                ):
-                                                    track_supervisee.profile.rejection_date = (
-                                                        now + expiration_date_delta
-                                                    )
-                                            else:
                                                 track_supervisee.profile.rejection_date = (
-                                                    None
+                                                    now + expiration_date_delta
                                                 )
-
-                                            track_supervisee.profile.supervision_key = (
+                                        else:
+                                            track_supervisee.profile.rejection_date = (
                                                 None
                                             )
 
-                                            track.save()
-                                            track_supervisee.profile.save()
-                                            track_supervisee.save()
-
-                                            context = {
-                                                "supervisor": track_supervisor,
-                                                "supervisee": track_supervisee,
-                                                "prefix": server_address,
-                                            }
-
-                                            mail.send_email(
-                                                "registration/mail.supervisor_failed_rejected.subject.txt",
-                                                "registration/mail.supervisor_failed_rejected.message.txt",
-                                                context,
-                                                [track_supervisee.email],
-                                            )
+                                        track_supervisee.profile.supervision_key = None
 
-                                            if (
-                                                track_supervisee.profile.status
-                                                == Profile.WAITINGVALIDATION
-                                            ):
-                                                registration_profile = RegistrationProfile.objects.get(
-                                                    user=track_supervisee
-                                                )
-                                                track_supervisee.profile.delete()
-                                                track_supervisee.delete()
-                                                registration_profile.delete()
-
-                                            # New supervision request refused
-                                            if track.start_date is None:
-                                                track.delete()
-
-                                    if supervisiontracks_new_users.count() > 0:
-                                        for track in supervisiontracks_new_users:
-                                            track_supervisee = track.supervisee
-                                            track_supervisor = track.supervisor
-
-                                            context = {
-                                                "supervisor": track_supervisor,
-                                                "supervisee": track_supervisee,
-                                                "prefix": server_address,
-                                            }
-
-                                            # New user account waiting validation, so delete this account and inform by email the user
-                                            mail.send_email(
-                                                "registration/mail.supervisor_rejected.subject.txt",
-                                                "registration/mail.supervisor_rejected_delete_account.message.txt",
-                                                context,
-                                                [track_supervisee.email],
-                                            )
+                                        track.save()
+                                        track_supervisee.profile.save()
+                                        track_supervisee.save()
+
+                                        context = {
+                                            "supervisor": track_supervisor,
+                                            "supervisee": track_supervisee,
+                                            "prefix": server_address,
+                                        }
+
+                                        mail.send_email(
+                                            "registration/mail.supervisor_failed_rejected.subject.txt",
+                                            "registration/mail.supervisor_failed_rejected.message.txt",
+                                            context,
+                                            [track_supervisee.email],
+                                        )
 
+                                        if (
+                                            track_supervisee.profile.status
+                                            == Profile.WAITINGVALIDATION
+                                        ):
                                             registration_profile = RegistrationProfile.objects.get(
                                                 user=track_supervisee
                                             )
@@ -254,75 +204,92 @@ class Command(BaseCommand):
                                             track_supervisee.delete()
                                             registration_profile.delete()
 
-                                            # New supervision request refused
-                                            if track.start_date is None:
-                                                track.delete()
-
-                                blocked_count += 1
-                                # terminate supervision
-                                supervisiontrack.expiration_date = now
-                                supervisiontrack.is_valid = False
+                                        # New supervision request refused
+                                        if track.start_date is None:
+                                            track.delete()
 
-                                # block user
-                                user.profile.status = Profile.BLOCKED
-                                user.profile.rejection_date = None
-                                user.profile.supervision_key = None
-                                user.is_active = False
-
-                                # save all changes
-                                supervisiontrack.save()
-                                user.profile.save()
-                                user.save()
-                            else:
-                                # send the warning information
-                                # set user to YEARREVALIDATION
-                                if user.profile.status == Profile.ACCEPTED:
-                                    user.profile.status = Profile.YEARREVALIDATION
-                                    user.profile.save()
-                                # send email to user
-                                for (
-                                    expiration_reminder
-                                ) in settings.EXPIRATION_REMINDERS_REVALIDATION:
-                                    if supervisiontrack.expiration_date.date() - now.date() == datetime.timedelta(
-                                        days=expiration_reminder
-                                    ):
-                                        warned_count += 1
-
-                                        temp_url = TemporaryUrl.objects.create_temporary_url(
-                                            TemporaryUrl.YEARREVALIDATION,
-                                            supervisiontrack,
-                                        )
+                                if supervisiontracks_new_users.count() > 0:
+                                    for track in supervisiontracks_new_users:
+                                        track_supervisee = track.supervisee
+                                        track_supervisor = track.supervisor
 
                                         context = {
-                                            "user": user,
-                                            "expiration_date": supervisiontrack.expiration_date.date(),
+                                            "supervisor": track_supervisor,
+                                            "supervisee": track_supervisee,
                                             "prefix": server_address,
-                                            "temp_url": temp_url.url_hash,
                                         }
 
+                                        # New user account waiting validation, so delete this account and inform by email the user
                                         mail.send_email(
-                                            "registration/mail.account_revalidation.subject.txt",
-                                            "registration/mail.account_revalidation.message.txt",
+                                            "registration/mail.supervisor_rejected.subject.txt",
+                                            "registration/mail.supervisor_rejected_delete_account.message.txt",
                                             context,
-                                            [supervisiontrack.supervisee.email],
+                                            [track_supervisee.email],
                                         )
 
-            self.stdout.write(
-                "{} blocked user(s) and ".format(blocked_count)
-                + "{} warned user(s)/".format(warned_count)
-                + "{} Total user(s) that need revalidation".format(
-                    torevalidate_profiles.count()
-                )
-            )
+                                        registration_profile = RegistrationProfile.objects.get(
+                                            user=track_supervisee
+                                        )
+                                        track_supervisee.profile.delete()
+                                        track_supervisee.delete()
+                                        registration_profile.delete()
+
+                                        # New supervision request refused
+                                        if track.start_date is None:
+                                            track.delete()
+
+                            blocked_count += 1
+                            # terminate supervision
+                            supervisiontrack.expiration_date = now
+                            supervisiontrack.is_valid = False
+
+                            # block user
+                            user.profile.status = Profile.BLOCKED
+                            user.profile.rejection_date = None
+                            user.profile.supervision_key = None
+                            user.is_active = False
+
+                            # save all changes
+                            supervisiontrack.save()
+                            user.profile.save()
+                            user.save()
+                        else:
+                            # send the warning information
+                            # set user to YEARREVALIDATION
+                            if user.profile.status == Profile.ACCEPTED:
+                                user.profile.status = Profile.YEARREVALIDATION
+                                user.profile.save()
+                            # send email to user
+                            for (
+                                expiration_reminder
+                            ) in settings.EXPIRATION_REMINDERS_REVALIDATION:
+                                if supervisiontrack.expiration_date.date() - now.date() == datetime.timedelta(
+                                    days=expiration_reminder
+                                ):
+                                    warned_count += 1
+
+                                    temp_url = TemporaryUrl.objects.create_temporary_url(
+                                        TemporaryUrl.YEARREVALIDATION, supervisiontrack,
+                                    )
 
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = input(message)
+                                    context = {
+                                        "user": user,
+                                        "expiration_date": supervisiontrack.expiration_date.date(),
+                                        "prefix": server_address,
+                                        "temp_url": temp_url.url_hash,
+                                    }
 
-        if default and raw_value == "":
-            raw_value = default
+                                    mail.send_email(
+                                        "registration/mail.account_revalidation.subject.txt",
+                                        "registration/mail.account_revalidation.message.txt",
+                                        context,
+                                        [supervisiontrack.supervisee.email],
+                                    )
 
-        return raw_value
+        self.stdout.write(
+            "{} blocked user(s) and ".format(blocked_count)
+            + "{} warned user(s)/".format(warned_count)
+            + "{} Total user(s) that need revalidation".format(
+                torevalidate_profiles.count()
+            )
+        )
diff --git a/beat/web/attestations/management/commands/clean_attestations.py b/beat/web/attestations/management/commands/clean_attestations.py
index d9df5aa1d01188c6b397c3f0d76233a63bcda125..22736d4af8ca7fc11a8a63721b4b157a230daddf 100644
--- a/beat/web/attestations/management/commands/clean_attestations.py
+++ b/beat/web/attestations/management/commands/clean_attestations.py
@@ -27,52 +27,39 @@
 ###############################################################################
 
 
-from django.core.management.base import BaseCommand, CommandError
-
+import sys
 from datetime import date
 
+from ....common.management.commands.base import InteractiveCommand
 from ...models import Attestation
 
-import sys
-
-class Command(BaseCommand):
-
-    help = 'Cleanup outdated attestations'
 
-    def add_arguments(self, parser):
-        parser.add_argument('--noinput', action='store_false', dest='interactive', default=True,
-                            help=('Tells Django to NOT prompt the user for input of any kind.'))
+class Command(InteractiveCommand):
 
+    help = "Cleanup outdated attestations"
 
     def handle(self, *args, **options):
         clean = True
 
-        if options['interactive']:
+        if options["interactive"]:
             try:
-                answer = self.get_input_data('Delete attestation(s) (Y/n)? ', 'y').lower()
+                answer = self.get_input_data(
+                    "Delete attestation(s) (Y/n)? ", "y"
+                ).lower()
             except KeyboardInterrupt:
                 self.stderr.write("\nOperation canceled.")
                 sys.exit(1)
 
-            if answer != 'y':
-                self.stdout.write('Cleanup canceled')
+            if answer != "y":
+                self.stdout.write("Cleanup canceled")
                 sys.exit(1)
 
         if clean:
-            expired_attestations = Attestation.objects.filter(locked=True, expiration_date__lte=date.today())
+            expired_attestations = Attestation.objects.filter(
+                locked=True, expiration_date__lte=date.today()
+            )
             attestion_count = expired_attestations.count()
             expired_attestations.delete()
-            self.stdout.write('{} attestation(s) successfully cleaned'.format(attestion_count))
-
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = raw_input(message)
-
-        if default and raw_value == '':
-            raw_value = default
-
-        return raw_value
+            self.stdout.write(
+                "{} attestation(s) successfully cleaned".format(attestion_count)
+            )
diff --git a/beat/web/common/migrations/__init__.py b/beat/web/common/management/__init__.py
similarity index 100%
rename from beat/web/common/migrations/__init__.py
rename to beat/web/common/management/__init__.py
diff --git a/beat/web/common/management/commands/__init__.py b/beat/web/common/management/commands/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/beat/web/common/management/commands/base.py b/beat/web/common/management/commands/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..aec1dfa80a439dde5d1d73e2ebf2f96a2497655d
--- /dev/null
+++ b/beat/web/common/management/commands/base.py
@@ -0,0 +1,55 @@
+# vim: set fileencoding=utf-8 :
+# encoding: utf-8
+
+###############################################################################
+#                                                                             #
+# Copyright (c) 2020 Idiap Research Institute, http://www.idiap.ch/           #
+# Contact: beat.support@idiap.ch                                              #
+#                                                                             #
+# This file is part of the beat.web module of the BEAT platform.              #
+#                                                                             #
+# Commercial License Usage                                                    #
+# Licensees holding valid commercial BEAT licenses may use this file in       #
+# accordance with the terms contained in a written agreement between you      #
+# and Idiap. For further information contact tto@idiap.ch                     #
+#                                                                             #
+# Alternatively, this file may be used under the terms of the GNU Affero      #
+# Public License version 3 as published by the Free Software and appearing    #
+# in the file LICENSE.AGPL included in the packaging of this file.            #
+# The BEAT platform is distributed in the hope that it will be useful, but    #
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  #
+# or FITNESS FOR A PARTICULAR PURPOSE.                                        #
+#                                                                             #
+# You should have received a copy of the GNU Affero Public License along      #
+# with the BEAT platform. If not, see http://www.gnu.org/licenses/.           #
+#                                                                             #
+###############################################################################
+
+
+from django.core.management.base import BaseCommand
+
+
+class InteractiveCommand(BaseCommand):
+    """Base class for all interactive commands"""
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            "--noinput",
+            action="store_false",
+            dest="interactive",
+            default=True,
+            help=("Tells Django to NOT prompt the user for input of any kind."),
+        )
+
+    def get_input_data(self, message, default=None):
+        """
+        Override this method if you want to customize data inputs or
+        validation exceptions.
+        """
+
+        raw_value = input(message)  # nosec only running on Python 3
+
+        if default and raw_value == "":
+            raw_value = default
+
+        return raw_value
diff --git a/beat/web/reports/management/commands/clean_report.py b/beat/web/reports/management/commands/clean_report.py
index 8526144918f310a27434a57dfd37a9e1dd4db67e..495560fb9a3583feb4fa06bdd1f7654b8d257f73 100644
--- a/beat/web/reports/management/commands/clean_report.py
+++ b/beat/web/reports/management/commands/clean_report.py
@@ -27,64 +27,51 @@
 ###############################################################################
 
 
-from django.core.management.base import BaseCommand, CommandError
-
+import random
+import sys
 from datetime import date
 
+from ....common.management.commands.base import InteractiveCommand
 from ...models import Report
 
-import sys
-import random
-
-class Command(BaseCommand):
 
-    help = 'Cleanup outdated locked reports'
-
-    def add_arguments(self, parser):
-        parser.add_argument('--noinput', action='store_false', dest='interactive', default=True,
-                            help=('Tells Django to NOT prompt the user for input of any kind.'))
+class Command(InteractiveCommand):
 
+    help = "Cleanup outdated locked reports"
 
     def handle(self, *args, **options):
         clean = True
 
-        if options['interactive']:
+        if options["interactive"]:
             try:
-                answer = self.get_input_data('Make report(s) editable again with new unique id (Y/n)? ', 'y').lower()
+                answer = self.get_input_data(
+                    "Make report(s) editable again with new unique id (Y/n)? ", "y"
+                ).lower()
             except KeyboardInterrupt:
                 self.stderr.write("\nOperation canceled.")
                 sys.exit(1)
 
-            if answer != 'y':
-                self.stdout.write('Cleanup canceled')
+            if answer != "y":
+                self.stdout.write("Cleanup canceled")
                 sys.exit(1)
 
         if clean:
-            expired_reports = Report.objects.filter(status=Report.LOCKED, expiration_date__lte=date.today())
+            expired_reports = Report.objects.filter(
+                status=Report.LOCKED, expiration_date__lte=date.today()
+            )
             report_count = expired_reports.count()
             for expired_report in expired_reports:
                 # Generate a unique report number
-                used_numbers = map(lambda x: x.number, Report.objects.all())
+                used_numbers = Report.objects.values_list("number", flat=True)
                 number = 0
                 while (number == 0) or number in used_numbers:
-                    number = random.randint(100000, 2**31)
+                    number = random.randint(100000, 2 ** 31)  # nosec
 
                 expired_report.status = Report.EDITABLE
                 expired_report.number = number
                 expired_report.expiration_date = None
                 expired_report.save()
 
-            self.stdout.write('{} locked report(s) successfully cleaned'.format(report_count))
-
-
-    def get_input_data(self, message, default=None):
-        """
-        Override this method if you want to customize data inputs or
-        validation exceptions.
-        """
-        raw_value = raw_input(message)
-
-        if default and raw_value == '':
-            raw_value = default
-
-        return raw_value
+            self.stdout.write(
+                "{} locked report(s) successfully cleaned".format(report_count)
+            )