168 lines
5.3 KiB
Python
168 lines
5.3 KiB
Python
from datetime import timedelta, datetime
|
|
from urllib.parse import urlencode
|
|
|
|
import pytz
|
|
from django.db.models import Count, Q, Sum
|
|
from django.http import HttpResponse, Http404
|
|
from django.shortcuts import render, redirect, get_object_or_404
|
|
from django.views.decorators.http import require_GET
|
|
from icalendar import Calendar, Event
|
|
|
|
from authn.decorators.auth import require_auth
|
|
from badges.models import UserBadge
|
|
from misc.models import NetworkGroup
|
|
from users.models.achievements import Achievement, UserAchievement
|
|
from users.models.user import User
|
|
|
|
|
|
@require_auth
|
|
def stats(request):
|
|
achievements = Achievement.objects\
|
|
.annotate(user_count=Count('users'))\
|
|
.filter(is_visible=True)\
|
|
.filter(user_count__gt=0)\
|
|
.exclude(code__in=["old", "parliament_member"])\
|
|
.order_by('-user_count')
|
|
|
|
latest_badges = UserBadge.objects\
|
|
.select_related("badge", "to_user")\
|
|
.order_by('-created_at')[:20]
|
|
|
|
top_badges = list(filter(None.__ne__, [
|
|
User.registered_members().filter(id=to_user).first() for to_user, _ in UserBadge.objects
|
|
.filter(created_at__gte=datetime.utcnow() - timedelta(days=150))
|
|
.values_list("to_user")
|
|
.annotate(sum_price=Sum("badge__price_days"))
|
|
.order_by("-sum_price")[:7] # select more in case someone gets deleted
|
|
]))[:5] # filter None
|
|
|
|
moderators = User.objects\
|
|
.filter(Q(roles__contains=[User.ROLE_MODERATOR]) | Q(roles__contains=[User.ROLE_GOD]))
|
|
|
|
parliament = User.objects.filter(achievements__achievement_id="parliament_member")
|
|
|
|
top_users = User.objects\
|
|
.filter(
|
|
moderation_status=User.MODERATION_STATUS_APPROVED,
|
|
membership_expires_at__gte=datetime.utcnow() + timedelta(days=70)
|
|
)\
|
|
.order_by("-membership_expires_at")[:64]
|
|
|
|
return render(request, "pages/stats.html", {
|
|
"achievements": achievements,
|
|
"latest_badges": latest_badges,
|
|
"top_badges": top_badges,
|
|
"top_users": top_users,
|
|
"moderators": moderators,
|
|
"parliament": parliament,
|
|
})
|
|
|
|
|
|
@require_auth
|
|
def show_achievement(request, achievement_code):
|
|
achievement = get_object_or_404(Achievement, code=achievement_code)
|
|
if not achievement.is_visible:
|
|
raise Http404()
|
|
|
|
users = User.objects.filter(achievements__achievement_id=achievement_code)
|
|
|
|
# calculate rarity of the achievement
|
|
achievement_stats = dict(
|
|
UserAchievement.objects.all()
|
|
.values("achievement_id")
|
|
.annotate(total=Count("achievement_id"))
|
|
.order_by("-total")
|
|
.values_list("achievement_id", "total")
|
|
)
|
|
|
|
total_count = len(achievement_stats.values())
|
|
index = list(achievement_stats.keys()).index(achievement_code)
|
|
rarity = (index / total_count) * 100
|
|
|
|
return render(request, "achievements/show_achievement.html", {
|
|
"achievement": achievement,
|
|
"users": users,
|
|
"rarity": round(rarity, 1)
|
|
})
|
|
|
|
|
|
@require_auth
|
|
def network(request):
|
|
network_groups = NetworkGroup.visible_objects()
|
|
return render(request, "pages/network.html", {
|
|
"network": network_groups,
|
|
})
|
|
|
|
|
|
@require_GET
|
|
def robots(request):
|
|
lines = [
|
|
"User-agent: *",
|
|
"Sitemap: https://vas3k.club/sitemap.xml",
|
|
"Host: https://vas3k.club",
|
|
"Disallow: /intro/",
|
|
"Disallow: /user/",
|
|
"Disallow: /people/",
|
|
"Clean-param: comment_order&goto /",
|
|
]
|
|
return HttpResponse("\n".join(lines), content_type="text/plain")
|
|
|
|
|
|
@require_auth
|
|
def generate_ical_invite(request):
|
|
event_title = request.GET.get("title")
|
|
event_date = request.GET.get("date")
|
|
event_url = request.GET.get("url")
|
|
event_location = request.GET.get("location")
|
|
event_timezone = request.GET.get("timezone")
|
|
|
|
if not event_title or not event_date or not event_timezone:
|
|
return HttpResponse("No date, tz or title")
|
|
|
|
event_date = datetime.fromisoformat(event_date).replace(tzinfo=pytz.timezone(event_timezone))
|
|
|
|
cal = Calendar()
|
|
event = Event()
|
|
event.add("summary", event_title)
|
|
event.add("dtstart", event_date)
|
|
event.add("dtend", event_date + timedelta(hours=2))
|
|
|
|
if event_url:
|
|
event.add("description", f"{event_url}")
|
|
|
|
if event_location:
|
|
event.add("location", event_location)
|
|
|
|
cal.add_component(event)
|
|
|
|
response = HttpResponse(cal.to_ical(), content_type="application/force-download")
|
|
response["Content-Disposition"] = "attachment; filename=ical_vas3k_club.ics"
|
|
return response
|
|
|
|
|
|
@require_auth
|
|
def generate_google_invite(request):
|
|
event_title = request.GET.get("title")
|
|
event_date = request.GET.get("date")
|
|
event_url = request.GET.get("url")
|
|
event_location = request.GET.get("location")
|
|
event_timezone = request.GET.get("timezone")
|
|
|
|
if not event_title or not event_date or not event_timezone:
|
|
return HttpResponse("No date, tz or title")
|
|
|
|
event_date = datetime.fromisoformat(event_date)
|
|
|
|
google_url_params = urlencode({
|
|
"text": event_title,
|
|
"dates": "{}/{}".format(
|
|
event_date.strftime("%Y%m%dT%H%M%S"),
|
|
(event_date + timedelta(hours=2)).strftime("%Y%m%dT%H%M%S"),
|
|
),
|
|
"details": f"{event_url}",
|
|
"location": event_location,
|
|
"ctz": event_timezone,
|
|
})
|
|
|
|
return redirect(f"https://calendar.google.com/calendar/u/0/r/eventedit?{google_url_params}")
|