Skip to content
This repository has been archived by the owner on Jun 7, 2023. It is now read-only.

Commit

Permalink
Merge 79f20b3 into b00dbed
Browse files Browse the repository at this point in the history
  • Loading branch information
bnmnetp committed Nov 19, 2019
2 parents b00dbed + 79f20b3 commit fa130e3
Show file tree
Hide file tree
Showing 9 changed files with 420 additions and 503 deletions.
404 changes: 5 additions & 399 deletions controllers/assignments.py

Large diffs are not rendered by default.

55 changes: 49 additions & 6 deletions controllers/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import six
import pandas as pd
from db_dashboard import DashboardDataAnalyzer

from rs_practice import _get_practice_data

logger = logging.getLogger(settings.logger)
logger.setLevel(settings.log_level)
Expand Down Expand Up @@ -199,6 +199,8 @@ def index():
logger.debug("getting user activity")
user_activity = data_analyzer.user_activity

# All of this can be replaced by a nice crosstab call
# See UserActivityCrosstab.ipynb
for user, activity in six.iteritems(user_activity.user_activities):
read_data.append(
{
Expand Down Expand Up @@ -274,10 +276,15 @@ def index():
@auth.requires_login()
def studentreport():
data_analyzer = DashboardDataAnalyzer(auth.user.course_id)
# todo: Test to see if vars.id is there -- if its not then load_user_metrics will crash
# todo: This seems redundant with assignments/index -- should use this one... id should be text sid
data_analyzer.load_user_metrics(request.vars.id)
data_analyzer.load_assignment_metrics(request.vars.id)
for_dashboard = verifyInstructorStatus(auth.user.course_id, auth.user.id)
if "id" in request.vars and for_dashboard:
sid = request.vars.id
else:
sid = auth.user.username
response.view = "assignments/index.html"

data_analyzer.load_user_metrics(sid)
data_analyzer.load_assignment_metrics(sid)

chapters = []
for chapter_label, chapter in six.iteritems(
Expand All @@ -290,15 +297,51 @@ def studentreport():
"subchapters": chapter.get_sub_chapter_progress(),
}
)
activity = data_analyzer.formatted_activity.activities
activity = data_analyzer.formatted_activity

logger.debug("GRADES = %s", data_analyzer.grades)

pd = dict()
if response.view == "assignments/index.html":
(
pd["now"],
pd["now_local"],
pd["practice_message1"],
pd["practice_message2"],
pd["practice_graded"],
pd["spacing"],
pd["interleaving"],
pd["practice_completion_count"],
pd["remaining_days"],
pd["max_days"],
pd["max_questions"],
pd["day_points"],
pd["question_points"],
pd["presentable_flashcards"],
pd["flashcard_count"],
pd["practiced_today_count"],
pd["questions_to_complete_day"],
pd["practice_today_left"],
pd["points_received"],
pd["total_possible_points"],
pd["flashcard_creation_method"],
) = _get_practice_data(
auth.user,
float(session.timezoneoffset) if "timezoneoffset" in session else 0,
db,
)
pd["total_today_count"] = min(
pd["practice_today_left"] + pd["practiced_today_count"],
pd["questions_to_complete_day"],
)

return dict(
course=get_course_row(db.courses.ALL),
user=data_analyzer.user,
chapters=chapters,
activity=activity,
assignments=data_analyzer.grades,
**pd
)


Expand Down
152 changes: 69 additions & 83 deletions modules/db_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,24 +166,52 @@ def retrieve_chapter_problems(self):


class UserActivityMetrics(object):
def __init__(self, course_id, users):
self.course_id = course_id
def __init__(self, course_name, users):
self.course_id = course_name
self.user_activities = {}
for user in users:
self.user_activities[user.username] = UserActivity(user)

def update_metrics(self, logs):
for row in logs:
if row.sid in self.user_activities:
self.user_activities[row.sid].add_activity(row)
# Get summary of logs
self.logs = current.db.executesql(
"""select sid, event, count(*)
from useinfo where course_id = '{}'
group by sid, event
order by sid, event""".format(
self.course_id
),
as_dict=True,
)

self.recent_logs = current.db.executesql(
"""select sid, event, count(*)
from useinfo where course_id = '{}'
and timestamp > now() - interval '7 days'
group by sid, event
order by sid, event""".format(
self.course_id
),
as_dict=True,
)
# read logs here

def update_metrics(self):

for row in self.logs:
if row["sid"] in self.user_activities:
self.user_activities[row["sid"]].add_activity(row)

for row in self.recent_logs:
if row["sid"] in self.user_activities:
self.user_activities[row["sid"]].add_recent_activity(row)


class UserActivity(object):
def __init__(self, user):
self.name = "{0} {1}".format(user.first_name, user.last_name)
self.username = user.username
self.rows = []
self.page_views = []
self.page_views = 0
self.correct_count = 0
self.missed_count = 0
self.recent_page_views = 0
Expand All @@ -192,28 +220,26 @@ def __init__(self, user):

def add_activity(self, row):
# row is a row from useinfo
week_ago = datetime.datetime.utcnow() - datetime.timedelta(days=7)
if row.event in UNGRADED_EVENTS:
self.page_views.append(row)
if row.timestamp > week_ago:
self.recent_page_views += 1
else:
if row["event"] == "page":
self.page_views += row["count"]
elif row["event"] == "activecode":
self.rows.append(row)
# this is a start but needs to be made more accurate
if "correct" in row.act:
self.correct_count += 1
elif row.event == "unittest" and "percent:100" in row.act:
self.correct_count += 1
if row.timestamp > week_ago:
self.recent_correct += 1
elif row.event not in UNGRADED_EVENTS:
self.missed_count += 1
if row.timestamp > week_ago:
self.recent_missed += 1
self.correct_count += row["count"]
else:
self.missed_count += row["count"]

def add_recent_activity(self, row):
# row is a row from useinfo
if row["event"] == "page":
self.recent_page_views += row["count"]
elif row["event"] == "activecode":
self.recent_correct += row["count"]
else:
self.recent_missed += row["count"]

def get_page_views(self):
# returns page views for all time
return len(self.page_views)
return self.page_views

def get_recent_page_views(self):
return self.recent_page_views
Expand Down Expand Up @@ -331,7 +357,7 @@ def __init__(self, course_id, sub_chapters, users):
sub_chapter, len(users)
)

def update_metrics(self, logs, chapter_progress):
def update_metrics(self, chapter_progress):
for row in chapter_progress:
try:
self.sub_chapters[
Expand Down Expand Up @@ -375,46 +401,6 @@ def get_completed_percent(self):
return "{0:.2f}%".format(float(self.completed) / self.total_users * 100)


class UserLogCategorizer(object):
def __init__(self, logs):
self.activities = []
for log in logs:
self.activities.append(
{
"time": log.timestamp,
"event": UserLogCategorizer.format_event(
log.event, log.act, log.div_id
),
}
)

@staticmethod
def format_event(event, action, div_id):
short_div_id = div_id
if len(div_id) > 25:
short_div_id = "...{0}".format(div_id[-25:])
if (event == "page") & (action == "view"):
return "{0} {1}".format("Viewed", short_div_id)
elif (event == "timedExam") & (action == "start"):
return "{0} {1}".format("Started Timed Exam", div_id)
elif (event == "timedExam") & (action == "finish"):
return "{0} {1}".format("Finished Timed Exam", div_id)
elif event == "highlight":
return "{0} {1}".format("Highlighted", short_div_id)
elif (event == "activecode") & (action == "run"):
return "{0} {1}".format("Ran Activecode", div_id)
elif (event == "parsons") & (action == "yes"):
return "{0} {1}".format("Solved Parsons", div_id)
elif (event == "parsons") & (action != "yes"):
return "{0} {1}".format("Attempted Parsons", div_id)
elif (event == "mChoice") | (event == "fillb"):
answer = action.split(":")
if action.count(":") == 2 and answer[2] == "correct":
return "{0} {1}".format("Solved", div_id)
return "{0} {1}".format("Attempted", div_id)
return "{0} {1}".format(event, div_id)


class DashboardDataAnalyzer(object):
def __init__(self, course_id, chapter=None):
self.course_id = course_id
Expand Down Expand Up @@ -442,19 +428,6 @@ def __init__(self, course_id, chapter=None):
self.inums = [x.instructor for x in self.instructors]
self.users.exclude(lambda x: x.id in self.inums)

# todo - load this into a DataFrame
self.logs = current.db(
(current.db.useinfo.course_id == self.course.course_name)
& (current.db.useinfo.timestamp >= self.course.term_start_date)
).select(
current.db.useinfo.timestamp,
current.db.useinfo.sid,
current.db.useinfo.event,
current.db.useinfo.act,
current.db.useinfo.div_id,
orderby=current.db.useinfo.timestamp,
)

def load_chapter_metrics(self, chapter):
if not chapter:
rslogger.error("chapter not set, abort!")
Expand Down Expand Up @@ -486,12 +459,15 @@ def load_chapter_metrics(self, chapter):
self.problem_metrics = CourseProblemMetrics(self.course_id, self.users, chapter)
rslogger.debug("About to call update_metrics")
self.problem_metrics.update_metrics(self.course.course_name)
self.user_activity = UserActivityMetrics(self.course_id, self.users)
self.user_activity.update_metrics(self.logs)

self.user_activity = UserActivityMetrics(self.course.course_name, self.users)
self.user_activity.update_metrics()

self.progress_metrics = ProgressMetrics(
self.course_id, self.db_sub_chapters, self.users
)
self.progress_metrics.update_metrics(self.logs, self.db_chapter_progress)
self.progress_metrics.update_metrics(self.db_chapter_progress)

self.questions = {}
for i in self.problem_metrics.problems.keys():
self.questions[i] = (
Expand Down Expand Up @@ -546,11 +522,21 @@ def load_user_metrics(self, username):
current.db.user_sub_chapter_progress.sub_chapter_id,
current.db.user_sub_chapter_progress.status,
)
self.formatted_activity = UserLogCategorizer(self.logs)
self.formatted_activity = self.load_recent_activity()
self.chapter_progress = UserActivityChapterProgress(
self.chapters, self.db_chapter_progress
)

def load_recent_activity(self):
week_ago = datetime.datetime.utcnow() - datetime.timedelta(days=7)
res = current.db(
(current.db.useinfo.sid == self.user.username)
& (current.db.useinfo.course_id == self.course.course_name)
& (current.db.useinfo.timestamp > week_ago)
).select(orderby=~current.db.useinfo.timestamp)

return res

def load_exercise_metrics(self, exercise):
self.problem_metrics = CourseProblemMetrics(
self.course_id, self.users, self.db_chapter
Expand Down

0 comments on commit fa130e3

Please sign in to comment.