Browse Source

Fix engagement tracking.

develop
Sam Black 3 years ago
parent
commit
b3350a9035
  1. 2
      vowel/models/analytics.py
  2. 17
      vowel/utils/analytics.py
  3. 33
      vowel/views/course/learner/analytics.py

2
vowel/models/analytics.py

@ -62,7 +62,7 @@ class Engagement(db.Model):
return getattr(dur, division)
elif division == "minutes":
# This is not accurate, but see TODO above
return dur.seconds // 60
return dur.seconds // 60 + (1 if dur.seconds % 60 else 0)
else:
return dur.seconds

17
vowel/utils/analytics.py

@ -24,13 +24,9 @@ from flask import url_for
from flask_security import current_user
from vowel.models.analytics import Engagement
from vowel.models.assessments import Assessmentinstance
from vowel.models.courses import Course
from vowel.models.courses import Enrolment
from vowel.models.lessons import Lessoninstance
from vowel.utils.course import instance_program
from vowel.utils.redis_conn import redis_conn
from vowel.utils.route import route_from
ANALYTICS_ENGAGEMENT_NAMESPACE = "/analytics/engagement"
@ -49,7 +45,7 @@ ANALYTICS_ENGAGEMENT_REDIS_HKEY = {
def engagement_tracking():
"""
If the we should add engagement tracking to the current page.
If we should add engagement tracking to the current page.
:return: URL to track, or False to disable tracking
:rtype: str or bool
@ -136,18 +132,15 @@ def course_engagements(course_id, course_instance_id=None):
ci_url = url_for("courses_learner.view_instance",
org_slug=org_slug,
course_instance_name=course_instance_name,
course_id=course_id,
course_instance_id=course_instance_id, _external=True)
_external=True)
urls[course_instance_name] = [ci_url]
urls["all"].append(ci_url)
else:
instances = []
for ci in course.instances:
ci_url = url_for("courses_learner.view_instance",
org_slug=org_slug,
course_instance_name=ci.name,
course_id=course_id,
course_instance_id=ci.id, _external=True)
org_slug=org_slug, course_instance_name=ci.name,
_external=True)
urls[ci.name] = [ci_url]
urls["all"].append(ci_url)
@ -160,7 +153,6 @@ def course_engagements(course_id, course_instance_id=None):
lesson_url = url_for("lessons_learner.view_instance",
org_slug=org_slug,
course_instance_name=ci_name,
lesson_id=lesson.lesson_id,
lesson_instance_id=lesson.id, _external=True)
urls[ci_name].append(lesson_url)
urls["all"].append(lesson_url)
@ -168,7 +160,6 @@ def course_engagements(course_id, course_instance_id=None):
assessment_url = url_for("assessments_learner.view_instance",
org_slug=org_slug,
course_instance_name=ci_name,
assessment_id=assessment.assessment_id,
assessment_instance_id=assessment.id,
_external=True)
urls[ci_name].append(assessment_url)

33
vowel/views/course/learner/analytics.py

@ -18,13 +18,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import arrow
from flask import g
from flask import request
from flask_security import current_user
from werkzeug.urls import url_fix
from vowel.models import db
from vowel.models.analytics import Engagement
from vowel.models.analytics import EngagementVisibility
from vowel.models.courses import Courseinstance
from vowel.models.organisations import Organisation
from vowel.utils import socketio
from vowel.utils.analytics import ANALYTICS_ENGAGEMENT_NAMESPACE
@ -32,6 +34,7 @@ from vowel.utils.analytics import ANALYTICS_ENGAGEMENT_REDIS_HKEY as VAE
from vowel.utils.analytics import check_sid_user_url
from vowel.utils.auth import socketio_authenticated_only
from vowel.utils.redis_conn import redis_conn
from vowel.utils.route import route_from
@socketio.on("init", namespace=ANALYTICS_ENGAGEMENT_NAMESPACE)
@ -103,11 +106,31 @@ def engagement_disconnect():
if current_user.id == vae_user:
vae_url = redis_conn.hget(VAE["url"], request.sid)
# This shouldn't happen, but reject any non course instance views
if not g.course_instance:
endpoint, args = route_from(vae_url)
# This shouldn't happen, but ignore any URLs that are
# not for learners or
# have no course instance name
if ("learner" not in endpoint or "org_slug" not in args or
"course_instance_name" not in args):
return
org_slug = args["org_slug"]
course_instance_name = args["course_instance_name"]
organisation = Organisation.query.filter_by(slug=org_slug).first()
if not organisation:
return
course_instance = Courseinstance.query.filter_by(
name=course_instance_name).join("course").filter_by(
organisation_id=organisation.id).first()
if not course_instance:
return
enrol = g.course_instance.is_enrolled(vae_user)
enrol = course_instance.is_enrolled(vae_user)
# This shouldn't happen, but discard staff members looking at courses
if enrol.staff:
@ -124,7 +147,7 @@ def engagement_disconnect():
data = {
"user_id": vae_user,
"enrolment_id": enrol.id,
"url": vae_url,
"url": url_fix(vae_url),
"start": arrow.get(redis_conn.hget(VAE["start"], request.sid)),
"end": end
}

Loading…
Cancel
Save