Skip to content

Commit

Permalink
Course: Refactor discord credit
Browse files Browse the repository at this point in the history
  • Loading branch information
ConnorNelson committed Nov 21, 2024
1 parent fa69205 commit 4944678
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 90 deletions.
12 changes: 7 additions & 5 deletions dojo_plugin/api/v1/discord.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ def get(self, discord_id):

def get_user_activity_prop(discord_id, activity, start=None, end=None):
user = DiscordUsers.query.filter_by(discord_id=discord_id).first()

if activity == "thanks":
count = user.thanks_count(start, end) if user else 0
if not user:
count = 0
elif activity == "thanks":
count = (user.thanks(start, end)
.group_by(DiscordUserActivity.message_id, DiscordUserActivity.source_user_id)
.count())
elif activity == "memes":
count = user.meme_count(start, end) if user else 0

count = user.memes(start, end).count()
return {"success": True, activity: count}

def get_user_activity(discord_id, activity, request):
Expand Down
51 changes: 10 additions & 41 deletions dojo_plugin/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,52 +768,21 @@ class DiscordUsers(db.Model):

user = db.relationship("Users")

def thanks_count(self, start=None, end=None, unique_messages=False):
query = DiscordUserActivity.query.filter(
DiscordUserActivity.type == 'thanks',
def thanks(self, start=None, end=None):
return DiscordUserActivity.query.filter(
DiscordUserActivity.type == "thanks",
DiscordUserActivity.user_id == self.discord_id,
DiscordUserActivity.message_timestamp >= start if start else True,
DiscordUserActivity.message_timestamp <= end if end else True)

if unique_messages:
query = query.with_entities(DiscordUserActivity.message_id)
else:
query = query.with_entities(DiscordUserActivity.user_id, DiscordUserActivity.source_user_id, DiscordUserActivity.message_id)

return query.distinct().count()

def meme_count(self, start=None, end=None, weekly=True):
if not weekly:
return DiscordUserActivity.query.filter(and_(DiscordUserActivity.user_id == self.discord_id),
DiscordUserActivity.message_timestamp >= start if start else True,
DiscordUserActivity.message_timestamp <= end if end else True,
DiscordUserActivity.type == "memes"
).with_entities(db.func.distinct(DiscordUserActivity.message_id)).count()

meme_weeks = self.meme_dates(start, end)
return len(meme_weeks)
DiscordUserActivity.message_timestamp <= end if end else True
)

def meme_dates(self, start=None, end=None):
memes = DiscordUserActivity.query.filter(and_(DiscordUserActivity.user_id == self.discord_id),
def memes(self, start=None, end=None):
return DiscordUserActivity.query.filter(
DiscordUserActivity.user_id == self.discord_id,
DiscordUserActivity.message_timestamp >= start if start else True,
DiscordUserActivity.message_timestamp <= end if end else True,
DiscordUserActivity.type == "memes"
).order_by(DiscordUserActivity.message_timestamp).all()

default_start = datetime.datetime.fromisoformat(f"{datetime.datetime.today().year}-01-01")
utc_start = default_start if not start else start.astimezone().replace(tzinfo=None)
utc_end = datetime.datetime.now() if not end else end.astimezone().replace(tzinfo=None)

def valid_week(week, memes):
return bool([m for m in memes if m.message_timestamp >= week[0] and m.message_timestamp <= week[1]])

week_count = (utc_end - utc_start) // datetime.timedelta(days=7)
class_weeks = [(utc_start + datetime.timedelta(days=7 * i), utc_start + datetime.timedelta(days= 7 * (i + 1)) - datetime.timedelta(microseconds=1)) for i in range(week_count)]

def to_local_tz(d):
return d.replace(tzinfo=datetime.timezone.utc).astimezone(start.tzinfo) if start else d

return [(to_local_tz(s),to_local_tz(e)) for (s, e) in class_weeks if valid_week((s,e), memes)]
DiscordUserActivity.type == "memes",
)

__repr__ = columns_repr(["user", "discord_id"])

Expand Down
108 changes: 64 additions & 44 deletions dojo_plugin/pages/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,33 +114,45 @@ def query(module_id):

module_solves = {}

def get_thanks_progress(dojo, user_id, unique):
discord_user = DiscordUsers.query.where(DiscordUsers.user_id == user_id).first()
if not discord_user:
return "Discord not linked"
if "start_date" not in dojo.course:
return "Error: unknown course start date"

course_start = datetime.datetime.fromisoformat(dojo.course["start_date"])
thanks = (discord_user.thanks(start=course_start, end=course_start + datetime.timedelta(weeks=16))
.group_by(DiscordUserActivity.message_id))
if not unique:
thanks = thanks.group_by(DiscordUserActivity.source_user_id)
return f"{thanks.count()} thanks"

def get_meme_progress(dojo, user_id):
discord_user = DiscordUsers.query.where(DiscordUsers.user_id == user_id).first()
if not discord_user:
return ""
discord_user = DiscordUsers.query.where(DiscordUsers.user_id == user_id).first()
if not discord_user:
return "Discord not linked"
if "start_date" not in dojo.course:
return "Error: unknown course start date"

course_start = datetime.datetime.fromisoformat(dojo.course.get("start_date")) or datetime.datetime.min
meme_weeks = discord_user.meme_dates(start=course_start, end=course_start + datetime.timedelta(weeks=16))
course_start = datetime.datetime.fromisoformat(dojo.course["start_date"])
memes = (discord_user.memes(start=course_start, end=course_start + datetime.timedelta(weeks=16))
.order_by(DiscordUserActivity.message_timestamp))

def clean_date(d):
return f"{d.month:02d}/{d.day:02d}"
week_ranges = ' '.join([f"{clean_date(s)}-{clean_date(e)}" for s, e in meme_weeks])
return week_ranges
weekly_memes = set((meme.message_timestamp.astimezone(datetime.timezone.utc) - course_start).days // 7
for meme in memes)

def get_thanks_progress(dojo, user_id, unique):
discord_user = DiscordUsers.query.where(DiscordUsers.user_id == user_id).first()
if not discord_user:
return 0
course_start = datetime.datetime.fromisoformat(dojo.course.get("start_date")) or datetime.datetime.min
thanks_count = discord_user.thanks_count(start=course_start, unique_messages=unique)
def week_string(week):
start = course_start + datetime.timedelta(weeks=week)
end = start + datetime.timedelta(days=6)
return f"{start.month:02d}/{start.day:02d}-{end.month:02d}/{end.day:02d}"

return thanks_count
return " ".join(week_string(week) for week in weekly_memes)

def result(user_id):
assessment_grades = []

max_extra = dojo.course.get("max_extra", float("inf"))
max_extra = dojo.course.get("max_extra") or float("inf")
def limit_extra(func, limit=max_extra):
def wrapper(*args, **kwargs):
nonlocal limit
Expand All @@ -150,28 +162,35 @@ def wrapper(*args, **kwargs):
return wrapper

@limit_extra
def get_thanks_credit(dojo, user_id, method, max_credit, unique):
def get_thanks_credit(dojo, user_id, method, unique, max_credit):
discord_user = DiscordUsers.query.where(DiscordUsers.user_id == user_id).first()
if not discord_user:
if not discord_user or "start_date" not in dojo.course:
return 0
course_start = dojo.course.get("start_date") or datetime.datetime.min
thanks_count = discord_user.thanks_count(start=course_start,unique_messages=unique)

if method == 'log50':
return min(max_credit * math.log(thanks_count, 50), max_credit) if thanks_count else 0
elif method == '1337log2':
return min(1.337 ** math.log(thanks_count,2) / 100, max_credit) if thanks_count else 0
return 0
course_start = datetime.datetime.fromisoformat(dojo.course["start_date"])
thanks = (discord_user.thanks(start=course_start, end=course_start + datetime.timedelta(weeks=16))
.group_by(DiscordUserActivity.message_id))
if not unique:
thanks = thanks.group_by(DiscordUserActivity.source_user_id)
thanks_count = thanks.count()

if thanks_count == 0:
return 0.0

credit = 0.0
if method == "log50":
credit = max_credit * math.log(thanks_count, 50)
elif method == "1337log2":
credit = 1.337 ** math.log(thanks_count, 2) / 100
return min(credit, max_credit)

@limit_extra
def get_meme_credit(dojo, user_id, max_credit, meme_value=0.005):
def get_meme_credit(dojo, user_id, value, max_credit):
discord_user = DiscordUsers.query.where(DiscordUsers.user_id == user_id).first()
if not discord_user:
return 0
course_start = datetime.datetime.fromisoformat(dojo.course.get("start_date")) or datetime.datetime.min
meme_count = discord_user.meme_count(start=course_start, end=course_start + datetime.timedelta(weeks=16))

return min(meme_count * meme_value, max_credit)
if not discord_user or "start_date" not in dojo.course:
return 0.0
course_start = datetime.datetime.fromisoformat(dojo.course["start_date"])
meme_count = discord_user.memes(start=course_start, end=course_start + datetime.timedelta(weeks=16)).count()
return min(meme_count * value, max_credit)

@limit_extra
def get_extra(user_id):
Expand Down Expand Up @@ -275,22 +294,23 @@ def get_extra(user_id):

if type == "helpfulness":
method = assessment.get("method")
max_credit = assessment.get("max_credit") or 1.00
unique_messages = assessment.get("unique") or False
max_credit = assessment.get("max_credit") or float("inf")
unique = assessment.get("unique") or False
assessment_grades.append(dict(
name=assessment_name(dojo, assessment),
progress=get_thanks_progress(dojo, user_id, unique_messages),
credit=get_thanks_credit(dojo, user_id, method, max_credit, unique_messages)
))
progress=get_thanks_progress(dojo, user_id, unique),
credit=get_thanks_credit(dojo, user_id, method, unique, max_credit)
))

if type == "memes":
max_credit = assessment.get("max_credit") or 1.00
credit = get_meme_credit(dojo, user_id, max_credit)
value = assessment.get("value") or 0.0
max_credit = assessment.get("max_credit") or float("inf")
credit = get_meme_credit(dojo, user_id, value, max_credit)
assessment_grades.append(dict(
name=assessment_name(dojo, assessment),
progress=get_meme_progress(dojo, user_id),
credit=credit
))
credit=credit,
))

overall_grade = (
sum(grade["credit"] * grade["weight"] for grade in assessment_grades if "weight" in grade) /
Expand All @@ -308,7 +328,7 @@ def get_extra(user_id):
assessment_grades=assessment_grades,
overall_grade=overall_grade,
letter_grade=letter_grade,
show_extra_late_date= any(row.get('extra_late_date',None) is not None for row in assessments))
show_extra_late_date= any(row.get("extra_late_date", None) is not None for row in assessments))

user_id = None
previous_user_id = None
Expand Down

0 comments on commit 4944678

Please sign in to comment.