dummy.py 5.0 KB

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