# Path: privacyscore/backend/models.py
# class Site(models.Model):
#     """A site."""
#     url = models.CharField(max_length=500, unique=True)
#     scan_lists = models.ManyToManyField(ScanList, related_name='sites', blank=True)
# 
#     views = models.IntegerField(default=0)
# 
#     last_scan = models.OneToOneField(
#         'Scan', on_delete=models.SET_NULL, blank=True, null=True,
#         related_name='+')
# 
#     created = models.DateTimeField(default=timezone.now)
# 
#     objects = models.Manager.from_queryset(SiteQuerySet)()
# 
#     # Site is scannable
#     SCAN_OK = 0
#     # Cooldown period has not expired, no scan scheduled
#     SCAN_COOLDOWN = 1
#     # Website is blacklisted, not scanned
#     SCAN_BLACKLISTED = 2
# 
#     def __str__(self) -> str:
#         return self.url
# 
#     def as_dict(self) -> dict:
#         """Return the current list as dict."""
#         return {
#             'id': self.pk,
#             'url': self.url,
#             'column_values': [
#                 v.value for v in self.column_values.order_by('column__sort_key')],
#         }
# 
#     def get_screenshot(self) -> Union[bytes, None]:
#         """Get the most recent screenshot of this site."""
#         screenshots = RawScanResult.objects.filter(
#             scan__site=self, identifier='cropped_screenshot').order_by(
#             'scan__end')
#         screenshot = screenshots.last()
#         if screenshot:
#             return screenshot.retrieve()
# 
#     def has_screenshot(self) -> bool:
#         """Check whether a screenshot for this site exists."""
#         return self.get_screenshot() is not None
# 
#     def scan(self) -> int:
#         """
#         Schedule a scan of this site if requirements are fulfilled.
# 
#         Returns a status code from the list SCAN_OK, SCAN_COOLDOWN,
#         SCAN_BLACKLISTED.
#         """
# 
#         scan_status = self.scannable()
#         if scan_status != Site.SCAN_OK:
#             return scan_status
# 
#         # create Scan
#         scan = Scan.objects.create(site=self)
# 
#         from privacyscore.scanner.tasks import schedule_scan
#         schedule_scan.delay(scan.pk)
# 
#         return Site.SCAN_OK
# 
#     def scannable(self) -> int:
#         now = timezone.now()
# 
#         # fetch missing attributes
#         if (not hasattr(self, 'last_scan__end_or_null') or
#                 not hasattr(self, 'last_scan__start')):
#             last_scan = self.scans.order_by('end').last()
#             self.last_scan__end_or_null = last_scan.end if last_scan else None
#             self.last_scan__start = last_scan.start if last_scan else None
# 
#         if ((self.last_scan and 
#                 now - self.last_scan.end < settings.SCAN_REQUIRED_TIME_BEFORE_NEXT_SCAN) or
#                 (not self.last_scan__end_or_null and self.last_scan__start)):
#             return Site.SCAN_COOLDOWN
# 
#         for entry in BlacklistEntry.objects.all():
#             if entry.match(self.url):
#                 return Site.SCAN_BLACKLISTED
# 
#         return Site.SCAN_OK
# 
#     def evaluate(self, group_order: list) -> SiteEvaluation:
#         """Evaluate the result of the last scan."""
#         if not self.last_scan__result:
#             return None
#         from privacyscore.evaluation.evaluation import evaluate_result
# 
#         return evaluate_result(self.last_scan__result, group_order)


from time import sleep
from django.conf import settings
from django.core.management import BaseCommand
from privacyscore.backend.models import Site
import sys
# scan any more sites
# TODO: find better solution that is independent of number of
# blacklisted sites
MAX_TRIES = 50


class Command(BaseCommand):
    help = 'Schedules a new scan every minute.'

    def add_arguments(self, parser):
        parser.add_argument('--oneshot',
                            action='store_true',
                            dest='oneshot',
                            default=False,
                            help='Do not run as daemon')

    def handle(self, *args, **options):
        """Schedules a new scan regularly."""
        while True:
            sites = Site.objects.annotate_most_recent_scan_start() \
                .annotate_most_recent_scan_end_or_null().filter(
                last_scan__end_or_null__isnull=False).order_by(
                'last_scan__end')
            sites = list(sites[:MAX_TRIES])
            
            # Try several times to find a scannable site
            for i in range(min(MAX_TRIES, len(sites))):
                site = sites.pop()
                
                status_code = site.scan()

# Path: privacyscore/backend/models.py
# class Site(models.Model):
#     """A site."""
#     url = models.CharField(max_length=500, unique=True)
#     scan_lists = models.ManyToManyField(ScanList, related_name='sites', blank=True)
# 
#     views = models.IntegerField(default=0)
# 
#     last_scan = models.OneToOneField(
#         'Scan', on_delete=models.SET_NULL, blank=True, null=True,
#         related_name='+')
# 
#     created = models.DateTimeField(default=timezone.now)
# 
#     objects = models.Manager.from_queryset(SiteQuerySet)()
# 
#     # Site is scannable
#     SCAN_OK = 0
#     # Cooldown period has not expired, no scan scheduled
#     SCAN_COOLDOWN = 1
#     # Website is blacklisted, not scanned
#     SCAN_BLACKLISTED = 2
# 
#     def __str__(self) -> str:
#         return self.url
# 
#     def as_dict(self) -> dict:
#         """Return the current list as dict."""
#         return {
#             'id': self.pk,
#             'url': self.url,
#             'column_values': [
#                 v.value for v in self.column_values.order_by('column__sort_key')],
#         }
# 
#     def get_screenshot(self) -> Union[bytes, None]:
#         """Get the most recent screenshot of this site."""
#         screenshots = RawScanResult.objects.filter(
#             scan__site=self, identifier='cropped_screenshot').order_by(
#             'scan__end')
#         screenshot = screenshots.last()
#         if screenshot:
#             return screenshot.retrieve()
# 
#     def has_screenshot(self) -> bool:
#         """Check whether a screenshot for this site exists."""
#         return self.get_screenshot() is not None
# 
#     def scan(self) -> int:
#         """
#         Schedule a scan of this site if requirements are fulfilled.
# 
#         Returns a status code from the list SCAN_OK, SCAN_COOLDOWN,
#         SCAN_BLACKLISTED.
#         """
# 
#         scan_status = self.scannable()
#         if scan_status != Site.SCAN_OK:
#             return scan_status
# 
#         # create Scan
#         scan = Scan.objects.create(site=self)
# 
#         from privacyscore.scanner.tasks import schedule_scan
#         schedule_scan.delay(scan.pk)
# 
#         return Site.SCAN_OK
# 
#     def scannable(self) -> int:
#         now = timezone.now()
# 
#         # fetch missing attributes
#         if (not hasattr(self, 'last_scan__end_or_null') or
#                 not hasattr(self, 'last_scan__start')):
#             last_scan = self.scans.order_by('end').last()
#             self.last_scan__end_or_null = last_scan.end if last_scan else None
#             self.last_scan__start = last_scan.start if last_scan else None
# 
#         if ((self.last_scan and 
#                 now - self.last_scan.end < settings.SCAN_REQUIRED_TIME_BEFORE_NEXT_SCAN) or
#                 (not self.last_scan__end_or_null and self.last_scan__start)):
#             return Site.SCAN_COOLDOWN
# 
#         for entry in BlacklistEntry.objects.all():
#             if entry.match(self.url):
#                 return Site.SCAN_BLACKLISTED
# 
#         return Site.SCAN_OK
# 
#     def evaluate(self, group_order: list) -> SiteEvaluation:
#         """Evaluate the result of the last scan."""
#         if not self.last_scan__result:
#             return None
#         from privacyscore.evaluation.evaluation import evaluate_result
# 
#         return evaluate_result(self.last_scan__result, group_order)


# Path: privacyscore/backend/management/commands/schedulerescans.py
from time import sleep
from django.conf import settings
from django.core.management import BaseCommand
from privacyscore.backend.models import Site
import sys

# scan any more sites
# TODO: find better solution that is independent of number of
# blacklisted sites
MAX_TRIES = 50


class Command(BaseCommand):
    help = 'Schedules a new scan every minute.'

    def add_arguments(self, parser):
        parser.add_argument('--oneshot',
                            action='store_true',
                            dest='oneshot',
                            default=False,
                            help='Do not run as daemon')

    def handle(self, *args, **options):
        """Schedules a new scan regularly."""
        while True:
            sites = Site.objects.annotate_most_recent_scan_start() \
                .annotate_most_recent_scan_end_or_null().filter(
                last_scan__end_or_null__isnull=False).order_by(
                'last_scan__end')
            sites = list(sites[:MAX_TRIES])
            
            # Try several times to find a scannable site
            for i in range(min(MAX_TRIES, len(sites))):
                site = sites.pop()
                
                status_code = site.scan()

                if status_code == Site.SCAN_OK: