kattis2canvas 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kattis2canvas
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: CLI tool to integrate Kattis offerings with Canvas LMS courses
5
5
  Author: bcr33d
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "kattis2canvas"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  description = "CLI tool to integrate Kattis offerings with Canvas LMS courses"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -614,7 +614,7 @@ def course2canvas(offering, canvas_course, dryrun, force, add_to_module, assignm
614
614
  assignment_data = {
615
615
  'assignment_group_id': canvas_group.id,
616
616
  'name': assignment.title,
617
- 'description': f'Solve the problems found at <a href="{assignment.url}">{assignment.url}</a>. {description}',
617
+ 'description': f'Solve the problems found at <a href="{assignment.url}" target="kattis-details">{assignment.url}</a>. {description}',
618
618
  'points_possible': 100,
619
619
  'published': True,
620
620
  }
@@ -734,10 +734,12 @@ def kattislinks(canvas_course):
734
734
  @click.option("--dryrun/--no-dryrun", default=True, help="show planned actions, do not make them happen.")
735
735
  @click.option("--assignment-group", default="kattis", help="the canvas assignment group to use (default: kattis).")
736
736
  @click.option("--section", help="only process submissions for students in this specific section.")
737
- def submissions2canvas(offering, canvas_course, dryrun, assignment_group, section):
737
+ @click.option("--force-comment/--no-force-comment", default=False, help="add a comment about the best submission even if there is already a comment in canvas.")
738
+ def submissions2canvas(offering, canvas_course, dryrun, assignment_group, section, force_comment):
738
739
  """
739
740
  mirror summary of submission from kattis into canvas as a submission comment.
740
741
  """
742
+ print(force_comment)
741
743
  load_config()
742
744
  offerings = list(get_offerings(offering))
743
745
  if len(offerings) == 0:
@@ -796,74 +798,93 @@ def submissions2canvas(offering, canvas_course, dryrun, assignment_group, sectio
796
798
  f'duplicate submission for {kattis_user2canvas_id[canvas_submission.user_id]} in {assignment.title}')
797
799
  submissions_by_user[canvas_id2kattis_user[canvas_submission.user_id]] = canvas_submission
798
800
  last_comment = datetime.datetime.fromordinal(1).replace(tzinfo=datetime.timezone.utc)
801
+ last_comment_text = ''
799
802
  if canvas_submission.submission_comments:
800
803
  for comment in canvas_submission.submission_comments:
801
804
  created_at = extract_canvas_date(comment['created_at'])
802
- if created_at > last_comment:
805
+ if config.kattis_hostname in comment.get('comment', '') and created_at > last_comment:
803
806
  last_comment = created_at
807
+ last_comment_text = comment.get('comment', '')
804
808
  canvas_submission.last_comment = last_comment
805
-
809
+ canvas_submission.last_comment_text = last_comment_text
806
810
  for user, best in best_submissions.items():
807
811
  for kattis_submission in best.values():
808
812
  if user not in submissions_by_user:
809
813
  warn(f"i don't see a canvas user for {user}")
810
814
  elif user not in kattis_user2canvas_id:
811
815
  warn(f'skipping submission for unknown user {user}')
812
- elif kattis_submission.date > submissions_by_user[user].last_comment:
816
+ elif kattis_submission.date > submissions_by_user[user].last_comment or force_comment:
813
817
  if dryrun:
814
818
  warn(
815
819
  f"would update {kattis_user2canvas_id[kattis_submission.user]} on problem {kattis_submission.problem} scored {kattis_submission.score}")
816
820
  else:
821
+ href_url = f"https://{config.kattis_hostname}{kattis_submission.url}"
817
822
  submissions_by_user[user].edit(comment={
818
- 'text_comment': f"{prefix}Submission https://{config.kattis_hostname}{kattis_submission.url} scored {kattis_submission.score} on {kattis_submission.problem}."})
823
+ 'text_comment': f"{prefix}Submission <a href={href_url}>{href_url}</a> scored {kattis_submission.score} on {kattis_submission.problem}."})
819
824
  info(
820
825
  f"updated {submissions_by_user[user]} {kattis_user2canvas_id[kattis_submission.user]} for {assignment.title}")
821
826
  else:
822
- info(f"{user} up to date")
827
+ info(f"{user} up to date {kattis_submission.date} > {submissions_by_user[user].last_comment} {submissions_by_user[user].last_comment_text} ")
823
828
 
824
829
 
825
830
  def get_best_submissions(offering: str, assignment_id: str) -> {str: {str: Submission}}:
826
831
  best_submissions = collections.defaultdict(dict)
827
- url = f"https://{config.kattis_hostname}{offering}/assignments/{assignment_id}/submissions"
828
- rsp = web_get(url)
829
- bs = BeautifulSoup(rsp.content, "html.parser")
830
- judge_table = bs.find("table", id="judge_table")
831
- if not judge_table:
832
- info(f"no submissions yet for {assignment_id}")
833
- return best_submissions
834
- headers = [x.get_text().strip() for x in judge_table.find_all("th")]
835
- tbody = judge_table.find("tbody")
836
- for submissions in tbody.find_all("tr", recursive=False):
837
- if not submissions.get("data-submission-id"):
838
- continue
839
- submissions = submissions.find_all("td", recursive=False)
840
- if not submissions:
841
- continue
842
- props = {}
843
- for index, td in enumerate(submissions):
844
- a = td.find("a")
845
- props[headers[index]] = a.get("href") if a else td.get_text().strip()
846
- date = props["Date"]
847
- if "-" in date:
848
- date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S").replace(tzinfo=now.tzinfo)
849
- else:
850
- hms = datetime.datetime.strptime(date, "%H:%M:%S")
851
- date = now.replace(hour=hms.hour, minute=hms.minute, second=hms.second)
852
- # it's not clear when the short date version is used. it might be used when it is less than 24 hours,
853
- # in which case, just setting the time will make the date 24 hours more than it should be
854
- if date > now:
855
- date -= datetime.timedelta(days=1)
856
-
857
- score = 0.0 if props["Test cases"] == "-/-" else float(Fraction(props["Test cases"])) * 100
858
- submission = Submission(user=extract_last(props["User"]), problem=extract_last(props["Problem"]), date=date,
859
- score=score, url=props[""])
860
- if submission.problem not in best_submissions[submission.user]:
861
- best_submissions[submission.user] = {submission.problem: submission}
862
- else:
863
- current_best = best_submissions[submission.user][submission.problem]
864
- if current_best.score < submission.score or (
865
- current_best.score == submission.score and current_best.date < submission.date):
832
+ base_url = f"https://{config.kattis_hostname}{offering}/assignments/{assignment_id}/submissions"
833
+ headers = None
834
+ page = 0
835
+
836
+ while True:
837
+ url = f"{base_url}?page={page}"
838
+ rsp = web_get(url)
839
+ bs = BeautifulSoup(rsp.content, "html.parser")
840
+ judge_table = bs.find("table", id="judge_table")
841
+
842
+ if not judge_table:
843
+ if page == 0:
844
+ info(f"no submissions yet for {assignment_id}")
845
+ break
846
+
847
+ if headers is None:
848
+ headers = [x.get_text().strip() for x in judge_table.find_all("th")]
849
+
850
+ tbody = judge_table.find("tbody")
851
+ rows = [r for r in tbody.find_all("tr", recursive=False) if r.get("data-submission-id")]
852
+
853
+ if not rows:
854
+ break
855
+
856
+ for row in rows:
857
+ cells = row.find_all("td", recursive=False)
858
+ if not cells:
859
+ continue
860
+ props = {}
861
+ for index, td in enumerate(cells):
862
+ a = td.find("a")
863
+ props[headers[index]] = a.get("href") if a else td.get_text().strip()
864
+ date = props["Date"]
865
+ if "-" in date:
866
+ date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S").replace(tzinfo=now.tzinfo)
867
+ else:
868
+ hms = datetime.datetime.strptime(date, "%H:%M:%S")
869
+ date = now.replace(hour=hms.hour, minute=hms.minute, second=hms.second)
870
+ # it's not clear when the short date version is used. it might be used when it is less than 24 hours,
871
+ # in which case, just setting the time will make the date 24 hours more than it should be
872
+ if date > now:
873
+ date -= datetime.timedelta(days=1)
874
+
875
+ score = 0.0 if props["Test cases"] == "-/-" else float(Fraction(props["Test cases"])) * 100
876
+ submission = Submission(user=extract_last(props["User"]), problem=extract_last(props["Problem"]), date=date,
877
+ score=score, url=props[""])
878
+ if submission.problem not in best_submissions[submission.user]:
866
879
  best_submissions[submission.user][submission.problem] = submission
880
+ else:
881
+ current_best = best_submissions[submission.user][submission.problem]
882
+ if current_best.score < submission.score or (
883
+ current_best.score == submission.score and current_best.date < submission.date):
884
+ best_submissions[submission.user][submission.problem] = submission
885
+
886
+ page += 1
887
+
867
888
  return best_submissions
868
889
 
869
890
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kattis2canvas
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: CLI tool to integrate Kattis offerings with Canvas LMS courses
5
5
  Author: bcr33d
6
6
  License-Expression: MIT
File without changes
File without changes