merging from rep in production

This commit is contained in:
oslomp
2019-02-15 17:41:40 +01:00
30 changed files with 733 additions and 180 deletions

View File

@ -111,7 +111,7 @@ def songs(request):
except EmptyPage:
songs = paginator.page(paginator.num_pages)
songs_dict = [song_to_dict(song, user=True) for song in songs.object_list]
songs_dict = [song_to_dict(song, include_user=True) for song in songs.object_list]
return JsonResponse({
'per_page': pagesize,
'current_page': page,

View File

@ -5,9 +5,6 @@ from django.utils.translation import ugettext_lazy as _
class AuthenticationForm(BaseAuthenticationForm):
def __init__(self, request=None, *args, **kwargs):
super(AuthenticationForm, self).__init__(request, *args, **kwargs)
def confirm_login_allowed(self, user):
if user.activation_token:
raise forms.ValidationError(

View File

@ -1,14 +1,14 @@
from django.db import models
from queues.models import Queue
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.validators import ASCIIUsernameValidator, UnicodeUsernameValidator
from django.core.mail import send_mail
from django.db import models
from django.utils import six, timezone
from django.utils.translation import ugettext_lazy as _
from django.core.mail import send_mail
from marietje.utils import get_first_queue
from queues.models import Queue
class UserManager(BaseUserManager):

View File

@ -62,7 +62,7 @@ DATABASES = {
'PASSWORD': 'v8TzZwdAdSi7Tk5I',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" },
'OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
}
}
@ -95,12 +95,17 @@ CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/MarietjeDjango_cache/default',
'OPTIONS': { 'MAX_ENTRIES': 1000 },
'OPTIONS': {'MAX_ENTRIES': 1000},
},
'song_search': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/MarietjeDjango_cache/song_search',
'OPTIONS': { 'MAX_ENTRIES': 1000 },
'OPTIONS': {'MAX_ENTRIES': 1000},
},
'userstats': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/MarietjeDjango_cache/default',
'OPTIONS': {'MAX_ENTRIES': 1500},
},
'userstats': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
@ -144,8 +149,8 @@ CONTACT_EMAIL = 'marietje@science.ru.nl'
STATS_TOP_COUNT = 50
STATS_REQUEST_IGNORE_USER_IDS = []
ISSUES_URL = 'https://gitlab.science.ru.nl/Marietje/MarietjeDjango/issues'
MERGE_REQUESTS_URL = 'https://gitlab.science.ru.nl/Marietje/MarietjeDjango/merge_requests'
ISSUES_URL = 'https://gitlab.science.ru.nl/dsprenkels/MarietjeDjango/issues'
MERGE_REQUESTS_URL = 'https://gitlab.science.ru.nl/dsprenkels/MarietjeDjango/merge_requests'
TRUSTED_IP_RANGES = [
'131.174.0.0/16', # RU wired
'145.116.136.0/22', # eduroam

View File

@ -23,10 +23,9 @@ footer {
}
.marietjequeue {
color: #777777;"
color: #777777;
}
.marietjequeuestart {
.marietjequeue-start {
border-top: 4px double #777777;
color: #777777;"
}

View File

@ -52,6 +52,9 @@ $(function () {
createAlert('danger', 'Please enter a message.');
return false
}
if (message == null) {
return false
}
$.post('/api/report', {id: songId, msg: message, csrfmiddlewaretoken: csrf_token}, function (result) {
if (result.success) {
createAlert('success', 'Thanks for your song report!');
@ -198,14 +201,15 @@ function renderQueue(playNextAt, now)
var requestedBy = song.requested_by;
var reqMarietje = requestedBy != 'Marietje';
var startMarietje = false
//checks if id is the last item and returns false if the next song is Marietje, while the current song is not.
//checks if id is the last item and returns false if the next song is Marietje, while the current song is not.
if(id === queue.length-1){
var requestNext = false
} else {
var requestNext = !((queue[id+1].requested_by === 'Marietje') && (requestedBy !== 'Marietje'))
}
//checks if id is the first item and returns false if the previous song is not Marietje, while the current song is.
//checks if id is the first item and returns false if the previous song is not Marietje, while the current song is.
if(id === 0){
var requestPrev = false
} else {
@ -226,7 +230,7 @@ function renderQueue(playNextAt, now)
var artist = song.song.artist.trim() === '' ? '?' : song.song.artist;
var title = song.song.title.trim() === '' ? '?' : song.song.title;
var marietjeclass = reqMarietje ? '' : ' class="marietjequeue"';
var marietjestartclass = startMarietje ? ' class="marietjequeuestart"' : '';
var marietjestartclass = startMarietje ? ' class="marietjequeue marietjequeue-start"' : '';
showTime = showTimeToPlay ? (timeToPlay < 0 ? '' : timeToPlay.secondsToMMSS()) : (playNextAt < now ? '' : playNextAt.timestampToHHMMSS())

View File

@ -1,10 +1,13 @@
import socket, struct, binascii
import binascii
import socket
import struct
from django.conf import settings
from queues.models import Queue, Playlist
from django.http import StreamingHttpResponse
from queues.models import Queue, Playlist
def song_to_dict(song, hash=False, user=False, replaygain=False):
def song_to_dict(song, include_hash=False, include_user=False, include_replaygain=False, **options):
data = {
'id': song.id,
'artist': song.artist,
@ -12,13 +15,13 @@ def song_to_dict(song, hash=False, user=False, replaygain=False):
'duration': song.duration,
}
if hash:
if include_hash:
data['hash'] = song.hash
if user is not None and song.user is not None and song.user.name:
if include_user is not None and song.user is not None and song.user.name:
data['uploader_name'] = song.user.name
if replaygain:
if include_replaygain:
data['rg_gain'] = song.rg_gain
data['rg_peak'] = song.rg_peak
@ -44,9 +47,9 @@ def send_to_bertha(file):
for chunk in file.chunks():
sock.sendall(chunk)
sock.shutdown(socket.SHUT_WR)
hash = binascii.hexlify(sock.recv(64))
song_hash = binascii.hexlify(sock.recv(64))
sock.close()
return hash
return song_hash
def get_first_queue():
@ -61,10 +64,10 @@ def get_first_queue():
return queue
def bertha_stream(hash):
def bertha_stream(song_hash):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(settings.BERTHA_HOST)
sock.sendall(struct.pack("<B", 2) + binascii.unhexlify(hash))
sock.sendall(struct.pack("<B", 2) + binascii.unhexlify(song_hash))
data = sock.recv(4096)
while data:
yield data
@ -72,7 +75,7 @@ def bertha_stream(hash):
sock.close()
def get_from_bertha(hash):
response = StreamingHttpResponse(bertha_stream(hash))
response['Content-Disposition'] = 'attachment; filename="{}"'.format(hash)
def get_from_bertha(song_hash):
response = StreamingHttpResponse(bertha_stream(song_hash))
response['Content-Disposition'] = 'attachment; filename="{}"'.format(song_hash)
return response

View File

@ -8,8 +8,7 @@ from django.core.mail import send_mail
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from marietje.utils import get_first_queue
from .forms import RegistrationForm, ResetPasswordForm
from .forms import ResetPasswordForm
def register(request):

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,4 +1,3 @@
from django.db.models import Count, Q
from django.http import HttpResponse
from django.db.utils import OperationalError
@ -16,13 +15,12 @@ queue_users_gauge = Gauge('marietje_queue_users', 'Users holding a queue at some
try:
for queue in Queue.objects.all():
def _get_queue_length():
return (PlaylistSong.objects.filter(playlist=queue.playlist_id, state=0)
.count())
return PlaylistSong.objects.filter(playlist=queue.playlist_id, state=0).count()
def _get_queue_duration():
playlist_songs = (PlaylistSong.objects.filter(playlist=queue.playlist_id, state=0)
.select_related('song')
.all())
.select_related('song')
.all())
return sum(ps.song.duration for ps in playlist_songs)
def _get_queue_distinct_users():
@ -31,7 +29,7 @@ try:
# that much of confidence that it would also work on mysql.
# Furtermore, we do not expect the queue to be very long at any moment.
return len(set(PlaylistSong.objects.filter(playlist=queue.playlist_id, state=0)
.values_list('user')))
.values_list('user')))
queue_length_gauge.labels(name=queue).set_function(_get_queue_length)
queue_duration_gauge.labels(name=queue).set_function(_get_queue_duration)

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -14,16 +14,16 @@ from .decorators import token_required
@csrf_exempt
@token_required
def queue(request):
queue = get_object_or_404(Queue, id=request.POST.get('queue'))
current_queue = get_object_or_404(Queue, id=request.POST.get('queue'))
commands = queue.queuecommand_set.filter(executed=False)
commands = current_queue.queuecommand_set.filter(executed=False)
for command in commands:
command.executed = True
command.save()
return JsonResponse({
'current_song': playlist_song_to_dict(queue.current_song(), hash=True, replaygain=True),
'queue': [playlist_song_to_dict(playlist_song, hash=True, replaygain=True) for playlist_song in queue.queue()[:1]],
'current_song': playlist_song_to_dict(current_queue.current_song(), include_hash=True, include_replaygain=True),
'queue': [playlist_song_to_dict(playlist_song, include_hash=True, include_replaygain=True) for playlist_song in current_queue.queue()[:1]],
'commands': [command.command for command in commands]
})
@ -31,9 +31,9 @@ def queue(request):
@csrf_exempt
@token_required
def play(request):
queue = get_object_or_404(Queue, id=request.POST.get('queue'))
queue.started_at = timezone.now()
queue.save()
current_queue = get_object_or_404(Queue, id=request.POST.get('queue'))
current_queue.started_at = timezone.now()
current_queue.save()
current_song = queue.current_song()
current_song.played_at = queue.started_at
current_song.save()
@ -41,11 +41,12 @@ def play(request):
return JsonResponse({})
# pylint: disable=redefined-builtin
@csrf_exempt
@token_required
def next(request):
queue = get_object_or_404(Queue, id=request.POST.get('queue'))
player_song = queue.current_song()
current_queue = get_object_or_404(Queue, id=request.POST.get('queue'))
player_song = current_queue.current_song()
player_song.state = 2
player_song.save()
return JsonResponse({})

View File

@ -1,7 +1,5 @@
import time
from django.db import models
from django.db.models import Q, Max
from django.db.models import Q
from django.conf import settings
from django.utils import timezone
@ -99,7 +97,7 @@ class Queue(models.Model):
def current_song(self):
songs = self.get_songs()
if len(songs) < 1:
if not songs:
return None
song = songs[0]
if song.state != 1:
@ -136,7 +134,8 @@ class Queue(models.Model):
playlist_song.save()
# If the song was auto-queue'd, then remove it from the auto-queue
autolist_songs = PlaylistSong.objects.filter(playlist=self.random_playlist, state=0, song=song).delete()
autolist_songs = PlaylistSong.objects.filter(playlist=self.random_playlist, state=0, song=song)
autolist_songs.delete()
return None

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,8 +1,2 @@
from django.conf.urls import url
from . import views
app_name = 'queue'
urlpatterns = [
]
urlpatterns = []

View File

@ -13,7 +13,8 @@ class SongAdmin(admin.ModelAdmin):
search_fields = ('artist', 'title', 'user__name')
inlines = [ReportNoteInline]
def reports(self, song):
@staticmethod
def reports(song):
return ReportNote.objects.filter(song=song).count()
@staticmethod
@ -31,3 +32,4 @@ class SongAdmin(admin.ModelAdmin):
class ReportNoteAdmin(admin.ModelAdmin):
list_display = ('song', 'note', 'user')
search_fields = ('song__artist', 'song__title', 'user__name')
readonly_fields = ('song',)

View File

@ -43,7 +43,8 @@ class Song(models.Model):
return self.artist + ' - ' + self.title
class ReportNote(models.Model):
song = models.ForeignKey(Song,
song = models.ForeignKey(
Song,
on_delete=models.CASCADE,
blank=False,
null=False,
@ -54,7 +55,9 @@ class ReportNote(models.Model):
blank=True,
null=True,
db_index=True)
note = models.TextField(verbose_name='reason', blank=True,
note = models.TextField(
verbose_name='reason',
blank=True,
help_text='reason for edit request')
def __str__(self):

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,5 +1,5 @@
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.decorators import login_required
from .models import Song
@ -14,8 +14,8 @@ def manage(request):
@login_required
def edit(request, id):
song = get_object_or_404(Song, pk=id, user=request.user)
def edit(request, song_id):
song = get_object_or_404(Song, pk=song_id, user=request.user)
if not request.POST:
return render(request, 'songs/edit.html', {'song': song})

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,9 +1,8 @@
from datetime import datetime, timedelta, time
from datetime import datetime, timedelta
from django.core.cache import caches
from django.conf import settings
from django.db.models import Count, Q, Sum, When, Case
from django.shortcuts import render
from django.db.models import Count, Q, Sum
from django.utils import timezone
from queues.models import PlaylistSong
@ -30,74 +29,62 @@ def recache_user_stats():
return new_stats
def time_convert(time):
try:
for tr in time:
tr['duration'] = str(round(tr['total'] / 86400, 2)) + ' days'
avg_dur_sec = tr['avg_dur'] % 60
avg_dur_min = int((tr['avg_dur'] - avg_dur_sec) / 60)
tr['avg_dur'] = '{}:{}'.format(avg_dur_min, avg_dur_sec)
return time
except:
avg_dur_sec = round(time % 60)
avg_dur_min = int(round((time - avg_dur_sec) / 60))
return ('{} minutes and {} seconds'.format(avg_dur_min, avg_dur_sec))
def calculate_uploaders(requests_uploader, most_requested_uploaders):
for x in requests_uploader:
def best_uploaders_list(requests_uploader, most_requested_uploaders):
for requests in requests_uploader:
a = len(most_requested_uploaders)
b = 0
while b <= a:
if b == a:
adding_list_item(most_requested_uploaders, x)
elif x['song__user__id'] == most_requested_uploaders[b]['id']:
if x['song__user__name'] == x['user__name']:
most_requested_uploaders[b]['own_total'] = x['total']
adding_list_item(most_requested_uploaders, requests)
elif requests[
'song__user__id'] == most_requested_uploaders[b]['id']:
if requests['song__user__name'] == requests['user__name']:
most_requested_uploaders[b][
'own_total'] = requests['total']
else:
most_requested_uploaders[b]['total'] += x['total']
most_requested_uploaders[b]['total'] += requests['total']
break
b += 1
return
def adding_list_item(list, x):
list.append({
'id': x['song__user__id'],
'name': x['song__user__name'],
def adding_list_item(most_requested_list, requests):
# adds a single item to the best_uploaders list
most_requested_list.append({
'id': requests['song__user__id'],
'name': requests['song__user__name'],
'total': 0,
'own_total': 0
})
if x['song__user__id'] == x['user__id']:
list[-1]['own_total']: x['total']
if requests['song__user__id'] == requests['user__id']:
most_requested_list[-1]['own_total'] = requests['total']
else:
list[-1]['_total']: x['total']
return
most_requested_list[-1]['total'] = requests['total']
def compute_stats():
# We want to grab the time now, because otherwise we would be reporting a minute too late
last_updated = datetime.now()
stats = {}
total_uploads = Song.objects.filter(deleted=False).exclude(
stats['total_uploads'] = Song.objects.filter(deleted=False).exclude(
user_id=None).count()
upload_stats = Song.objects.filter(deleted=False).exclude(
stats['upload_stats'] = Song.objects.filter(deleted=False).exclude(
user_id=None).values(
'user__id', 'user__name').annotate(total=Count('id')).order_by(
'-total', 'user__name')[:settings.STATS_TOP_COUNT]
total_requests = PlaylistSong.objects.filter(state=2).exclude(
stats['total_requests'] = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).count()
request_stats = PlaylistSong.objects.filter(state=2).exclude(
stats['request_stats'] = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values(
'user__id', 'user__name').annotate(total=Count('id')).order_by(
'-total', 'user__name')[:settings.STATS_TOP_COUNT]
unique_request_stats = PlaylistSong.objects.filter(state=2).exclude(
stats['unique_request_stats'] = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values(
'user__id', 'user__name').annotate(
@ -105,26 +92,26 @@ def compute_stats():
unique_requests=Count('song__id', distinct=True)).order_by(
'-unique_requests')[:settings.STATS_TOP_COUNT]
total_unique_requests = PlaylistSong.objects.filter(state=2).exclude(
stats['total_unique_requests'] = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).aggregate(
total=Count('song__id', distinct=True))
most_played_songs = PlaylistSong.objects.filter(state=2).exclude(
stats['most_played_songs'] = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values(
'song__artist',
'song__title').annotate(total=Count('id')).order_by(
'-total', 'song__artist')[:settings.STATS_TOP_COUNT]
most_played_songs_14_days = PlaylistSong.objects.filter(
state=2, played_at__gte=timezone.now() - timedelta(days=14)).exclude(
user_id=None).values(
'song__artist',
'song__title').annotate(total=Count('id')).order_by(
'-total', 'song__artist')[:settings.STATS_TOP_COUNT]
stats['most_played_songs_14_days'] = PlaylistSong.objects.filter(
state=2, played_at__gte=timezone.now() -
timedelta(days=14)).exclude(user_id=None).values(
'song__artist',
'song__title').annotate(total=Count('id')).order_by(
'-total', 'song__artist')[:settings.STATS_TOP_COUNT]
time_requested = PlaylistSong.objects.filter(state=2).exclude(
stats['time_requested'] = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values(
'user__id', 'user__name').annotate(
@ -132,18 +119,16 @@ def compute_stats():
avg_dur=Sum('song__duration') /
Count('id')).order_by('-total')[:settings.STATS_TOP_COUNT]
total_time_requested = PlaylistSong.objects.all().filter(state=2).exclude(
stats['total_time_requested'] = PlaylistSong.objects.all().filter(state=2).exclude(
Q(user_id=None)
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).aggregate(
total=Sum('song__duration'))
total_time_overall = 0
count = 0
for x in list(time_requested):
total_time_overall += x['avg_dur']
count += 1
total_average = total_time_overall / count
total_average = time_convert(total_average)
total_time_overall = sum(x['avg_dur'] for x in list(stats['time_requested']))
total_average = total_time_overall / len(stats['time_requested'])
avg_dur_min, avg_dur_sec = divmod(total_average, 60)
total_average = '{} minutes and {} seconds'.format(
avg_dur_min, avg_dur_sec)
requests_uploader = PlaylistSong.objects.filter(state=2).exclude(
Q(user_id=None)
@ -152,20 +137,34 @@ def compute_stats():
'user__id').annotate(total=Count('song__user__name'))
most_requested_uploaders = []
calculate_uploaders(list(requests_uploader), most_requested_uploaders)
best_uploaders_list(list(requests_uploader), most_requested_uploaders)
for time in list(stats['time_requested']):
# converts total time and average time in respectively days and minutes, seconds
time['duration'] = str(round(time['total'] / 86400, 2)) + ' days'
avg_dur_min, avg_dur_sec = divmod(time['avg_dur'], 60)
if avg_dur_sec < 10:
avg_dur_sec = '0' + str(avg_dur_sec)
time['avg_dur'] = '{}:{}'.format(avg_dur_min, avg_dur_sec)
# Convert requested time to days
time_requested = list(stats['time_requested'])
for tr in time_requested:
tr['duration'] = str(round(tr['total'] / 86400, 2)) + ' days'
return {
'last_updated': last_updated,
'total_uploads': total_uploads,
'upload_stats': list(upload_stats),
'total_requests': total_requests,
'request_stats': list(request_stats),
'unique_request_stats': list(unique_request_stats),
'total_unique_requests': total_unique_requests,
'most_played_songs': list(most_played_songs),
'most_played_songs_14_days': list(most_played_songs_14_days),
'time_requested': time_convert(list(time_requested)),
'total_time_requested': str(round(float(total_time_requested['total']) / 86400, 2)) + ' days',
'total_uploads': stats['total_uploads'],
'upload_stats': list(stats['upload_stats']),
'total_requests': stats['total_requests'],
'request_stats': list(stats['request_stats']),
'unique_request_stats': list(stats['unique_request_stats']),
'total_unique_requests': stats['total_unique_requests'],
'most_played_songs': list(stats['most_played_songs']),
'most_played_songs_14_days': list(stats['most_played_songs_14_days']),
'time_requested': stats['time_requested'],
'total_time_requested': str(round(float(
stats['total_time_requested']['total']) / 86400, 2)) + ' days',
'stats_top_count': settings.STATS_TOP_COUNT,
'most_requested_uploaders': list(most_requested_uploaders),
'total_average': total_average,
@ -228,4 +227,4 @@ def user_stats(request):
'stats_top_count': settings.STATS_TOP_COUNT,
'total_played_uploads': total_played_uploads,
'total_played_user_uploads': total_played_user_uploads,
}
}

View File

@ -2,34 +2,33 @@ from datetime import datetime, timedelta
from django.core.cache import caches
from django.shortcuts import render
from stats.utils import user_stats
from django.http import JsonResponse, HttpResponseForbidden
def stats(request):
stats = caches['default'].get('stats')
stats_data = caches['default'].get('stats')
status = 503
current_age = None
current_age_text = None
if stats:
if stats_data:
status = 200
current_age_text = age_text(stats['last_updated'])
current_age_text = age_text(stats_data['last_updated'])
data = {'stats': stats, 'current_age': current_age, 'current_age_text': current_age_text}
data = {'stats': stats_data, 'current_age': current_age, 'current_age_text': current_age_text}
return render(request, 'stats/stats.html', data, status=status)
def user_stats(request):
stats = caches['userstats'].get('userstats_{}'.format(request.user.id))
stats_data = caches['default'].get('userstats_{}'.format(request.user.id))
status = 503
current_age = None
current_age_text = None
if stats:
if stats_data:
status = 200
current_age_text = age_text(stats['last_updated'])
current_age_text = age_text(stats_data['last_updated'])
data = {'stats': stats, 'current_age': current_age, 'current_age_text': current_age_text}
data = {'stats': stats_data, 'current_age': current_age, 'current_age_text': current_age_text}
return render(request, 'stats/user.html', data, status=status)
def age_text(last_updated):
@ -40,7 +39,6 @@ def age_text(last_updated):
hourstr = "hour" if hours == 1 else "hours"
if current_age < timedelta(hours=1):
return 'Stats were updated {:.0f} {} ago.'.format(minutes, minutestr)
else:
return 'Stats were updated {:.0f} {} and {:.0f} {} ago.'.format(
hours, hourstr, minutes, minutestr)
return 'Stats were updated {:.0f} {} and {:.0f} {} ago.'.format(
hours, hourstr, minutes, minutestr)