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

Cherijs develop #29

Merged
merged 23 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0e12a2d
Merge tag '3.0' into develop
NachE May 25, 2023
a00b0df
Create and set up an event loop, if code is executing in non-main thr…
cherijs Jul 6, 2023
fc5de76
Merge pull request #1 from cherijs/event-loop-patch
cherijs Jul 6, 2023
a7a18fc
Merge pull request #20 from cherijs/event-loop-patch
alexandernst Jul 6, 2023
1ad7809
ADD Human-readable name for the application
cherijs Jul 9, 2023
605a03b
string representation
cherijs Jul 9, 2023
3b33657
Django Admin tweaks for Models - searchable, filterable
cherijs Jul 9, 2023
7a69f41
Merge branch 'feature/models-string-representation' into develop
cherijs Jul 9, 2023
6d6d7b2
Add fields to the Log model
cherijs Jul 9, 2023
ed0c197
Add LogAdmin
cherijs Jul 9, 2023
020428c
parse_log Class method
cherijs Jul 9, 2023
203f19c
parse_log when log data is received
cherijs Jul 9, 2023
4a9b21f
Merge branch 'feature/parse-log' into develop
cherijs Jul 9, 2023
7efc96f
add web_service_root_view to prevent error log web service url https:…
cherijs Jul 9, 2023
aa5e3d2
Fix typo and search_fields
cherijs Jul 10, 2023
88d14e1
Remove web_service_root_view
cherijs Jul 10, 2023
3c3178e
Log representation - creation date
cherijs Jul 10, 2023
9e08466
Add more patterns to parse_log
cherijs Jul 11, 2023
3d4b755
Adjust the regular expression
cherijs Jul 11, 2023
62cd074
Wrap pass file deletion try except statement - if file is deleted fro…
cherijs Jul 11, 2023
4daee23
Revert "Wrap pass file deletion try except statement - if file is del…
cherijs Jul 11, 2023
2127221
fix value too long for type character varying(150) - received push to…
cherijs Jul 13, 2023
160a175
svg must be in img file
patroqueeet Jan 22, 2024
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
106 changes: 102 additions & 4 deletions django_walletpass/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,104 @@
from django.contrib import admin
from django_walletpass.models import Pass, Registration, Log
from django.template import Context, Template
from django.urls import reverse
from django.utils.html import format_html

admin.site.register(Pass)
admin.site.register(Registration)
admin.site.register(Log)
from django_walletpass.models import Log, Pass, Registration


@admin.register(Log)
class LogAdmin(admin.ModelAdmin):
list_display = (
"created_at",
"status",
"task_type",
# "pass_type_identifier",
# "serial_number",
"pass_",
# "web_service_url",
"device_id",
"msg",
)
list_filter = ("status", "task_type", "pass_type_identifier")
search_fields = (
"pass_type_identifier",
"serial_number",
"device_id",
"msg",
"message",
)
readonly_fields = ("created_at", "pass_")
raw_id_fields = ("pazz",)
list_select_related = ("pazz",)

def pass_(self, obj: Log):
if obj.pazz_id:
url = reverse(
"admin:%s_%s_change"
% (obj.pazz._meta.app_label, obj.pazz._meta.model_name),
args=[obj.pazz_id],
)
return format_html(
"<a href='{url}'>{title}</a>",
url=url,
title=obj.serial_number,
)
return obj.serial_number

pass_.short_description = "Pass"


@admin.register(Pass)
class PassAdmin(admin.ModelAdmin):
list_display = (
"serial_number",
"updated_at",
"pass_type_identifier",
"wallet_pass_",
)
search_fields = (
"serial_number",
"pass_type_identifier",
"authentication_token",
"data",
)
list_filter = ("pass_type_identifier", "updated_at")
date_hierarchy = "updated_at"
readonly_fields = ("wallet_pass_", "updated_at")

def wallet_pass_(self, obj: Pass):
if obj.data:
return format_html(
Template(
"{% load static %}<a href='{url}' alt='{title}'><img src='{% static 'admin/passbook_icon.svg' %}'/></a>"
Copy link
Member

Choose a reason for hiding this comment

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

👍

).render(Context({})),
url=obj.data.url,
title=obj.data.name,
)
return

wallet_pass_.short_description = "Pass"


@admin.register(Registration)
class RegistrationAdmin(admin.ModelAdmin):
list_display = ("device_library_identifier", "push_token", "pass_")
search_fields = ("device_library_identifier", "push_token", "pazz__serial_number")
raw_id_fields = ("pazz",)
readonly_fields = ("pass_",)

def pass_(self, obj: Registration):
if obj.pazz_id:
url = reverse(
"admin:%s_%s_change"
% (obj.pazz._meta.app_label, obj.pazz._meta.model_name),
args=[obj.pazz_id],
)
return format_html(
"<a href='{url}'>{title}</a>",
url=url,
title=obj.pazz.serial_number,
)
return

pass_.short_description = "Pass"
1 change: 1 addition & 0 deletions django_walletpass/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class DjangoWalletpassConfig(AppConfig):
name = 'django_walletpass'
verbose_name = 'Django walletpass'

def ready(self):
from django_walletpass import signals as _signals # pylint: disable=import-outside-toplevel
3 changes: 2 additions & 1 deletion django_walletpass/classviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,6 @@ class LogViewSet(viewsets.ViewSet):
def create(self, request):
json_body = json.loads(request.body)
for message in json_body['logs']:
Log(message=message).save()
log = Log(message=message)
Log.parse_log(log, message)
return Response({}, status=status.HTTP_200_OK)
66 changes: 66 additions & 0 deletions django_walletpass/migrations/0009_auto_20230709_2143.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Generated by Django 3.2.14 on 2023-07-09 18:43

from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import django_walletpass.storage


class Migration(migrations.Migration):

dependencies = [
('django_walletpass', '0008_alter_pass_data'),
]

operations = [
migrations.AddField(
model_name='log',
name='created_at',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name='log',
name='device_id',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name='log',
name='msg',
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name='log',
name='pass_type_identifier',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name='log',
name='pazz',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='django_walletpass.pass'),
),
migrations.AddField(
model_name='log',
name='serial_number',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name='log',
name='status',
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AddField(
model_name='log',
name='task_type',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name='log',
name='web_service_url',
field=models.URLField(blank=True, null=True),
),
migrations.AlterField(
model_name='pass',
name='data',
field=models.FileField(storage=django_walletpass.storage.WalletPassStorage(), upload_to='passes'),
),
]
18 changes: 18 additions & 0 deletions django_walletpass/migrations/0010_alter_registration_push_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.14 on 2023-07-13 10:41

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('django_walletpass', '0009_auto_20230709_2143'),
]

operations = [
migrations.AlterField(
model_name='registration',
name='push_token',
field=models.CharField(max_length=255),
),
]
79 changes: 78 additions & 1 deletion django_walletpass/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import datetime
import os
import re
import uuid
import hashlib
import json
Expand All @@ -7,6 +9,7 @@
import zipfile
from glob import glob
from django.core.exceptions import ValidationError
from django.utils import timezone
from django.utils.module_loading import import_string
from django.db import models
from django.utils.translation import gettext_lazy as _
Expand Down Expand Up @@ -285,6 +288,9 @@ def get_pass_builder(self):
def __unicode__(self):
return self.serial_number

def __str__(self):
return self.serial_number

class Meta:
verbose_name_plural = "passes"
unique_together = (
Expand All @@ -298,7 +304,7 @@ class Registration(models.Model):
Registration of a Pass on a device
"""
device_library_identifier = models.CharField(max_length=150)
push_token = models.CharField(max_length=150)
push_token = models.CharField(max_length=255)
pazz = models.ForeignKey(
Pass,
on_delete=models.CASCADE,
Expand All @@ -308,12 +314,83 @@ class Registration(models.Model):
def __unicode__(self):
return self.device_library_identifier

def __str__(self):
return self.device_library_identifier


class Log(models.Model):
"""
Log message sent by a device
"""
created_at = models.DateTimeField(default=timezone.now)
status = models.CharField(max_length=100, null=True, blank=True)
task_type = models.CharField(max_length=255, null=True, blank=True)
pass_type_identifier = models.CharField(max_length=255, null=True, blank=True)
serial_number = models.CharField(max_length=255, null=True, blank=True)
pazz = models.ForeignKey(Pass, null=True, blank=True, on_delete=models.CASCADE, related_name='logs')
web_service_url = models.URLField(null=True, blank=True)
device_id = models.CharField(max_length=255, null=True, blank=True)
msg = models.TextField(null=True, blank=True)
message = models.TextField()

def __unicode__(self):
return self.message

def __str__(self):
return self.created_at.strftime('%d/%m/%y %H:%M:%S')

@classmethod
def parse_log(cls, log, message):
pattern_register = r"\[(.*?)\]\s(.*?)\s\(for device (.*?), pass type (.*?), serial number (.*?); with web service url (.*?)\)\s(.*?): (.*$)"
pattern_get = r"\[(.*?)\]\s(.*?)\s\(pass type (.*?), serial number (.*?), if-modified-since \(.*?\); with web service url (.*?)\) (.*?): (.*$)"
pattern_web_service_error = r"\[(.*?)\]\s(.*?)\sfor (.*?)\s\((.*?)\):\s(.*$)"
pattern_get_warning = r"\[(.*?)\]\s(.*?)\s\(pass type (.*?), serial number (.*?), if-modified-since \(.*?\); with web service url (.*?)\) (.*?): (.*\.)\s(.*$)"

match_register = re.match(pattern_register, message)
match_get = re.match(pattern_get, message)
match_web_service_error = re.match(pattern_web_service_error, message)
match_get_warning = re.match(pattern_get_warning, message)

if match_register:
timestamp_str, task_type, device_id, pass_type_identifier, serial_number, web_service_url, status, msg = match_register.groups()
elif match_get:
timestamp_str, task_type, pass_type_identifier, serial_number, web_service_url, status, msg = match_get.groups()
device_id = None # 'Get pass task' entries don't include device_id
elif match_web_service_error:
timestamp_str, task_type, pass_type_identifier, web_service_url, msg = match_web_service_error.groups()
serial_number = None
device_id = None
status = "error"
elif match_get_warning:
timestamp_str, task_type, pass_type_identifier, serial_number, web_service_url, status, msg = match_get_warning.groups()
device_id = None
status = "warning"
else:
log.status = 'unknown'
log.message = message
log.save()
return # Log entry didn't match any known pattern

if 'error' in status:
status = 'error'
elif 'warning' in status:
status = 'warning'

log.created_at = datetime.datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S %z")
Copy link
Member

Choose a reason for hiding this comment

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

This will crash if timestamp_str doesn't have the expected format (which will happen if the code falls through the final else). Maybe default to now()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good morning, the final else will trigger return. in that case timestamp_str wouldn't even be defined. in case timestamp_str changes and does not match the expected pattern anymore, we should get noticed (exception?) and not fill it with a default value which would result in the data speaking non-exact facts.

Copy link
Member

Choose a reason for hiding this comment

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

ohh, true! hmmm... 🤔... maybe add a new TextField and store the raw received message? This way we won't loose any messages (that might be useful, but we didn't have the right pattern match for them).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

😅 time for another coffee I guess

log.status = status
log.task_type = task_type
log.device_id = device_id
log.pass_type_identifier = pass_type_identifier
log.serial_number = serial_number
log.web_service_url = web_service_url
log.msg = msg
log.message = message

if serial_number:
try:
pazz = Pass.objects.get(serial_number=serial_number)
log.pazz = pazz
except Pass.DoesNotExist:
pass

log.save()
6 changes: 5 additions & 1 deletion django_walletpass/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

class PushBackend:
def __init__(self):
self.loop = asyncio.get_event_loop()
try:
self.loop = asyncio.get_event_loop()
except RuntimeError:
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)

async def push_notification(self, client, token):

Expand Down
3 changes: 3 additions & 0 deletions django_walletpass/static/admin/passbook_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading