def test_available_polls(self): Record.objects.create(student=self.student, group=self.groups[0], status=RecordStatus.ENROLLED) time_in_semester = self.semester.semester_beginning + ( self.semester.semester_ending - self.semester.semester_beginning) / 2 time_after_semester = self.semester.semester_ending + timedelta(days=1) with freeze_time(time_after_semester): # When semester is gone, no Polls should be available. self.assertListEqual(Poll.get_all_polls_for_student(self.student), []) with freeze_time(time_in_semester): # When grade is closed, no Polls should be available. self.assertListEqual(Poll.get_all_polls_for_student(self.student), []) self.semester.is_grade_active = True self.semester.save() with freeze_time(time_after_semester): # This still should be empty. self.assertListEqual(Poll.get_all_polls_for_student(self.student), []) with freeze_time(time_in_semester): # Three Polls should be available to the student. self.assertEqual(len(Poll.get_all_polls_for_student(self.student)), 3)
def get_poll_data(request): """Lists Polls available to the student. The response follows the format: [ # Every poll comes in a record. { "key": { "n": 12345..., "e": 12345..., }, "poll_info": { "id": 123, # Name and Type only serve as a description. Name specifies the # exact poll (exam, group), Type says which course it concerns. "name": "Egzamin: Zbigniew Religa", "type": "Przeszczep serca dla zuchwałych", } }, ] """ students_polls = Poll.get_all_polls_for_student(request.user.student) keys = RSAKeys.objects.filter(poll__in=students_polls).select_related( 'poll', 'poll__group', 'poll__course', 'poll__semester') response_data = [] for key in keys: poll = key.poll poll_data = { 'key': key.serialize_for_signing_protocol(), 'poll_info': poll.serialize_for_signing_protocol(), } response_data.append(poll_data) return JsonResponse(response_data, safe=False)
def make_poll_from_template(request, template): """Returns a poll object based on the template. Raises: Employee.DoesNotExist: If the user is not an employee. """ poll = Poll() poll.author = request.user.employee poll.title = template['title'] poll.description = template['description'] poll.semester = template['semester'] poll.group = template['iterate_group'] poll.studies_type = template['studies_type'] poll.save() return poll
def test_polls_list(self): c = test.Client() time_in_semester = self.semester.semester_beginning + ( self.semester.semester_ending - self.semester.semester_beginning) / 2 with freeze_time(time_in_semester): c.force_login(self.student.user) polls = Poll.get_all_polls_for_student(self.student) keys = RSAKeys.objects.filter(poll__in=polls) self.assertEqual(len(keys), len(polls)) r = c.get('/grade/ticket/get-poll-data') self.assertEqual(len(r.json()), len(polls))
def make_polls_for_groups(request, groups, template): polls = [] origin = Origin() origin.save() for group in groups: if template['groups_without'] == 'on' and Poll.get_all_polls_for_group( group, template.semeter).count() > 0: continue poll = make_poll(request, template, group, origin) polls.append(str(poll)) if not len(polls): raise NoPollException return polls
def generate_keys_for_polls(semester=None): from apps.enrollment.courses.models.semester import Semester if not semester: semester = Semester.get_current_semester() poll_list = Poll.get_polls_without_keys(semester) pub_list = [] priv_list = [] i = 1 for el in poll_list: (pub, priv) = generate_rsa_key() pub_list.append(pub) priv_list.append(priv) i = i + 1 save_public_keys(list(zip(poll_list, pub_list))) save_private_keys(list(zip(poll_list, priv_list))) print(i - 1) return
def sign_tickets(request): """Signs the tickets sent by a student and returns list of signatures. The student must request to sign all the tickets he is entitled to. The signing may only be performed once in a semester. Request must be a dict of objects: { "signing_requests": [ # An object for every poll. { # Id of the poll. "id": 123, # A blinded ticket. "ticket": 12345..., }, ] } Returns: A list of signed tickets, each being a dict like below. { # Id of the poll. 'id': 123, # The ticket from the request signed using a private key # corresponding to the poll. 'signature': 1234... } Errors: 400 BadRequest: When JSON request could not be parsed. 403 Forbidden: When the student tries to sign a ticket for a poll he is not entitled to, fails to request a ticket he is entitled to, or has already been signing this semester. """ try: signing_requests_dict = json.loads(request.body.decode('utf-8')) except json.decoder.JSONDecodeError: return HttpResponseBadRequest("Couldn't parse JSON") signing_requests = signing_requests_dict['signing_requests'] semester = Semester.get_current_semester() student_polls = { poll.pk for poll in Poll.get_all_polls_for_student(request.user.student, semester) } request_polls = {int(req['id']) for req in signing_requests} if request_polls - student_polls: return HttpResponseForbidden( f"Student nie jest upoważniony do tych ankiet: {request_polls - student_polls}." ) if student_polls - request_polls: return HttpResponseForbidden( f"Student powinien również wygenerować bilety dla tych " "ankiet: {student_polls - request_polls}.") if len(request_polls) != len(signing_requests): return HttpResponseForbidden( f"Próbowano podpisać wiele biletów do jednej ankiety.") # Now we made sure that student_polls == request_polls # We obtain a lock on RSA keys. keys = RSAKeys.objects.filter(poll__in=request_polls).select_for_update() keys_by_poll = {key.poll_id: key for key in keys} _, created = StudentGraded.objects.get_or_create( student=request.user.student, semester=semester) if not created: return HttpResponseForbidden( f"Student już podpisywał bilety w tym semestrze.") response = [] for signing_request in signing_requests: key = keys_by_poll[int(signing_request['id'])] signed_ticket = key.sign_ticket(signing_request['ticket']) signing_response = { 'id': signing_request['id'], 'signature': str(signed_ticket), } response.append(signing_response) return JsonResponse(response, safe=False)
def get_grouped_polls(student: Student) -> Dict: """Groups polls into a format used by the grade/ticket_create app.""" polls = Poll.get_all_polls_for_student(student) return group_submissions(polls)
def handle(self, *args, **kwargs): semester_id = kwargs["semester"] created, skipped = 0, 0 if semester_id: semester = Semester.objects.get(id=semester_id) else: semester = Semester.get_current_semester() self.stdout.write(f"Selected semester: `{semester}` with id {semester.id}") # Check whether poll exists for a selected semester self.stdout.write(f"\n{HEADER}Semester polls") semester_poll = Poll.objects.filter(semester=semester).count() > 0 if semester_poll: self.stdout.write(f"{MARGIN}Poll for a selected semester already exists") skipped += 1 else: new_poll = Poll(group=None, course=None, semester=semester) new_poll.save() self.stdout.write( f"{CREATED}Poll for a selected semester does not exist, creating" ) created += 1 # Check whether poll exists for courses held in a selected semester self.stdout.write(f"\n{HEADER}Course/group polls") courses = CourseInstance.objects.filter(semester=semester) for course in courses: course_poll = Poll.objects.filter(course=course).count() > 0 if not course.has_exam or course_poll: self.stdout.write(f"{MARGIN}{course}") skipped += 1 else: new_poll = Poll(group=None, course=course, semester=None) new_poll.save() self.stdout.write(f"{CREATED}{course}") created += 1 groups = Group.objects.filter(course=course) for group in groups: group_poll = Poll.objects.filter(group=group).count() > 0 if group_poll: self.stdout.write(f"{MARGIN}{MARGIN}{group}") skipped += 1 else: new_poll = Poll(group=group, course=None, semester=None) new_poll.save() self.stdout.write(f"{CREATED}{MARGIN}{group}") created += 1 self.stdout.write(f"\n{HEADER}Summary") self.stdout.write(f"{MARGIN}Created: {created}, skipped: {skipped}")
def get(self, request, semester_id=None, poll_id=None, submission_id=None): """Controls the main logic of passing the data to the template responsible for presenting the results of the poll. :param semester_id: if given, fetches polls from requested semester. :param poll_id: if given, displays summary for a given poll. :param submission_id: if given, displays detailed submission view. """ is_grade_active = check_grade_status() if semester_id is None: semester_id = Semester.get_current_semester().id current_semester = Semester.get_current_semester() selected_semester = Semester.objects.filter(pk=semester_id).get() available_polls = Poll.get_all_polls_for_semester( user=request.user, semester=selected_semester) current_poll = Poll.objects.filter(id=poll_id).first() if poll_id is not None: submissions = Submission.objects.filter( poll=poll_id, submitted=True).order_by('modified') if current_poll not in available_polls: # User does not have permission to view details about # the selected poll messages.error( request, "Nie masz uprawnień do wyświetlenia tej ankiety.") return redirect('grade-poll-results', semester_id=semester_id) else: submissions = [] semesters = Semester.objects.all() if request.user.is_superuser or request.user.employee: return render( request, self.template_name, { 'is_grade_active': is_grade_active, 'polls': group(entries=available_polls, sort=True), 'results': self.__get_processed_results(submissions), 'results_iterator': itertools.count(), 'semesters': semesters, 'current_semester': current_semester, 'current_poll_id': poll_id, 'current_poll': current_poll, 'selected_semester': selected_semester, 'submissions_count': self.__get_counter_for_categories(available_polls), 'iterator': itertools.count(), }, ) messages.error(request, "Nie masz uprawnień do wyświetlania wyników oceny.") return redirect('grade-main')
def make_poll(request, template, group=None, origin=None): """Prepares a poll object for the group based on the template. Raises: Employee.DoesNotExist: If the user in the request is not an employee. """ poll = Poll() poll.author = request.user.employee poll.title = template['title'] poll.description = template['description'] poll.semester = template['semester'] poll.group = group poll.studies_type = template['studies_type'] poll.origin = origin poll.save() make_section_for_poll(request, poll, template) return poll