예제 #1
0
 def filter_only_mine(self: QuerySet, user: User):
     if BaseUser.is_student(user):
         return self.filter(students__in=[user.student])
     elif BaseUser.is_employee(user):
         return self.filter(Q(advisor=user.employee) | Q(supporting_advisor=user.employee))
     # this is an error situation, one of the conditions above should have caught it
     return self
예제 #2
0
def all_news(request):
    """
        Latest news, result of query search or given page with focused news
    """
    if BaseUser.is_student(request.user):
        student = request.user.student
        student.last_news_view = datetime.datetime.now()
        student.save()

    elif BaseUser.is_employee(request.user):
        employee = request.user.employee
        employee.last_news_view = datetime.datetime.now()
        employee.save()

    query = request.GET.get('q')
    if query:
        query = query.strip()
        items = News.objects.get_published().filter(
            Q(title__icontains=query) | Q(body__icontains=query))
    else:
        items = News.objects.exclude(category='-')

    paginator = Paginator(items, settings.NEWS_PER_PAGE)
    page = request.GET.get('page')
    try:
        news = paginator.page(page)
    except (PageNotAnInteger, EmptyPage):
        news = paginator.page(1)

    data = {'items': news, 'page_range': paginator.page_range, 'query': query}

    return render(request, 'news/list_all.html', data)
def roles(request):
    """Merge user's group membership info into template context."""
    return {
        'is_employee': BaseUser.is_employee(request.user),
        'is_external_contractor':
        BaseUser.is_external_contractor(request.user),
        'is_student': BaseUser.is_student(request.user),
    }
예제 #4
0
def can_user_view_students_list_for_group(user: BaseUser,
                                          group: Group) -> bool:
    """Tell whether the user is authorized to see students' names
    and surnames in the given group.
    """
    is_user_proper_employee = (BaseUser.is_employee(user)
                               and not BaseUser.is_external_contractor(user))
    is_user_group_teacher = user == group.teacher.user
    return is_user_proper_employee or is_user_group_teacher
예제 #5
0
def create_ical_file(request: HttpRequest) -> HttpResponse:
    user = request.user
    semester = Semester.get_default_semester()

    cal = iCalendar()
    cal.add('x-wr-timezone').value = 'Europe/Warsaw'
    cal.add('version').value = '2.0'
    cal.add('prodid').value = 'Fereol'
    cal.add('calscale').value = 'GREGORIAN'
    cal.add('calname').value = "{} - schedule".format(user.get_full_name())
    cal.add('method').value = 'PUBLISH'

    if BaseUser.is_student(user):
        student = user.student
        records = Record.objects.filter(
            student_id=student.pk,
            group__course__semester_id=semester.pk,
            status=RecordStatus.ENROLLED).select_related(
                'group', 'group__course')
        groups = [r.group for r in records]
    elif BaseUser.is_employee(user):
        groups = list(
            Group.objects.filter(course__semester=semester,
                                 teacher=user.employee))
    else:
        raise InvalidUserException()
    for group in groups:
        course_name = group.course.name
        group_type = group.human_readable_type().lower()
        try:
            terms = group.get_all_terms_for_export()
        except IndexError:
            continue
        for term in terms:
            start_datetime = datetime.datetime.combine(term.day, term.start)
            start_datetime += BREAK_DURATION
            end_datetime = datetime.datetime.combine(term.day, term.end)
            event = cal.add('vevent')
            event.add('summary').value = "{} - {}".format(
                course_name, group_type)
            if term.room:
                event.add('location').value = 'sala ' + term.room.number \
                    + ', Instytut Informatyki Uniwersytetu Wrocławskiego'

            event.add('description').value = 'prowadzący: ' \
                + group.get_teacher_full_name()
            event.add('dtstart').value = start_datetime
            event.add('dtend').value = end_datetime

    cal_str = cal.serialize()
    response = HttpResponse(cal_str, content_type='application/calendar')
    ical_file_name = get_ical_filename(user, semester)
    response['Content-Disposition'] = "attachment; filename={}".format(
        ical_file_name)
    return response
예제 #6
0
def get_theses_user_full_name(user: BaseUser):
    """Returns the full name of the user for use by the theses system.

    If the user is an Employee, `get_full_name_with_academic_title` will be used;
    otherwise, `get_full_name` will be used.

    Accepts a BaseUser instance because this is only called by the person serializer,
    and doing it this way is faster (no need to look up the employee/student instance
    via FK)
    """
    if isinstance(user, Employee):
        return user.get_full_name_with_academic_title()
    return user.get_full_name()
예제 #7
0
def is_theses_regular_employee(user: User):
    """Is the specified user a regular university employee?

    Those have permissions to create theses and can be set as advisors,
    but otherwise have no administrative privileges
    """
    return BaseUser.is_employee(user) and not user.is_staff
예제 #8
0
def can_set_advisor(user: User, advisor: Optional[Employee]) -> bool:
    """Is the specified user permitted to set the given advisor (may be None)?

    Only called if the user is permitted to modify the thesis in general
    (that is, `can_modify_thesis` returns True)
    """
    return is_thesis_staff(user) or (BaseUser.is_employee(user) and user.employee == advisor)
예제 #9
0
def dispatch_notifications_task(user):
    """Dispatch all pending notifications for the given user by email.

    We batch all the e-mails for the user together and send them using one SMTP
    connection. We also wait for THROTTLE_SECONDS until we let the next task in
    the work queue to send emails. This rate limiting is introduced for Gmail to
    accept our queries.
    """
    if BaseUser.is_employee(user):
        model, created = NotificationPreferencesTeacher.objects.get_or_create(user=user)
    elif BaseUser.is_student(user):
        model, created = NotificationPreferencesStudent.objects.get_or_create(user=user)
    else:
        return

    repo = get_notifications_repository()
    pending_notifications = repo.get_unsent_for_user(user)
    if not pending_notifications:
        return

    messages = []
    for pn in pending_notifications:
        # User controls in account settings
        # what notifications will be send
        if not getattr(model, pn.description_id, None):
            continue

        ctx = {
            'content': render_description(
                pn.description_id, pn.description_args),
            'greeting': f'Dzień dobry, {user.first_name}',
        }

        message_contents = render_to_string('notifications/email_base.html', ctx)
        messages.append((
            'Wiadomość od Systemu Zapisów IIUWr',
            strip_tags(message_contents),
            settings.MASS_MAIL_FROM,
            [user.email],
        ))
    send_mass_mail(messages, fail_silently=False)

    # Only mark the notifications as sent if the e-mails went out successfully.
    for pn in pending_notifications:
        repo.mark_as_sent(user, pn)

    time.sleep(settings.EMAIL_THROTTLE_SECONDS)
예제 #10
0
    def common_groups(cls, user: User, groups: List[Group]) -> Set[int]:
        """Returns ids of those of groups that user is involved in.

        User may be an employee — we then return groups he is teaching. If user
        is a student, we return those of the groups, he is enrolled into. If
        user is neither a student nor an employee, an empty set is returned.
        """
        common_groups = set()
        if BaseUser.is_student(user):
            student_records = Record.objects.filter(
                group__in=groups, student=user.student, status=RecordStatus.ENROLLED)
            common_groups = {r.group_id for r in student_records}
        if BaseUser.is_employee(user):
            common_groups = set(
                Group.objects.filter(pk__in=[g.pk for g in groups],
                                     teacher=user.employee).values_list('pk', flat=True))
        return common_groups
예제 #11
0
def student_profile(request: HttpRequest, user_id: int) -> HttpResponse:
    """student profile"""
    try:
        student: Student = Student.objects.select_related(
            'user', 'consent').get(user_id=user_id)
    except Student.DoesNotExist:
        raise Http404

    # We will not show the student profile if he decides to hide it.
    if not BaseUser.is_employee(
            request.user) and not student.consent_granted():
        return HttpResponseRedirect(reverse('students-list'))

    semester = Semester.objects.get_next()

    records = Record.objects.filter(
        student=student,
        group__course__semester=semester,
        status=RecordStatus.ENROLLED).select_related(
            'group__teacher', 'group__teacher__user',
            'group__course').prefetch_related('group__term',
                                              'group__term__classrooms')
    groups = [r.group for r in records]

    # Highlight groups shared with the viewer in green.
    viewer_groups = Record.common_groups(request.user, groups)
    for g in groups:
        g.is_enrolled = g.pk in viewer_groups

    group_dicts = build_group_list(groups)
    data = {
        'student': student,
        'groups_json': json.dumps(group_dicts, cls=DjangoJSONEncoder),
    }

    if request.is_ajax():
        return render(request, 'users/student_profile_contents.html', data)

    active_students = Student.get_list(
        begin='All',
        restrict_list_consent=not BaseUser.is_employee(request.user))
    data.update({
        'students': active_students,
        'char': "All",
    })
    return render(request, 'users/student_profile.html', data)
예제 #12
0
    def __init__(self, user, data=None, **kwargs):

        if data:
            data = deepcopy(data)
            if 'type' not in data:
                data['type'] = Event.TYPE_GENERIC

        super(EventForm, self).__init__(data, **kwargs)
        if not self.instance.pk:
            self.instance.author = user
        if BaseUser.is_employee(user):
            self.fields['type'].choices = Event.TYPES_FOR_TEACHER
        else:
            self.fields['type'].choices = Event.TYPES_FOR_STUDENT

        if not BaseUser.is_employee(user):
            self.fields['course'].queryset = CourseInstance.objects.none()
        else:
            semester = Semester.get_current_semester()

            previous_semester = Semester.get_semester(datetime.now().date() -
                                                      timedelta(days=30))

            queryset = CourseInstance.objects.filter(semester__in=[semester, previous_semester]). \
                select_related('semester'). \
                order_by('semester')

            if not user.has_perm('schedule.manage_events'):
                queryset = CourseInstance.objects.filter(
                    groups__type='1',
                    groups__teacher=user.employee,
                    semester__in=[semester, previous_semester])

            self.fields['course'].queryset = queryset

        self.fields['title'].widget.attrs.update({'class': 'form-control'})
        self.fields['type'].widget.attrs.update({'class': 'form-control'})
        self.fields['course'].widget.attrs.update({'class': 'form-control'})
        self.fields['description'].widget.attrs.update(
            {'class': 'form-control'})
        self.fields['visible'].widget.attrs.update({
            'checked':
            '',
            'class':
            'custom-control-input'
        })
예제 #13
0
 def filter_by_user(self: QuerySet, user: User):
     """Filter the queryset based on special logic depending
     on the type of the user
     """
     # Students should not see theses that are not "ready" yet
     if BaseUser.is_student(user):
         return self.exclude(status__in=NOT_READY_STATUSES)
     return self
예제 #14
0
def course_view_data(request,
                     slug) -> Tuple[Optional[CourseInstance], Optional[Dict]]:
    """Retrieves course and relevant data for the request.

    If course does not exist it returns two None objects.
    """
    course: CourseInstance = None
    try:
        course = CourseInstance.objects.filter(slug=slug).select_related(
            'semester', 'course_type').prefetch_related('tags',
                                                        'effects').get()
    except CourseInstance.DoesNotExist:
        return None, None

    student: Student = None
    if request.user.is_authenticated and BaseUser.is_student(request.user):
        student = request.user.student

    groups = course.groups.exclude(extra='hidden').select_related(
        'teacher',
        'teacher__user',
    ).prefetch_related('term', 'term__classrooms', 'guaranteed_spots',
                       'guaranteed_spots__role')

    # Collect the general groups statistics.
    groups_stats = Record.groups_stats(groups)
    # Collect groups information related to the student.
    student_status_groups = Record.is_recorded_in_groups(student, groups)
    student_can_enqueue = Record.can_enqueue_groups(student,
                                                    course.groups.all())
    student_can_dequeue = Record.can_dequeue_groups(student,
                                                    course.groups.all())

    for group in groups:
        group.num_enrolled = groups_stats.get(group.pk).get('num_enrolled')
        group.num_enqueued = groups_stats.get(group.pk).get('num_enqueued')
        group.is_enrolled = student_status_groups.get(group.pk).get('enrolled')
        group.is_enqueued = student_status_groups.get(group.pk).get('enqueued')
        group.priority = student_status_groups.get(group.pk).get('priority')
        group.can_enqueue = student_can_enqueue.get(group.pk)
        group.can_dequeue = student_can_dequeue.get(group.pk)

    teachers = {g.teacher for g in groups}

    course.is_enrollment_on = any(g.can_enqueue for g in groups)

    data = {
        'course':
        course,
        'teachers':
        teachers,
        'groups':
        groups,
        'grouped_waiting_students':
        get_grouped_waiting_students(course, request.user)
    }
    return course, data
예제 #15
0
 def _serialize_user_type(user: User):
     if is_theses_admin(user):
         return ThesisUserType.ADMIN
     elif is_theses_regular_employee(user):
         return ThesisUserType.REGULAR_EMPLOYEE
     elif BaseUser.is_student(user):
         return ThesisUserType.STUDENT
     # We're generally not expecting this to happen
     return ThesisUserType.NONE
예제 #16
0
    def get_queryset(self):
        from apps.enrollment.courses.models.group import Group

        query = []

        if BaseUser.is_student(self.request.user):
            query.append(Q(record__student=self.request.user.student) & Q(record__status='1'))

        if BaseUser.is_employee(self.request.user):
            query.append(Q(teacher=self.request.user.employee))

        queryset = super(MyScheduleAjaxView, self).get_queryset()
        groups = Group.objects.filter(reduce(operator.or_, query))

        return queryset.filter(Q(event__group__in=groups) |
                               Q(event__interested=self.request.user) |
                               Q(event__author=self.request.user)).select_related('event', 'event__group',
                                                                                  'event__group__teacher')
예제 #17
0
 def _test_current_user_for_user(self, user: BaseUser,
                                 expected_type: ThesisUserType):
     self.login_as(user)
     response = self.client.get(reverse("theses:current_user"))
     self.assertEqual(response.status_code, status.HTTP_200_OK)
     data = response.data
     self.assertEqual(data["type"], expected_type.value)
     self.assertEqual(data["person"]["id"], user.pk)
     self.assertEqual(data["person"]["name"], user.get_full_name())
예제 #18
0
 def get_serializer_context(self):
     """When serializing votes for a thesis, we need to know the user type
     determining it for every thesis would be expensive as it requires
     a DB hit, so it's a good idea to do it here and pass it to the serializer
     """
     result = super().get_serializer_context()
     user = self.request.user
     result["user"] = user
     result["is_staff"] = is_thesis_staff(user)
     result["is_employee"] = BaseUser.is_employee(user)
     return result
예제 #19
0
def create_form(request):
    """It is not a view itself, just factory for preferences and preferences_save"""
    if BaseUser.is_employee(request.user):
        instance, created = NotificationPreferencesTeacher.objects.get_or_create(
            user=request.user)
        if request.method == 'POST':
            return PreferencesFormTeacher(request.POST, instance=instance)
        return PreferencesFormTeacher(instance=instance)

    instance, created = NotificationPreferencesStudent.objects.get_or_create(
        user=request.user)
    if request.method == 'POST':
        return PreferencesFormStudent(request.POST, instance=instance)
    return PreferencesFormStudent(instance=instance)
예제 #20
0
def students_list(request: HttpRequest,
                  begin: str = 'All',
                  query: Optional[str] = None) -> HttpResponse:
    students = Student.get_list(begin, not BaseUser.is_employee(request.user))

    if request.is_ajax():
        students = prepare_ajax_students_list(students)
        return AjaxSuccessMessage(message="ok", data=students)
    else:
        data = {
            "students": students,
            "char": begin,
            "query": query,
            'mailto_group': mailto(request.user, students),
            'mailto_group_bcc': mailto(request.user, students, True)
        }
        return render(request, 'users/students_list.html', data)
예제 #21
0
def external_contractor_forbidden(view_func=None,
                                  redirect_field_name=REDIRECT_FIELD_NAME,
                                  login_url=None):
    """
    Check whether the logged user is either a student or an actual employee
    (i.e. not external contractor).
    Redirect to the login page if that's not the case.
    """

    decorator = user_passes_test(
        lambda u: not BaseUser.is_external_contractor(u),
        login_url=login_url,
        redirect_field_name=redirect_field_name)

    if view_func:
        return decorator(view_func)

    return decorator
예제 #22
0
def change_user_password(
    *,
    user: BaseUser,
    old_password: str,
    new_password: str
) -> BaseUser:

    if not user.is_active:
        raise ValidationError('User account is disabled.')

    if not user.check_password(old_password):
        raise ValidationError('Old password is invalid.')

    validate_password(new_password)
    user.set_password(new_password)
    user.rotate_secret_key()

    user.save()

    return user
예제 #23
0
def is_owner_of_thesis(user: User, thesis: Thesis) -> bool:
    """Is the specified user the advisor of the specified thesis?"""
    return BaseUser.is_employee(user) and thesis.advisor == user.employee
예제 #24
0
def client_connection(request):
    if request.method == 'POST':

        form = ContactForm(request.POST)

        if form.is_valid():
            idUser = form.cleaned_data['idUser']
            passwordUser = form.cleaned_data['passwordUser']
            groupNumber = form.cleaned_data['groupNumber']
            groupKey = int(form.cleaned_data['groupKey'])

            user = authenticate(username=idUser, password=passwordUser)

            if user is None:
                return HttpResponse("nie ma takiego użytkownika")
            if BaseUser.is_student(user):
                return HttpResponse("użytkownik nie jest studentem")

            if groupNumber == "*":
                st = ""
                students_polls = Poll.get_all_polls_for_student(user.student)

                if students_polls:
                    semester = students_polls[0].semester
                    StudentGraded.objects.get_or_create(student=user.student,
                                                        semester=semester)
                groupped_polls = group_polls_by_course(students_polls)
                for polls in groupped_polls:

                    if len(polls) == 1:

                        st += str(polls[0].pk) + '***'
                        st += '[' + str(polls[0].title) + ']%%%'

                        if polls[0].group:
                            st += str(polls[0].group.course.name) + '%%%'
                            st += str(
                                polls[0].group.get_type_display()) + ': %%%'
                            st += str(
                                polls[0].group.get_teacher_full_name()) + '%%%'

                        st += str('***')

                        st += str(
                            PublicKey.objects.get(
                                poll=polls[0].pk).public_key) + '???'

                    else:
                        for poll in polls:
                            st += str(poll.pk) + '***'
                            if not poll.group:
                                st += 'Ankiety ogólne: %%%   [' + poll.title + '] '
                            else:
                                st += 'Przedmiot: ' + polls[0].group.course.name + '%%%    [' + poll.title + '] ' + \
                                      poll.group.get_type_display() + ': ' + poll.group.get_teacher_full_name() + '***'
                                st += str(
                                    PublicKey.objects.get(
                                        poll=poll.pk).public_key) + '&&&'
                        st += '???'

                return HttpResponse(st)

            students_polls = Poll.get_all_polls_for_student(user.student)

            st = ""

            for students_poll in students_polls:
                if int(students_poll.pk) == int(groupNumber):
                    st = secure_signer_without_save(user, students_poll,
                                                    groupKey)
                    secure_signer(user, students_poll, groupKey)
                    p = students_poll
                    break
            if st == "":
                st = "Nie jesteś zapisany do tej ankiety"

            try:
                a = int(st[0][0])
            except ValueError as err:
                return HttpResponse(st)
            if st == "Nie jesteś zapisany do tej ankiety":
                return HttpResponse(st)
            elif st == "Bilet już pobrano":
                return HttpResponse(st)
            else:
                return HttpResponse(
                    to_plaintext([(p, '***', '%%%')]) + '???' + str(a))
예제 #25
0
def my_profile(request):
    """User profile page.

    The profile page displays user settings (e-mail address, notifications). If
    he is a student, his opening times will be displayed. If the user is an
    employee, the page allows him to modify his public information (office,
    consultations).
    """
    semester = Semester.objects.get_next()

    data = {
        'semester': semester,
    }

    if BaseUser.is_employee(request.user):
        data.update({
            'consultations': request.user.employee.consultations,
            'room': request.user.employee.room,
            'homepage': request.user.employee.homepage,
            'title': request.user.employee.title,
        })

    if semester and BaseUser.is_student(request.user):
        student: Student = request.user.student
        groups_opening_times = GroupOpeningTimes.objects.filter(
            student_id=student.pk,
            group__course__semester_id=semester.pk).select_related(
                'group', 'group__course', 'group__teacher',
                'group__teacher__user').prefetch_related(
                    'group__term', 'group__term__classrooms')
        groups_times = []
        got: GroupOpeningTimes
        for got in groups_opening_times:
            group: Group = got.group
            group.opening_time = got.time
            groups_times.append(group)
        t0_time_obj = T0Times.objects.filter(student_id=student.pk,
                                             semester_id=semester.pk)
        try:
            t0_time = t0_time_obj.get().time
        except T0Times.DoesNotExist:
            t0_time = None
        grade_info = StudentGraded.objects.filter(
            student=student).select_related('semester').order_by(
                '-semester__records_opening')
        semesters_participated_in_grade = [x.semester for x in grade_info]
        current_semester_ects = Record.student_points_in_semester(
            student, semester)
        data.update({
            't0_time': t0_time,
            'groups_times': groups_times,
            'semesters_participated_in_grade': semesters_participated_in_grade,
            'current_semester_ects': current_semester_ects,
        })

    notifications_form = create_form(request)
    data.update({
        'form': notifications_form,
    })

    return render(request, 'users/my_profile.html', data)
예제 #26
0
def logout(*, user: BaseUser) -> BaseUser:
    user.rotate_secret_key()

    return user
예제 #27
0
 def _to_base_person(user: User):
     if BaseUser.is_employee(user):
         return user.employee
     elif BaseUser.is_student(user):
         return user.student
     raise exceptions.NotFound()