예제 #1
0
def download_file(request,
                  course_slug,
                  activity_slug,
                  component_slug=None,
                  submission_id=None,
                  userid=None):
    course = get_object_or_404(CourseOffering, slug=course_slug)
    activity = get_object_or_404(course.activity_set,
                                 slug=activity_slug,
                                 deleted=False)
    staff = False
    if is_course_staff_by_slug(request, course_slug):
        staff = True

    # find the appropriate submission object
    if submission_id:
        # explicit request: get that one.
        try:
            submission_info = SubmissionInfo.from_submission_id(submission_id)
        except ValueError:
            return NotFoundResponse(request)
    elif userid:
        # userid specified: get their most recent submission
        student = get_object_or_404(Person, find_userid_or_emplid(userid))
        submission_info = SubmissionInfo(student=student,
                                         activity=activity,
                                         include_deleted=staff)
    else:
        return NotFoundResponse(request)

    if not submission_info.have_submitted(
    ) or submission_info.activity != activity:
        return NotFoundResponse(request)

    if not submission_info.accessible_by(request):
        return ForbiddenResponse(request)

    # create the result
    if component_slug:
        # download single component if specified
        submission_info.get_most_recent_components()
        submitted_components = [
            subcomp
            for comp, subcomp in submission_info.components_and_submitted()
            if subcomp and comp.slug == component_slug
        ]
        if not submitted_components:
            return NotFoundResponse(request)

        submitted_component = submitted_components[0]
        return submitted_component.download_response(
            slug=submission_info.submissions[0].file_slug())
    else:
        # no component specified: give back the full ZIP file.
        return submission_info.generate_student_zip()
예제 #2
0
def download_file(request, course_slug, activity_slug, component_slug=None, submission_id=None, userid=None):
    course = get_object_or_404(CourseOffering, slug=course_slug)
    activity = get_object_or_404(course.activity_set, slug = activity_slug, deleted=False)
    staff = False
    if is_course_staff_by_slug(request, course_slug):
        staff = True
    
    # find the appropriate submission object
    if submission_id:
        # explicit request: get that one.
        submission = get_submission(submission_id)
        if not submission or submission.activity!=activity:
            return NotFoundResponse(request)
        submitted_components = get_submission_components(submission, activity, include_deleted=staff)

    elif userid:
        # userid specified: get their most recent submission
        student = get_object_or_404(Person, find_userid_or_emplid(userid))
        submission, submitted_components = get_current_submission(student, activity, include_deleted=staff)
        if not submission:
            return NotFoundResponse(request)
    
    else:
        return NotFoundResponse(request)

    
    # make sure this user is allowed to see the file
    if staff:
        pass
    elif isinstance(submission, GroupSubmission):
        membership = submission.group.groupmember_set.filter(student__person__userid=request.user.username, activity=activity, confirmed=True)
        if not membership:
            return ForbiddenResponse(request)
    elif isinstance(submission, StudentSubmission):
        if submission.member.person.userid != request.user.username:
            return ForbiddenResponse(request)

    # create the result
    if component_slug:
        # download single component if specified
        # get the actual component: already did the searching above, so just look in that list
        components = [sub for comp,sub in submitted_components if sub and sub.component.slug==component_slug]
        if not components:
            return NotFoundResponse(request)
        return components[0].download_response()
    else:
        # no component specified: give back the full ZIP file.
        return generate_zip_file(submission, submitted_components)
예제 #3
0
파일: views.py 프로젝트: skyemason/coursys
def news_config(request):
    users = Person.objects.filter(userid=request.user.username)
    if users.count() == 1:
        user = users[0]
    else:
        return NotFoundResponse(
            request,
            errormsg=
            "Your account is not known to this system.  There is nothing to configure."
        )

    # get appropriate UserConfig object
    configs = UserConfig.objects.filter(user=user, key='newsitems')
    if configs:
        config = configs[0]
    else:
        config = UserConfig(user=user, key='newsitems', value={})

    if request.method == 'POST':
        form = NewsConfigForm(request.POST)
        if form.is_valid():
            config.value['email'] = form.cleaned_data['want_email']
            config.save()
            messages.add_message(request, messages.SUCCESS,
                                 'News settings updated.')
            return HttpResponseRedirect(reverse('config:config'))
    else:
        initial = {
            'want_email': 'email' not in config.value or config.value['email']
        }
        form = NewsConfigForm(initial)

    context = {'form': form}
    return render(request, "dashboard/news_config.html", context)
예제 #4
0
파일: views.py 프로젝트: skyemason/coursys
def calendar_data(request):
    """
    AJAX JSON results for the calendar (rendered by dashboard.views.calendar)
    """
    try:
        st = iso8601.parse_date(request.GET['start'])
        en = iso8601.parse_date(request.GET['end'])
    except (KeyError, ValueError, iso8601.ParseError):
        return NotFoundResponse(request, errormsg="Bad request")

    user = get_object_or_404(Person, userid=request.user.username)
    local_tz = pytz.timezone(settings.TIME_ZONE)
    start = st - datetime.timedelta(days=1)
    end = en + datetime.timedelta(days=1)

    resp = HttpResponse(content_type="application/json")
    events = _calendar_event_data(user,
                                  start,
                                  end,
                                  local_tz,
                                  dt_string=True,
                                  colour=True,
                                  due_before=datetime.timedelta(minutes=1),
                                  due_after=datetime.timedelta(minutes=30))
    json.dump(list(events), resp, indent=1)
    return resp
예제 #5
0
def _offering_meeting_time_data(request, offering):
    """
    fullcalendar.js data for this offering's events
    """
    try:
        int(request.GET['start'])
        int(request.GET['end'])
    except (KeyError, ValueError):
        return NotFoundResponse(request, errormsg="Bad request")

    local_tz = pytz.timezone(settings.TIME_ZONE)
    start = local_tz.localize(
        datetime.datetime.fromtimestamp(int(
            request.GET['start']))) - datetime.timedelta(days=1)
    end = local_tz.localize(
        datetime.datetime.fromtimestamp(int(
            request.GET['end']))) + datetime.timedelta(days=1)

    response = HttpResponse(content_type='application/json')
    data = list(
        _offerings_calendar_data([offering],
                                 None,
                                 start,
                                 end,
                                 local_tz,
                                 dt_string=True,
                                 colour=True,
                                 browse_titles=True))
    json.dump(data, response, indent=1)
    return response
예제 #6
0
파일: views.py 프로젝트: xhacker/coursys
def atom_feed(request, token, userid, course_slug=None):
    """
    Return an Atom feed for this user, authenticated by the token in the URL
    """
    user = get_object_or_404(Person, userid=userid)
    
    # make sure the token in the URL (32 hex characters) matches the token stored in the DB
    configs = UserConfig.objects.filter(user=user, key="feed-token")
    if not configs or 'token' not in configs[0].value or configs[0].value['token'] != token:
        # no token configured or wrong token provided
        return NotFoundResponse(request)
    #else:
        # authenticated

    news_list = NewsItem.objects.filter(user=user).order_by('-updated')
    course = None
    if course_slug:
        course = get_object_or_404(CourseOffering, slug=course_slug)
        news_list = news_list.filter(course=course)
    news_list = news_list[:20]
    
    if news_list:
        updated = news_list[0].rfc_updated()
    else:
        # no news items -> no recent updates.
        updated = '2000-01-01T00:00:00Z'

    context = {"news_list": news_list, 'person': user, 'updated': updated, 'course': course, 'server_url': settings.BASE_ABS_URL}
    return render(request, "dashboard/atom_feed.xml", context, content_type="application/atom+xml")
예제 #7
0
def config(request):
    users = Person.objects.filter(userid=request.user.username)
    if users.count() == 1:
        user = users[0]
    else:
        return NotFoundResponse(request, errormsg="Your account is not known to this system.  There is nothing to configure.")

    # calendar config
    config = _get_calendar_config(user)
    if 'token' not in config:
        caltoken = None
    else:
        caltoken = config['token']

    # feed config
    configs = UserConfig.objects.filter(user=user, key="feed-token")
    if not configs:
        newstoken = None
    else:
        newstoken = configs[0].value['token']
    
    # news config
    configs = UserConfig.objects.filter(user=user, key="newsitems")
    # By default, users get emails for news items unless they specifically opted-out.  The value here doesn't
    # change any data, it just displays the same thing as if someone had a UserConfig where they specifically set
    # email to True.
    if not configs:
        newsconfig = {'email': True}
    else:
        newsconfig = configs[0].value
    
    # advisor note API config
    advisortoken = None
    advisor = False
    if has_role('ADVS', request):
        advisor = True
        configs = UserConfig.objects.filter(user=user, key='advisor-token')
        if len(configs) > 0:
            advisortoken = configs[0].value['token']
    
    # ID photo agreement
    instructor = False
    photo_agreement = False
    if Member.objects.filter(person=user, role__in=['INST', 'TA']).count() > 0:
        instructor = True
        configs = UserConfig.objects.filter(user=user, key='photo-agreement')
        if len(configs) > 0:
            photo_agreement = configs[0].value['agree']

    # privacy config
    roles = Role.all_roles(user.userid)
    roles_with_privacy = [r for r in roles if r in PRIVACY_ROLES]
    privacy_visible = len(roles_with_privacy) > 0

    context={'caltoken': caltoken, 'newstoken': newstoken, 'newsconfig': newsconfig, 'advisor': advisor, 'advisortoken': advisortoken, 
             'instructor': instructor, 'photo_agreement': photo_agreement, 'userid': user.userid, 'server_url': settings.BASE_ABS_URL,
             'privacy_visible': privacy_visible}
    return render(request, "dashboard/config.html", context)
예제 #8
0
def calendar_ical(request, token, userid):
    """
    Return an iCalendar for this user, authenticated by the token in the URL
    """
    local_tz = pytz.timezone(settings.TIME_ZONE)
    utc = pytz.utc
    user = get_object_or_404(Person, userid=userid)

    # make sure the token in the URL (32 hex characters) matches the token stored in the DB
    config = _get_calendar_config(user)
    if 'token' not in config or config['token'] != token:
        # no token set or wrong token provided
        return NotFoundResponse(request)
    #else:
    # authenticated

    now = datetime.datetime.now()
    start = local_tz.localize(now - datetime.timedelta(days=180))
    end = local_tz.localize(now + datetime.timedelta(days=365))

    cal = Calendar()
    cal.add('version', '2.0')
    cal.add('prodid', '-//SFU CourSys//courses.cs.sfu.ca//')
    cal.add('X-PUBLISHED-TTL', 'PT1D')

    for data in _calendar_event_data(user,
                                     start,
                                     end,
                                     local_tz,
                                     dt_string=False):
        e = Event()
        e['uid'] = str(data['id'])
        e.add('summary', data['title'])
        e.add('dtstart', _ical_datetime(utc, data['start']))
        e.add('dtend', _ical_datetime(utc, data['end']))
        if data['category'] in ('DUE', 'HOLIDAY'):
            # these shouldn't be "busy" on calendars
            e.add('transp', 'TRANSPARENT')
        else:
            e.add('transp', 'OPAQUE')

        # spec says no TZID on UTC times
        if 'TZID' in e['dtstart'].params:
            del e['dtstart'].params['TZID']
        if 'TZID' in e['dtend'].params:
            del e['dtend'].params['TZID']

        e.add('categories', data['category'])
        if 'url' in data:
            e.add('url', data['url'])
        if 'location' in data:
            e.add('location', data['location'])
        cal.add_component(e)

    resp = HttpResponse(cal.to_ical(), content_type="text/calendar")
    print resp.reason_phrase
    return resp
예제 #9
0
def edit_single(request, course_slug, activity_slug):
    course = get_object_or_404(CourseOffering, slug=course_slug)
    activity = get_object_or_404(course.activity_set,
                                 slug=activity_slug,
                                 deleted=False)
    component_list = select_all_components(activity)

    #get component
    edit_id = request.GET.get('id')
    component = get_component(activity=activity, id=edit_id)
    if component is None:
        return NotFoundResponse(request)

    form = component.Type.ComponentForm(instance=component)

    #if form submitted
    if request.method == 'POST':
        new_form = component.Type.ComponentForm(request.POST)
        if new_form.is_valid():
            new_component = new_form.save(commit=False)
            new_component.activity = activity
            new_component.id = component.id
            if new_component.position == None:
                count = len(select_all_components(activity))
                new_component.position = count + 1
            new_component.save()
            #LOG EVENT#
            l = LogEntry(userid=request.user.username,
                         description=("edited component %s of %s") %
                         (component.title, activity),
                         related_object=new_component)
            l.save()
            messages.add_message(
                request, messages.SUCCESS, 'Component "' +
                new_component.title + '" successfully updated.')
            return HttpResponseRedirect(
                reverse('offering:submission:show_components',
                        args=[course_slug, activity_slug]))
        else:
            form = new_form
            messages.add_message(request, messages.ERROR,
                                 'Please correct the errors in the form.')

    return render(
        request, "submission/component_edit_single.html", {
            "course": course,
            "activity": activity,
            "component": component,
            "edit_id": edit_id,
            "form": form
        })
예제 #10
0
def delete_savedsearch(request):
    current_user = Person.objects.get(userid=request.user.username)
    if request.method != 'POST':
        return ForbiddenResponse(request)
    savedsearches = SavedSearch.objects.filter(
                person=request.POST['person'], 
                query=request.POST['query'])
    if not savedsearches:
        return NotFoundResponse(request, "This Saved Search doesn't exist.")
    savedsearch = savedsearches[0]
    if current_user != savedsearch.person:
        return ForbiddenResponse(request, "You cannot delete this Saved Search.")
    savedsearch.delete()
    messages.add_message(request, messages.SUCCESS, "Saved Search '%s' was successfully deleted." % savedsearch.name())
    return HttpResponseRedirect(reverse('grad:index'))
예제 #11
0
def get_form(request, grad_slug):
    grad = get_object_or_404(GradStudent,
                             slug=grad_slug,
                             program__unit__in=request.units)

    if 'type' in request.GET and request.GET['type'] == 'cardreq':
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = 'inline; filename="card_access.pdf"'
        card_req_forms([grad], response)
    elif 'type' in request.GET and request.GET['type'] == 'fasnet':
        response = HttpResponse(content_type='application/pdf')
        response[
            'Content-Disposition'] = 'inline; filename="fasnet_access.pdf"'
        fasnet_forms([grad], response)
    else:
        response = NotFoundResponse(request)

    return response
예제 #12
0
def _get_file(request, course_slug, page_label, disposition):
    """
    view for either inlinte viewing or downloading file contents
    """
    offering = get_object_or_404(CourseOffering, slug=course_slug)
    page = get_object_or_404(Page, offering=offering, label=page_label)
    version = page.current_version()
    if not version.is_filepage():
        return NotFoundResponse(request)
    
    member = _check_allowed(request, offering, page.can_read, page.releasedate())
    # check that we have an allowed member of the course (and can continue)
    if not member:
        return _forbidden_response(request, page.get_can_read_display())
    
    resp = HttpResponse(version.file_attachment.chunks(), content_type=version.file_mediatype)
    resp['Content-Disposition'] = disposition+'; filename="' + version.file_name + '"'
    resp['Content-Length'] = version.file_attachment.size
    return resp
예제 #13
0
def browse_courses_info(request, course_slug):
    """
    Browsing info about a single course offering.
    """
    offering = get_object_or_404(CourseOffering, slug=course_slug)
    if offering.flags.combined:
        return NotFoundResponse(request)

    if 'data' in request.GET:
        # more_course_info data requested
        response = HttpResponse(content_type='application/json')
        try:
            data = more_offering_info(offering,
                                      browse_data=True,
                                      offering_effdt=True)
        except SIMSProblem as e:
            data = {'error': e.message}
        json.dump(data, response, indent=1)
        return response

    elif 'caldata' in request.GET:
        # calendar data requested
        return _offering_meeting_time_data(request, offering)

    elif 'outline' in request.GET:
        # course outline data requested
        response = HttpResponse(content_type='application/json')
        data = outlines_data_json(offering)
        response.write(data)
        return response

    # the page itself (with most data assembled by AJAX requests to the above)
    context = {
        'offering': offering,
    }
    return render(request, 'coredata/browse_courses_info.html', context)
예제 #14
0
def view(request, grad_slug, section=None):
    grad, authtype, units = _can_view_student(request, grad_slug)
    if grad is None or authtype == 'student':
        return ForbiddenResponse(request)

    # uses of the cortez link routed through here to see if they're actually being used
    if 'cortez-bounce' in request.GET and 'cortezid' in grad.config:
        from log.models import LogEntry
        from django.shortcuts import redirect
        l = LogEntry(userid=request.user.username,
                     description="used cortez link for %s" % (grad.slug, ),
                     related_object=grad)
        l.save()
        return redirect(
            "https://cortez.cs.sfu.ca/grad/scripts/grabcurrent.asp?Identifier="
            + grad.config['cortezid'])

    # Only an authtype ruled as "admin" by _can_view_student should be allowed to edit anything here.
    can_edit = authtype == 'admin'
    context = {
        'grad': grad,
        'can_edit': can_edit,
        'authtype': authtype,
    }

    for s in all_sections:
        context[s + '_content'] = ''

    if 'section' in request.GET:
        # page sections fetched by AJAX calls
        section = request.GET['section']

    if section:
        if section not in all_sections:
            return NotFoundResponse(request)

        elif section == 'general':
            programhistory = GradProgramHistory.objects.filter(
                student=grad, program__unit__in=units).order_by('starting')
            context['programhistory'] = programhistory
            flag_values = grad.flags_and_values()
            context['extras'] = [(title, grad.config[field])
                                 for field, title in grad.tacked_on_fields
                                 if field in grad.config]
            context['flag_values'] = flag_values
            return render(request, 'grad/view__general.html', context)

        elif section == 'supervisors':
            supervisors = Supervisor.objects.filter(
                student=grad, removed=False).select_related('supervisor')
            context['supervisors'] = supervisors
            return render(request, 'grad/view__supervisors.html', context)

        elif section == 'status':
            statuses = GradStatus.objects.filter(
                student=grad, hidden=False).order_by('start__name')
            context['statuses'] = statuses
            return render(request, 'grad/view__status.html', context)

        elif section == 'requirements':
            completed_req = CompletedRequirement.objects.filter(student=grad,
                                                                removed=False)
            completed_gradreq_id = [
                cr.requirement_id for cr in completed_req
                if cr.removed == False
            ]
            req = GradRequirement.objects.filter(program=grad.program,
                                                 hidden=False)
            missing_req = req.exclude(id__in=completed_gradreq_id)
            context['completed_req'] = completed_req
            context['missing_req'] = missing_req
            return render(request, 'grad/view__requirements.html', context)

        elif section == 'scholarships':
            scholarships = Scholarship.objects.filter(
                student=grad, removed=False).select_related(
                    'scholarship_type').order_by('start_semester__name')
            comments = FinancialComment.objects.filter(
                student=grad, comment_type='SCO',
                removed=False).order_by('created_at')
            context['scholarships'] = scholarships
            context['scholarship_comments'] = comments
            return render(request, 'grad/view__scholarships.html', context)

        elif section == 'otherfunding':
            otherfunding = OtherFunding.objects.filter(
                student=grad, removed=False).order_by('semester__name')
            context['otherfunding'] = otherfunding
            return render(request, 'grad/view__otherfunding.html', context)

        elif section == 'promises':
            promises = Promise.objects.filter(
                student=grad, removed=False).order_by('start_semester__name')
            context['promises'] = promises
            return render(request, 'grad/view__promises.html', context)

        elif section == 'tacontracts':
            tacontracts = TAContract.objects.filter(person=grad.person,
                                                    status__in=['NEW', 'SGN'])
            oldcontracts = OldTAContract.objects.filter(
                application__person=grad.person)
            context['tacontracts'] = tacontracts
            context['oldcontracts'] = oldcontracts
            return render(request, 'grad/view__tacontracts.html', context)

        elif section == 'financialcomments':
            comments = FinancialComment.objects.filter(
                student=grad, removed=False).order_by('created_at')
            context['financial_comments'] = comments
            return render(request, 'grad/view__financialcomments.html',
                          context)

        elif section == 'letters':
            letters = Letter.objects.filter(
                student=grad,
                removed=False).select_related('template').order_by('date')
            context['letters'] = letters
            return render(request, 'grad/view__letters.html', context)

        elif section == 'progressreports':
            progressreports = ProgressReport.objects.filter(student=grad,
                                                            removed=False)\
                                                            .order_by('date')
            context['progress_reports'] = progressreports
            return render(request, 'grad/view__progress.html', context)

        elif section == 'documents':
            documents = ExternalDocument.objects.filter(student=grad,
                                                        removed=False)\
                                                        .order_by('date')
            context['documents'] = documents
            return render(request, 'grad/view__documents.html', context)

        elif section == 'visas':
            visas = Visa.get_visas([grad.person])
            context['visas'] = visas
            return render(request, 'grad/view__visas.html', context)

        else:
            raise ValueError("Not all sections handled by view code: " +
                             repr(section))

    elif '_escaped_fragment_' in request.GET:
        # Implement google-suggested hash-bang workaround. Not terribly efficient, but probably uncommon.
        # https://developers.google.com/webmasters/ajax-crawling/docs/getting-started
        sections = request.GET['_escaped_fragment_'].split(',')
        for s in sections:
            resp = view(request, grad_slug, section=s)
            context[s + '_content'] = mark_safe(resp.content.decode('utf8'))

    other_grad = GradStudent.objects \
                 .filter(program__unit__in=units, person=grad.person) \
                 .exclude(id=grad.id)
    other_applicant = [x for x in other_grad if x.is_applicant()]
    other_grad = [x for x in other_grad if not x.is_applicant()]
    context['other_grad'] = other_grad
    context['other_applicant'] = other_applicant

    return render(request, 'grad/view.html', context)
예제 #15
0
def _show_components_student(request, course_slug, activity_slug, userid=None, template="dashboard_student.html", staff=False):
    """
    Show all the component submission history of this activity
    """
    if userid == None:
        userid = request.user.username
    course = get_object_or_404(CourseOffering, slug=course_slug)
    activity = get_object_or_404(course.activity_set,slug=activity_slug, deleted=False)
    student = get_object_or_404(Person, find_userid_or_emplid(userid))
    cansubmit = True

    submission, submitted_components = get_current_submission(student, activity, include_deleted=staff)
    if len(submitted_components) == 0:
        return NotFoundResponse(request)

    if submission and activity.due_date and activity.due_date < submission.created_at:
        late = submission.created_at - activity.due_date
    else:
        late = 0
    
    if activity.group:
        gm = GroupMember.objects.filter(student__person=student, activity=activity, confirmed=True)
        if gm:
            group = gm[0].group
            member = gm[0].student
        else:
            group = None
            #cansubmit = False
            #messages.add_message(request, messages.INFO, "This is a group submission. You cannot submit since you aren't in a group.")
    else:
        group = None

    # activity should be submitable
    cansubmit = cansubmit and activity.submitable()

    if not cansubmit:
        messages.add_message(request, messages.ERROR, "This activity is not submittable.")
        return render(request, "submission/" + template,
        {"course":course, "activity":activity, "submission": submission, "submitted_components":submitted_components,
         "userid":userid, "late":late, "student":student, "group":group, "cansubmit":cansubmit})

    # get all components of activity
    component_list = select_all_components(activity)
    component_list.sort()
    component_form_list=[]

    if request.method == 'POST':
        component_form_list = make_form_from_list(component_list, request=request)
        submitted_comp = []    # list all components which has content submitted in the POST
        not_submitted_comp = [] #list allcomponents which has no content submitted in the POST
        if not activity.group:
            new_sub = StudentSubmission()   # the submission foreign key for newly submitted components
            new_sub.member = get_object_or_404(Member, offering__slug=course_slug, person__userid=request.user.username)
        elif gm:
            new_sub = GroupSubmission()
            new_sub.group = group
            new_sub.creator = member
        else:
            messages.add_message(request, messages.ERROR, "This is a group submission. You cannot submit since you aren't in a group.")
            return ForbiddenResponse(request)
        new_sub.activity = activity

        # begin validating uploaded data
        submitted_comp = []
        not_submitted_comp = []
        # validate forms one by one
        for data in component_form_list:
            component = data['comp']
            form = data['form']
            if form.is_valid():
                sub = form.save(commit=False)
                sub.component = component
                submitted_comp.append(sub)
            else:
                # hack to replace the "required" message to something more appropriate
                for k,v in form.errors.items():
                    for i,e in enumerate(v):
                        if e == "This field is required.":
                            v[i] = "Nothing submitted."

                not_submitted_comp.append(component)
        # check duplicate filenames here
        all_ok = False
        while not all_ok:
            all_ok = True
            d = {}
            for c,s in submitted_components:
                d[c] = s and s.get_filename()
            for s in submitted_comp:
                d[s.component] = s.get_filename()
            # a list holding all file names
            file_name_list = [a[1] for a in d.items() if a[1] is not None]
            to_be_removed = []
            for (i, s) in enumerate(submitted_comp):
                if file_name_list.count(s.get_filename()) > 1:
                    all_ok = False
                    to_be_removed.append(i)
                    not_submitted_comp.append(s.component)
                    #HACK: modify the 'errors' field in the form
                    for data in component_form_list:
                        if s.component == data['comp']:
                            # assume we have only one field for submission form
                            field_name = data['form'].fields.keys()[0]
                            data['form']._errors[field_name] = ErrorList([u"This file has the same name as another file in your submission."])
            # remove those has errors in submitted_comp
            to_be_removed.reverse()
            for t in to_be_removed:
                submitted_comp.pop(t)
        # all okay now
        # end validating, begin saving
        if len(submitted_comp) > 0:
            new_sub.save()    
        for sub in submitted_comp:
            sub.submission = new_sub
            sub.save()
            #LOG EVENT#
            if activity.group:
                group_str = " as a member of group %s" % new_sub.group.name
            else:
                group_str = ""
            l = LogEntry(userid=request.user.username,
                  description=u"submitted for %s %s%s" % (activity, sub.component.title, group_str),
                  related_object=sub)
            l.save()

        if len(not_submitted_comp) == 0:
            messages.add_message(request, messages.SUCCESS, "Your submission was successful.")
            return HttpResponseRedirect(reverse(show_components, args=[course_slug, activity_slug]))

        return render(request, "submission/submission_error.html",
            {"course":course, "activity":activity, "component_list":component_form_list,
            "submitted_comp":submitted_comp, "not_submitted_comp":not_submitted_comp})
    else: #not POST
        if activity.group and gm:
            messages.add_message(request, messages.INFO, "This is a group submission. You will submit on behalf of the group %s." % group.name)
        
        component_form_list = make_form_from_list(component_list)
        return render(request, "submission/" + template,
        {'component_form_list': component_form_list, "course": course, "activity": activity, "submission": submission,
         "submitted_components":submitted_components, "userid":userid, "late":late, "student":student, "group":group,
         "cansubmit":cansubmit, "is_staff":staff})
예제 #16
0
def financials(request, grad_slug, style='complete'):
    if style not in STYLES:
        return NotFoundResponse(request)

    grad, _, units = _can_view_student(request, grad_slug, funding=True)
    if grad is None:
        return ForbiddenResponse(request)

    current_status = GradStatus.objects.filter(
        student=grad, hidden=False).order_by('-start')[0]
    grad_status_qs = GradStatus.objects.filter(
        student=grad, hidden=False,
        status__in=STATUS_ACTIVE).select_related('start', 'end')
    scholarships_qs = Scholarship.objects.filter(student=grad,
                                                 removed=False).select_related(
                                                     'start_semester',
                                                     'end_semester')
    promises_qs = Promise.objects.filter(student=grad,
                                         removed=False).select_related(
                                             'start_semester', 'end_semester')
    other_fundings = OtherFunding.objects.filter(
        student=grad, removed=False).select_related('semester')

    contracts = TAContract.objects.filter(
        application__person=grad.person).exclude(
            status__in=STATUSES_NOT_TAING).select_related('posting__semester')
    other_contracts = NewTAContract.objects.filter(person=grad.person, status__in=['NEW', 'SGN'])\
                    .select_related('category')\
                    .select_related('email_receipt')\
                    .prefetch_related('course')
    appointments = RAAppointment.objects.filter(person=grad.person,
                                                deleted=False)
    program_history = GradProgramHistory.objects.filter(
        student=grad).select_related('start_semester', 'program')
    financial_comments = FinancialComment.objects.filter(
        student=grad, removed=False).select_related('semester')

    # initialize earliest starting and latest ending semesters for display.
    # Falls back on current semester if none
    all_semesters = itertools.chain(  # every semester we have info for
        (s.start for s in grad_status_qs),
        (s.end for s in grad_status_qs),
        (p.start_semester for p in promises_qs),
        (p.end_semester for p in promises_qs),
        (s.start_semester for s in scholarships_qs),
        (s.end_semester for s in scholarships_qs),
        (o.semester for o in other_fundings),
        (c.posting.semester for c in contracts),
        (c.semester for c in financial_comments),
        (get_semester(a.start_date) for a in appointments),
        (get_semester(a.end_date) for a in appointments),
        (ph.start_semester for ph in program_history),
    )
    all_semesters = itertools.ifilter(lambda x: isinstance(x, Semester),
                                      all_semesters)
    all_semesters = set(all_semesters)
    if len(all_semesters) == 0:
        all_semesters = [get_semester()]
    earliest_semester = min(all_semesters)
    latest_semester = max(all_semesters)

    semesters = []
    semesters_qs = Semester.objects.filter(
        start__gte=earliest_semester.start,
        end__lte=latest_semester.end).order_by('-start')
    current_acad_year = None

    # build data structure with funding for each semester
    for semester in semesters_qs:
        semester_total = decimal.Decimal(0)

        yearpos = (
            semester - grad.start_semester
        ) % 3  # position in academic year: 0 is start of a new academic year for this student
        if not current_acad_year or yearpos == 2:
            # keep this (mutable) structure that we can alias in each semester and keep running totals
            current_acad_year = {'total': 0, 'semcount': 0, 'endsem': semester}

        # other funding
        other_funding = other_fundings.filter(semester=semester)
        other_total = 0
        for other in other_funding:
            if other.eligible:
                other_total += other.amount
                semester_total += other.amount

        # scholarships
        semester_scholarships = scholarships_qs.filter(
            start_semester__name__lte=semester.name,
            end_semester__name__gte=semester.name)
        semester_eligible_scholarships = semester_scholarships.filter(
            scholarship_type__eligible=True)
        scholarships = []

        scholarship_total = 0
        for ss in semester_scholarships:
            amt = ss.amount / (ss.end_semester - ss.start_semester + 1)
            scholarship_total += amt
            scholarships.append({'scholarship': ss, 'semester_amount': amt})

        for semester_eligible_scholarship in semester_eligible_scholarships:
            if (semester_eligible_scholarship.start_semester !=
                    semester_eligible_scholarship.end_semester):
                semester_span = semester_eligible_scholarship.end_semester - semester_eligible_scholarship.start_semester + 1
                semester_total += semester_eligible_scholarship.amount / semester_span
            else:
                semester_total += semester_eligible_scholarship.amount

        # grad status
        status = None
        status_short = None
        for s in GradStatus.objects.filter(student=grad):
            if s.start <= semester and (s.end == None or semester <= s.end):
                status = s.get_status_display()
                status_short = s.get_short_status_display()

        # grad program
        program = None
        for ph in program_history:
            if ph.start_semester == semester:
                program = ph

        # financial comments
        comments = []
        for c in financial_comments:
            if c.semester == semester:
                comments.append(c)

        # TAs
        ta_total = 0
        courses = []
        for contract in contracts:
            if contract.posting.semester == semester:
                for course in TACourse.objects.filter(
                        contract=contract).exclude(
                            bu=0).select_related('course'):
                    ta_total += course.pay()
                    if contract.status == 'SGN':
                        text = "%s (%s BU)" % (course.course.name(),
                                               course.total_bu)
                    else:
                        text = "%s (%s BU, current status: %s)" \
                             % (course.course.name(), course.total_bu, contract.get_status_display().lower())
                    courses.append({'course': text, 'amount': course.pay()})
        for contract in other_contracts:
            if contract.category.hiring_semester.semester == semester:
                if contract.status == 'SGN':
                    for course in contract.course.all():
                        ta_total += course.total
                        courses.append({
                            'course':
                            "%s (%s BU)" %
                            (course.course.name(), course.total_bu),
                            'amount':
                            course.total
                        })
                else:
                    for course in contract.course.all():
                        courses.append({
                            'course':
                            "%s (%s BU - $%.02f) - Draft" %
                            (course.course.name(), course.total_bu,
                             course.total),
                            'amount':
                            0
                        })
        ta = {'courses': courses, 'amount': ta_total}
        semester_total += ta_total

        # RAs
        ra_total = 0
        appt = []
        for appointment in appointments:
            app_start_sem = appointment.start_semester()
            app_end_sem = appointment.end_semester()
            length = appointment.semester_length()
            if app_start_sem <= semester and app_end_sem >= semester:
                sem_pay = appointment.lump_sum_pay / length
                ra_total += sem_pay
                appt.append({
                    'desc':
                    "RA for %s - %s" %
                    (appointment.hiring_faculty.name(), appointment.project),
                    'amount':
                    sem_pay,
                    'semesters':
                    appointment.semester_length()
                })
        ra = {'appt': appt, 'amount': ra_total}
        semester_total += ra_total

        # promises (ending in this semester, so we display them in the right spot)
        try:
            promise = promises_qs.get(end_semester=semester)
        except Promise.DoesNotExist:
            promise = None

        current_acad_year['total'] += semester_total
        current_acad_year['semcount'] += 1
        semester_data = {
            'semester': semester,
            'status': status,
            'status_short': status_short,
            'scholarships': scholarships,
            'promise': promise,
            'semester_total': semester_total,
            'comments': comments,
            'ta': ta,
            'ra': ra,
            'other_funding': other_funding,
            'program': program,
            'other_total': other_total,
            'scholarship_total': scholarship_total,
            'ta_total': ta_total,
            'ra_total': ra_total,
            'acad_year': current_acad_year
        }
        semesters.append(semester_data)

    promises = []
    for promise in promises_qs:
        received = decimal.Decimal(0)
        for semester in semesters:
            if semester['semester'] < promise.start_semester or semester[
                    'semester'] > promise.end_semester:
                continue
            received += semester['semester_total']

        owing = received - promise.amount
        # minor logic for display.
        if owing < 0:
            owing = abs(owing)
        else:
            owing = -1

        # annotate the semester where we're displaying the promise with relevant info
        for semester in semesters:
            if semester['semester'] == promise.end_semester:
                semester['promisereceived'] = received
                semester['promiseowing'] = owing

    totals = {'ta': 0, 'ra': 0, 'scholarship': 0, 'other': 0, 'total': 0}
    for s in semesters:
        totals['ta'] += s['ta_total']
        totals['ra'] += s['ra_total']
        totals['scholarship'] += s['scholarship_total']
        totals['other'] += s['other_total']
        totals['total'] += s['semester_total']

    context = {
        'semesters': semesters,
        'promises': promises,
        'grad': grad,
        'status': current_status,
        'unit': units,
        'totals': totals,
    }
    return render(request, 'grad/view_financials-%s.html' % (style), context)