from rowers.views.statements import * from rowsandall_app.settings import SITE_URL from rowers.scoring import * from django.contrib.gis.geoip2 import GeoIP2 from django import forms from rowers.plannedsessions import timefield_to_seconds_duration from rowers.courses import getnearestraces, getnearestcourses,coursetokml, coursestokml from random import sample # landing page for challenges & courses def courses_challenges_view(request): r = getrower(request.user) g = GeoIP2() ip = request.META.get('HTTP_X_REAL_IP', '1.1.1.1') try: lat_lon = g.lat_lon(ip) city = g.city(ip) except: # pragma: no cover lat_lon = None city = { 'city': '', 'country_name': '', 'time_zone': '', } courses = GeoCourse.objects.all().order_by("country", "name", "distance") nearby_courses = getnearestcourses(lat_lon, courses, whatisnear=2000) liked_courses = GeoCourse.objects.filter(followers=r) courses = GeoCourse.objects.filter(id__in=[course.id for course in nearby_courses]) | liked_courses if courses.count() >= 3: courses = sample(list(courses),3) else: courses = GeoCourse.objects.all().order_by("country", "name", "distance") coursesdicts = [] for course in courses: script, div = course_map(course) coursesdicts.append({ 'course': course, 'script': script, 'div': div, }) allchallenges = VirtualRace.objects.all().order_by("-startdate") totalnrchallenges = allchallenges.count() challenges = VirtualRace.objects.filter(startdate__gte=timezone.now()) challenges2 = VirtualRace.objects.filter(startdate__lte=timezone.now(), evaluation_closure__gte=timezone.now()-datetime.timedelta(days=3)) challenges = challenges | challenges2 count = 3 if totalnrchallenges > count: allchallenges = list(allchallenges) while len(challenges) < count: try: challenges = list(challenges)+sample(allchallenges, count-len(challenges)) except ValueError: count = count-1 challenges = list(set(challenges)) else: challenges = VirtualRace.objects.all() count = challenges.count() challenges = sample(list(challenges),count) challengesdicts = [] for challenge in challenges: script = '' div = '' if challenge.course: script, div = course_map(challenge.course) challengesdicts.append( { 'script': script, 'div': div, 'challenge': challenge, } ) breadcrumbs = [ { 'url': reverse('courses_challenges_view'), 'name': 'Courses and Challenges' } ] return render(request, "courses_challenges.html", { 'coursesdicts': coursesdicts, 'rower': r, 'challengesdicts': challengesdicts, 'breadcrumbs': breadcrumbs, }) # List Courses def courses_view(request): r = getrower(request.user) g = GeoIP2() if request.method == 'POST': try: tdict = dict(request.POST.lists()) ids = tdict['courseid'] courseids = [int(id) for id in ids] kmlstring = coursestokml(courseids) kmlfilename = 'courses.kml' response = HttpResponse(kmlstring) response['Content-Disposition'] = 'attachment; filename="{filename}"'.format( filename=kmlfilename) response['Content-Type'] = 'application/octet-stream' return response except KeyError: pass except ValueError: pass ip = request.META.get('HTTP_X_REAL_IP', '1.1.1.1') try: lat_lon = g.lat_lon(ip) city = g.city(ip) except: # pragma: no cover lat_lon = None city = { 'city': '', 'country_name': '', 'time_zone': '', } courses = GeoCourse.objects.all().order_by("country", "name", "distance") nearby = request.GET.get('nearby') liked = request.GET.get('liked') if nearby and lat_lon is not None: # pragma: no cover courses = getnearestcourses(lat_lon, courses) if liked: courses = GeoCourse.objects.filter(followers=r) # add search processing query = request.GET.get('q') if query: # pragma: no cover query_list = query.split() courses = GeoCourse.objects.filter( reduce(operator.and_, (Q(name__icontains=q) for q in query_list)) | reduce(operator.and_, (Q(country__icontains=q) for q in query_list)) | reduce(operator.and_, (Q(notes__icontains=q) for q in query_list)) ) searchform = SearchForm(initial={'q': query}) else: searchform = SearchForm() return render(request, 'list_courses.html', {'courses': courses, 'active': 'nav-racing', 'searchform': searchform, 'rower': r, 'location': lat_lon, 'city': city['city'], 'country_name': city['country_name'], 'time_zone': city['time_zone'], }) # List Courses def standards_view(request): r = getrower(request.user) standards = StandardCollection.objects.filter(active=True).order_by("name") # add search processing query = request.GET.get('q') if query: # pragma: no cover query_list = query.split() standards = StandardCollection.objects.filter( reduce(operator.and_, (Q(name__icontains=q) for q in query_list)) | reduce(operator.and_, (Q(notes__icontains=q) for q in query_list)) ) searchform = SearchForm(initial={'q': query}) else: searchform = SearchForm() return render(request, 'list_standards.html', {'standards': standards, 'active': 'nav-racing', 'searchform': searchform, 'rower': r, }) # for ajax calls def course_map_view(request, id=0): try: course = GeoCourse.objects.get(id=id) except GeoCourse.DoesNotExist: # pragma: no cover # pragma: no cover raise Http404("Course doesn't exist") script, div = course_map(course) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse(courses_view), 'name': 'Courses' }, { 'url': reverse(course_view, kwargs={'id': course.id}), 'name': course.name }, { 'url': reverse(course_map_view, kwargs={'id': course.id}), 'name': 'Map' } ] r = getrower(request.user) return render(request, 'coursemap.html', { 'mapdiv': div, 'course': course, 'mapscript': script, 'active': 'nav-racing', 'rower': r, 'breadcrumbs': breadcrumbs, }) @login_required() @permission_required('course.delete_course', fn=get_course_by_pk, raise_exception=True) def course_delete_view(request, id=0): course = get_object_or_404(GeoCourse, pk=id) ps = PlannedSession.objects.filter(course=course) nosessions = len(ps) == 0 if nosessions: course.delete() url = reverse(courses_view) return HttpResponseRedirect(url) @login_required() @permission_required('course.change_course', fn=get_course_by_pk, raise_exception=True) def course_edit_view(request, id=0): course = get_object_or_404(GeoCourse, pk=id) r = getrower(request.user) ps = PlannedSession.objects.filter(course=course) nosessions = len(ps) == 0 script, div = course_map(course) if request.method == 'POST': form = GeoCourseEditForm(request.POST) if form.is_valid(): name = form.cleaned_data['name'] country = form.cleaned_data['country'] notes = form.cleaned_data['notes'] course.name = name course.country = country course.notes = notes course.save() form = GeoCourseEditForm(instance=course) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse(courses_view), 'name': 'Courses' }, { 'url': reverse(course_view, kwargs={'id': course.id}), 'name': course.name }, { 'url': reverse(course_edit_view, kwargs={'id': course.id}), 'name': 'Edit' } ] return render(request, 'course_edit_view.html', { 'course': course, 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, 'mapscript': script, 'mapdiv': div, 'nosessions': nosessions, 'rower': r, 'form': form, } ) @login_required() def course_follow_view(request, id=0): try: course = GeoCourse.objects.get(id=id) except GeoCourse.DoesNotExist: # pragma: no cover raise Http404("Course doesn't exist") r = getrower(request.user) course.followers.add(r) messages.info(request,"You have liked {c}. If you use CrewNerd, you can sync your course list to CrewNerd".format(c=course)) if request_is_ajax(request): return JSONResponse({"course": course.id}) url = reverse("course_view", kwargs={'id':course.id}) return HttpResponseRedirect(url) @login_required() def course_unfollow_view(request, id=0): try: course = GeoCourse.objects.get(id=id) except GeoCourse.DoesNotExist: # pragma: no cover raise Http404("Course doesn't exist") r = getrower(request.user) course.followers.remove(r) messages.info(request,"You have stopped following {c}.".format(c=course)) if request_is_ajax(request): return JSONResponse({"course": course.id}) url = reverse("courses_view") return HttpResponseRedirect(url) def course_view(request, id=0, workoutid=0): try: course = GeoCourse.objects.get(id=id) except GeoCourse.DoesNotExist: # pragma: no cover raise Http404("Course doesn't exist") r = getrower(request.user) script, div = course_map(course) # get results records = VirtualRaceResult.objects.filter( course=course, workoutid__isnull=False, coursecompleted=True).order_by("duration", "-distance") # get own training results if not request.user.is_anonymous: ownrecords = CourseTestResult.objects.filter( courseid = course.id, userid = r.id, coursecompleted=True ).order_by("duration", "-distance") else: ownrecords = [] if request.user.is_authenticated: notsharing = Rower.objects.filter( share_course_results=False).exclude(id=r.id) else: # pragma: no cover notsharing = Rower.objects.filter(share_course_results=False) notsharing_ids = [o.user.id for o in notsharing] records = records.exclude(userid__in=notsharing_ids) if 'onlyme' in request.GET: # pragma: no cover onlyme = request.GET.get('onlyme', False) if onlyme == 'true': onlyme = True if onlyme and request.user.is_authenticated: records = records.filter(userid=r.user.id) else: onlyme = False form = RaceResultFilterForm(records=records, groups=False) if request.method == 'POST': # pragma: no cover form = RaceResultFilterForm( request.POST, records=records, groups=False) if form.is_valid(): cd = form.cleaned_data try: sex = cd['sex'] except KeyError: sex = ['female', 'male', 'mixed'] try: boattype = cd['boattype'] except KeyError: boattype = mytypes.waterboattype try: boatclass = cd['boatclass'] except KeyError: boatclass = [t for t in mytypes.otwtypes] age_min = cd['age_min'] age_max = cd['age_max'] try: weightcategory = cd['weightcategory'] except KeyError: weightcategory = ['hwt', 'lwt'] try: adaptiveclass = cd['adaptiveclass'] except KeyError: adaptiveclass = ['None', 'PR1', 'PR2', 'PR3', 'FES'] records = VirtualRaceResult.objects.filter( course=course, workoutid__isnull=False, coursecompleted=True, weightcategory__in=weightcategory, sex__in=sex, age__gte=age_min, age__lte=age_max, boatclass__in=boatclass, boattype__in=boattype, adaptiveclass__in=adaptiveclass, ).order_by("duration", "-distance") breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse(courses_view), 'name': 'Courses' }, { 'url': reverse(course_view, kwargs={'id': course.id}), 'name': course.name }, ] return render(request, 'course_view.html', { 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, 'course': course, 'mapscript': script, 'mapdiv': div, 'nosessions': False, 'records': records, 'ownrecords': ownrecords, 'rower': r, 'form': form, 'onlyme': onlyme, 'workoutid': workoutid, } ) def standard_view(request, id=0): try: collection = StandardCollection.objects.get(id=id) except StandardCollection.DoesNotExist: # pragma: no cover raise Http404("Standard Collection does not exist") r = getrower(request.user) allowed = ["-referencespeed", "agemax", "agemin", "sex", "name", "referencespeed", "-agemax", "-agemin", "-sex", "-name"] orderby = request.GET.get('order_by') if orderby not in allowed: orderby = None if orderby is not None: # pragma: no cover standards = CourseStandard.objects.filter( standardcollection=collection ).order_by(orderby, "-referencespeed", "agemax", "agemin", "sex", "name") else: standards = CourseStandard.objects.filter( standardcollection=collection ).order_by("-referencespeed", "agemax", "agemin", "sex", "name") breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse(standards_view), 'name': 'Standards' }, { 'url': reverse(standard_view, kwargs={'id': collection.id}), 'name': collection.name }, ] return render(request, 'standard_view.html', { 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, 'collection': collection, 'standards': standards, 'rower': r, } ) @login_required() @permission_required('racelogo.delete_logo', fn=get_logo_by_pk, raise_exception=True) def logo_delete_view(request, id=0): # pragma: no cover logo = get_object_or_404(RaceLogo, pk=id) if logo.user == request.user: logo.delete() messages.info(request, "Logo Deleted") url = reverse('virtualevents_view') return HttpResponseRedirect(url) @login_required() @permission_required('virtualevent.change_race', fn=get_virtualevent_by_pk, raise_exception=True) def virtualevent_setlogo_view(request, id=0, logoid=0): # pragma: no cover race = get_object_or_404(VirtualRace, pk=id) logo = get_object_or_404(RaceLogo, pk=logoid) otherlogos = race.logos.all() for otherlogo in otherlogos: otherlogo.race.remove(race) logo.race.add(race) logo.save() url = reverse('virtualevent_view', kwargs={'id': id}) return HttpResponseRedirect(url) # Image upload to virtual event @login_required() def virtualevent_uploadimage_view(request, id=0): # pragma: no cover is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' r = getrower(request.user) race = get_object_or_404(VirtualRace, pk=id) logos = RaceLogo.objects.filter( user=request.user).order_by("-creationdatetime") breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': id}), 'name': race.name }, { 'url': reverse(virtualevent_uploadimage_view, kwargs={'id': id}), 'name': 'Add Image' } ] if request.method == 'POST': if len(logos) >= 6: messages.error(request, "You cannot have more than 6 logos") url = reverse(virtualevent_imageupload_view, kwargs={'id': id}) return HttpResponseRedirect(url) form = ImageForm(request.POST, request.FILES) if form.is_valid(): f = form.cleaned_data['file'] if f is not None: filename, path_and_filename = handle_uploaded_image(f) try: width, height = Image.open(path_and_filename).size except: message = "Not a valid image" messages.error(request, message) os.remove(path_and_filename) url = reverse(virtualevent_image_view, kwargs={'id': id}) if is_ajax: return JSONResponse({'result': 0, 'url': 0}) else: return HttpResponseRedirect(url) otherlogos = race.logos.all() for logo in otherlogos: logo.race.remove(race) logo = RaceLogo(user=request.user, creationdatetime=timezone.now(), filename=path_and_filename, width=width, height=height) logo.save() logo.race.add(race) logo.save() url = reverse('virtualevent_view', kwargs={'id': id}) if is_ajax: return JSONResponse({'result': 1, 'url': url}) else: return HttpResponseRedirect(url) else: messages.error( request, "Something went wrong - no file attached") url = reverse(virtualevent_uploadimage_view, kwargs={'id': id}) if is_ajax: return JSONResponse({'result': 0, 'url': 1}) else: return HttpResponseRedirect(url) else: form = ImageForm() if is_ajax: return {'result': 0} return render(request, 'logo_form.html', {'form': form, 'rower': r, 'logos': logos, 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, 'race': race, }) @login_required() @permission_required('course.change_course', fn=get_course_by_pk, raise_exception=True) def course_upload_replace_view(request, id=0): is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' r = getrower(request.user) course = get_object_or_404(GeoCourse, pk=id) if request.method == 'POST': form = CourseForm(request.POST, request.FILES) if form.is_valid(): f = form.cleaned_data['file'] notes = form.cleaned_data['notes'] country = form.cleaned_data['country'] if f is not None: filename, path_and_filename = handle_uploaded_file(f) cs = courses.kmltocourse(path_and_filename) os.remove(path_and_filename) if cs and len(cs) > 1: # pragma: no cover messages.info( request, 'File contained multiple courses. We use the first one.') if cs: course = cs[0] cname = course['name'] cnotes = notes+'\n\n'+course['description'] polygons = course['polygons'] course = courses.createcourse( r, cname, polygons, notes=cnotes) if course.country == 'unknown': # pragma: no cover course.country = country course.save() url = reverse(course_update_confirm, kwargs={ 'newid': course.id, 'id': id, } ) if is_ajax: # pragma: no cover return JSONResponse({'result': 1, 'url': url}) else: return HttpResponseRedirect(url) else: # pragma: no cover messages.error(request, "File does not contain a course") else: # pragma: no cover messages.error(request, "No file attached") else: # pragma: no cover messages.error(request, "Form is not valid") else: form = CourseForm() form.fields['name'].widget = forms.HiddenInput() if not is_ajax: return render(request, 'course_form_update.html', {'form': form, 'course': course, 'active': 'nav-racing', }) else: # pragma: no cover return {'result': 0} @login_required() @permission_required('course.change_course', fn=get_course_by_pk, raise_exception=True) def course_update_confirm(request, id=0, newid=0): course = get_object_or_404(GeoCourse, pk=id) course2 = get_object_or_404(GeoCourse, pk=newid) r = getrower(request.user) if request.method == 'POST': form = CourseConfirmForm(request.POST) if form.is_valid(): doupdate = form.cleaned_data['doupdate'] if doupdate: _ = courses.replacecourse(course, course2) messages.info( request, 'All challenges with this course are updated') url = reverse(course_view, kwargs={ 'id': course2.id, }) return HttpResponseRedirect(url) else: # pragma: no cover course2.delete() url = reverse(course_view, kwargs={ 'id': course.id, }) return HttpResponseRedirect(url) else: form = CourseConfirmForm() # GET call or invalid form script, div = course_map(course2) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse(courses_view), 'name': 'Courses' }, { 'url': reverse(course_view, kwargs={'id': course.id}), 'name': course.name }, { 'url': reverse(course_upload_replace_view, kwargs={'id': course.id}), 'name': 'Replace Markers' } ] return render(request, 'course_replace_confirm.html', {'course': course, 'form': form, 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, 'rower': r, 'mapdiv': div, 'mapscript': script, }) # Course upload @login_required() def course_upload_view(request): is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' r = getrower(request.user) if request.method == 'POST': form = CourseForm(request.POST, request.FILES) if form.is_valid(): f = form.cleaned_data['file'] name = form.cleaned_data['name'] notes = form.cleaned_data['notes'] country = form.cleaned_data['country'] if f is not None: filename, path_and_filename = handle_uploaded_file(f) try: cs = courses.kmltocourse(path_and_filename) except ParseError: os.remove(path_and_filename) messages.error( request, 'Something went wrong - error parsing the file') url = reverse(course_upload_view) if is_ajax: return JSONResponse({'result': 0, 'url': 0}) else: return HttpResponseRedirect(url) for course in cs: cname = name+' - '+course['name'] try: cnotes = notes+'\n\n'+course['description'] except TypeError: try: cnotes = notes except TypeError: try: cnotes = course['description'] except TypeError: cnotes = '' polygons = course['polygons'] course = courses.createcourse( r, cname, polygons, notes=cnotes) if course.country == 'unknown': # pragma: no cover course.country = country course.save() os.remove(path_and_filename) url = reverse(courses_view) if is_ajax: # pragma: no cover return JSONResponse({'result': 1, 'url': url}) else: return HttpResponseRedirect(url) else: # pragma: no cover messages.error( request, 'Something went wrong - no file attached') url = reverse(course_upload_view) if is_ajax: return JSONResponse({'result': 0, 'url': 0}) else: return HttpResponseRedirect(url) else: # pragma: no cover messages.error(request, 'Form is not valid') return render(request, 'course_form.html', {'form': form, }) else: if not is_ajax: form = CourseForm() return render(request, 'course_form.html', {'form': form, 'active': 'nav-racing', }) else: # pragma: no cover return {'result': 0} # Standards deactivate @login_required() def standard_deactivate_view(request, id=0): try: collection = StandardCollection.objects.get(id=id) except StandardCollection.DoesNotExist: # pragma: no cover raise Http404("Does not exist") if request.user != collection.manager: # pragma: no cover raise PermissionDenied("You cannot change this set of time standards") collection.active = False collection.save() url = reverse(standards_view) return HttpResponseRedirect(url) def standards_download_view(request, id=0): try: collection = StandardCollection.objects.get(id=id) except StandardCollection.DoesNotExist: # pragma: no cover raise Http404("Does not exist") filename = 'Standard Times {name} {id} {date}.csv'.format( id=id, name=collection.name, date=timezone.now().strftime("%Y-%m-%d %H:%M:%S %Z") ) standards = CourseStandard.objects.filter(standardcollection=collection) df = pd.DataFrame.from_records(standards.values()) response = HttpResponse(df.to_csv()) response['Content-Disposition'] = 'attachment; filename="%s"' % filename response['Content-Type'] = 'application/octet-stream' return response # Standards upload @login_required() def standards_upload_view(request, id=0): is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' if id != 0: # pragma: no cover collection = StandardCollection.objects.get(id=id) if request.user != collection.manager: raise PermissionDenied( "You cannot change this set of time standards") if request.method == 'POST': form = StandardsForm(request.POST, request.FILES) if form.is_valid(): f = form.cleaned_data['file'] name = form.cleaned_data['name'] notes = form.cleaned_data['notes'] if f is not None: filename, path_and_filename = handle_uploaded_file(f) id = save_scoring(name, request.user, path_and_filename, notes=notes, id=id) os.remove(path_and_filename) if id == 0: # pragma: no cover url = reverse(standards_view) else: url = reverse(standard_view, kwargs={'id': id}) if is_ajax: # pragma: no cover return JSONResponse({'result': 1, 'url': url}) return HttpResponseRedirect(url) else: # pragma: no cover messages.error( request, 'Something went wrong - no file attached') url = reverse(standards_upload_view) if is_ajax: return JSONResponse({'result': 0, 'url': 0}) return HttpResponseRedirect(url) else: # pragma: no cover messages.error(request, 'Form is not valid') return render(request, 'standard_form.html', {'form': form, 'active': 'nav-racing', 'id': id, }) else: if not is_ajax: form = StandardsForm() if id != 0: # pragma: no cover collection = StandardCollection.objects.get(id=id) form = StandardsForm(initial={ 'name': collection.name, 'notes': collection.notes, }) return render(request, 'standard_form.html', {'form': form, 'active': 'nav-racing', 'id': id, }) return {'result': 0} # pragma: no cover def virtualevents_view(request): is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' g = GeoIP2() ip = request.META.get('HTTP_X_REAL_IP', '1.1.1.1') try: lat_lon = g.lat_lon(ip) city = g.city(ip) except: # pragma: no cover lat_lon = None city = { 'city': '', 'country_name': '', 'time_zone': '', } # default races races1 = VirtualRace.objects.filter( startdate__gte=timezone.now(), ) races2 = VirtualRace.objects.filter( startdate__lte=timezone.now(), evaluation_closure__gte=timezone.now()-datetime.timedelta(days=3), ) races = (races1 | races2).order_by("startdate", "start_time") if len(races) == 0: races = VirtualRace.objects.all().order_by("-startdate") if not request.user.is_anonymous: r = getrower(request.user) else: r = None if request.method == 'POST': # process form form = VirtualRaceSelectForm(request.POST) if form.is_valid(): cd = form.cleaned_data country = cd['country'] regattatype = cd['regattatype'] if country == 'All': countries = VirtualRace.objects.order_by( 'country').values_list('country').distinct() else: # pragma: no cover countries = [country, 'Indoor'] if regattatype == 'upcoming': races1 = VirtualRace.objects.filter( startdate__gte=timezone.now(), country__in=countries ) races2 = VirtualRace.objects.filter( startdate__lte=timezone.now(), evaluation_closure__gte=timezone.now(), country__in=countries ) races = (races1 | races2).order_by("startdate", "start_time") elif regattatype == 'previous': races = VirtualRace.objects.filter( evaluation_closure__lt=timezone.now(), country__in=countries ).order_by("-startdate", "-start_time") elif regattatype == 'ongoing': races = VirtualRace.objects.filter( startdate__lte=timezone.now(), evaluation_closure__gte=timezone.now(), country__in=countries ).order_by("startdate", "start_time") elif regattatype == 'my': # pragma: no cover mysessions = get_my_session_ids(r) races = VirtualRace.objects.filter( id__in=mysessions, country__in=countries ).order_by("startdate", "start_time") elif regattatype == 'all': # pragma: no cover races = VirtualRace.objects.filter( country__in=countries ).order_by("startdate", "start_time") else: form = VirtualRaceSelectForm() nearby = request.GET.get('nearby') participate = request.GET.get('participate') if nearby and lat_lon is not None: # pragma: no cover races = getnearestraces(lat_lon, races) if participate and r is not None: ress = VirtualRaceResult.objects.filter(userid=r.id).order_by("-race__evaluation_closure") races = [res.race for res in ress if res.race is not None] if is_ajax: # pragma: no cover return render(request, 'racelist.html', {'races': races, 'rower': r, 'location': lat_lon, 'city': city['city'], 'country_name': city['country_name'], 'time_zone': city['time_zone'], }) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, ] return render(request, 'virtualevents.html', {'races': races, 'form': form, 'breadcrumbs': breadcrumbs, 'active': 'nav-racing', 'rower': r, 'location': lat_lon, 'city': city['city'], 'country_name': city['country_name'], 'time_zone': city['time_zone'], } ) @login_required() @permission_required('virtualevent.change_race', fn=get_virtualevent_by_pk, raise_exception=True) def virtualevent_disqualify_view(request, id=0, recordid=0): r = getrower(request.user) race = get_object_or_404(VirtualRace, pk=id) raceid = race.id if race.sessiontype == 'race': recordobj = VirtualRaceResult else: # pragma: no cover recordobj = IndoorVirtualRaceResult # datum moet voor race evaluation date zijn (ook in template controleren) try: record = recordobj.objects.get(id=recordid) except recordobj.DoesNotExist: # pragma: no cover messages.error(request, "We couldn't find the record") if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1): # pragma: no cover messages.error( request, "The evaluation is already closed and the results are official") url = reverse('virtualevent_view', kwargs={'id': raceid}) return HttpResponseRedirect(url) if request.method == 'POST': form = DisqualificationForm(request.POST) if form.is_valid(): message = form.cleaned_data['message'] reason = form.cleaned_data['reason'] disqualifier = disqualifiers[reason] r = Rower.objects.get(id=record.userid) name = record.username _ = myqueue(queue, handle_send_disqualification_email, r.user.email, name, disqualifier, message, race.name) messages.info( request, "We have invalidated the result for: "+str(record)) record.coursecompleted = False record.startsecond = 0 record.endsecond = 0 record.save() url = reverse('virtualevent_view', kwargs={'id': raceid}) return HttpResponseRedirect(url) else: form = DisqualificationForm(request.POST) try: workout = Workout.objects.get(id=record.workoutid) except Workout.DoesNotExist: # pragma: no cover workout = None script = '' div = '' g = [] mapscript = '' mapdiv = '' if workout is not None: g = GraphImage.objects.filter( workout=workout).order_by("-creationdatetime") for i in g: # pragma: no cover try: width, height = Image.open(i.filename).size i.width = width i.height = height i.save() except: pass script, div = interactive_chart(record.workoutid) f1 = workout.csvfilename rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: latitude = rowdata.df[' latitude'] if not latitude.std(): # pragma: no cover hascoordinates = 0 except (KeyError, AttributeError): # pragma: no cover hascoordinates = 0 else: # pragma: no cover hascoordinates = 0 if hascoordinates: mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'], rowdata.df[' longitude'], workout.name) else: # pragma: no cover mapscript = "" mapdiv = "" breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id}), 'name': race.name }, { 'url': reverse(virtualevent_disqualify_view, kwargs={'id': id, 'recordid': recordid}), 'name': 'Disqualify Entry' }, ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, "disqualification_view.html", {'workout': workout, 'active': 'nav-racing', 'graphs': g, 'buttons': buttons, 'interactiveplot': script, 'the_div': div, 'mapscript': mapscript, 'mapdiv': mapdiv, 'form': form, 'race': race, 'breadcrumbs': breadcrumbs, 'record': record, }) @login_required() def virtualevent_withdrawresult_view(request, id=0, recordid=0): r = getrower(request.user) race = get_object_or_404(VirtualRace, pk=id) if race.sessiontype == 'race': recordobj = VirtualRaceResult else: recordobj = IndoorVirtualRaceResult # datum moet voor race evaluation date zijn (ook in template controleren) try: record = recordobj.objects.get(id=recordid) except recordobj.DoesNotExist: # pragma: no cover messages.error(request, "We couldn't find the record") if r.id != record.userid: # pragma: no cover raise PermissionDenied("You are not the owner of this result") if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1): # pragma: no cover messages.error( request, "The evaluation is already closed and the results are official") url = reverse('virtualevent_view', kwargs={'id': raceid}) return HttpResponseRedirect(url) if request.method == 'POST': form = DisqualificationForm(request.POST) if form.is_valid(): message = form.cleaned_data['message'] reason = form.cleaned_data['reason'] disqualifier = disqualifiers[reason] r = Rower.objects.get(id=record.userid) name = record.username _ = myqueue(queue, handle_send_withdraw_email, r.user.email, name, disqualifier, message, race.name) messages.info( request, "We have invalidated the result for: "+str(record)) record.coursecompleted = False record.startsecond = 0 record.endsecond = 0 record.save() url = reverse('virtualevent_view', kwargs={'id': id}) return HttpResponseRedirect(url) else: form = DisqualificationForm(request.POST) try: # pragma: no cover workout = Workout.objects.get(id=record.workoutid) g = GraphImage.objects.filter( workout=workout).order_by("-creationdatetime") for i in g: try: width, height = Image.open(i.filename).size i.width = width i.height = height i.save() except: pass script, div = interactive_chart(record.workoutid) f1 = workout.csvfilename rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: latitude = rowdata.df[' latitude'] if not latitude.std(): hascoordinates = 0 except (KeyError, AttributeError): hascoordinates = 0 else: hascoordinates = 0 if hascoordinates: mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'], rowdata.df[' longitude'], workout.name) else: mapscript = "" mapdiv = "" except Workout.DoesNotExist: # pragma: no cover mapscript = "" mapdiv = "" workout = None script = "" div = "" g = None breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id}), 'name': race.name }, { 'url': reverse(virtualevent_disqualify_view, kwargs={'id': id, 'recordid': recordid}), 'name': 'Disqualify Entry' }, ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, "withdraw_view.html", {'workout': workout, 'active': 'nav-racing', 'graphs': g, 'buttons': buttons, 'interactiveplot': script, 'the_div': div, 'mapscript': mapscript, 'mapdiv': mapdiv, 'form': form, 'race': race, 'breadcrumbs': breadcrumbs, 'record': record, }) def virtualevent_view(request, id=0): results = [] if not request.user.is_anonymous: r = getrower(request.user) else: # pragma: no cover r = None try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': script, div = course_map(race.course) resultobj = VirtualRaceResult else: script = '' div = '' resultobj = IndoorVirtualRaceResult records = resultobj.objects.filter(race=race) buttons = [] # to-do - add DNS dns = [] if timezone.now() > race.evaluation_closure: # pragma: no cover dns = resultobj.objects.filter( race=race, workoutid__isnull=True, ) dnf = resultobj.objects.filter( race=race, workoutid__isnull=False, coursecompleted=False, ) if not request.user.is_anonymous: if race_can_register(r, race): buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] if request.method == 'POST': # pragma: no cover form = RaceResultFilterForm(request.POST, records=records) if form.is_valid(): cd = form.cleaned_data try: sex = cd['sex'] except KeyError: sex = ['female', 'male', 'mixed'] try: boattype = cd['boattype'] except KeyError: boattype = mytypes.waterboattype try: boatclass = cd['boatclass'] except KeyError: if race.sessiontype == 'race': boatclass = [t for t in mytypes.otwtypes] else: boatclass = [t for t in mytypes.otetypes] age_min = cd['age_min'] age_max = cd['age_max'] try: weightcategory = cd['weightcategory'] except KeyError: weightcategory = ['hwt', 'lwt'] try: adaptiveclass = cd['adaptiveclass'] except KeyError: adaptiveclass = ['None', 'PR1', 'PR2', 'PR3', 'FES'] try: entrycategory = cd['entrycategory'] except KeyError: entrycategory = None if race.sessiontype == 'race': results = resultobj.objects.filter( race=race, workoutid__isnull=False, boatclass__in=boatclass, boattype__in=boattype, sex__in=sex, weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max, coursecompleted=True, ).order_by("duration") else: results = resultobj.objects.filter( race=race, workoutid__isnull=False, boatclass__in=boatclass, sex__in=sex, weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max, coursecompleted=True, ).order_by("duration", "-distance") if entrycategory is not None: results = results.filter(entrycategory__in=entrycategory) # to-do - add DNS dns = [] if timezone.now() > race.evaluation_closure: dns = resultobj.objects.filter( race=race, workoutid__isnull=True, boatclass__in=boatclass, sex__in=sex, weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ) else: results = resultobj.objects.filter( race=race, workoutid__isnull=False, coursecompleted=True, ).order_by("duration", "-distance") if results: form = RaceResultFilterForm(records=records) else: form = None breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name } ] allowed = ["duration", "distance", "-distance", "points", "-points", "-duration", "-distance"] orderby = request.GET.get('order_by') if orderby not in allowed: orderby = None if orderby is not None: # pragma: no cover try: results = results.order_by(orderby) except AttributeError: pass racelogos = race.logos.all() if racelogos: # pragma: no cover racelogo = racelogos[0] else: racelogo = None comments = PlannedSessionComment.objects.filter( plannedsession=race).order_by("created") return render(request, 'virtualevent.html', { 'coursescript': script, 'coursediv': div, 'breadcrumbs': breadcrumbs, 'race': race, 'rower': r, 'results': results, 'buttons': buttons, 'dns': dns, 'dnf': dnf, 'records': records, 'racelogo': racelogo, 'form': form, 'active': 'nav-racing', 'comments': comments }) def do_encode(x): try: return encoder.encode_hex(int(x)) except: return x @login_required() @permission_required('virtualevent.change_race', fn=get_virtualevent_by_pk, raise_exception=True) def virtualevent_results_download_view(request, id=0): try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': resultobj = VirtualRaceResult else: # pragma: no cover resultobj = IndoorVirtualRaceResult records = resultobj.objects.filter(race=race) filename = 'Challenge Results {name} {id} {date}.csv'.format( id=id, name=race.name, date=timezone.now().strftime("%Y-%m-%d %H:%M:%S %Z") ) df = pd.DataFrame.from_records(records.values()) df['workoutid'] = df['workoutid'].apply(lambda x: do_encode(x)) response = HttpResponse(df.to_csv()) response['Content-Disposition'] = 'attachment; filename="%s"' % filename response['Content-Type'] = 'application/octet-stream' return response def virtualevent_ranking_view(request, id=0): results = [] if not request.user.is_anonymous: r = getrower(request.user) else: # pragma: no cover r = None try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': script, div = course_map(race.course) resultobj = VirtualRaceResult else: script = '' div = '' resultobj = IndoorVirtualRaceResult records = resultobj.objects.filter(race=race) buttons = [] # to-do - add DNS dns = [] if timezone.now() > race.evaluation_closure: # pragma: no cover dns = resultobj.objects.filter( race=race, workoutid__isnull=True, ) if not request.user.is_anonymous: if race_can_register(r, race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] if request.method == 'POST': # pragma: no cover form = RaceResultFilterForm(request.POST, records=records) if form.is_valid(): cd = form.cleaned_data try: sex = cd['sex'] except KeyError: sex = ['female', 'male', 'mixed'] try: boattype = cd['boattype'] except KeyError: boattype = mytypes.waterboattype try: boatclass = cd['boatclass'] except KeyError: if race.sessiontype == 'race': boatclass = [t for t in mytypes.otwtypes] else: boatclass = [t for t in mytypes.otetypes] age_min = cd['age_min'] age_max = cd['age_max'] try: weightcategory = cd['weightcategory'] except KeyError: weightcategory = ['hwt', 'lwt'] try: adaptiveclass = cd['adaptiveclass'] except KeyError: adaptiveclass = ['None', 'PR1', 'PR2', 'PR3', 'FES'] if race.sessiontype == 'race': results = resultobj.objects.filter( race=race, workoutid__isnull=False, boatclass__in=boatclass, boattype__in=boattype, sex__in=sex, weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ).order_by("duration") else: results = resultobj.objects.filter( race=race, workoutid__isnull=False, boatclass__in=boatclass, sex__in=sex, weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ).order_by("duration", "-distance") # to-do - add DNS dns = [] if timezone.now() > race.evaluation_closure: dns = resultobj.objects.filter( race=race, workoutid__isnull=True, boatclass__in=boatclass, sex__in=sex, weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ) else: results = resultobj.objects.filter( race=race, workoutid__isnull=False, coursecompleted=True, ).order_by("duration", "-distance") if results: form = RaceResultFilterForm(records=records) else: # pragma: no cover form = None breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name } ] racelogos = race.logos.all() if racelogos: # pragma: no cover racelogo = racelogos[0] else: racelogo = None return render(request, 'virtualeventranking.html', { 'coursescript': script, 'coursediv': div, 'breadcrumbs': breadcrumbs, 'race': race, 'rower': r, 'results': results, 'buttons': buttons, 'dns': dns, 'records': records, 'racelogo': racelogo, 'form': form, 'active': 'nav-racing', }) @login_required() def virtualevent_withdraw_view(request, id=0, recordid=None): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race_can_withdraw(r, race): remove_rower_race(r, race, recordid=recordid) messages.info(request, "You have successfully withdrawn from this race.") else: # pragma: no cover messages.error(request, "You cannot withdraw from this race") url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) @login_required() def virtualevent_addboat_view(request, id=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype in ['race']: resultobj = VirtualRaceResult else: # pragma: no cover resultobj = IndoorVirtualRaceResult categories = None hasinitial, boattype, boatclass, adaptiveclass, weightclass, sex, referencespeed, initialcategory = default_class( r, None, race) if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") if not race_can_adddiscipline(r, race): # pragma: no cover messages.error(request, "You cannot register for this race") url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) records = resultobj.objects.filter( userid=r.id, race=race ) boattypes = [record.boattype for record in records] boatclasses = [record.boatclass for record in records] # we're still here if request.method == 'POST': # process form form = VirtualRaceResultForm(request.POST, categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] boattype = cd['boattype'] boatclass = cd['boatclass'] weightcategory = cd['weightcategory'] adaptiveclass = cd['adaptiveclass'] age = cd['age'] mix = cd['mix'] acceptsocialmedia = cd['acceptsocialmedia'] sex = r.sex if boattype == '1x' and r.birthdate: age = calculate_age(r.birthdate) sex = r.sex if sex == 'not specified': sex = 'male' if mix: # pragma: no cover sex = 'mixed' if boattype in boattypes and boatclass in boatclasses and race.coursestandards is None: # pragma: no cover # check if different sexes therecords = records.filter( boattype=boattype, boatclass=boatclass) thesexes = [record.sex for record in therecords] if sex in thesexes: messages.error( request, "You have already registered in that boat class/type" ) url = reverse('virtualevent_view', kwargs={ 'id': race.id } ) return HttpResponseRedirect(url) coursestandard = None referencespeed = 5.0 if race.coursestandards is not None: coursestandard = cd['entrycategory'] thegroups = [record.entrycategory for record in records] if coursestandard in thegroups: # pragma: no cover messages.error( request, "You have already registered in that group") url = reverse('virtualevent_view', kwargs={ 'id': race.id } ) return HttpResponseRedirect(url) referencespeed = coursestandard.referencespeed boattype = coursestandard.boattype boatclass = coursestandard.boatclass weightcategory = coursestandard.weightclass adaptiveclass = coursestandard.adaptiveclass returnurl = reverse(virtualevent_register_view, kwargs={'id': race.id}) if age < coursestandard.agemin: # pragma: no cover messages.error( request, 'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) if age > coursestandard.agemax: # pragma: no cover messages.error( request, 'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) if sex == 'male' and coursestandard.sex != 'male': # pragma: no cover messages.error( request, 'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) if sex == 'mixed' and coursestandard.sex not in ['mixed', 'male']: # pragma: no cover messages.error( request, 'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) record = resultobj( userid=r.id, teamname=teamname, race=race, username=u'{f} {l}'.format( f=r.user.first_name, l=r.user.last_name ), weightcategory=weightcategory, adaptiveclass=adaptiveclass, duration=datetime.time(0, 0), boattype=boattype, boatclass=boatclass, coursecompleted=False, referencespeed=referencespeed, entrycategory=coursestandard, sex=sex, age=age, acceptsocialmedia=acceptsocialmedia, ) record.save() add_rower_race(r, race) # send email about opt out if not acceptsocialmedia: _ = myqueue( queue, handle_sendemail_optout, race.manager.email, race.manager.first_name, r.user.first_name+' '+r.user.last_name, race.name, race.id, ) messages.info( request, "You have successfully registered for this race. Good luck!" ) otherrecords = resultobj.objects.filter( race=race).exclude(userid=r.id) registereduserids = [otherrecord.userid for otherrecord in otherrecords] for otherrecord in otherrecords: try: otheruser = Rower.objects.get(id=otherrecord.userid) othername = otheruser.user.first_name+' '+otheruser.user.last_name registeredname = r.user.first_name+' '+r.user.last_name if otherrecord.emailnotifications: _ = myqueue( queue, handle_sendemail_raceregistration, otheruser.user.email, othername, registeredname, race.name, race.id ) except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race=race) for follower in followers: othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name registeredname = r.user.first_name+' '+r.user.last_name email = follower.emailaddress try: if follower.user.id not in registereduserids: _ = myqueue( queue, handle_sendemail_raceregistration, email, othername, registeredname, race.name, race.id, ) registereduserids.append(follower.user.id) except AttributeError: pass url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: if hasinitial: initial = { 'age': calculate_age(r.birthdate), 'boattype': boattype, 'boatclass': boatclass, 'adaptiveclass': adaptiveclass, 'weightclass': weightclass, 'sex': sex, 'entrycategory': initialcategory, } else: # pragma: no cover initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, 'adaptiveclass': r.adaptiveclass, } categories = None if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") form = VirtualRaceResultForm(initial=initial, categories=categories) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse('virtualevent_addboat_view', kwargs={'id': race.id} ), 'name': 'Add Discipline' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'virtualeventregister.html', { 'form': form, 'buttons': buttons, 'breadcrumbs': breadcrumbs, 'race': race, 'userid': r.user.id, 'active': 'nav-racing', }) @login_required() def virtualevent_register_view(request, id=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") categories = None hasinitial, boattype, boatclass, adaptiveclass, weightclass, sex, referencespeed, initialcategory = default_class( r, None, race) if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") if not race_can_register(r, race): messages.error(request, "You cannot register for this race") url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) if race.sessiontype == 'race': resultobj = VirtualRaceResult else: # pragma: no cover resultobj = IndoorVirtualRaceResult # we're still here if request.method == 'POST': # process form form = VirtualRaceResultForm(request.POST, categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] boattype = cd['boattype'] boatclass = cd['boatclass'] weightcategory = cd['weightcategory'] adaptiveclass = cd['adaptiveclass'] age = cd['age'] mix = cd['mix'] acceptsocialmedia = cd['acceptsocialmedia'] sex = r.sex if boattype == '1x' and r.birthdate: age = calculate_age(r.birthdate) sex = r.sex if sex == 'not specified': sex = 'male' if mix: # pragma: no cover sex = 'mixed' coursestandard = None referencespeed = 5.0 if race.coursestandards is not None: coursestandard = cd['entrycategory'] referencespeed = coursestandard.referencespeed boattype = coursestandard.boattype boatclass = coursestandard.boatclass weightcategory = coursestandard.weightclass adaptiveclass = coursestandard.adaptiveclass returnurl = reverse(virtualevent_register_view, kwargs={'id': race.id}) if age < coursestandard.agemin: # pragma: no cover messages.error( request, 'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) if age > coursestandard.agemax: # pragma: no cover messages.error( request, 'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) if sex == 'male' and coursestandard.sex != 'male': # pragma: no cover messages.error( request, 'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) if sex == 'mixed' and coursestandard.sex not in ['mixed', 'male']: # pragma: no cover messages.error( request, 'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) record = resultobj( userid=r.id, teamname=teamname, race=race, username=u'{f} {l}'.format( f=r.user.first_name, l=r.user.last_name ), weightcategory=weightcategory, adaptiveclass=adaptiveclass, duration=datetime.time(0, 0), boatclass=boatclass, boattype=boattype, coursecompleted=False, sex=sex, age=age, entrycategory=coursestandard, referencespeed=referencespeed, acceptsocialmedia=acceptsocialmedia, ) record.save() add_rower_race(r, race) # send email about opt out if not acceptsocialmedia: _ = myqueue( queue, handle_sendemail_optout, race.manager.email, race.manager.first_name, r.user.first_name+' '+r.user.last_name, race.name, race.id, ) # remove followers myfollows = VirtualRaceFollower.objects.filter( user=r.user, race=race) for f in myfollows: # pragma: no cover f.delete() otherrecords = resultobj.objects.filter( race=race).exclude(userid=r.id) for otherrecord in otherrecords: try: otheruser = Rower.objects.get(id=otherrecord.userid) othername = otheruser.user.first_name+' '+otheruser.user.last_name registeredname = r.user.first_name+' '+r.user.last_name if otherrecord.emailnotifications: _ = myqueue( queue, handle_sendemail_raceregistration, otheruser.user.email, othername, registeredname, race.name, race.id ) except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race=race) for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name registeredname = r.user.first_name+' '+r.user.last_name email = follower.emailaddress _ = myqueue( queue, handle_sendemail_raceregistration, email, othername, registeredname, race.name, race.id, ) messages.info( request, "You have successfully registered for this race. Good luck!" ) url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: if hasinitial: initial = { 'age': calculate_age(r.birthdate), 'boattype': boattype, 'boatclass': boatclass, 'adaptiveclass': adaptiveclass, 'weightclass': weightclass, 'sex': sex, 'entrycategory': initialcategory, } else: # pragma: no cover initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, 'adaptiveclass': r.adaptiveclass, } categories = None if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") form = VirtualRaceResultForm(initial=initial, categories=categories) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(virtualevent_register_view, kwargs={'id': race.id} ), 'name': 'Register' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): buttons += ['registerbutton'] if race_can_adddiscipline(r, race): # pragma: no cover buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'virtualeventregister.html', { 'form': form, 'buttons': buttons, 'breadcrumbs': breadcrumbs, 'race': race, 'userid': r.user.id, }) @login_required() def virtualevent_toggle_email_view(request, id=0): r = getrower(request.user) race = VirtualRace.objects.get(id=id) records = VirtualRaceResult.objects.filter(userid=r.id, race=race) if True in [record.emailnotifications for record in records]: newsetting = False else: # pragma: no cover newsetting = True for record in records: record.emailnotifications = newsetting record.save() url = reverse('virtualevent_view', kwargs={'id': race.id}) return HttpResponseRedirect(url) @login_required() def indoorvirtualevent_toggle_email_view(request, id=0): r = getrower(request.user) race = VirtualRace.objects.get(id=id) records = IndoorVirtualRaceResult.objects.filter(userid=r.id, race=race) if True in [record.emailnotifications for record in records]: newsetting = False else: # pragma: no cover newsetting = True for record in records: record.emailnotifications = newsetting record.save() url = reverse('virtualevent_view', kwargs={'id': race.id}) return HttpResponseRedirect(url) @login_required() def indoorvirtualevent_register_view(request, id=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") categories = None if race.coursestandards is not None: # pragma: no cover categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") if not race_can_register(r, race): messages.error(request, "You cannot register for this race") url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) # we're still here if request.method == 'POST': # process form form = IndoorVirtualRaceResultForm(request.POST, categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] weightcategory = cd['weightcategory'] adaptiveclass = cd['adaptiveclass'] age = cd['age'] boatclass = cd['boatclass'] acceptsocialmedia = cd['acceptsocialmedia'] sex = r.sex if r.birthdate: age = calculate_age(r.birthdate) sex = r.sex if sex == 'not specified': sex = 'male' coursestandard = None referencespeed = 5.0 if race.coursestandards is not None: # pragma: no cover coursestandard = cd['entrycategory'] referencespeed = coursestandard.referencespeed boatclass = coursestandard.boatclass weightcategory = coursestandard.weightclass adaptiveclass = coursestandard.adaptiveclass returnurl = reverse(virtualevent_register_view, kwargs={'id': race.id}) if age < coursestandard.agemin: messages.error( request, 'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) if age > coursestandard.agemax: messages.error( request, 'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) if sex == 'male' and coursestandard.sex != 'male': messages.error( request, 'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) if sex == 'mixed' and coursestandard.sex not in ['mixed', 'male']: messages.error( request, 'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) record = IndoorVirtualRaceResult( userid=r.id, teamname=teamname, race=race, username=u'{f} {l}'.format( f=r.user.first_name, l=r.user.last_name ), weightcategory=weightcategory, adaptiveclass=adaptiveclass, duration=datetime.time(0, 0), boatclass=boatclass, coursecompleted=False, sex=sex, age=age, entrycategory=coursestandard, referencespeed=referencespeed, acceptsocialmedia=acceptsocialmedia, ) record.save() add_rower_race(r, race) # send email about opt out if not acceptsocialmedia: _ = myqueue( queue, handle_sendemail_optout, race.manager.email, race.manager.first_name, r.user.first_name+' '+r.user.last_name, race.name, race.id, ) # remove followers myfollows = VirtualRaceFollower.objects.filter( user=r.user, race=race) for f in myfollows: # pragma: no cover f.delete() otherrecords = IndoorVirtualRaceResult.objects.filter( race=race).exclude(userid=r.id) for otherrecord in otherrecords: try: otheruser = Rower.objects.get(id=otherrecord.userid) othername = otheruser.user.first_name+' '+otheruser.user.last_name registeredname = r.user.first_name+' '+r.user.last_name if otherrecord.emailnotifications: _ = myqueue( queue, handle_sendemail_raceregistration, otheruser.user.email, othername, registeredname, race.name, race.id ) except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race=race) for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name registeredname = r.user.first_name+' '+r.user.last_name email = follower.emailaddress _ = myqueue( queue, handle_sendemail_raceregistration, email, othername, registeredname, race.name, race.id, ) messages.info( request, "You have successfully registered for this race. Good luck!" ) url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, 'adaptiveclass': r.adaptiveclass, } categories = None if race.coursestandards is not None: # pragma: no cover categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") form = IndoorVirtualRaceResultForm( initial=initial, categories=categories) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(indoorvirtualevent_register_view, kwargs={'id': race.id} ), 'name': 'Register' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): buttons += ['registerbutton'] if race_can_adddiscipline(r, race): # pragma: no cover buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'virtualeventregister.html', { 'form': form, 'buttons': buttons, 'race': race, 'breadcrumbs': breadcrumbs, 'userid': r.user.id, }) @login_required() def indoorvirtualevent_create_view(request): r = getrower(request.user) if request.method == 'POST': racecreateform = IndoorVirtualRaceForm(request.POST) if racecreateform.is_valid(): cd = racecreateform.cleaned_data startdate = cd['startdate'] start_time = cd['start_time'] enddate = cd['enddate'] end_time = cd['end_time'] comment = cd['comment'] sessionunit = cd['sessionunit'] sessionvalue = cd['sessionvalue'] name = cd['name'] registration_form = cd['registration_form'] registration_closure = cd['registration_closure'] evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] coursestandards = cd['coursestandards'] # correct times timezone_str = cd['timezone'] startdatetime = datetime.datetime.combine(startdate, start_time) enddatetime = datetime.datetime.combine(enddate, end_time) startdatetime = pytz.timezone(timezone_str).localize( startdatetime ) enddatetime = pytz.timezone(timezone_str).localize( enddatetime ) evaluation_closure = pytz.timezone(timezone_str).localize( evaluation_closure.replace(tzinfo=None) ) if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str ).localize( registration_closure.replace(tzinfo=None) ) except AttributeError: registration_closure = startdatetime elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure if sessionunit == 'min': # pragma: no cover sessionmode = 'time' else: sessionmode = 'distance' vs = VirtualRace( name=name, startdate=startdate, preferreddate=startdate, start_time=start_time, enddate=enddate, end_time=end_time, comment=comment, sessiontype='indoorrace', sessionunit=sessionunit, sessionmode=sessionmode, sessionvalue=sessionvalue, course=None, timezone=timezone_str, coursestandards=coursestandards, evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, contact_email=contact_email, country='Indoor', manager=request.user, ) vs.save() announcementshort = "New Virtual Indoor Challenge on rowsandall.com: {name}".format( name=name, ) announcement = announcementshort + " {siteurl}/rowers/virtualevent/{raceid}/".format( siteurl=SITE_URL, raceid=vs.id ) if len(announcement) > 250: # pragma: no cover announcement = announcementshort sa = SiteAnnouncement( announcement=announcement, ) sa.save() url = reverse('virtualevents_view') return HttpResponseRedirect(url) else: racecreateform = IndoorVirtualRaceForm(timezone=r.defaulttimezone) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('indoorvirtualevent_create_view', ), 'name': 'New Indoor Virtual Regatta' }, ] return render(request, 'indoorvirtualeventcreate.html', { 'form': racecreateform, 'breadcrumbs': breadcrumbs, 'rower': r, 'active': 'nav-racing', }) @login_required() def fastestvirtualevent_create_view(request): r = getrower(request.user) if request.method == 'POST': racecreateform = IndoorVirtualRaceForm(request.POST) if racecreateform.is_valid(): cd = racecreateform.cleaned_data startdate = cd['startdate'] start_time = cd['start_time'] enddate = cd['enddate'] end_time = cd['end_time'] comment = cd['comment'] sessionunit = cd['sessionunit'] sessionvalue = cd['sessionvalue'] name = cd['name'] registration_form = cd['registration_form'] registration_closure = cd['registration_closure'] evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] coursestandards = cd['coursestandards'] # correct times timezone_str = cd['timezone'] startdatetime = datetime.datetime.combine(startdate, start_time) enddatetime = datetime.datetime.combine(enddate, end_time) startdatetime = pytz.timezone(timezone_str).localize( startdatetime ) enddatetime = pytz.timezone(timezone_str).localize( enddatetime ) evaluation_closure = pytz.timezone(timezone_str).localize( evaluation_closure.replace(tzinfo=None) ) if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str ).localize( registration_closure.replace(tzinfo=None) ) except AttributeError: registration_closure = startdatetime elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure if sessionunit == 'min': # pragma: no cover sessionmode = 'time' sessiontype = 'fastest_time' else: sessionmode = 'distance' sessiontype = 'fastest_distance' vs = VirtualRace( name=name, startdate=startdate, preferreddate=startdate, start_time=start_time, enddate=enddate, end_time=end_time, comment=comment, sessiontype=sessiontype, sessionunit=sessionunit, sessionmode=sessionmode, sessionvalue=sessionvalue, course=None, timezone=timezone_str, coursestandards=coursestandards, evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, contact_email=contact_email, country='Indoor', manager=request.user, ) vs.save() if vs.sessiontype == 'fastest_distance': vs.approximate_distance = vs.sessionvalue vs.save() announcementshort = "New Virtual Challenge on rowsandall.com: {name}".format( name=name, ) announcement = announcementshort + " {siteurl}/rowers/virtualevent/{raceid}/".format( siteurl=SITE_URL, raceid=vs.id ) if len(announcement) > 250: # pragma: no cover announcement = announcementshort sa = SiteAnnouncement( announcement=announcement, ) sa.save() url = reverse('virtualevents_view') return HttpResponseRedirect(url) else: racecreateform = IndoorVirtualRaceForm(timezone=r.defaulttimezone) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('indoorvirtualevent_create_view', ), 'name': 'New Indoor Virtual Regatta' }, ] return render(request, 'fastestvirtualeventcreate.html', { 'form': racecreateform, 'breadcrumbs': breadcrumbs, 'rower': r, 'active': 'nav-racing', }) @login_required() def virtualevent_create_view(request): r = getrower(request.user) if request.method == 'POST': racecreateform = VirtualRaceForm(request.POST) if racecreateform.is_valid(): cd = racecreateform.cleaned_data startdate = cd['startdate'] start_time = cd['start_time'] enddate = cd['enddate'] end_time = cd['end_time'] comment = cd['comment'] course = cd['course'] name = cd['name'] registration_form = cd['registration_form'] registration_closure = cd['registration_closure'] evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] coursestandards = cd['coursestandards'] # correct times geocourse = GeoCourse.objects.get(id=course.id) timezone_str = get_course_timezone(geocourse) startdatetime = datetime.datetime.combine(startdate, start_time) enddatetime = datetime.datetime.combine(enddate, end_time) startdatetime = pytz.timezone(timezone_str).localize( startdatetime ) enddatetime = pytz.timezone(timezone_str).localize( enddatetime ) evaluation_closure = pytz.timezone(timezone_str).localize( evaluation_closure.replace(tzinfo=None) ) if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str ).localize( registration_closure.replace(tzinfo=None) ) except AttributeError: registration_closure = startdatetime elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure vs = VirtualRace( name=name, startdate=startdate, preferreddate=startdate, start_time=start_time, enddate=enddate, end_time=end_time, course=geocourse, comment=comment, sessiontype='race', timezone=timezone_str, evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, coursestandards=coursestandards, contact_email=contact_email, country=course.country, manager=request.user, ) vs.save() announcementshort = "New Virtual Challenge on rowsandall.com: {name} on course {course}".format( name=name, course=course.name, ) announcement = announcementshort + " {siteurl}/rowers/virtualevent/{raceid}/".format( siteurl=SITE_URL, raceid=vs.id ) if len(announcement) > 250: # pragma: no cover announcement = announcementshort sa = SiteAnnouncement( announcement=announcement, ) sa.save() url = reverse('virtualevents_view') return HttpResponseRedirect(url) else: racecreateform = VirtualRaceForm() breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse(virtualevent_create_view, ), 'name': 'New Virtual Regatta' }, ] return render(request, 'virtualeventcreate.html', { 'form': racecreateform, 'breadcrumbs': breadcrumbs, 'rower': r, 'active': 'nav-racing', }) @login_required() @permission_required('virtualevent.change_race', fn=get_virtualevent_by_pk, raise_exception=True) def virtualevent_edit_view(request, id=0): r = getrower(request.user) race = get_object_or_404(VirtualRace, pk=id) start_time = race.start_time start_date = race.startdate startdatetime = datetime.datetime.combine(start_date, start_time) startdatetime = pytz.timezone(race.timezone).localize( startdatetime ) end_time = race.end_time end_date = race.enddate enddatetime = datetime.datetime.combine(end_date, end_time) enddatetime = pytz.timezone(race.timezone).localize( enddatetime ) if timezone.now() > enddatetime: # pragma: no cover messages.error( request, "You cannot edit a race after the end of the race window") url = reverse('virtualevent_view', kwargs={ 'id': race.id, }) if request.method == 'POST': racecreateform = VirtualRaceForm(request.POST, instance=race) if racecreateform.is_valid(): cd = racecreateform.cleaned_data res, message = update_virtualrace(race, cd) if res: messages.info(request, message) else: # pragma: no cover messages.error(request, message) url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: racecreateform = VirtualRaceForm(instance=race) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(virtualevent_edit_view, kwargs={'id': race.id} ), 'name': 'Edit' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): buttons += ['registerbutton'] if race_can_adddiscipline(r, race): # pragma: no cover buttons += ['adddisciplinebutton'] if race_can_submit(r, race): # pragma: no cover buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'virtualeventedit.html', { 'form': racecreateform, 'breadcrumbs': breadcrumbs, 'buttons': buttons, 'rower': r, 'race': race, }) @login_required() @permission_required('virtualevent.change_race', fn=get_virtualevent_by_pk, raise_exception=True) def indoorvirtualevent_edit_view(request, id=0): r = getrower(request.user) race = get_object_or_404(VirtualRace, pk=id) start_time = race.start_time start_date = race.startdate startdatetime = datetime.datetime.combine(start_date, start_time) startdatetime = pytz.timezone(race.timezone).localize( startdatetime ) end_time = race.end_time end_date = race.enddate enddatetime = datetime.datetime.combine(end_date, end_time) enddatetime = pytz.timezone(race.timezone).localize( enddatetime ) if timezone.now() > enddatetime: # pragma: no cover messages.error( request, "You cannot edit a race after the end of the race window") url = reverse('virtualevent_view', kwargs={ 'id': race.id, }) if request.method == 'POST': racecreateform = IndoorVirtualRaceForm(request.POST, instance=race) if racecreateform.is_valid(): cd = racecreateform.cleaned_data res, message = update_indoorvirtualrace(race, cd) if res: messages.info(request, message) else: # pragma: no cover messages.error(request, message) url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: racecreateform = IndoorVirtualRaceForm(instance=race) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(indoorvirtualevent_edit_view, kwargs={'id': race.id} ), 'name': 'Edit' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): buttons += ['registerbutton'] if race_can_adddiscipline(r, race): # pragma: no cover buttons += ['adddisciplinebutton'] if race_can_submit(r, race): # pragma: no cover buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'virtualeventedit.html', { 'form': racecreateform, 'buttons': buttons, 'breadcrumbs': breadcrumbs, 'rower': r, 'race': race, }) @login_required() def virtualevent_submit_result_view(request, id=0, workoutid=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") start_time = race.start_time start_date = race.startdate startdatetime = datetime.datetime.combine(start_date, start_time) startdatetime = pytz.timezone(race.timezone).localize(startdatetime) end_time = race.end_time end_date = race.enddate enddatetime = datetime.datetime.combine(end_date, end_time) enddatetime = pytz.timezone(race.timezone).localize(enddatetime) can_submit = race_can_submit(r, race) or race_can_resubmit(r, race) if race.sessiontype == 'race': resultobj = VirtualRaceResult else: resultobj = IndoorVirtualRaceResult records = resultobj.objects.filter( userid=r.id, race=race ) if records.count() == 0: # pragma: no cover ( hasinitial, boattype, boatclass, adaptiveclass, weightclass, sex, referencespeed, initialcategory) = default_class(r, None, race) if not hasinitial: messages.error(request, "Sorry, you have to register first") url = reverse('virtualevent_view', kwargs={ 'id': id, }) return HttpResponseRedirect(url) record = resultobj( userid=r.id, username=r.user.first_name+' '+r.user.last_name, weightcategory=weightclass, adaptiveclass=adaptiveclass, race=race, boatclass=boatclass, sex=sex, age=calculate_age(r.birthdate), entrycategory=initialcategory, referencespeed=referencespeed, ) record.save() records = [record] entrychoices = [] for record in records: rtpl = (record.id, record.__str__()) entrychoices.append(rtpl) entries = {} entries['choices'] = entrychoices entries['initial'] = [records[0].id] if not can_submit: # pragma: no cover messages.error(request, 'You cannot submit a result to this race') url = reverse('virtualevent_view', kwargs={ 'id': id } ) return HttpResponseRedirect(url) ws = Workout.objects.filter( user=r, # workouttype__in=mytypes.rowtypes, startdatetime__gte=startdatetime, startdatetime__lte=enddatetime, distance__gte=race.approximate_distance, ).order_by("-date", "-startdatetime", "id").exclude(workoutsource='strava') if not ws: # pragma: no cover messages.info( request, 'You have no eligible workouts executed during the race window. Please upload a result or enter it manually.' ) url = reverse('virtualevent_view', kwargs={ 'id': id }) return HttpResponseRedirect(url) initialworkouts = [w.id for w in Workout.objects.filter( user=r, plannedsession=race )] workoutdata = {} workoutdata['initial'] = [] choices = [] for w in ws: wtpl = (w.id, w.__str__()) choices.append(wtpl) if w.id in initialworkouts: # pragma: no cover workoutdata['initial'].append(w.id) workoutdata['choices'] = tuple(choices) if request.method == 'POST': w_form = WorkoutRaceSelectForm(workoutdata, entries, request.POST) if w_form.is_valid(): selectedworkout = w_form.cleaned_data['workouts'] splitsecond = 0 recordid = w_form.cleaned_data['record'] else: messages.error(request,"Error in form") selectedworkout = None if selectedworkout is not None: workouts = Workout.objects.filter(id=selectedworkout) if race.sessiontype == 'race': result, comments, errors, jobid = add_workout_race( workouts, race, r, splitsecond=splitsecond, recordid=recordid) elif race.sessiontype in ['fastest_time', 'fastest_distance']: # pragma: no cover result, comments, errors, jobid = add_workout_fastestrace( workouts, race, r, recordid=recordid ) else: result, comments, errors, jobid = add_workout_indoorrace( workouts, race, r, recordid=recordid) for c in comments: messages.info(request, c) for er in errors: messages.error(request, er) if jobid: try: request.session['async_tasks'] += [(jobid, 'submit_race')] except KeyError: request.session['async_tasks'] = [(jobid, 'submit_race')] messages.info( request, "We are evaluating your result." " The page will reload when we're done. Your result will show up if you adhered" " to the course") if result: otherrecords = resultobj.objects.filter( race=race).exclude(userid=r.id) if not jobid: messages.info(request, "Result submitted successfully.") for otherrecord in otherrecords: try: otheruser = Rower.objects.get(id=otherrecord.userid) othername = otheruser.user.first_name+' '+otheruser.user.last_name registeredname = r.user.first_name+' '+r.user.last_name if otherrecord.emailnotifications: _ = myqueue( queue, handle_sendemail_racesubmission, otheruser.user.email, othername, registeredname, race.name, race.id ) except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race=race) for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name registeredname = r.user.first_name+' '+r.user.last_name email = follower.emailaddress _ = myqueue( queue, handle_sendemail_racesubmission, email, othername, registeredname, race.name, race.id, ) # redirect to race page url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: if workoutid: try: w = Workout.objects.get(id=workoutid) if w.workoutsource != 'strava': workoutdata['initial'] = encoder.decode_hex(workoutid) except Workout.DoesNotExist: pass w_form = WorkoutRaceSelectForm(workoutdata, entries) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(virtualevent_submit_result_view, kwargs={'id': race.id} ), 'name': 'Submit Result' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'race_submit.html', { 'race': race, 'buttons': buttons, 'workouts': ws, 'breadcrumbs': breadcrumbs, 'active': 'nav-racing', 'rower': r, 'w_form': w_form, }) def addfollower_view(request, id=0): try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if not request.user.is_anonymous: follower = VirtualRaceFollower( user=request.user, race=race, emailaddress=request.user.email ) follower.save() messages.info( request, "You will receive challenge notifications per email") url = reverse(virtualevent_view, kwargs={'id': id}) return HttpResponseRedirect(url) # Anonymous if request.method == 'POST': # pragma: no cover form = FollowerForm(request.POST) if form.is_valid(): email = form.cleaned_data['emailaddress'] follower = VirtualRaceFollower( race=race, emailaddress=email ) follower.save() messages.info( request, "You will receive challenge notifications per email") url = reverse(virtualevent_view, kwargs={'id': id}) return HttpResponseRedirect(url) else: # pragma: no cover form = FollowerForm() breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(addfollower_view, kwargs={'id': race.id} ), 'name': 'Follow' } ] # pragma: no cover return render(request, 'followerform.html', { 'form': form, 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, } ) # pragma: no cover @login_required() def virtualevent_entry_edit_view(request, id=0, entryid=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if not race_can_editentry(r, race): # pragma: no cover messages.error( request, 'You cannot change your entries for this challenge') url = reverse('virtualevent_view', kwargs={'id': race.id} ) return HttpResponseRedirect(url) categories = None if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") if race.sessiontype == 'race': resultobj = VirtualRaceResult formobj = VirtualRaceResultForm elif race.sessiontype in ['fastest_distance', 'fastest_time']: # pragma: no cover resultobj = IndoorVirtualRaceResult formobj = VirtualRaceResultForm else: # pragma: no cover resultobj = IndoorVirtualRaceResult formobj = IndoorVirtualRaceResultForm records = resultobj.objects.filter( userid=r.id, race=race ).exclude(id=entryid) try: record = resultobj.objects.get(id=entryid) except resultobj.DoesNotExist: # pragma: no cover raise Http404("Could not find your entry") if request.method == 'POST': form = formobj(request.POST, categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] try: boattype = cd['boattype'] except KeyError: # pragma: no cover boattype = None boatclass = cd['boatclass'] weightcategory = cd['weightcategory'] adaptiveclass = cd['adaptiveclass'] age = cd['age'] try: mix = cd['mix'] except KeyError: # pragma: no cover mix = None acceptsocialmedia = cd['acceptsocialmedia'] sex = r.sex if mix: # pragma: no cover sex = 'mixed' if boattype == '1x' and r.birthdate: age = calculate_age(r.birthdate) if sex == 'not specified': sex = 'male' coursestandard = None referencespeed = 5.0 returnurl = reverse(virtualevent_entry_edit_view, kwargs={'id': race.id, 'entryid': record.id}) if race.coursestandards is not None: coursestandard = cd['entrycategory'] referencespeed = coursestandard.referencespeed boattype = coursestandard.boattype boatclass = coursestandard.boatclass weightcategory = coursestandard.weightclass adaptiveclass = coursestandard.adaptiveclass if age < coursestandard.agemin: # pragma: no cover messages.error( request, 'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) if age > coursestandard.agemax: # pragma: no cover messages.error( request, 'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) if sex == 'male' and coursestandard.sex != 'male': # pragma: no cover messages.error( request, 'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) if sex == 'mixed' and coursestandard.sex not in ['mixed', 'male']: # pragma: no cover messages.error( request, 'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) if record.workoutid: # pragma: no cover try: w = Workout.objects.get(id=record.workoutid) except Workout.DoesNotExist: # pragma: no cover w = None if w is not None: if boattype != w.boattype: messages.error( request, 'You cannot change boat type to a different one than your row') return HttpResponseRedirect(returnurl) if boatclass != w.workouttype: messages.error( request, 'You cannot change the class to a different one than your row') return HttpResponseRedirect(returnurl) if weightcategory != w.weightcategory: messages.error( request, 'You cannot change weight class to a different one than your row') return HttpResponseRedirect(returnurl) if adaptiveclass != w.adaptiveclass: messages.error( request, 'You cannot change adaptive class to a different one than your row') return HttpResponseRedirect(returnurl) else: if boattype != record.boattype: messages.error( request, 'You cannot change boat type to a different one ') return HttpResponseRedirect(returnurl) if boatclass != record.boatclass: messages.error( request, 'You cannot change the class to a different one ') return HttpResponseRedirect(returnurl) if weightcategory != record.weightcategory: messages.error( request, 'You cannot change weight class to a different one ') return HttpResponseRedirect(returnurl) if adaptiveclass != record.adaptiveclass: messages.error( request, 'You cannot change adaptive class to a different one ') return HttpResponseRedirect(returnurl) if record.points != 0: # pragma: no cover if race.sessiontype == 'race': coursedistance = race.course.distance else: coursedistance = record.distance v = coursedistance / \ timefield_to_seconds_duration(record.duration) points = 100.*(2-(referencespeed/v)) record.points = points record.teamname = teamname record.weightcategory = weightcategory record.adaptiveclass = adaptiveclass record.boatclass = boatclass if race.sessiontype == 'race': record.boattype = boattype record.mix = mix record.sex = sex record.age = age record.entrycategory = coursestandard record.referencespeed = referencespeed record.acceptsocialmedia = acceptsocialmedia duplicates = False for otherrecord in records: if record.isduplicate(otherrecord): # pragma: no cover duplicates = True if duplicates: # pragma: no cover messages.error(request, "You have already entered this group") return HttpResponseRedirect(returnurl) else: record.save() messages.info( request, "You have successfully altered your entry for this race. Good luck!" ) url = reverse('virtualevent_view', kwargs={ 'id': race.id }) return HttpResponseRedirect(url) else: form = formobj(instance=record, categories=categories) breadcrumbs = [ { 'url': reverse('virtualevents_view'), 'name': 'Challenges' }, { 'url': reverse('virtualevent_view', kwargs={'id': race.id} ), 'name': race.name }, { 'url': reverse(virtualevent_entry_edit_view, kwargs={'id': race.id, 'entryid': entryid} ), 'name': 'Follow' } ] buttons = [] if not request.user.is_anonymous: if race_can_register(r, race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r, race): buttons += ['adddisciplinebutton'] if race_can_submit(r, race): buttons += ['submitbutton'] if race_can_resubmit(r, race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r, race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r, race): buttons += ['editbutton'] return render(request, 'entryedit.html', { 'form': form, 'active': 'nav-racing', 'breadcrumbs': breadcrumbs, 'userid': r.user.id, 'race': race, })