From dcfcd63db117e7e7904bdc1c9b75580bd90799ea Mon Sep 17 00:00:00 2001 From: oslomp Date: Fri, 14 Dec 2018 22:56:26 +0100 Subject: [PATCH 01/20] untrack settings --- marietje/marietje/settings.py | 147 ---------------------------------- 1 file changed, 147 deletions(-) delete mode 100644 marietje/marietje/settings.py diff --git a/marietje/marietje/settings.py b/marietje/marietje/settings.py deleted file mode 100644 index fa3a15f..0000000 --- a/marietje/marietje/settings.py +++ /dev/null @@ -1,147 +0,0 @@ -""" -Django settings for marietje project. -""" - -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -SECRET_KEY = 'sae2hahHao1soo0Ocoz5Ieh1Ushae6feJe4mooliooj0Ula8' -DEBUG = True -ALLOWED_HOSTS = ['*'] - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'marietje', - 'queues', - 'songs', - 'stats' -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'marietje.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'marietje.context_processors.global_settings', - ], - }, - }, -] - -WSGI_APPLICATION = 'marietje.wsgi.application' - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'marietje', - 'USER': 'marietje', - 'PASSWORD': 'v8TzZwdAdSi7Tk5I', - 'HOST': 'localhost', - 'PORT': '3306', - 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" }, - } -} - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -PASSWORD_HASHERS = [ - 'django.contrib.auth.hashers.Argon2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', - 'django.contrib.auth.hashers.Argon2PasswordHasher', - 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', - 'django.contrib.auth.hashers.BCryptPasswordHasher', - 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', -] - -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', - 'OPTIONS': { 'MAX_ENTRIES': 1000 }, - }, - 'song_search': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/tmp/MarietjeDjango_cache/song_search', - 'OPTIONS': { 'MAX_ENTRIES': 1000 }, - }, -} - -AUTH_USER_MODEL = 'marietje.User' -LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'Europe/Amsterdam' -USE_I18N = True -USE_L10N = True -USE_TZ = True - - -# zc files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.10/howto/static-files/ - -BASE_URL = 'https://marietje-zuid.science.ru.nl' - -STATIC_ROOT = os.path.join(BASE_DIR, 'static') -STATIC_URL = '/static/' -LOGIN_URL = '/login/' -LOGIN_REDIRECT_URL = '/' -LOGOUT_REDIRECT_URL = '/' - -# App specific settings - -BERTHA_HOST = ('bach.science.ru.nl', 1234) -MAIL_FROM = 'marietje@marietje.science.ru.nl' -MAX_MINUTES_IN_A_ROW = 45 - -# Time range (dependent on timezone specified) when MAX_MINUTES_IN_A_ROW is in effect. -LIMIT_HOURS = (12, 13) -LIMIT_MINUTES = (15, 45) -LIMIT_ALWAYS = True - -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' -TRUSTED_IP_RANGES = [ - '131.174.0.0/16', # RU wired - '145.116.136.0/22', # eduroam -] From 0140119828833d7eb2008d6b1d0cb890f163585b Mon Sep 17 00:00:00 2001 From: oslomp Date: Fri, 14 Dec 2018 23:23:46 +0100 Subject: [PATCH 02/20] Changed cache location for userstats. Settings needs to be added: 'userstats': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', 'OPTIONS': { 'MAX_ENTRIES': 1500 }, }, --- marietje/.gitignore | 1 + marietje/stats/utils.py | 4 ++-- marietje/stats/views.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/marietje/.gitignore b/marietje/.gitignore index 23527b2..d633baa 100644 --- a/marietje/.gitignore +++ b/marietje/.gitignore @@ -1,2 +1,3 @@ /.idea/ *.sqlite3 +settings.py \ No newline at end of file diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index a4cae4b..9cd17e7 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -23,8 +23,8 @@ def recache_user_stats(): for user in users: new_stats = user_stats(user['id']) cacheloc = 'userstats_{}'.format(user['id']) - caches['default'].delete(cacheloc) - caches['default'].set(cacheloc, new_stats, 48 * 3600) + caches['userstats'].delete(cacheloc) + caches['userstats'].set(cacheloc, new_stats, 48 * 3600) return new_stats def to_days(time): diff --git a/marietje/stats/views.py b/marietje/stats/views.py index 232de2a..c3acf33 100644 --- a/marietje/stats/views.py +++ b/marietje/stats/views.py @@ -20,7 +20,7 @@ def stats(request): return render(request, 'stats/stats.html', data, status=status) def user_stats(request): - stats = caches['default'].get('userstats_{}'.format(request.user.id)) + stats = caches['userstats'].get('userstats_{}'.format(request.user.id)) status = 503 current_age = None current_age_text = None From 29bd66c8818788fc259a593ca2b210e063d33ce9 Mon Sep 17 00:00:00 2001 From: Olaf Slomp Date: Fri, 14 Dec 2018 23:28:50 +0100 Subject: [PATCH 03/20] updated settings for cashing userstats --- marietje/marietje/settings.py | 152 ++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 marietje/marietje/settings.py diff --git a/marietje/marietje/settings.py b/marietje/marietje/settings.py new file mode 100644 index 0000000..5d83da5 --- /dev/null +++ b/marietje/marietje/settings.py @@ -0,0 +1,152 @@ +""" +Django settings for marietje project. +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SECRET_KEY = 'sae2hahHao1soo0Ocoz5Ieh1Ushae6feJe4mooliooj0Ula8' +DEBUG = True +ALLOWED_HOSTS = ['*'] + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'marietje', + 'queues', + 'songs', + 'stats' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'marietje.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'marietje.context_processors.global_settings', + ], + }, + }, +] + +WSGI_APPLICATION = 'marietje.wsgi.application' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'marietje', + 'USER': 'marietje', + 'PASSWORD': 'v8TzZwdAdSi7Tk5I', + 'HOST': 'localhost', + 'PORT': '3306', + 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" }, + } +} + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + 'django.contrib.auth.hashers.BCryptPasswordHasher', + 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', +] + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', + 'OPTIONS': { 'MAX_ENTRIES': 1000 }, + }, + 'song_search': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/MarietjeDjango_cache/song_search', + 'OPTIONS': { 'MAX_ENTRIES': 1000 }, + }, + 'userstats': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', + 'OPTIONS': { 'MAX_ENTRIES': 1500 }, + }, +} + +AUTH_USER_MODEL = 'marietje.User' +LANGUAGE_CODE = 'en-us' +TIME_ZONE = 'Europe/Amsterdam' +USE_I18N = True +USE_L10N = True +USE_TZ = True + + +# zc files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + +BASE_URL = 'https://marietje-zuid.science.ru.nl' + +STATIC_ROOT = os.path.join(BASE_DIR, 'static') +STATIC_URL = '/static/' +LOGIN_URL = '/login/' +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' + +# App specific settings + +BERTHA_HOST = ('bach.science.ru.nl', 1234) +MAIL_FROM = 'marietje@marietje.science.ru.nl' +MAX_MINUTES_IN_A_ROW = 45 + +# Time range (dependent on timezone specified) when MAX_MINUTES_IN_A_ROW is in effect. +LIMIT_HOURS = (12, 13) +LIMIT_MINUTES = (15, 45) +LIMIT_ALWAYS = True + +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' +TRUSTED_IP_RANGES = [ + '131.174.0.0/16', # RU wired + '145.116.136.0/22', # eduroam +] From ce73e5d874d3ece013dbde0bf089c3f242ec559a Mon Sep 17 00:00:00 2001 From: oslomp Date: Fri, 14 Dec 2018 23:47:55 +0100 Subject: [PATCH 04/20] Fix unique requests stats ordering --- marietje/marietje/settings.py | 152 ---------------------------------- marietje/stats/utils.py | 2 +- 2 files changed, 1 insertion(+), 153 deletions(-) delete mode 100644 marietje/marietje/settings.py diff --git a/marietje/marietje/settings.py b/marietje/marietje/settings.py deleted file mode 100644 index 5d83da5..0000000 --- a/marietje/marietje/settings.py +++ /dev/null @@ -1,152 +0,0 @@ -""" -Django settings for marietje project. -""" - -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -SECRET_KEY = 'sae2hahHao1soo0Ocoz5Ieh1Ushae6feJe4mooliooj0Ula8' -DEBUG = True -ALLOWED_HOSTS = ['*'] - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'marietje', - 'queues', - 'songs', - 'stats' -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'marietje.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'marietje.context_processors.global_settings', - ], - }, - }, -] - -WSGI_APPLICATION = 'marietje.wsgi.application' - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'marietje', - 'USER': 'marietje', - 'PASSWORD': 'v8TzZwdAdSi7Tk5I', - 'HOST': 'localhost', - 'PORT': '3306', - 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" }, - } -} - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -PASSWORD_HASHERS = [ - 'django.contrib.auth.hashers.Argon2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', - 'django.contrib.auth.hashers.Argon2PasswordHasher', - 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', - 'django.contrib.auth.hashers.BCryptPasswordHasher', - 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', -] - -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', - 'OPTIONS': { 'MAX_ENTRIES': 1000 }, - }, - 'song_search': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/tmp/MarietjeDjango_cache/song_search', - 'OPTIONS': { 'MAX_ENTRIES': 1000 }, - }, - 'userstats': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', - 'OPTIONS': { 'MAX_ENTRIES': 1500 }, - }, -} - -AUTH_USER_MODEL = 'marietje.User' -LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'Europe/Amsterdam' -USE_I18N = True -USE_L10N = True -USE_TZ = True - - -# zc files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.10/howto/static-files/ - -BASE_URL = 'https://marietje-zuid.science.ru.nl' - -STATIC_ROOT = os.path.join(BASE_DIR, 'static') -STATIC_URL = '/static/' -LOGIN_URL = '/login/' -LOGIN_REDIRECT_URL = '/' -LOGOUT_REDIRECT_URL = '/' - -# App specific settings - -BERTHA_HOST = ('bach.science.ru.nl', 1234) -MAIL_FROM = 'marietje@marietje.science.ru.nl' -MAX_MINUTES_IN_A_ROW = 45 - -# Time range (dependent on timezone specified) when MAX_MINUTES_IN_A_ROW is in effect. -LIMIT_HOURS = (12, 13) -LIMIT_MINUTES = (15, 45) -LIMIT_ALWAYS = True - -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' -TRUSTED_IP_RANGES = [ - '131.174.0.0/16', # RU wired - '145.116.136.0/22', # eduroam -] diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index 9cd17e7..94e505e 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -60,7 +60,7 @@ def compute_stats(): 'user__id', 'user__name').annotate( total_requests=Count('id', distinct=True), unique_requests=Count('song__id', distinct=True)).order_by( - '-total_requests')[:settings.STATS_TOP_COUNT] + '-unique_requests')[:settings.STATS_TOP_COUNT] total_unique_requests = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) From aff8ddf878b6266e77f3846539feace52628ae59 Mon Sep 17 00:00:00 2001 From: oslomp Date: Sat, 15 Dec 2018 01:42:52 +0100 Subject: [PATCH 05/20] Small fixes in stats and userstats, changed Most_played_uploads to exclude your own plays --- marietje/stats/templates/stats/user.html | 15 +++++++++++---- marietje/stats/utils.py | 13 ++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/marietje/stats/templates/stats/user.html b/marietje/stats/templates/stats/user.html index 9f23409..f0bff7d 100644 --- a/marietje/stats/templates/stats/user.html +++ b/marietje/stats/templates/stats/user.html @@ -8,17 +8,22 @@

User Statistics

+ {% if not stats %} +
+ Stats unavailable :( +
+ {% else %} {% if current_age_text %}
{{ current_age_text }} {% endif %} +

Total uploads: {{ stats.total_uploads }}

-

Total requests: {{ stats.total_requests }}

Unique requests: {{ stats.unique_requests }} ({% widthratio stats.unique_requests stats.total_requests 100 %}%)

-

Total requested uploads: {{stats.total_played_uploads}}

Most played songs

+

Total: {{ stats.total_requests }}

Top {{ stats.stats_top_count }}:

@@ -45,7 +50,8 @@
-

Most played uploads

+

Uploads requested by others

+

Total: {{stats.total_played_uploads}}

Top {{ stats.stats_top_count }}:

@@ -87,7 +93,7 @@ - + {% endfor %} @@ -95,5 +101,6 @@ + {% endif %} {% endblock %} \ No newline at end of file diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index 94e505e..79a7542 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -145,16 +145,15 @@ def user_stats(request): '-total')[:settings.STATS_TOP_COUNT] most_played_uploads = PlaylistSong.objects.filter( - state=2, song_id__in=Song.objects.filter(user__id=request)).exclude( - Q(user_id=None) - | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( - 'pk').values( + state=2, song_id__in=Song.objects.filter(user__id=request)).exclude(Q(user__id=None)|Q(user__id=request)).values( 'song__artist', 'song__title').annotate(total=Count('id')).order_by( '-total', 'song__artist', 'song__title')[:settings.STATS_TOP_COUNT] - - total_played_uploads = most_played_uploads.aggregate(newtotal=Sum('total')) + most_played = list(most_played_uploads) + total_played_uploads = 0 + for x in most_played: + total_played_uploads += x['total'] return { 'last_updated': last_updated, @@ -165,6 +164,6 @@ def user_stats(request): 'most_played_uploaders': list(most_played_uploaders), 'most_played_uploads': list(most_played_uploads), 'stats_top_count': settings.STATS_TOP_COUNT, - 'total_played_uploads': total_played_uploads['newtotal'], + 'total_played_uploads': total_played_uploads, } From 027ee6b3e5d3e1f61a095d19f07b4995f6218501 Mon Sep 17 00:00:00 2001 From: Olaf Slomp Date: Sat, 15 Dec 2018 01:45:35 +0100 Subject: [PATCH 06/20] I need to find out how to do this efficiently. --- marietje/marietje/settings.py | 152 ++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 marietje/marietje/settings.py diff --git a/marietje/marietje/settings.py b/marietje/marietje/settings.py new file mode 100644 index 0000000..5d83da5 --- /dev/null +++ b/marietje/marietje/settings.py @@ -0,0 +1,152 @@ +""" +Django settings for marietje project. +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SECRET_KEY = 'sae2hahHao1soo0Ocoz5Ieh1Ushae6feJe4mooliooj0Ula8' +DEBUG = True +ALLOWED_HOSTS = ['*'] + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'marietje', + 'queues', + 'songs', + 'stats' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'marietje.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'marietje.context_processors.global_settings', + ], + }, + }, +] + +WSGI_APPLICATION = 'marietje.wsgi.application' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'marietje', + 'USER': 'marietje', + 'PASSWORD': 'v8TzZwdAdSi7Tk5I', + 'HOST': 'localhost', + 'PORT': '3306', + 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" }, + } +} + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + 'django.contrib.auth.hashers.BCryptPasswordHasher', + 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', +] + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', + 'OPTIONS': { 'MAX_ENTRIES': 1000 }, + }, + 'song_search': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/MarietjeDjango_cache/song_search', + 'OPTIONS': { 'MAX_ENTRIES': 1000 }, + }, + 'userstats': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', + 'OPTIONS': { 'MAX_ENTRIES': 1500 }, + }, +} + +AUTH_USER_MODEL = 'marietje.User' +LANGUAGE_CODE = 'en-us' +TIME_ZONE = 'Europe/Amsterdam' +USE_I18N = True +USE_L10N = True +USE_TZ = True + + +# zc files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + +BASE_URL = 'https://marietje-zuid.science.ru.nl' + +STATIC_ROOT = os.path.join(BASE_DIR, 'static') +STATIC_URL = '/static/' +LOGIN_URL = '/login/' +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' + +# App specific settings + +BERTHA_HOST = ('bach.science.ru.nl', 1234) +MAIL_FROM = 'marietje@marietje.science.ru.nl' +MAX_MINUTES_IN_A_ROW = 45 + +# Time range (dependent on timezone specified) when MAX_MINUTES_IN_A_ROW is in effect. +LIMIT_HOURS = (12, 13) +LIMIT_MINUTES = (15, 45) +LIMIT_ALWAYS = True + +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' +TRUSTED_IP_RANGES = [ + '131.174.0.0/16', # RU wired + '145.116.136.0/22', # eduroam +] From 1da2f4cc05a45882960200cab89e8b61bf6e1855 Mon Sep 17 00:00:00 2001 From: oslomp Date: Sat, 15 Dec 2018 14:14:24 +0100 Subject: [PATCH 07/20] Changed alert messages for successfull or failed reports --- marietje/marietje/static/js/queue.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/marietje/marietje/static/js/queue.js b/marietje/marietje/static/js/queue.js index 1d6e209..9282852 100644 --- a/marietje/marietje/static/js/queue.js +++ b/marietje/marietje/static/js/queue.js @@ -49,13 +49,13 @@ $(function () { var songId = $(this).data('report-song-id'); var message = prompt("What is wrong with the song?"); if (message == "") { - alert("Please enter a message."); + createAlert('danger', 'Please enter a message.'); return false } $.post('/api/report', {id: songId, msg: message, csrfmiddlewaretoken: csrf_token}, function (result) { console.log(result); if (result.success) { - alert("Thanks for the report!"); + createAlert('success', 'Thanks for your song report!'); } }); return false; From 2e9be85cc4de579fc53266987ee1044f543c4075 Mon Sep 17 00:00:00 2001 From: oslomp Date: Sat, 15 Dec 2018 15:19:47 +0100 Subject: [PATCH 08/20] Split Uploads Requested in two columns, for others and for you personally --- marietje/stats/templates/stats/user.html | 9 ++++++--- marietje/stats/utils.py | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/marietje/stats/templates/stats/user.html b/marietje/stats/templates/stats/user.html index f0bff7d..d6a877c 100644 --- a/marietje/stats/templates/stats/user.html +++ b/marietje/stats/templates/stats/user.html @@ -50,8 +50,9 @@
-

Uploads requested by others

-

Total: {{stats.total_played_uploads}}

+

Uploads requested

+

Total played by you: {{stats.total_played_user_uploads}}

+

Total played by others: {{stats.total_played_uploads}}

Top {{ stats.stats_top_count }}:

{{ forloop.counter }} {{ stat.song__user__name }}{{ stat.total }} ({% widthratio stat.total total_requests 100 %}%){{ stat.total }} ({% widthratio stat.total stats.total_requests 100 %}%)
@@ -60,7 +61,8 @@ - + + @@ -70,6 +72,7 @@ + {% endfor %} diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index 79a7542..d5b5a40 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -2,7 +2,7 @@ from datetime import datetime, timedelta, time from django.core.cache import caches from django.conf import settings -from django.db.models import Count, Q, Sum +from django.db.models import Count, Q, Sum, When, Case from django.shortcuts import render from django.utils import timezone @@ -145,15 +145,18 @@ def user_stats(request): '-total')[:settings.STATS_TOP_COUNT] most_played_uploads = PlaylistSong.objects.filter( - state=2, song_id__in=Song.objects.filter(user__id=request)).exclude(Q(user__id=None)|Q(user__id=request)).values( + state=2, song_id__in=Song.objects.filter(user__id=request)).exclude(user__id=None).values( 'song__artist', - 'song__title').annotate(total=Count('id')).order_by( + 'song__title').annotate(total=Count('id', filter=~Q(user__id=request)), user_total=Count('id', filter=Q(user__id=request))).order_by( '-total', 'song__artist', 'song__title')[:settings.STATS_TOP_COUNT] + most_played = list(most_played_uploads) total_played_uploads = 0 + total_played_user_uploads = 0 for x in most_played: total_played_uploads += x['total'] + total_played_user_uploads += x['user_total'] return { 'last_updated': last_updated, @@ -165,5 +168,6 @@ def user_stats(request): 'most_played_uploads': list(most_played_uploads), 'stats_top_count': settings.STATS_TOP_COUNT, 'total_played_uploads': total_played_uploads, + 'total_played_user_uploads': total_played_user_uploads, } From 6adbecec9c86455ce31e22090ee42fa318a2b5f6 Mon Sep 17 00:00:00 2001 From: oslomp Date: Sat, 15 Dec 2018 16:43:15 +0100 Subject: [PATCH 09/20] Added average duration to Time Requested in stats --- marietje/stats/templates/stats/stats.html | 6 ++++-- marietje/stats/utils.py | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/marietje/stats/templates/stats/stats.html b/marietje/stats/templates/stats/stats.html index 4262d7e..ae73f43 100644 --- a/marietje/stats/templates/stats/stats.html +++ b/marietje/stats/templates/stats/stats.html @@ -76,7 +76,8 @@ - + + @@ -84,7 +85,8 @@ - + + {% endfor %} diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index d5b5a40..d5a68a4 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -27,9 +27,12 @@ def recache_user_stats(): caches['userstats'].set(cacheloc, new_stats, 48 * 3600) return new_stats -def to_days(time): +def time_convert(time): 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 def compute_stats(): @@ -84,7 +87,7 @@ def compute_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(total=Sum('song__duration')).order_by( + 'user__id', 'user__name').annotate(total=Sum('song__duration'), avg_dur=Sum('song__duration')/Count('id')).order_by( '-total')[:settings.STATS_TOP_COUNT] total_time_requested = PlaylistSong.objects.all().filter(state=2).exclude( @@ -108,7 +111,7 @@ def compute_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': to_days(list(time_requested)), + 'time_requested': time_convert(list(time_requested)), 'total_time_requested': str(round(float(total_time_requested['total']) / 86400, 2)) + ' days', 'stats_top_count': settings.STATS_TOP_COUNT, 'most_requested_uploaders': list(most_requested_uploaders), From 6cf1b4bef229e405f19d12d31877af59737c17f1 Mon Sep 17 00:00:00 2001 From: oslomp Date: Sun, 16 Dec 2018 21:39:11 +0100 Subject: [PATCH 10/20] Fixes on arrows in the main screen --- marietje/api/views.py | 7 +++++++ marietje/marietje/static/js/queue.js | 13 ++++++++++--- marietje/queues/models.py | 8 ++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/marietje/api/views.py b/marietje/api/views.py index 30e9871..a2bbe7e 100644 --- a/marietje/api/views.py +++ b/marietje/api/views.py @@ -201,7 +201,14 @@ def move_up(request): @require_http_methods(["POST"]) @api_auth_required def move_down(request): +# print('') +# print(request) +# print('') + ide=(request.POST.get('id')) +# print('') playlist_song = get_object_or_404(PlaylistSong, id=request.POST.get('id')) +# print(playlist_song) +# print('') if playlist_song.user != request.user and not request.user.has_perm('queues.can_move'): return HttpResponseForbidden() playlist_song.move_down() diff --git a/marietje/marietje/static/js/queue.js b/marietje/marietje/static/js/queue.js index 9282852..7b847ac 100644 --- a/marietje/marietje/static/js/queue.js +++ b/marietje/marietje/static/js/queue.js @@ -194,12 +194,18 @@ function renderQueue(playNextAt, now) { $('.queuebody').empty(); var timeToPlay = playNextAt - now; + var canDeletePrevious = false; $.each(queue, function (id, song) { var requestedBy = song.requested_by; var canDelete = song.can_move_down || canMoveSongs; - var canMoveDown = canDelete && id < queue.length - 1; + var canMoveUp = canMoveSongs && id != queue.length -5 || canDeletePrevious && id < queue.length - 5; + var canMoveDown = canDelete && id < queue.length - 6 || canMoveSongs && id < queue.length - 1 && id != queue.length - 6; var artist = song.song.artist.trim() === '' ? '?' : song.song.artist; var title = song.song.title.trim() === '' ? '?' : song.song.title; + var prevId = song.id - 1; + console.log(song.id, id); + console.log(song); + console.log(queue); showTime = showTimeToPlay ? (timeToPlay < 0 ? '' : timeToPlay.secondsToMMSS()) : (playNextAt < now ? '' : playNextAt.timestampToHHMMSS()) @@ -207,14 +213,15 @@ function renderQueue(playNextAt, now) + ''); timeToPlay += parseInt(song.song.duration); + canDeletePrevious = canDelete if(playNextAt >= now) { playNextAt += parseInt(song.song.duration); diff --git a/marietje/queues/models.py b/marietje/queues/models.py index 7f765eb..c027f5d 100644 --- a/marietje/queues/models.py +++ b/marietje/queues/models.py @@ -53,8 +53,12 @@ class PlaylistSong(models.Model): self.switch_order(other_song) def move_down(self): - other_song = PlaylistSong.objects.filter(playlist=self.playlist, id__gt=self.id).order_by('id').first() - self.switch_order(other_song) + other_song = PlaylistSong.objects.filter(playlist=self.playlist, id__gt=self.id).first() + old_id = self.id + self.id = other_song.id + other_song.id = old_id + self.save() + other_song.save() def switch_order(self, other_song): old_id = self.id From fe5a4b911948f2bf3584bc97f556903f2f61f245 Mon Sep 17 00:00:00 2001 From: oslomp Date: Mon, 17 Dec 2018 19:59:36 +0100 Subject: [PATCH 11/20] fixing arrows homescreen --- marietje/marietje/static/js/queue.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/marietje/marietje/static/js/queue.js b/marietje/marietje/static/js/queue.js index 7b847ac..d970f4f 100644 --- a/marietje/marietje/static/js/queue.js +++ b/marietje/marietje/static/js/queue.js @@ -197,15 +197,29 @@ function renderQueue(playNextAt, now) var canDeletePrevious = false; $.each(queue, function (id, song) { var requestedBy = song.requested_by; + var requestCurr = requestedBy != 'Marietje'; + + //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. + if(id === 0){ + var requestPrev = false + // + } else { + var requestPrev = !((queue[id-1].requested_by !== 'Marietje') && (requestedBy === 'Marietje')) + } + + console.log(requestNext, requestPrev, requestCurr); var canDelete = song.can_move_down || canMoveSongs; - var canMoveUp = canMoveSongs && id != queue.length -5 || canDeletePrevious && id < queue.length - 5; - var canMoveDown = canDelete && id < queue.length - 6 || canMoveSongs && id < queue.length - 1 && id != queue.length - 6; + var canMoveUp = canMoveSongs && requestPrev || canDeletePrevious && requestCurr && requestPrev; + var canMoveDown = canMoveSongs && requestNext || canDelete && requestCurr && requestNext; var artist = song.song.artist.trim() === '' ? '?' : song.song.artist; var title = song.song.title.trim() === '' ? '?' : song.song.title; var prevId = song.id - 1; - console.log(song.id, id); - console.log(song); - console.log(queue); showTime = showTimeToPlay ? (timeToPlay < 0 ? '' : timeToPlay.secondsToMMSS()) : (playNextAt < now ? '' : playNextAt.timestampToHHMMSS()) From afb0886fcaf2655b3efc2c3bfb1bf4275e97c1b0 Mon Sep 17 00:00:00 2001 From: oslomp Date: Tue, 18 Dec 2018 18:53:49 +0100 Subject: [PATCH 12/20] Added explanation to stats and changed some details --- marietje/stats/templates/stats/stats.html | 33 ++--- marietje/stats/templates/stats/user.html | 15 ++- marietje/stats/utils.py | 143 ++++++++++++++++------ 3 files changed, 134 insertions(+), 57 deletions(-) diff --git a/marietje/stats/templates/stats/stats.html b/marietje/stats/templates/stats/stats.html index ae73f43..f6ed1f6 100644 --- a/marietje/stats/templates/stats/stats.html +++ b/marietje/stats/templates/stats/stats.html @@ -18,8 +18,8 @@

Uploads

-

Total: {{ stats.total_uploads }}

-

Top {{ stats.stats_top_count }}:

+

In total {{ stats.total_uploads }} songs have been uploaded. + These are the {{ stats.stats_top_count }} people who have uploaded the most.

# Artist Title# RequestsOthersYou
{{ stat.song__artist }} {{ stat.song__title }} {{ stat.total }}{{ stat.user_total }}
# UserDurationDurationAverage
{{ forloop.counter }} {{ stat.user__name }}{{ stat.duration }}{{ stat.duration }}{{stat.avg_dur}}
' + title + '' + '        
@@ -43,8 +43,8 @@

Requests

-

Total: {{ stats.total_requests }}

-

Top {{ stats.stats_top_count }}:

+

In total {{ stats.total_requests }} songs have been requested. + These are the {{ stats.stats_top_count }} people who have requested the most songs.

@@ -68,8 +68,9 @@

Time requested

-

Total: {{stats.total_time_requested}}

-

Top {{ stats.stats_top_count }}:

+

In total {{ stats.total_time_requested }} of music have been requested, with an + average song length of {{ stats.total_average }}. + These are the {{ stats.stats_top_count }} people with the longest total time queued

@@ -95,8 +96,9 @@

Unique requests

-

Total: {{stats.total_unique_requests.total}}

-

Top {{ stats.stats_top_count }}:

+

In total {{stats.total_unique_requests.total}} different songs + have been requested. The {{ stats.stats_top_count }} people that have requested the largest number of + different songs are shown below.

@@ -120,7 +122,7 @@

Most played songs

-

Top {{ stats.stats_top_count }}:

+

These are the {{ stats.stats_top_count }} most played songs ever.

@@ -146,22 +148,25 @@

Most played uploaders

-

Top {{ stats.stats_top_count }}:

+

The left column shows the {{ stats.stats_top_count }} people whose songs are requested most often by other people + people. The right column shows how many times that person has queued his own songs.

- + + {% for stat in stats.most_requested_uploaders %} - - + + + {% endfor %} @@ -170,7 +175,7 @@

Most played songs last 14 days

-

Top {{ stats.stats_top_count }}:

+

These songs are played the {{ stats.stats_top_count }} most in the last two weeks.

# User# Songs# Others# Own
{{ forloop.counter }}{{ stat.song__user__name }}{{ stat.total }} ({% widthratio stat.total stats.total_requests 100 %}%){{ stat.name }}{{ stat.total }}{{ stat.own_total}}
diff --git a/marietje/stats/templates/stats/user.html b/marietje/stats/templates/stats/user.html index d6a877c..0b373a5 100644 --- a/marietje/stats/templates/stats/user.html +++ b/marietje/stats/templates/stats/user.html @@ -19,11 +19,11 @@ {% endif %} -

Total uploads: {{ stats.total_uploads }}

-

Unique requests: {{ stats.unique_requests }} ({% widthratio stats.unique_requests stats.total_requests 100 %}%)

Most played songs

-

Total: {{ stats.total_requests }}

+

You have requested {{ stats.unique_requests }} different + songs a total of {{ stats.total_requests }} times. This + means {% widthratio stats.unique_requests stats.total_requests 100 %}% of your requests have been unique.

Top {{ stats.stats_top_count }}:

@@ -51,8 +51,11 @@

Uploads requested

-

Total played by you: {{stats.total_played_user_uploads}}

-

Total played by others: {{stats.total_played_uploads}}

+

You have uploaded a total of {{stats.total_uploads }} songs. The left column + shows how many times these have been requested by other people. The right column shows + how many times you requested your own songs. In total your songs + have been queued {{stats.total_played_uploads }} times by others and + {{stats.total_played_user_uploads }} by yourself.

Top {{ stats.stats_top_count }}:

@@ -81,7 +84,7 @@

Most played uploaders

-

Top {{ stats.stats_top_count }}:

+

The people whose songs you have queued the most are:

diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index d5a68a4..20b95cd 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -16,9 +16,11 @@ def recache_stats(): caches['default'].delete('stats') caches['default'].set('stats', new_stats, 2 * 3600) return new_stats - + + def recache_user_stats(): - users = User.objects.exclude(Q(id=None) + users = User.objects.exclude( + Q(id=None) | Q(id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values('id') for user in users: new_stats = user_stats(user['id']) @@ -27,13 +29,51 @@ def recache_user_stats(): caches['userstats'].set(cacheloc, new_stats, 48 * 3600) return new_stats + def time_convert(time): - 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 + 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: + 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'] + else: + most_requested_uploaders[b]['total'] += x['total'] + break + b += 1 + return + + +def adding_list_item(list, x): + list.append({ + 'id': x['song__user__id'], + 'name': x['song__user__name'], + 'total': 0, + 'own_total': 0 + }) + if x['song__user__id'] == x['user__id']: + list[-1]['own_total']: x['total'] + else: + list[-1]['_total']: x['total'] + return + def compute_stats(): # We want to grab the time now, because otherwise we would be reporting a minute too late @@ -78,45 +118,74 @@ def compute_stats(): '-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] + 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( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( - 'user__id', 'user__name').annotate(total=Sum('song__duration'), avg_dur=Sum('song__duration')/Count('id')).order_by( - '-total')[:settings.STATS_TOP_COUNT] + 'user__id', 'user__name').annotate( + total=Sum('song__duration'), + avg_dur=Sum('song__duration') / + Count('id')).order_by('-total')[:settings.STATS_TOP_COUNT] 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')) - most_requested_uploaders = PlaylistSong.objects.filter(state=2).exclude( + 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) + + requests_uploader = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( - 'song__user__id', 'song__user__name').annotate(total=Count( - 'song__user__id')).order_by('-total')[:settings.STATS_TOP_COUNT] + 'song__user__id', 'song__user__name', 'user__name', + 'user__id').annotate(total=Count('song__user__name')) + + most_requested_uploaders = [] + calculate_uploaders(list(requests_uploader), most_requested_uploaders) 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', - 'stats_top_count': settings.STATS_TOP_COUNT, - 'most_requested_uploaders': list(most_requested_uploaders), + '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', + 'stats_top_count': + settings.STATS_TOP_COUNT, + 'most_requested_uploaders': + list(most_requested_uploaders), + 'total_average': + total_average, } + def user_stats(request): last_updated = datetime.now() @@ -148,11 +217,12 @@ def user_stats(request): '-total')[:settings.STATS_TOP_COUNT] most_played_uploads = PlaylistSong.objects.filter( - state=2, song_id__in=Song.objects.filter(user__id=request)).exclude(user__id=None).values( - 'song__artist', - 'song__title').annotate(total=Count('id', filter=~Q(user__id=request)), user_total=Count('id', filter=Q(user__id=request))).order_by( - '-total', 'song__artist', - 'song__title')[:settings.STATS_TOP_COUNT] + state=2, song_id__in=Song.objects.filter(user__id=request)).exclude( + user__id=None).values('song__artist', 'song__title').annotate( + total=Count('id', filter=~Q(user__id=request)), + user_total=Count('id', filter=Q(user__id=request))).order_by( + '-total', 'song__artist', + 'song__title')[:settings.STATS_TOP_COUNT] most_played = list(most_played_uploads) total_played_uploads = 0 @@ -173,4 +243,3 @@ def user_stats(request): 'total_played_uploads': total_played_uploads, 'total_played_user_uploads': total_played_user_uploads, } - From fb111f8be53ddb7df9a82298a331bb4ec5acb74f Mon Sep 17 00:00:00 2001 From: oslomp Date: Tue, 18 Dec 2018 19:10:48 +0100 Subject: [PATCH 13/20] dont ignore settings.py --- marietje/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/marietje/.gitignore b/marietje/.gitignore index d633baa..23527b2 100644 --- a/marietje/.gitignore +++ b/marietje/.gitignore @@ -1,3 +1,2 @@ /.idea/ *.sqlite3 -settings.py \ No newline at end of file From a000774e0b404ede76482b0b6e3e133aa78dabfe Mon Sep 17 00:00:00 2001 From: oslomp Date: Tue, 18 Dec 2018 19:21:05 +0100 Subject: [PATCH 14/20] delete move_up and switch_order functions --- marietje/api/urls.py | 1 - marietje/api/views.py | 17 ----------------- marietje/queues/models.py | 11 ----------- 3 files changed, 29 deletions(-) diff --git a/marietje/api/urls.py b/marietje/api/urls.py index ac0ad39..8fe583d 100644 --- a/marietje/api/urls.py +++ b/marietje/api/urls.py @@ -13,7 +13,6 @@ urlpatterns = [ url(r'^request', views.request), url(r'^report', views.report), url(r'^skip', views.skip), - url(r'^moveup', views.move_up), url(r'^movedown', views.move_down), url(r'^cancel', views.cancel), url(r'^upload', views.upload), diff --git a/marietje/api/views.py b/marietje/api/views.py index a2bbe7e..7a21351 100644 --- a/marietje/api/views.py +++ b/marietje/api/views.py @@ -188,27 +188,10 @@ def skip(request): return JsonResponse({}) -@require_http_methods(["POST"]) -@api_auth_required -def move_up(request): - if not request.user.has_perm('queues.can_move'): - return HttpResponseForbidden() - playlist_song = get_object_or_404(PlaylistSong, id=request.POST.get('id')) - playlist_song.move_up() - return JsonResponse({}) - - @require_http_methods(["POST"]) @api_auth_required def move_down(request): -# print('') -# print(request) -# print('') - ide=(request.POST.get('id')) -# print('') playlist_song = get_object_or_404(PlaylistSong, id=request.POST.get('id')) -# print(playlist_song) -# print('') if playlist_song.user != request.user and not request.user.has_perm('queues.can_move'): return HttpResponseForbidden() playlist_song.move_down() diff --git a/marietje/queues/models.py b/marietje/queues/models.py index c027f5d..b6fbfef 100644 --- a/marietje/queues/models.py +++ b/marietje/queues/models.py @@ -47,10 +47,6 @@ class PlaylistSong(models.Model): ) state = models.IntegerField(default=0, db_index=True, choices=STATECHOICE) - def move_up(self): - other_song = PlaylistSong.objects.filter(playlist=self.playlist, id__lt=self.id)\ - .order_by('-id').first() - self.switch_order(other_song) def move_down(self): other_song = PlaylistSong.objects.filter(playlist=self.playlist, id__gt=self.id).first() @@ -60,13 +56,6 @@ class PlaylistSong(models.Model): self.save() other_song.save() - def switch_order(self, other_song): - old_id = self.id - self.id = other_song.id - other_song.id = old_id - self.save() - other_song.save() - def __str__(self): return 'Playlist #' + str(self.playlist_id) + ': ' + str(self.song) From b6a0f25d195ad87ba2ce44f60365231f245cb857 Mon Sep 17 00:00:00 2001 From: oslomp Date: Wed, 19 Dec 2018 00:39:21 +0100 Subject: [PATCH 15/20] completely fixed the arrows --- marietje/marietje/static/js/queue.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/marietje/marietje/static/js/queue.js b/marietje/marietje/static/js/queue.js index d970f4f..5916676 100644 --- a/marietje/marietje/static/js/queue.js +++ b/marietje/marietje/static/js/queue.js @@ -53,7 +53,6 @@ $(function () { return false } $.post('/api/report', {id: songId, msg: message, csrfmiddlewaretoken: csrf_token}, function (result) { - console.log(result); if (result.success) { createAlert('success', 'Thanks for your song report!'); } @@ -208,18 +207,17 @@ function renderQueue(playNextAt, now) //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 { var requestPrev = !((queue[id-1].requested_by !== 'Marietje') && (requestedBy === 'Marietje')) + var prevItem = queue[id-1].id } - console.log(requestNext, requestPrev, requestCurr); var canDelete = song.can_move_down || canMoveSongs; var canMoveUp = canMoveSongs && requestPrev || canDeletePrevious && requestCurr && requestPrev; var canMoveDown = canMoveSongs && requestNext || canDelete && requestCurr && requestNext; var artist = song.song.artist.trim() === '' ? '?' : song.song.artist; var title = song.song.title.trim() === '' ? '?' : song.song.title; - var prevId = song.id - 1; + showTime = showTimeToPlay ? (timeToPlay < 0 ? '' : timeToPlay.secondsToMMSS()) : (playNextAt < now ? '' : playNextAt.timestampToHHMMSS()) @@ -228,7 +226,7 @@ function renderQueue(playNextAt, now) + ' @@ -34,7 +34,8 @@ - + + {% endfor %} @@ -51,7 +52,7 @@ - + @@ -59,7 +60,8 @@ - + + {% endfor %} @@ -105,7 +107,7 @@ - + @@ -113,7 +115,8 @@ - + + {% endfor %} @@ -156,7 +159,7 @@ - + @@ -165,7 +168,7 @@ - + {% endfor %} diff --git a/marietje/stats/templates/stats/user.html b/marietje/stats/templates/stats/user.html index 0b373a5..d1bdcb3 100644 --- a/marietje/stats/templates/stats/user.html +++ b/marietje/stats/templates/stats/user.html @@ -41,7 +41,7 @@ - + {% endfor %} @@ -64,7 +64,7 @@ - + @@ -74,7 +74,7 @@ - + {% endfor %} @@ -91,7 +91,7 @@ - + @@ -99,7 +99,8 @@ - + + {% endfor %} diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index 5555ea1..096ca34 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -127,7 +127,7 @@ def compute_stats(): 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( + total_average = '{:.0f} minutes and {:.0f} seconds'.format( avg_dur_min, avg_dur_sec) requests_uploader = PlaylistSong.objects.filter(state=2).exclude( @@ -138,7 +138,7 @@ def compute_stats(): most_requested_uploaders = [] best_uploaders_list(list(requests_uploader), most_requested_uploaders) - + most_requested_uploaders = sorted(most_requested_uploaders, key=lambda x: x['total'], reverse=True)[:settings.STATS_TOP_COUNT] 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' @@ -150,13 +150,13 @@ def compute_stats(): # 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' + tr['duration'] = "{:5.2f} days".format(tr['total'] / 86400) return { 'last_updated': last_updated, - 'total_uploads': stats['total_uploads'], + 'total_uploads': "{0:,.0f}".format(stats['total_uploads']), 'upload_stats': list(stats['upload_stats']), - 'total_requests': stats['total_requests'], + 'total_requests': "{0:,.0f}".format(stats['total_requests']), 'request_stats': list(stats['request_stats']), 'unique_request_stats': list(stats['unique_request_stats']), 'total_unique_requests': stats['total_unique_requests'], @@ -207,7 +207,7 @@ def user_stats(request): total=Count('id', filter=~Q(user__id=request)), user_total=Count('id', filter=Q(user__id=request))).order_by( '-total', 'song__artist', - 'song__title')[:settings.STATS_TOP_COUNT] + 'song__title') most_played = list(most_played_uploads) total_played_uploads = 0 @@ -215,7 +215,8 @@ def user_stats(request): for x in most_played: total_played_uploads += x['total'] total_played_user_uploads += x['user_total'] - + most_played_uploads_list = sorted(most_played_uploads, key=lambda x: (x['song__artist'], x['song__title'])) + most_played_uploads_list = sorted(most_played_uploads_list, key=lambda x:x["total"], reverse=True)[:settings.STATS_TOP_COUNT] return { 'last_updated': last_updated, 'total_uploads': total_uploads, @@ -223,7 +224,7 @@ def user_stats(request): 'unique_requests': unique_requests, 'most_played_songs': list(most_played_songs), 'most_played_uploaders': list(most_played_uploaders), - 'most_played_uploads': list(most_played_uploads), + 'most_played_uploads': most_played_uploads_list, 'stats_top_count': settings.STATS_TOP_COUNT, 'total_played_uploads': total_played_uploads, 'total_played_user_uploads': total_played_user_uploads, From 25769d40e0936164a8b5a94b534931c5068c1348 Mon Sep 17 00:00:00 2001 From: oslomp Date: Fri, 15 Feb 2019 22:58:21 +0100 Subject: [PATCH 19/20] small fixes --- marietje/marietje/settings.py | 5 ----- marietje/stats/utils.py | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/marietje/marietje/settings.py b/marietje/marietje/settings.py index 6a7e99f..4745f32 100644 --- a/marietje/marietje/settings.py +++ b/marietje/marietje/settings.py @@ -107,11 +107,6 @@ CACHES = { 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', 'OPTIONS': {'MAX_ENTRIES': 1500}, }, - 'userstats': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/tmp/MarietjeDjango_cache/default', - 'OPTIONS': { 'MAX_ENTRIES': 1500 }, - }, } AUTH_USER_MODEL = 'marietje.User' diff --git a/marietje/stats/utils.py b/marietje/stats/utils.py index 096ca34..519c0d9 100644 --- a/marietje/stats/utils.py +++ b/marietje/stats/utils.py @@ -216,7 +216,7 @@ def user_stats(request): total_played_uploads += x['total'] total_played_user_uploads += x['user_total'] most_played_uploads_list = sorted(most_played_uploads, key=lambda x: (x['song__artist'], x['song__title'])) - most_played_uploads_list = sorted(most_played_uploads_list, key=lambda x:x["total"], reverse=True)[:settings.STATS_TOP_COUNT] + most_played_uploads_list = sorted(most_played_uploads_list, key=lambda x: x["total"], reverse=True)[:settings.STATS_TOP_COUNT] return { 'last_updated': last_updated, 'total_uploads': total_uploads, From 7f100ac1dfb63d6d35380698693e8697a661addf Mon Sep 17 00:00:00 2001 From: oslomp Date: Fri, 1 Mar 2019 19:57:33 +0100 Subject: [PATCH 20/20] broken admin-search fixed --- marietje/queues/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marietje/queues/admin.py b/marietje/queues/admin.py index 8acdccb..ffed8dd 100644 --- a/marietje/queues/admin.py +++ b/marietje/queues/admin.py @@ -13,7 +13,7 @@ class OrderAdmin(admin.ModelAdmin): class PlaylistSongAdmin(admin.ModelAdmin): list_display = ('playlist', 'song', 'user', 'state', 'played_at') list_filter = ('playlist', 'state', 'user') - search_fields = ('song', ) + search_fields = ('song__title', 'song__artist', 'user__name') admin.site.register(QueueCommand)
' + '        ' + artist + $('.queuebody:last-child').append('' + '' + artist + '' + title + '' + '# Songs
{{ forloop.counter }} {{ stat.user__name }}{{ stat.total }} ({% widthratio stat.total stats.total_uploads 100 %}%){{ stat.total }}({% widthratio stat.total stats.total_uploads 100 %}%)
# User# Requests# Requests
{{ forloop.counter }} {{ stat.user__name }}{{ stat.total }} ({% widthratio stat.total stats.total_requests 100 %}%){{ stat.total }}({% widthratio stat.total stats.total_requests 100 %}%)
# User# Unique# Unique
{{ forloop.counter }} {{ stat.user__name }}{{ stat.unique_requests }} ({% widthratio stat.unique_requests stat.total_requests 100 %}%){{ stat.unique_requests }}({% widthratio stat.unique_requests stat.total_requests 100 %}%)
# User# Others# Others # Own
{{ forloop.counter }} {{ stat.name }}{{ stat.total }}{{ stat.total }} {{ stat.own_total}}
{{ forloop.counter }} {{ stat.song__artist }} {{ stat.song__title }}{{ stat.total }}{{ stat.total }}
# Artist TitleOthersOthers You
{{ forloop.counter }} {{ stat.song__artist }} {{ stat.song__title }}{{ stat.total }}{{ stat.total }} {{ stat.user_total }}
# Uploader# Requests# Requests
{{ forloop.counter }} {{ stat.song__user__name }}{{ stat.total }} ({% widthratio stat.total stats.total_requests 100 %}%){{ stat.total }}({% widthratio stat.total stats.total_requests 100 %}%)