Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Black config and pre-commit hook #231

Merged
merged 3 commits into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[flake8]
max-line-length = 88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason for not including, flake8 to pre-commit config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Black doesn't always agree with flake8. For example E203.

16 changes: 16 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
#- repo: https://github.com/pre-commit/pre-commit-hooks
#rev: v3.2.0
#hooks:
#- id: trailing-whitespace
#- id: end-of-file-fixer
#- id: check-yaml
#- id: check-added-large-files

- repo: https://github.com/psf/black
rev: 22.8.0
hooks:
- id: black
exclude: 'migrations|^shynet/shynet/settings.py'
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ mypy = "^0.910"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.black]
line-length = 88
49 changes: 24 additions & 25 deletions shynet/analytics/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,26 @@ def _default_uuid():
class Session(models.Model):
uuid = models.UUIDField(default=_default_uuid, primary_key=True)
service = models.ForeignKey(
Service, verbose_name=_('Service'),
on_delete=models.CASCADE, db_index=True
Service, verbose_name=_("Service"), on_delete=models.CASCADE, db_index=True
)

# Cross-session identification; optional, and provided by the service
identifier = models.TextField(
blank=True, db_index=True, verbose_name=_('Identifier')
blank=True, db_index=True, verbose_name=_("Identifier")
)

# Time
start_time = models.DateTimeField(
default=timezone.now, db_index=True, verbose_name=_('Start time')
default=timezone.now, db_index=True, verbose_name=_("Start time")
)
last_seen = models.DateTimeField(
default=timezone.now, db_index=True, verbose_name=_('Last seen')
default=timezone.now, db_index=True, verbose_name=_("Last seen")
)

# Core request information
user_agent = models.TextField(verbose_name=_('User agent'))
browser = models.TextField(verbose_name=_('Browser'))
device = models.TextField(verbose_name=_('Device'))
user_agent = models.TextField(verbose_name=_("User agent"))
browser = models.TextField(verbose_name=_("Browser"))
device = models.TextField(verbose_name=_("Device"))
device_type = models.CharField(
max_length=7,
choices=[
Expand All @@ -46,23 +45,25 @@ class Session(models.Model):
("OTHER", _("Other")),
],
default="OTHER",
verbose_name=_('Device type')
verbose_name=_("Device type"),
)
os = models.TextField(verbose_name=_('OS'))
ip = models.GenericIPAddressField(db_index=True, null=True, verbose_name=_('IP'))
os = models.TextField(verbose_name=_("OS"))
ip = models.GenericIPAddressField(db_index=True, null=True, verbose_name=_("IP"))

# GeoIP data
asn = models.TextField(blank=True, verbose_name=_('Asn'))
country = models.TextField(blank=True, verbose_name=_('Country'))
longitude = models.FloatField(null=True, verbose_name=_('Longitude'))
latitude = models.FloatField(null=True, verbose_name=_('Latitude'))
time_zone = models.TextField(blank=True, verbose_name=_('Time zone'))

is_bounce = models.BooleanField(default=True, db_index=True, verbose_name=_('Is bounce'))
asn = models.TextField(blank=True, verbose_name=_("Asn"))
country = models.TextField(blank=True, verbose_name=_("Country"))
longitude = models.FloatField(null=True, verbose_name=_("Longitude"))
latitude = models.FloatField(null=True, verbose_name=_("Latitude"))
time_zone = models.TextField(blank=True, verbose_name=_("Time zone"))

is_bounce = models.BooleanField(
default=True, db_index=True, verbose_name=_("Is bounce")
)

class Meta:
verbose_name = _('Session')
verbose_name_plural = _('Sessions')
verbose_name = _("Session")
verbose_name_plural = _("Sessions")
ordering = ["-start_time"]
indexes = [
models.Index(fields=["service", "-start_time"]),
Expand Down Expand Up @@ -96,8 +97,7 @@ def recalculate_bounce(self):

class Hit(models.Model):
session = models.ForeignKey(
Session, on_delete=models.CASCADE, db_index=True,
verbose_name=_('Session')
Session, on_delete=models.CASCADE, db_index=True, verbose_name=_("Session")
)
initial = models.BooleanField(default=True, db_index=True)

Expand All @@ -119,8 +119,8 @@ class Hit(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE, db_index=True)

class Meta:
verbose_name = _('Hit')
verbose_name_plural = _('Hits')
verbose_name = _("Hit")
verbose_name_plural = _("Hits")
ordering = ["-start_time"]
indexes = [
models.Index(fields=["session", "-start_time"]),
Expand All @@ -129,7 +129,6 @@ class Meta:
models.Index(fields=["session", "referrer"]),
]


@property
def duration(self):
return self.last_seen - self.start_time
Expand Down
4 changes: 2 additions & 2 deletions shynet/api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@


class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'
default_auto_field = "django.db.models.BigAutoField"
name = "api"
6 changes: 3 additions & 3 deletions shynet/api/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

class ApiTokenRequiredMixin:
def _get_user_by_token(self, request):
token = request.headers.get('Authorization')
if not token or not token.startswith('Token '):
token = request.headers.get("Authorization")
if not token or not token.startswith("Token "):
return AnonymousUser()

token = token.split(' ')[1]
token = token.split(" ")[1]
user = User.objects.filter(api_token=token).first()

return user if user else AnonymousUser()
Expand Down
22 changes: 11 additions & 11 deletions shynet/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,37 @@ def get(self, request, *args, **kwargs):
Q(owner=request.user) | Q(collaborators__in=[request.user])
).distinct()

uuid = request.GET.get('uuid')
uuid = request.GET.get("uuid")
if uuid and is_valid_uuid(uuid):
services = services.filter(uuid=uuid)

try:
start = self.get_start_date()
end = self.get_end_date()
except ValueError:
return JsonResponse(status=400, data={'error': 'Invalid date format'})
return JsonResponse(status=400, data={"error": "Invalid date format"})

services_data = [
{
'name': s.name,
'uuid': s.uuid,
'link': s.link,
'stats': s.get_core_stats(start, end),
"name": s.name,
"uuid": s.uuid,
"link": s.link,
"stats": s.get_core_stats(start, end),
}
for s in services
]

services_data = self._convert_querysets_to_lists(services_data)

return JsonResponse(data={'services': services_data})
return JsonResponse(data={"services": services_data})

def _convert_querysets_to_lists(self, services_data):
for service_data in services_data:
for key, value in service_data['stats'].items():
for key, value in service_data["stats"].items():
if isinstance(value, QuerySet):
service_data['stats'][key] = list(value)
for key, value in service_data['stats']['compare'].items():
service_data["stats"][key] = list(value)
for key, value in service_data["stats"]["compare"].items():
if isinstance(value, QuerySet):
service_data['stats']['compare'][key] = list(value)
service_data["stats"]["compare"][key] = list(value)

return services_data
53 changes: 33 additions & 20 deletions shynet/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,38 +64,51 @@ class Service(models.Model):
SERVICE_STATUSES = [(ACTIVE, _("Active")), (ARCHIVED, _("Archived"))]

uuid = models.UUIDField(default=_default_uuid, primary_key=True)
name = models.TextField(max_length=64, verbose_name=_('Name'))
name = models.TextField(max_length=64, verbose_name=_("Name"))
owner = models.ForeignKey(
User, verbose_name=_('Owner'),
on_delete=models.CASCADE, related_name="owning_services"
User,
verbose_name=_("Owner"),
on_delete=models.CASCADE,
related_name="owning_services",
)
collaborators = models.ManyToManyField(
User, verbose_name=_('Collaborators'),
related_name="collaborating_services", blank=True
User,
verbose_name=_("Collaborators"),
related_name="collaborating_services",
blank=True,
)
created = models.DateTimeField(auto_now_add=True, verbose_name=_('created'))
link = models.URLField(blank=True, verbose_name=_('link'))
origins = models.TextField(default="*", verbose_name=_('origins'))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
link = models.URLField(blank=True, verbose_name=_("link"))
origins = models.TextField(default="*", verbose_name=_("origins"))
status = models.CharField(
max_length=2, choices=SERVICE_STATUSES, default=ACTIVE, db_index=True,
verbose_name=_('status')
max_length=2,
choices=SERVICE_STATUSES,
default=ACTIVE,
db_index=True,
verbose_name=_("status"),
)
respect_dnt = models.BooleanField(default=True, verbose_name=_('Respect dnt'))
ignore_robots = models.BooleanField(default=False, verbose_name=_('Ignore robots'))
collect_ips = models.BooleanField(default=True, verbose_name=_('Collect ips'))
respect_dnt = models.BooleanField(default=True, verbose_name=_("Respect dnt"))
ignore_robots = models.BooleanField(default=False, verbose_name=_("Ignore robots"))
collect_ips = models.BooleanField(default=True, verbose_name=_("Collect ips"))
ignored_ips = models.TextField(
default="", blank=True, validators=[_validate_network_list],
verbose_name=_('Igored ips')
default="",
blank=True,
validators=[_validate_network_list],
verbose_name=_("Igored ips"),
)
hide_referrer_regex = models.TextField(
default="", blank=True, validators=[_validate_regex],
verbose_name=_('Hide referrer regex')
default="",
blank=True,
validators=[_validate_regex],
verbose_name=_("Hide referrer regex"),
)
script_inject = models.TextField(
default="", blank=True, verbose_name=_("Script inject")
)
script_inject = models.TextField(default="", blank=True, verbose_name=_('Script inject'))

class Meta:
verbose_name = _('Service')
verbose_name_plural = _('Services')
verbose_name = _("Service")
verbose_name_plural = _("Services")
ordering = ["name", "uuid"]

def __str__(self):
Expand Down
40 changes: 30 additions & 10 deletions shynet/dashboard/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ class Meta:
"name": forms.TextInput(),
"origins": forms.TextInput(),
"ignored_ips": forms.TextInput(),
"respect_dnt": forms.RadioSelect(choices=[(True, _("Yes")), (False, _("No"))]),
"collect_ips": forms.RadioSelect(choices=[(True, _("Yes")), (False, _("No"))]),
"ignore_robots": forms.RadioSelect(choices=[(True, _("Yes")), (False, _("No"))]),
"respect_dnt": forms.RadioSelect(
choices=[(True, _("Yes")), (False, _("No"))]
),
"collect_ips": forms.RadioSelect(
choices=[(True, _("Yes")), (False, _("No"))]
),
"ignore_robots": forms.RadioSelect(
choices=[(True, _("Yes")), (False, _("No"))]
),
"hide_referrer_regex": forms.TextInput(),
"script_inject": forms.Textarea(attrs={"class": "font-mono", "rows": 5}),
}
Expand All @@ -45,17 +51,29 @@ class Meta:
"origins": _(
"At what origins does the service operate? Use commas to separate multiple values. This sets CORS headers, so use '*' if you're not sure (or don't care)."
),
"respect_dnt": _("Should visitors who have enabled <a href='https://en.wikipedia.org/wiki/Do_Not_Track'>Do Not Track</a> be excluded from all data?"),
"ignored_ips": _("A comma-separated list of IP addresses or IP ranges (IPv4 and IPv6) to exclude from tracking (e.g., '192.168.0.2, 127.0.0.1/32')."),
"ignore_robots": _("Should sessions generated by bots be excluded from tracking?"),
"hide_referrer_regex": _("Any referrers that match this <a href='https://regexr.com/'>RegEx</a> will not be listed in the referrer summary. Sessions will still be tracked normally. No effect if left blank."),
"script_inject": _("Optional additional JavaScript to inject at the end of the Shynet script. This code will be injected on every page where this service is installed."),
"respect_dnt": _(
"Should visitors who have enabled <a href='https://en.wikipedia.org/wiki/Do_Not_Track'>Do Not Track</a> be excluded from all data?"
),
"ignored_ips": _(
"A comma-separated list of IP addresses or IP ranges (IPv4 and IPv6) to exclude from tracking (e.g., '192.168.0.2, 127.0.0.1/32')."
),
"ignore_robots": _(
"Should sessions generated by bots be excluded from tracking?"
),
"hide_referrer_regex": _(
"Any referrers that match this <a href='https://regexr.com/'>RegEx</a> will not be listed in the referrer summary. Sessions will still be tracked normally. No effect if left blank."
),
"script_inject": _(
"Optional additional JavaScript to inject at the end of the Shynet script. This code will be injected on every page where this service is installed."
),
}

collect_ips = forms.BooleanField(
help_text=_("IP address collection is disabled globally by your administrator.")
if settings.BLOCK_ALL_IPS
else _("Should individual IP addresses be collected? IP metadata (location, host, etc) will still be collected."),
else _(
"Should individual IP addresses be collected? IP metadata (location, host, etc) will still be collected."
),
widget=forms.RadioSelect(choices=[(True, _("Yes")), (False, _("No"))]),
initial=False if settings.BLOCK_ALL_IPS else True,
required=False,
Expand All @@ -68,7 +86,9 @@ def clean_collect_ips(self):
return False if settings.BLOCK_ALL_IPS else collect_ips

collaborators = forms.CharField(
help_text=_("Which users on this Shynet instance should have read-only access to this service? (Comma separated list of emails.)"),
help_text=_(
"Which users on this Shynet instance should have read-only access to this service? (Comma separated list of emails.)"
),
required=False,
)

Expand Down
2 changes: 1 addition & 1 deletion shynet/dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,4 @@ class RefreshApiTokenView(LoginRequiredMixin, View):
def post(self, request):
request.user.api_token = _default_api_token()
request.user.save()
return redirect('account_change_password')
return redirect("account_change_password")