Update web/core/views.py
This commit is contained in:
parent
d70cc99e9c
commit
d4ef68ee72
@ -664,3 +664,149 @@ def api_get_recent_views(request):
|
|||||||
@login_required
|
@login_required
|
||||||
def settings_home(request):
|
def settings_home(request):
|
||||||
return render(request, "settings/home.html")
|
return render(request, "settings/home.html")
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def stats_page(request):
|
||||||
|
from collections import Counter, OrderedDict
|
||||||
|
from calendar import month_abbr
|
||||||
|
|
||||||
|
total = Entry.objects.count()
|
||||||
|
today = date.today()
|
||||||
|
last30 = Entry.objects.filter(date_added__gte=today - timedelta(days=30)).count()
|
||||||
|
last365 = Entry.objects.filter(date_added__gte=today - timedelta(days=365)).count()
|
||||||
|
|
||||||
|
# ---- Sparkline (last 12 months) ----
|
||||||
|
months = []
|
||||||
|
y = today.year
|
||||||
|
m = today.month
|
||||||
|
for i in range(12):
|
||||||
|
mm = m - i
|
||||||
|
yy = y
|
||||||
|
while mm <= 0:
|
||||||
|
mm += 12
|
||||||
|
yy -= 1
|
||||||
|
from datetime import date as _d
|
||||||
|
start = _d(yy, mm, 1)
|
||||||
|
end = _d(yy + 1, 1, 1) if mm == 12 else _d(yy, mm + 1, 1)
|
||||||
|
label = f"{month_abbr[mm]} {str(yy)[2:]}"
|
||||||
|
months.append((label, start, end))
|
||||||
|
months = list(reversed(months))
|
||||||
|
|
||||||
|
series = [
|
||||||
|
(label, Entry.objects.filter(date_added__gte=start, date_added__lt=end).count())
|
||||||
|
for label, start, end in months
|
||||||
|
]
|
||||||
|
peak = max((v for _, v in series), default=1)
|
||||||
|
heights = [
|
||||||
|
(label, value, 8 + int((value / peak) * 100) if peak else 8)
|
||||||
|
for label, value in series
|
||||||
|
]
|
||||||
|
|
||||||
|
# ---- Top subjects (existing) ----
|
||||||
|
subject_counts = Counter()
|
||||||
|
for subj in Entry.objects.exclude(subject="").values_list("subject", flat=True):
|
||||||
|
for tag in [t.strip() for t in subj.split(",") if t.strip()]:
|
||||||
|
subject_counts[tag.lower()] += 1
|
||||||
|
top_subjects = [{"name": n.title(), "count": c} for n, c in subject_counts.most_common(10)]
|
||||||
|
|
||||||
|
# ===============================
|
||||||
|
# Scripture analytics (from scripture_raw)
|
||||||
|
# ===============================
|
||||||
|
# A light normalizer so common abbreviations map to canonical book names.
|
||||||
|
BOOK_MAP = {
|
||||||
|
# OT (examples; extend as needed)
|
||||||
|
"gen":"Genesis","ge":"Genesis","gn":"Genesis",
|
||||||
|
"ex":"Exodus","exo":"Exodus",
|
||||||
|
"lev":"Leviticus","le":"Leviticus",
|
||||||
|
"num":"Numbers","nu":"Numbers",
|
||||||
|
"de":"Deuteronomy","deut":"Deuteronomy",
|
||||||
|
"jos":"Joshua","josh":"Joshua",
|
||||||
|
"jdg":"Judges","judg":"Judges",
|
||||||
|
"ru":"Ruth","rut":"Ruth",
|
||||||
|
"ps":"Psalms","psalm":"Psalms","psalms":"Psalms",
|
||||||
|
"pr":"Proverbs","pro":"Proverbs",
|
||||||
|
"ec":"Ecclesiastes","ecc":"Ecclesiastes",
|
||||||
|
"isa":"Isaiah","is":"Isaiah",
|
||||||
|
"jer":"Jeremiah","je":"Jeremiah",
|
||||||
|
"eze":"Ezekiel","ez":"Ezekiel",
|
||||||
|
"da":"Daniel","dan":"Daniel",
|
||||||
|
"ho":"Hosea","hos":"Hosea",
|
||||||
|
# NT (examples; extend as needed)
|
||||||
|
"mt":"Matthew","matt":"Matthew",
|
||||||
|
"mr":"Mark","mk":"Mark",
|
||||||
|
"lu":"Luke","lk":"Luke",
|
||||||
|
"joh":"John","john":"John","jn":"John",
|
||||||
|
"ac":"Acts","acts":"Acts",
|
||||||
|
"rom":"Romans","ro":"Romans",
|
||||||
|
"1cor":"1 Corinthians","1 co":"1 Corinthians","1 cor":"1 Corinthians",
|
||||||
|
"2cor":"2 Corinthians","2 co":"2 Corinthians","2 cor":"2 Corinthians",
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOK_RE = re.compile(r"""
|
||||||
|
^\s*
|
||||||
|
(?P<book>(?:[1-3]\s*)?[A-Za-z\.]+) # optional 1/2/3 prefix + word
|
||||||
|
[\s\.]+
|
||||||
|
(?P<ref>\d+[:\.]\d+.*)? # 3:16 or 3.16 etc (optional tail)
|
||||||
|
""", re.X)
|
||||||
|
|
||||||
|
def normalize_book(raw):
|
||||||
|
b = raw.strip().lower().replace('.', '')
|
||||||
|
b = re.sub(r'\s+', '', b) # "1 john" -> "1john"
|
||||||
|
return BOOK_MAP.get(b, raw.strip().title())
|
||||||
|
|
||||||
|
def split_refs(text):
|
||||||
|
if not text:
|
||||||
|
return []
|
||||||
|
# Entries are typically separated by semicolons; allow commas too.
|
||||||
|
parts = re.split(r'[;]+', text)
|
||||||
|
return [p.strip() for p in parts if p.strip()]
|
||||||
|
|
||||||
|
def parse_piece(piece):
|
||||||
|
m = BOOK_RE.match(piece)
|
||||||
|
if not m:
|
||||||
|
return None, None
|
||||||
|
book = normalize_book(m.group('book'))
|
||||||
|
ref = (m.group('ref') or '').strip()
|
||||||
|
return book, (f"{book} {ref}" if ref else book)
|
||||||
|
|
||||||
|
book_counts = Counter()
|
||||||
|
ref_counts = Counter()
|
||||||
|
refs_per_entry = []
|
||||||
|
|
||||||
|
entries_with_script = (Entry.objects
|
||||||
|
.exclude(scripture_raw__isnull=True)
|
||||||
|
.exclude(scripture_raw__exact=""))
|
||||||
|
for e in entries_with_script.iterator():
|
||||||
|
pieces = split_refs(e.scripture_raw)
|
||||||
|
entry_ref_count = 0
|
||||||
|
for piece in pieces:
|
||||||
|
book, full = parse_piece(piece)
|
||||||
|
if not book:
|
||||||
|
continue
|
||||||
|
book_counts[book] += 1
|
||||||
|
if full and full != book:
|
||||||
|
ref_counts[full] += 1
|
||||||
|
entry_ref_count += 1
|
||||||
|
if entry_ref_count:
|
||||||
|
refs_per_entry.append(entry_ref_count)
|
||||||
|
|
||||||
|
avg_refs_per_entry = round(sum(refs_per_entry) / len(refs_per_entry), 2) if refs_per_entry else 0
|
||||||
|
top_books = list(book_counts.most_common(10))
|
||||||
|
top_refs = list(ref_counts.most_common(10))
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"stats.html",
|
||||||
|
{
|
||||||
|
"total": total,
|
||||||
|
"last30": last30,
|
||||||
|
"last365": last365,
|
||||||
|
"series": series,
|
||||||
|
"heights": heights,
|
||||||
|
"top_subjects": top_subjects,
|
||||||
|
# NEW:
|
||||||
|
"avg_refs_per_entry": avg_refs_per_entry,
|
||||||
|
"top_books": top_books, # iterable of (book, count)
|
||||||
|
"top_refs": top_refs, # iterable of (ref, count)
|
||||||
|
},
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue
Block a user