diff --git a/proxylist/models.py b/proxylist/models.py index 257e6e1..c73c482 100644 --- a/proxylist/models.py +++ b/proxylist/models.py @@ -11,6 +11,7 @@ from proxylist.base64_decoder import decode_base64 from proxylist.proxy import update_proxy_status, get_proxy_location +from shadowmere import settings def validate_sip002(value): @@ -31,7 +32,7 @@ def validate_not_existing(value): def validate_proxy_can_connect(value): location = get_proxy_location(get_sip002(value)) - if location is None or location == 'unknown': + if location is None or location == "unknown": raise ValidationError( "Can't get the location for this address", params={"value": value}, @@ -47,17 +48,41 @@ class Proxy(ExportModelOperationsMixin("proxy"), models.Model): validate_not_existing, validate_proxy_can_connect, ], + help_text="SIP002 compatible URL representing a key", + ) + location = models.CharField( + max_length=100, + default="", + help_text="Where is this proxy located geographically", + ) + location_country_code = models.CharField( + max_length=3, default="", help_text="2 letters country code (e.g.: DE)" + ) + location_country = models.CharField( + max_length=50, default="", help_text="Country hosting this proxy" + ) + ip_address = models.CharField( + max_length=100, default="", help_text="Proxy IP address" + ) + port = models.IntegerField(default=0, help_text="Port used by this key") + is_active = models.BooleanField( + default=False, + help_text=f"Whether or not this key worked in the past {settings.CHECK_INTERVAL_MINUTES} minutes", + ) + last_checked = models.DateTimeField( + auto_now=True, help_text="Last time this key was tested" + ) + last_active = models.DateTimeField( + blank=True, + default=now, + help_text="Last time this key responded positively to a test", + ) + times_checked = models.IntegerField( + default=0, help_text="How many times was this key tested so far" + ) + times_check_succeeded = models.IntegerField( + default=0, help_text="How many times this key responded positively to a test" ) - location = models.CharField(max_length=100, default="") - location_country_code = models.CharField(max_length=3, default="") - location_country = models.CharField(max_length=50, default="") - ip_address = models.CharField(max_length=100, default="") - port = models.IntegerField(default=0) - is_active = models.BooleanField(default=False) - last_checked = models.DateTimeField(auto_now=True) - last_active = models.DateTimeField(blank=True, default=now) - times_checked = models.IntegerField(default=0) - times_check_succeeded = models.IntegerField(default=0) def __str__(self): return f"{self.location} ({self.url})" diff --git a/proxylist/serializers.py b/proxylist/serializers.py index c6200e4..aab4489 100644 --- a/proxylist/serializers.py +++ b/proxylist/serializers.py @@ -23,6 +23,7 @@ class Meta: read_only_fields = [ "id", "location", + "location_country", "location_country_code", "ip_address", "is_active", diff --git a/proxylist/views.py b/proxylist/views.py index 7716cd3..b3dc7da 100644 --- a/proxylist/views.py +++ b/proxylist/views.py @@ -11,7 +11,6 @@ from django.views.decorators.cache import cache_page from django_filters import rest_framework as filters from rest_framework import viewsets -from rest_framework.decorators import api_view from rest_framework.response import Response from proxylist.base64_decoder import decode_base64 @@ -115,6 +114,7 @@ class CountryCodeViewSet(viewsets.ViewSet): """ List all country codes and countries with active proxies """ + def list(self, request, format=None): country_codes = [ {"code": code["location_country_code"], "name": code["location_country"]} @@ -131,6 +131,7 @@ class PortViewSet(viewsets.ViewSet): """ List all available ports """ + def list(self, request, format=None): ports = [ port diff --git a/requirements.txt b/requirements.txt index ac1594c..f8c4958 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ botocore==1.28.3 celery==5.2.7 +coreapi==2.3.3 Django==4.1.2 django-admin-rangefilter==0.9.0 django-filter==22.1 diff --git a/shadowmere/settings.py b/shadowmere/settings.py index ab78759..6f375e2 100644 --- a/shadowmere/settings.py +++ b/shadowmere/settings.py @@ -227,11 +227,12 @@ CELERY_BROKER_URL = "redis://redis:6379" CELERY_RESULT_BACKEND = "redis://redis:6379" +CHECK_INTERVAL_MINUTES = 20 CELERY_BEAT_SCHEDULE = { "update_status": { "task": "proxylist.tasks.update_status", - "schedule": crontab(minute="*/20"), + "schedule": crontab(minute=f"*/{CHECK_INTERVAL_MINUTES}"), }, } @@ -240,6 +241,7 @@ PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008) REST_FRAMEWORK = { + 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', "DEFAULT_PAGINATION_CLASS": "proxylist.pagination.ProxiesPagination", "PAGE_SIZE": 10, } diff --git a/shadowmere/urls.py b/shadowmere/urls.py index f1e26f6..9455ebc 100644 --- a/shadowmere/urls.py +++ b/shadowmere/urls.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.urls import path, include from rest_framework import routers +from rest_framework.documentation import include_docs_urls import proxylist.views from proxylist import views @@ -19,4 +20,5 @@ path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), path("api/", include(router.urls)), path("", include("django_prometheus.urls")), + path('docs/', include_docs_urls(title='Shadowmere API docs')) ]