Пример #1
0
def list_second_choice(request):
    """
    list all students with a random distribution, without project and all non-full projects

    :param request:
    :return:
    """

    props = get_all_proposals().filter(
        Status=4, Private__isnull=True).distinct().annotate(
            num_distr=Count('distributions')).filter(
                TimeSlot=get_timeslot(),
                num_distr__lt=F('NumStudentsMax')).order_by('Title')
    prop_obj = [[prop, get_share_link(prop.pk)] for prop in props]
    no_dist = get_all_students(undistributed=True).filter(
        distributions__isnull=True, applications__isnull=False).distinct()
    # filter students in this year with only applications in other year
    no_dist = [
        s for s in no_dist
        if s.applications.filter(Proposal__TimeSlot=get_timeslot()).exists()
    ]

    return render(
        request, 'distributions/list_second_choice.html', {
            'distributions':
            Distribution.objects.filter(
                TimeSlot=get_timeslot(),
                Application__isnull=True,
                Proposal__Private__isnull=True).order_by('Student'),
            'no_dist':
            no_dist,
            'proposals':
            prop_obj,
        })
Пример #2
0
def finalize_preview(request, pk, step=0):
    """
    Edit grade for a category as indexed by step. For each student as given by pk.
    Also edit the individual aspects of each grade category. For trackheads and responsible staff

    :param request:
    :param pk: id of distribution
    :param step: number of step in the menu, index of category
    :return:
    """
    ts = get_timeslot()
    if not hasattr(ts, 'resultoptions'):
        raise PermissionDenied("Results menu is not yet visible.")
    else:
        if not get_timeslot().resultoptions.Visible:
            raise PermissionDenied("Results menu is not yet visible.")
    dstr = get_object_or_404(Distribution, pk=pk)
    if not hasattr(dstr, 'presentationtimeslot'):
        raise PermissionDenied('This student does not have a presentation planned. Please plan it first.')

    if not request.user.is_superuser and \
            request.user != dstr.Proposal.Track.Head and \
            request.user != dstr.Proposal.ResponsibleStaff and \
            get_grouptype('3') not in request.user.groups.all() and \
            request.user not in dstr.presentationtimeslot.Presentations.Assessors.all():
        raise PermissionDenied("You do not have the correct permissions to view print preview.")
    return render(request, "results/finalize_grades.html", {
        "dstr": dstr,
        "catresults": dstr.results.all(),
        "final": all(f.Final is True for f in dstr.results.all()) if dstr.results.all() else False,
        "finalgrade": dstr.TotalGradeRounded(),
        "preview": True,
    })
Пример #3
0
def manual(request):
    """
    Support page to distribute students manually to projects. Uses ajax calls to change distributions.
    Same table included as in list appls/dists

    :param request:
    """
    if get_timephase_number() < 4 or get_timephase_number() > 6:
        raise PermissionDenied(
            'Distribution is not possible in this timephase')

    props = get_all_proposals().filter(Q(Status__exact=4)) \
        .select_related('ResponsibleStaff__usermeta', 'Track', 'TimeSlot') \
        .prefetch_related('Assistants__usermeta', 'Private__usermeta', 'applications__Student__usermeta',
                          'distributions__Student__usermeta')
    # includes students without applications.
    # also show undistributed in phase 6
    studs = get_all_students(undistributed=True).exclude(distributions__TimeSlot=get_timeslot()) \
        .select_related('usermeta') \
        .prefetch_related('applications__Proposal').distinct()
    dists = Distribution.objects.filter(TimeSlot=get_timeslot()) \
        .select_related('Student__usermeta', 'Proposal', 'Application__Student__usermeta')
    return render(
        request, 'distributions/manual_distribute.html', {
            'proposals': props,
            'undistributedStudents': studs,
            'distributions': dists,
            'hide_sidebar': True
        })
Пример #4
0
def copy(request, pk=None):
    """
    Show a list of timeslots to import grades from.

    :param request:
    :param pk:
    :return:
    """
    # do a copy
    if pk:
        ts = get_object_or_404(TimeSlot, pk=pk)
        if ts == get_timeslot():
            raise PermissionDenied(
                "It is not possible to copy the grades from the current timeslot."
            )
        if get_timeslot().gradecategories.exists():
            return render(
                request, 'base.html', {
                    'Message':
                    "The current timeslot already has grade categories."
                    " Importing is not possible. "
                    "Please remove the categories in the current timeslot before copying.",
                    'return':
                    'results:list_categories'
                })

        if request.method == 'POST':
            form = ConfirmForm(request.POST)
            if form.is_valid():
                for cat in ts.gradecategories.all():
                    old_id = cat.id
                    old_aspects = cat.aspects.all()
                    cat.id = None
                    cat.TimeSlot = get_timeslot()
                    cat.save()
                    for aspect in old_aspects:
                        aspect.id = None
                        aspect.Category = cat
                        aspect.save()

                return render(
                    request, 'base.html', {
                        'Message': 'Finished importing!',
                        'return': 'results:list_categories'
                    })
        else:
            form = ConfirmForm()
        return render(
            request, 'GenericForm.html', {
                'form': form,
                'formtitle': 'Confirm copy grade categories and aspects',
                'buttontext': 'Confirm'
            })
    # list possible timeslots to copy from
    else:
        tss = TimeSlot.objects.filter(gradecategories__isnull=False).distinct()
        return render(request, "results/list_copy.html", {
            "tss": tss,
            'ts': get_timeslot(),
        })
Пример #5
0
def get_distributions(user, timeslot=None):
    """
    Function to return the distributions that a given staff user is allowed to see
    Type3 and 6 should see all distributions, to be able to mail them.

    :param user: The user to test
    :param timeslot: TimeSlot to get distributions from
    :return empty queryset on fail
    """
    if get_grouptype('2u') in user.groups.all():
        return Distribution.objects.none()
    if timeslot is None:
        timeslot = get_timeslot()
        if timeslot is None:
            return Distribution.objects.none(
            )  # similar to None, but can be used in chained filter.
    des_all = Distribution.objects.filter(TimeSlot=timeslot)
    if get_grouptype("3") in user.groups.all(
    ) or user.is_superuser or get_grouptype("6") in user.groups.all():
        return des_all
    else:
        tracks = Track.objects.filter(Head=user)
        if planning_public() and timeslot == get_timeslot():
            return des_all.filter(
                Q(Proposal__Track__in=tracks)
                | Q(Proposal__ResponsibleStaff=user)
                | Q(Proposal__Assistants__id=user.id)
                | Q(presentationtimeslot__Presentations__Assessors__id=user.id)
            ).distinct()
        else:
            return des_all.filter(
                Q(Proposal__Track__in=tracks)
                | Q(Proposal__ResponsibleStaff=user)
                | Q(Proposal__Assistants__id=user.id)).distinct()
Пример #6
0
    def wrapper(*args, **kw):
        if 'pk' in kw:
            pk = int(kw['pk'])
        else:
            pk = int(args[1])
        proj = get_cached_project(pk)
        request = args[0]

        # user needs to be logged in (so no need for login_required on top of this)
        if not request.user.is_authenticated:
            page = args[0].path
            return redirect_to_login(
                next=page,
                login_url='index:login',
                redirect_field_name='next',
            )

        # support staf or superusers are always allowed to view
        if get_grouptype(
                "3") in request.user.groups.all() or request.user.is_superuser:
            return fn(*args, **kw)

        # user is staffmember and involved in the project
        if proj.ResponsibleStaff == request.user \
                or request.user in proj.Assistants.all() \
                or proj.Track.Head == request.user:
            return fn(*args, **kw)

        # group administrators can view proposal
        if group_administrator_status(proj, request.user) > 0:
            return fn(*args, **kw)

        # if project is published, non private and its the right time phase
        if proj.Status == 4:
            if not proj.Private.exists() or request.user in proj.Private.all(
            ):  # only non-private proposals
                # else staff members are allowed to view public proposals in all timeslots and timephases
                # this includes assessors as they are type1 or type2.
                if request.user.groups.exists():
                    return fn(*args, **kw)
                # students view public proposals or private student views his proposal: Only in timephase after 2
                elif get_timephase_number(
                ) > 2 and proj.TimeSlot == get_timeslot():
                    return fn(*args, **kw)
            # assessors are allowed to view status4 private projects if they have to assess it.
            elif planning_public() and \
                    proj.Private.exists() and \
                    request.user.groups.exists() and \
                    proj.TimeSlot == get_timeslot():
                for dist in proj.distributions.all():
                    try:
                        if request.user in dist.presentationtimeslot.Presentations.Assessors.all(
                        ):
                            return fn(*args, **kw)
                    except PresentationTimeSlot.DoesNotExist:
                        continue
        raise PermissionDenied(
            "You are not allowed to view this project page.")
Пример #7
0
def lti(request):
    if not get_timeslot():
        return HttpResponse(
            'Login is not available. The system is currently closed.',
            status=403)
    config = getattr(settings, 'PYLTI_CONFIG', dict())
    consumers = config.get('consumers', dict())
    params = dict(request.POST.items())
    headers = request.META
    headers['X-Forwarded-Proto'] = headers['HTTP_X_FORWARDED_PROTO']
    try:
        verify_request_common(consumers, request.build_absolute_uri(),
                              request.method, headers, params)
    except LTIException as e:
        logger.error('LTI exception from canvas; {}'.format(e))
        return HttpResponse("Signature Validation failed!", status=403)

    data = request.POST
    try:
        username = data['lis_person_sourcedid']
        email = data['lis_person_contact_email_primary']
        studentnumber = data['custom_canvas_user_login_id']
        coursecode = data['context_label']
    except KeyError as e:
        logger.error('Invalid post data from canvas; {}; {}'.format(data, e))
        return HttpResponse("Missing data in POST", status=400)

    user = get_user(email, username)
    if user is None:
        user = User(email=email, username=username)
        user.save()
    try:
        meta = user.usermeta
    except UserMeta.DoesNotExist:
        meta = UserMeta(User=user)

    meta.Studentnumber = studentnumber
    if not meta.Overruled:
        if settings.COURSE_CODE_BEP in coursecode:
            meta.EnrolledBEP = True
        elif settings.COURSE_CODE_EXT in coursecode:
            meta.EnrolledBEP = True
            meta.EnrolledExt = True
        else:
            logger.warning(
                'Course code not matched on BEP or EXT for user {}. Code was: {}'
                .format(user, coursecode))

    meta.save()
    meta.TimeSlot.add(get_timeslot())
    meta.save()
    user.save()

    log = CanvasLogin()
    log.Subject = user
    log.save()

    return redirect("{}/login/".format(settings.DOMAIN))
def get_all_students(undistributed=False):
    """
    Return all active students in marketplace, used for instance for mailing.

    :param undistributed: Also return undistributed students in phase 6 and later.
    :return: user objects
    """
    users = User.objects.filter(
        Q(usermeta__EnrolledBEP=True) & Q(groups=None)
        & Q(usermeta__TimeSlot=get_timeslot())).distinct()
    if get_timephase_number() < 6 or undistributed:
        return users
    else:
        # only students with a distributions
        return users.filter(Q(distributions__TimeSlot=get_timeslot()))
Пример #9
0
 def save(self, commit=True):
     if commit:
         self.instance.TimeSlot = get_timeslot()
         self.instance.Public = False
         super().save(commit=True)
         self.instance.save()
     return self.instance
Пример #10
0
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super().__init__(*args, **kwargs)
        self.fields['ResponsibleStaff'].queryset = get_grouptype(
            '1').user_set.all()
        self.fields['Assistants'].queryset = get_grouptype('2').user_set.all() | \
                                             get_grouptype('2u').user_set.all() | \
                                             get_grouptype('1').user_set.all()
        self.fields[
            'ResponsibleStaff'].label_from_instance = self.user_label_from_instance
        self.fields[
            'Assistants'].label_from_instance = self.user_label_from_instance
        self.fields['addAssistantsEmail'].widget.attrs[
            'placeholder'] = "Add assistant via email address"
        self.fields['Private'].queryset = User.objects.filter(groups=None)
        # no user label_from_instance for private students because privacy.
        self.fields['addPrivatesEmail'].widget.attrs[
            'placeholder'] = "Add private student via email address"

        if get_timephase_number() == 1:
            self.fields['TimeSlot'].queryset = TimeSlot.objects.filter(
                End__gt=datetime.now())
            self.fields['TimeSlot'].initial = get_timeslot()
        else:
            if self.request.user.is_superuser or get_grouptype(
                    '3') in self.request.user.groups.all():
                self.fields['TimeSlot'].queryset = TimeSlot.objects.all()
            else:
                # phase 2+, only add for future timeslot
                self.fields['TimeSlot'].queryset = TimeSlot.objects.filter(
                    Begin__gt=datetime.now())
Пример #11
0
    def setUp(self):
        self.app = 'professionalskills'
        super().setUp()

        # create a filetype for testing
        f = FileType(Name='testfiletype',
                     TimeSlot=get_timeslot(),
                     Deadline=datetime(year=2018, month=5, day=4))
        f.id = 100
        f.save()
        fa = StaffResponseFileAspect(
            Name='Testaspect;',
            Description='TestAspectDescription',
            File=f,
        )
        fa.id = 100
        fa.save()
        sf = StudentFile(
            Caption='TestFile',
            Distribution=self.distribution_random,
            Type=f,
        )
        sf.id = 0
        sf.save()
        g1 = StudentGroup(Number=0, PRV=f, Max=10, Start=timezone.now())
        g1.id = 0
        # g1.Members.add(self.users['t-p'])
        # g1.Members.add(self.users['r-s'])
        g1.save()
        g2 = StudentGroup(Number=1, PRV=f, Max=10, Start=timezone.now())
        g2.id = 1
        g2.save()
        g2.Members.add(self.users.get('r-s'))
        g2.Members.add(self.users.get('t-p'))
        g2.save()
Пример #12
0
def upgrade_status_api(request, pk):
    """
    API call to increase the status of a proposal.

    :param request:
    :param pk: id of proposal
    :return:
    """
    obj = get_object_or_404(Proposal, pk=pk)

    if obj.Status == 4:
        return HttpResponse("Already at final stage", status=403)

    if obj.Status == 3 and obj.nextyear():
        return HttpResponse("Cannot publish proposal for future timeslot",
                            status=403)

    elif get_timephase_number() > 2 and \
            obj.TimeSlot == get_timeslot() and \
            get_grouptype('3') not in request.user.groups.all():
        return HttpResponse(
            "Proposal frozen in this timeslot. The timephase of editing has ended.",
            status=403)

    elif request.user in obj.Assistants.all() and obj.Status >= 2:
        return HttpResponse(
            "You are an assistant and not allowed to increase status further",
            status=403)
    # Done in can_edit decorator
    # elif obj.Track.Head != request.user and obj.Status > 2 and not get_grouptype('3') in request.user.groups.all():
    #     return HttpResponse("Not allowed to publish as non track head", status=403)

    else:
        oldstatus = obj.Status
        if oldstatus == 2:
            # per default go to publish from 4, 3 is only used if it is explicitly downgraded
            newstatus = 4
        else:
            newstatus = obj.Status + 1

        obj.Status = newstatus
        obj.save()
        mail_proposal_all(request, obj)

        notification = ProposalStatusChange()
        notification.Subject = obj
        notification.Actor = request.user
        notification.StatusFrom = oldstatus
        notification.StatusTo = newstatus
        notification.save()

        if obj.Status > 3:
            for assistant in obj.Assistants.all():
                if get_grouptype("2u") in assistant.groups.all():
                    verify_assistant_fn(assistant)
        if obj.Status == 4:
            # put the object in cache if status goes from 3->4
            cache.set('proposal_{}'.format(pk), obj, None)
            cache.delete('listproposalsbodyhtml')
        return HttpResponse(getStatStr(obj.Status))
Пример #13
0
def api_undistribute(request):
    """
    AJAX call from manual distribute to undistribute

    :param request:
    :return:
    """
    if get_timephase_number() < 4 or get_timephase_number() > 5:
        # Not in phase 6, because projects already started.
        raise PermissionDenied('Undistribution is not possible in this timephase')

    if request.method == 'POST':
        try:
            student = get_all_students(undistributed=True).get(pk=request.POST['student'])
        except User.DoesNotExist:
            return JsonResponse({'type': 'warning', 'txt': warningString + ' (User cannot be found)'})
        try:
            dist = student.distributions.get(TimeSlot=get_timeslot())
        except Distribution.DoesNotExist:
            return JsonResponse({'type': 'warning', 'txt': warningString + ' (Distribution cannot be found)'})
        try:
            n = dist.delete()
            if n[0] == 1:
                return JsonResponse(
                    {'type': 'success', 'txt': 'Undistributed Student ' + dist.Student.usermeta.get_nice_name()})
            else:
                return JsonResponse({'type': 'warning', 'txt': warningString + ' (distributions not deleted)'})
        except Exception as e:
            return JsonResponse({'type': 'warning', 'txt': warningString, 'exception': str(e)})
    else:
        raise PermissionDenied('You don\'t know what you\'re doing!')
Пример #14
0
 def save(self, commit=True):
     if commit:
         self.instance.PresentationOptions = get_timeslot(
         ).presentationoptions
         super().save(commit=True)
         self.instance.save()
     return self.instance
Пример #15
0
def add_file(request):
    """
    For students to upload a file. Used for the hand in system.
    Responsibles, assistants and trackheads can then view the files of their students.
    support staff can see all student files.

    :param request:
    """
    dist = get_object_or_404(Distribution,
                             Student=request.user,
                             TimeSlot=get_timeslot())

    if request.method == 'POST':
        form = StudentFileForm(request.POST, request.FILES, request=request)
        if form.is_valid():
            file = form.save(commit=False)
            file.Distribution = dist
            file.save()
            return render(
                request, 'base.html', {
                    'Message': 'File uploaded!',
                    'return': 'professionalskills:listownfiles'
                })
    else:
        form = StudentFileForm(request=request)
    return render(request, 'GenericForm.html', {
        'form': form,
        'formtitle': 'Upload a file ',
        'buttontext': 'Save'
    })
Пример #16
0
def edit_files(request):
    """
    Edit public files. Only for supportstaff
    These files are shown on the homepage for every logged in user.

    :param request:
    """
    form_set = modelformset_factory(PublicFile,
                                    form=PublicFileForm,
                                    can_delete=True,
                                    extra=0)
    qu = PublicFile.objects.filter(TimeSlot=get_timeslot())
    formset = form_set(queryset=qu)

    if request.method == 'POST':
        formset = form_set(request.POST, request.FILES)
        if formset.is_valid():
            formset.save()
            return render(request, "base.html", {
                "Message": "File changes saved!",
                "return": "index:index"
            })
    return render(
        request, 'GenericForm.html', {
            'formset': formset,
            'formtitle': 'All public uploaded files',
            'buttontext': 'Save changes'
        })
Пример #17
0
def list_categories(request):
    """

    :param request:
    :return:
    """
    ts = get_timeslot()
    cats = GradeCategory.objects.filter(TimeSlot=ts)
    ws = cats.aggregate(Sum('Weight'))['Weight__sum']
    wsa = GradeCategoryAspect.objects.filter(Category__in=cats).count()

    if not hasattr(ts, 'resultoptions'):
        r = ResultOptions(
            TimeSlot=ts
        )
        r.save()

    r = ts.resultoptions

    if request.method == "POST":
        form = MakeVisibleForm(request.POST, instance=r)
        if form.is_valid():
            options = form.save()
            options.save()
    else:
        form = MakeVisibleForm(instance=r)

    return render(request, "results/list_categories.html", {
        "categories": GradeCategory.objects.filter(TimeSlot=ts),
        'ts': ts,
        'gsum': ws,
        'asum': wsa,
        'visible': r.Visible,
        'form': form,
    })
Пример #18
0
def list_files_of_type(request, pk):
    """
    Lists all files of one type of professional skill.

    :param request:
    :param pk: filetype to show delivered files for
    :return:
    """
    ftype = get_object_or_404(FileType, pk=pk)
    if get_grouptype('3') in request.user.groups.all() or \
            get_grouptype('6') in request.user.groups.all():
        files = StudentFile.objects.filter(Type=ftype).distinct()
    elif get_grouptype('1') in request.user.groups.all() or \
            get_grouptype('2') in request.user.groups.all():
        # type1 or type2
        dists = get_distributions(request.user, timeslot=get_timeslot())
        if not dists:
            # raise PermissionDenied('You do not have any distributed students at this moment.')
            return render(
                request,
                'base.html',
                context={
                    'Message':
                    'You do not have any distributed students at this moment.'
                })
        files = StudentFile.objects.filter(Type=ftype, Distribution__in=dists)
    # elif not request.user.groups.exists():
    #     files = StudentFile.objects.filter(Type=ftype, Distribution=request.user.distribution.get(TimeSlot=get_timeslot()))
    else:
        raise PermissionDenied('Not allowed.')
    return render(request, 'professionalskills/list_files.html', {
        'type': ftype,
        'files': files,
    })
Пример #19
0
    def clean_DateTime(self):
        ts = get_timeslot()
        Phase = ts.timephases.get(Description=7)
        data = self.cleaned_data['DateTime']
        if data == '' or data is None:
            return data

        if data.date(
        ) < ts.Begin:  # allow presentations to be planned before phase 7, but not before timeslot.
            raise forms.ValidationError(
                "The date is before the begin of this time slot. Please choose a later date"
            )
        elif data.date(
        ) > Phase.End:  # presentations cannot be planned after phase 7.
            raise forms.ValidationError(
                "The date is after the presentations time phase. Please choose an earlier date"
            )
        elif data.time() > time(hour=23):
            raise forms.ValidationError(
                "The start time is after 23:00, which is too late")
        elif data.time() < time(hour=7):
            raise forms.ValidationError(
                "The start time is before 7:00, which is too early")
        else:
            return data
Пример #20
0
def list_users(request, filter=False):
    """
    List of all active users, including upgrade/downgrade button for staff and impersonate button for admins

    :param request:
    :return:
    """
    if filter == 'all':
        users = User.objects.all()
    elif filter == 'current':
        users = User.objects.filter(
            Q(groups__isnull=False)
            | Q(usermeta__TimeSlot=get_timeslot())).distinct()
    else:  # recent
        users = User.objects.filter(
            Q(groups__isnull=False) | Q(usermeta__TimeSlot__id__in=[
                x.id for x in get_recent_timeslots()
            ]) | (Q(usermeta__TimeSlot=None)
                  & Q(last_login__isnull=False))).distinct()

    return render(
        request, "support/list_users.html", {
            "users":
            users.prefetch_related('groups', 'usermeta', 'usermeta__TimeSlot',
                                   'administratoredgroups'),
            'hide_sidebar':
            True,
        })
Пример #21
0
def exports(request, download=None):
    ts = get_timeslot()
    if ts is None:
        # timeslot already finished, get last active timeslot.
        ts = TimeSlot.objects.order_by('End').last()
    if not download:
        return render(request,
                      'proposals/exports.html',
                      context={'timeslot': ts})
    else:
        if download == 'published':
            projects = Proposal.objects.filter(TimeSlot=ts,
                                               Status=4).order_by('Title')
        elif download == 'all':
            projects = Proposal.objects.filter(TimeSlot=ts).order_by('Title')
        elif download == 'nonfull':
            projects = Proposal.objects.annotate(
                num_distr=Count('distributions')).filter(
                    TimeSlot=ts, Status=4,
                    num_distr__lt=F('NumStudentsMax')).order_by('Title')
        elif download == 'nondistributed':
            projects = Proposal.objects.filter(
                TimeSlot=ts, Status=4,
                distributions__isnull=True).order_by('Title')
        else:
            raise PermissionDenied('Invalid download.')
    file = get_list_projects_xlsx(projects)
    response = HttpResponse(content=file)
    response[
        'Content-Disposition'] = 'attachment; filename=export-proposals-.xlsx'.format(
            download)
    response[
        'Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    return response
Пример #22
0
def delete_random_distributions(request):
    """
    Delete all distributions who have had a random assigned project

    :param request:
    :return:
    """
    dists = Distribution.objects.filter(TimeSlot=get_timeslot(),
                                        Application__isnull=True,
                                        Proposal__Private__isnull=True).order_by('Student')
    if request.method == 'POST':
        form = ConfirmForm(request.POST)
        if form.is_valid():
            dists.delete()
            return render(request, 'base.html', {
                'Message': 'Distributions deleted!'
            })
    else:
        form = ConfirmForm()

    return render(request, 'distributions/delete_random_dists.html', {
        'form': form,
        'buttontext': 'Confirm',
        'formtitle': 'Confirm deletion distributions of random assigned projects',
        'distributions': dists,
    })
def get_applications(student):
    """
    Get all applications of a student in this timeslot
    :param student:
    :return:
    """
    return student.applications.filter(Proposal__TimeSlot=get_timeslot())
Пример #24
0
def get_presentation_student(user):
    """
    Displays the presentation for a student

    :param user:
    :return:
    """
    if not user.is_authenticated or user.groups.exists():
        # anonymous or not student
        return False
    ts = get_timeslot()
    try:
        options = ts.presentationoptions
    except PresentationOptions.DoesNotExist:
        return "Your presentation is not yet planned."
    if options.Public or get_timephase_number() == 7:
        # check if user has presentations
        try:
            t = PresentationTimeSlot.objects.get(Q(Distribution__Student=user) &
                                                 Q(Presentations__PresentationOptions__TimeSlot=ts))
        except (PresentationTimeSlot.DoesNotExist, PresentationTimeSlot.MultipleObjectsReturned):
            return "Your presentation is not (yet) planned."
        start = timezone.localtime(t.DateTime).strftime("%A %d %B %Y %H:%M")
        room = t.Presentations.PresentationRoom
        url = reverse('presentations:presentationscalendar')
        title = "View all presentations"
        html = '<p>Your presentation is on {} in {}</p>' \
               '<a href="{}" class ="button primary">{}</a></p>'
        st = format_html(html, start, room, url, title)
        return st
    else:
        return "Your presentation time slot will appear here when the planning becomes public."
Пример #25
0
def copy_project(request, pk):
    """
    Copy a proposal from a previous timeslot. Only for staff that is allowed to see the proposal to copy.

    :param pk: the id of proposal to copy
    :param request:
    :return:
    """

    if request.method == 'POST':
        form = ProposalFormCreate(request.POST, request=request)
        if form.is_valid():
            prop = form.save()

            mail_proposal_all(request, prop)
            if prop.Private.all():
                for std in prop.Private.all():
                    mail_proposal_private(prop, std, "A private proposal was created for you.")
            return render(request, "proposals/message_project.html", {"Message": "Proposal created!", "Proposal": prop})
    else:
        old_proposal = get_object_or_404(Proposal, pk=pk)
        oldpk = old_proposal.pk
        old_proposal.pk = None
        # default timeslot. Overridden by form if this is not in phase 1.
        old_proposal.TimeSlot = get_timeslot()
        # Assistants and privates are removed, because m2m is not copied in this way.
        form = ProposalFormCreate(request=request, instance=old_proposal, copy=oldpk)
    if get_timephase_number() == 1:
        return render(request, 'GenericForm.html', {'form': form,
                                                    'formtitle': 'Edit copied proposal',
                                                    'buttontext': 'Create and go to next step'})
    else:
        return render(request, 'GenericForm.html', {'form': form,
                                                    'formtitle': 'Edit copied proposal (For next timeslot)',
                                                    'buttontext': 'Create and go to next step'})
Пример #26
0
def get_all_applications(user):
    """
    Get a users applications for this timeslot

    :param user: user to get applications for
    :return:
    """
    return user.applications.filter(Proposal__TimeSlot=get_timeslot())
Пример #27
0
def can_respond_file(user, dist):
    if dist.TimeSlot == get_timeslot():  # current timeslot
        if user in dist.Proposal.Assistants.all() \
                or user == dist.Proposal.ResponsibleStaff \
                or user == dist.Proposal.Track.Head \
                or get_grouptype('3') in user.groups.all():
            return True
    return False
Пример #28
0
def get_list_distributions_xlsx(proposals):
    """
    Excel export of proposals with distributions.
    Lists all proposals with their student.

    :param proposals:
    :return:
    """
    wb = Workbook()

    # grab the active worksheet
    ws = wb.active
    ws.title = "distributions"

    ws['A1'] = "Proposals with students and staff from {}".format(settings.NAME_PRETTY)
    ws['A1'].style = 'Headline 2'
    ws['F1'] = "Exported on: " + str(datetime.now())

    header = ["Title", "Track", "Research group", "Responsible", "Assistants", "Chosen", "Student Emails",
              "Staff Emails"]

    ws.column_dimensions['A'].width = 25  # title
    ws.column_dimensions['D'].width = 25  # responsible
    ws.column_dimensions['E'].width = 25  # assistants
    ws.column_dimensions['F'].width = 25  # chosen
    ws.column_dimensions['G'].width = 25  # student mail
    ws.column_dimensions['H'].width = 25  # staff mail

    ws.append(header)
    for col in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']:
        ws[col + '2'].style = 'Headline 3'

    for p in proposals:
        des = p.distributions.filter(TimeSlot=get_timeslot())
        row = [p.Title, p.Track.__str__(), p.Group.__str__(),
               p.ResponsibleStaff.usermeta.get_nice_name()]
        assistants = ''
        for a in p.Assistants.all():
            assistants += a.usermeta.get_nice_name() + "; "
        row.append(assistants)
        stds = ''
        stdsmail = ''
        for d in des:
            stdsmail += d.Student.email + '; '
            try:
                stds += d.Student.usermeta.get_nice_fullname() + " (" + d.Student.usermeta.Studentnumber + "); "
            except:
                stds += d.Student.usermeta.get_nice_fullname() + "; "
        row.append(stds)
        row.append(stdsmail)
        emails = '{};'.format(p.ResponsibleStaff.email)
        for a in p.Assistants.all():
            emails += '{};'.format(a.email)
        row.append(emails)
        # row[4].alignment = Alignment(wrapText=True)
        # row[5].alignment = Alignment(wrapText=True)
        ws.append(row)
    return save_virtual_workbook(wb)
Пример #29
0
def check_user(request, user):
    # insert checks on login here
    if user.is_superuser:
        return render(request, 'base.html', status=403, context={
            'Message': 'Superusers are not allowed to login via SSO. Please use 2FA login.'})
    else:
        # block all except supportstaff if there is no timeslot
        # support staff needs login to be able to set a new timeslot or timephase.
        if not get_timeslot() and not get_grouptype('3') in user.groups.all():  # if there isn't a timeslot and not type3
            return render(request, 'base.html', status=403, context={"Message": "Login is currently not available."})

        # login functions for staff and students.
        if is_staff(user):
            set_level(user)
            if not user.groups.exists():
                # existing staff member already have groups
                # new staff members get automatically type2staffunverified
                user.groups.add(get_grouptype("2u"))
            return True
        else:
            if not enrolled_osiris(user):
                return render(request, 'base.html', status=403, context={"Message": "You are not enrolled in our system yet. Please login once through canvas module BEP Marketplace"})
            elif get_timephase_number() < 3:  # if there isn't a timephase, this returns -1, so login is blocked.
                return render(request, 'base.html', status=403, context={"Message": "Student login is not available in "
                                                                                    "this timephase."})
            else:
                # student is enrolled in osiris. Set its usermeta from the osiris data
                data = osirisData()
                osirisdata = data.get(user.email)
                if osirisdata is not None:
                    set_osiris(user, osirisdata)

                if get_timephase_number() > 5:  # only students with project are allowed
                    if not user.distributions.exists():
                        return render(request, 'base.html', status=403,
                                      context={"Message": "You don't have a project assigned"
                                                          " to you, therefore login is not "
                                                          "allowed in this timephase."})

                if get_timeslot() not in user.usermeta.TimeSlot.all():  # user is not active in this timeslot
                    # not in this timeslot so old user, canvas app sets timeslot
                    # this security will fail if canvas does not close off old courses as it does now
                    return render(request, 'base.html', status=403, context={"Message": "You already did your BEP once"
                                                                                    ", login is not allowed."})
    return True
Пример #30
0
def list_staff(request):
    """
    List all staff with a distributed projects

    :param request:
    :return:
    """
    def nint(nr):
        """
        :param <int> nr:
        :return:
        """
        if nr is None:
            return 0
        else:
            return int(nr)

    staff = get_all_staff().filter(
        Q(groups=get_grouptype("2"))
        | Q(groups=get_grouptype("1"))).prefetch_related(
            'proposalsresponsible', 'proposals')
    se = []
    for s in staff:
        p1 = s.proposalsresponsible.filter(TimeSlot=get_timeslot())
        p2 = s.proposals.filter(TimeSlot=get_timeslot())
        pt1 = p1.count()
        pt2 = p2.count()
        pts = pt1 + pt2
        dt1 = nint(
            p1.annotate(Count('distributions')).aggregate(
                Sum('distributions__count'))['distributions__count__sum'])
        dt2 = nint(
            p2.annotate(Count('distributions')).aggregate(
                Sum('distributions__count'))['distributions__count__sum'])
        dts = dt1 + dt2
        se.append({
            "user": s,
            "pt1": pt1,
            "pt2": pt2,
            "pts": pts,
            "dt1": dt1,
            "dt2": dt2,
            "dts": dts
        })
    return render(request, 'support/list_staff.html', {"staff": se})