dummy.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. """
  2. Dummy backend
  3. Use as reference
  4. This file is part of polyglot, etc.
  5. """
  6. import datetime
  7. from backends.support import Backend, Course, AssignmentGrade, CategoryGrade, AuthTypes, ResourceCategory, ResourceRawHTML, Task, FileUpload, Quiz, MultipleChoiceQuestion, FreeResponseQuestion, Forum, Post
  8. class DummyQuiz(Quiz):
  9. def __init__(self, course, id, name):
  10. super().__init__(id, name)
  11. self.course = course
  12. # Fetch quiz questions
  13. # This should be call carefully, as it has nasty side effects in some courses!
  14. # Hence why it is a method, breaking with the usual @property technique.
  15. def questions(self):
  16. question1 = MultipleChoiceQuestion("Is mathematics fun?", ["Absolutely!", "Definitely!"])
  17. question2 = FreeResponseQuestion("What's your favourite part?")
  18. return [question1, question2]
  19. # Submit quiz where responses is the output of questions filled out
  20. # True on success
  21. def submit(self, responses):
  22. return True
  23. class DummyForum(Forum):
  24. def __init__(self, course, id, name):
  25. super().__init__(id, name)
  26. self.course = course
  27. # Existing discussion posts.
  28. # Returns a root Post object (with many nested replies, perhaps).
  29. @property
  30. def thread(self):
  31. reply2 = Post("Babs Seed", "That gives me a good idea to annoy the CMCs!", [])
  32. reply1 = Post("Jane Doe", "DNA nanotechnology involves forming artificial, designed nanostructures", [reply2])
  33. question = Post("Carl Smith", "In the homework problem set, you looked at a formula to estimate the number of basepairs in a DNA strand given the length. What are your thoughts?", [reply1])
  34. return question
  35. # Parent is the post to be replied to, body is the text
  36. # Usual return code
  37. def reply(self, parent, body):
  38. return True
  39. class DummyCourse(Course):
  40. def __init__(self, data):
  41. # Course ID unique within this backend but not necessarily in general
  42. self.id = data["id"]
  43. # Course name and teacher name, no localisation?
  44. self.title = data["title"]
  45. self.teacher = data["teacher"]
  46. # Single course grade, if that's available (otherwise, it's computed)
  47. self.grade_summary = data["grade"]
  48. # Detailed gradebook, including weighted categories
  49. @property
  50. def grades(self):
  51. # Uh-oh, let's make a request to the server
  52. # Request the grade break down for course id self.id
  53. # Then fill out like this
  54. grade1 = AssignmentGrade("Chapter 1 Test", 0.95)
  55. grade2 = AssignmentGrade("Homework 1", 0.95)
  56. category1 = CategoryGrade("Tests", 0.80, [grade1])
  57. category2 = CategoryGrade("Homeworks", 0.20, [grade2])
  58. return [category1, category2]
  59. # Arbitrary hierarchy of resources
  60. # Lectures, external links, the syllabus, etc should go here.
  61. # This is necessary as many (most? all?) LMSes support course-specific WYSIWYG editing
  62. # That said, use sparingly as it is not semantic (compare tasks, etc)
  63. @property
  64. def resources(self):
  65. rsrc1 = ResourceRawHTML("Notes", "<p>To-do: Should this be refactored more?</p>")
  66. rsrc2 = FileUpload("foobarbaz", "Essay")
  67. rsrc3 = DummyQuiz(self, "foobazbar", "Post-essay quiz")
  68. rsrc4 = DummyForum(self, "bazbar", "Post-quiz discussion")
  69. rsrc5 = ResourceRawHTML("Syllabus", "1. Be good")
  70. cat = ResourceCategory("Week 1", [], [rsrc1, rsrc2, rsrc3, rsrc4])
  71. cat2 = ResourceCategory("Modules", [cat], [])
  72. return ResourceCategory("Root", [], [cat2, rsrc5])
  73. # Tasks are assignments with a definite (near) due-date.
  74. # Naturally suited to traditional courses (where tonight's homework is here)
  75. # Probably not of much use to self-paced classes
  76. @property
  77. def tasks(self):
  78. return [Task("Homework 2", datetime.datetime.now() + datetime.timedelta(days=1))]
  79. # Upload a file where ID was passed in a FileUpload model
  80. # Returns true if the upload was successful and false otherwise
  81. def upload_file(self, id, file):
  82. return True
  83. class DummyBackend(Backend):
  84. # Parameters needed for authentication
  85. Config = ["Username", "Password"]
  86. # Attempts login based on config from Config
  87. # Return True on success and False on failure.
  88. # Caller is responsible for tracking authentication statement based on this response.
  89. def login(self, config):
  90. if not (config["Username"] == "AzureDiamond" and config["Password"] == "hunter2"):
  91. return False
  92. self.session_id = "cookies_are_tasty"
  93. return True
  94. # List of courses available (available post-auth)
  95. # Array of Course objects, although in practice this will be inherited
  96. @property
  97. def courses(self):
  98. # Fetch something with self.session_id
  99. course = DummyCourse({
  100. "id": "ABC123",
  101. "title": "Algebra II",
  102. "teacher": "Carl Smith",
  103. "grade": 0.95
  104. })
  105. return [course]