-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathadmin.py
More file actions
121 lines (102 loc) · 3.97 KB
/
admin.py
File metadata and controls
121 lines (102 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import csv
import logging
import re
from datetime import datetime
from io import TextIOWrapper
from django import forms
from django.shortcuts import redirect, render
from django.urls import path
from django.http import HttpResponseRedirect
from django.contrib import admin, messages
from django.conf import settings
from mailing_list.models import EmailData, PostingData, SubscriptionData
from mailing_list.tasks import sync_mailinglist_stats
logger = logging.getLogger(__name__)
@admin.register(EmailData)
class EmailDataAdmin(admin.ModelAdmin):
list_display = ["author", "version", "count"]
search_fields = [
"author__commitauthoremail__email",
"author__name",
]
raw_id_fields = ["author"]
list_filter = ["version"]
change_list_template = "admin/mailinglist_change_list.html"
def get_urls(self):
urls = super().get_urls()
my_urls = [
path(
"sync_mailinglist_stats/",
self.admin_site.admin_view(self.sync_mailinglist_stats),
name="sync_mailinglist_stats",
),
]
return my_urls + urls
def sync_mailinglist_stats(self, request):
if settings.HYPERKITTY_DATABASE_NAME:
sync_mailinglist_stats.delay()
self.message_user(request, "Syncing EmailData.")
else:
self.message_user(
request,
"HYPERKITTY_DATABASE_NAME setting not configured.",
level=messages.WARNING,
)
return HttpResponseRedirect("../")
def has_add_permission(self, request):
return False
@admin.register(PostingData)
class PostingDataAdmin(admin.ModelAdmin):
list_display = ["name", "post_time"]
search_fields = ["name"]
list_filter = ["post_time"]
class SubscribesCSVForm(forms.Form):
csv_file = forms.FileField()
@admin.register(SubscriptionData)
class SubscriptionDataAdmin(admin.ModelAdmin):
list_display = ["subscription_dt", "email"]
search_fields = ["email"]
change_list_template = "admin/mailinglist_change_list.html"
email_regex = re.compile("([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})")
def get_urls(self):
return [
path("import-csv", self.import_csv, name="import_csv")
] + super().get_urls()
def parse_rows(self, reader):
for row in reader:
date_str = " ".join(row[0:4])
try:
dt = datetime.strptime(date_str, "%b %d %H:%M:%S %Y")
except ValueError:
logger.error(f"Error parsing date {date_str} from {row=}")
dt = None
# re-merge, the email address isn't always in a consistent position
email_matches = re.search(self.email_regex, " ".join(row[6:]))
email = email_matches.group(0) if email_matches else None
entry_type = row[6]
# only save confirmed subscriber entries, it's all we need for now
if entry_type != "new":
continue
if not email:
logger.error(
f"Invalid email {row=} {email_matches=} {' '.join(row[6:])=}"
)
continue
yield SubscriptionData(
email=email,
entry_type=entry_type,
list=row[5].rstrip(":-1"),
subscription_dt=dt,
)
def import_csv(self, request):
if request.method == "POST":
csv_file = request.FILES["csv_file"]
rows = TextIOWrapper(csv_file, encoding="ISO-8859-1", newline="")
reader = csv.reader(rows, delimiter=" ")
SubscriptionData.objects.bulk_create(
self.parse_rows(reader), batch_size=500, ignore_conflicts=True
)
self.message_user(request, "Subscribe CSV file imported.")
return redirect("..")
payload = {"form": SubscribesCSVForm()}
return render(request, "admin/mailinglist_subscribe_csv_form.html", payload)