示例#1
0
class MembershipStatusesView(View):
    def post(self, request, *args, **kwargs):
        """ Return a mapping of participant IDs to membership statuses. """
        postdata = json.loads(self.request.body)
        par_pks = postdata.get('participant_ids')
        if not isinstance(par_pks, list):
            return JsonResponse({'message': 'Bad request'}, status=400)

        # Span databases to map from participants -> users -> email addresses
        participants = models.Participant.objects.filter(pk__in=par_pks)
        user_to_par = dict(participants.values_list('user_id', 'pk'))
        email_addresses = EmailAddress.objects.filter(user_id__in=user_to_par)
        email_to_user = dict(email_addresses.values_list('email', 'user_id'))

        # Gives email -> membership info for all matches
        matches = geardb_utils.matching_memberships(email_to_user)

        # Default to blank memberships in case not found
        no_membership = geardb_utils.repr_blank_membership()
        participant_memberships = {pk: no_membership for pk in par_pks}

        # Update participants where matching membership information was found
        for email, membership in matches.iteritems():
            par_pk = user_to_par[email_to_user[email]]
            # We might overwrite a previous membership record, but that will
            # only happen if the user has memberships under 2+ emails
            # (Older memberships come first, so this will safely yield the newest)
            participant_memberships[par_pk] = membership

        return JsonResponse({'memberships': participant_memberships})

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super(MembershipStatusesView,
                     self).dispatch(request, *args, **kwargs)
示例#2
0
class MembershipStatsView(TemplateView):
    template_name = 'stats/membership.html'

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        # TODO: Restrict to BOD only
        return super().dispatch(request, *args, **kwargs)
示例#3
0
class CreateTripView(CreateView):
    model = models.Trip
    form_class = forms.TripForm
    template_name = 'trips/create.html'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['initial'] = kwargs.get('initial', {})
        if not self.request.user.is_superuser:
            allowed_programs = list(self.request.participant.allowed_programs)
            kwargs['allowed_programs'] = allowed_programs

            if is_currently_iap(
            ) and enums.Program.WINTER_SCHOOL in allowed_programs:
                kwargs['initial'][
                    'program'] = enums.Program.WINTER_SCHOOL.value
            else:
                # The first program may not be open to the leader.
                # We restrict choices, so ensure leader can lead this program.
                allowed_program = next(iter(allowed_programs))
                kwargs['initial']['program'] = allowed_program.value
        return kwargs

    def get_success_url(self):
        return reverse('view_trip', args=(self.object.pk, ))

    def get_initial(self):
        """Default with trip creator among leaders."""
        initial = super().get_initial().copy()
        # It's possible for WSC to create trips while not being a leader
        if perm_utils.is_leader(self.request.user):
            initial['leaders'] = [self.request.participant]
        return initial

    def form_valid(self, form):
        """After is_valid(), assign creator from User, add empty waitlist."""
        creator = self.request.participant
        trip = form.save(commit=False)
        trip.creator = creator
        trip.last_updated_by = creator
        trip.activity = trip.get_legacy_activity()
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['is_currently_iap'] = is_currently_iap()

        # There is separate logic for determining if we allow choosing the WS program.
        # Rather than duplicate that logic here, just see if it's a selectable choice.
        form: forms.TripForm = context['form']
        context['can_select_ws_program'] = any(
            enums.Program(value) == enums.Program.WINTER_SCHOOL
            for category, choices in form.fields['program'].choices
            for value, label in choices)
        return context

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#4
0
class RawMembershipStatsView(View):
    def get(self, request, *args, **kwargs):
        return JsonResponse(
            {'members': list(geardb_utils.membership_information().values())})

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        # TODO: Restrict to BOD only
        return super().dispatch(request, *args, **kwargs)
示例#5
0
class LeaderSignUpView(BaseSignUpView):
    model = models.LeaderSignUp
    form_class = forms.LeaderSignUpForm

    def get_errors(self, signup):
        errors = super().get_errors(signup)
        if not signup.participant.can_lead(signup.trip.activity):
            errors.append("Can't lead {} trips!".format(signup.trip.activity))
        return errors

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#6
0
class WinterSchoolSettingsView(CreateView):
    form_class = forms.WinterSchoolSettingsForm
    template_name = 'chair/settings.html'

    def get_form_kwargs(self):
        """ Load existing settings. """
        kwargs = super().get_form_kwargs()
        kwargs['instance'] = models.WinterSchoolSettings.load()
        return kwargs

    def get_success_url(self):
        messages.success(self.request, "Updated Winter School settings!")
        return reverse('ws_settings')

    @method_decorator(group_required('WSC'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
class ParticipantLookupView(TemplateView, FormView):
    template_name = 'participants/view.html'
    form_class = forms.ParticipantLookupForm

    def get_context_data(self, **kwargs):
        context = super().get_context_data()
        context['user_viewing'] = False
        context['lookup_form'] = self.get_form(self.form_class)
        return context

    def form_valid(self, form):
        participant = form.cleaned_data['participant']
        return redirect(reverse('view_participant', args=(participant.id, )))

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#8
0
class CreateTripView(CreateView):
    model = models.Trip
    form_class = forms.TripForm
    template_name = 'trips/create.html'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['initial'] = kwargs.get('initial', {})
        if not self.request.user.is_superuser:
            allowed_programs = list(self.request.participant.allowed_programs)
            kwargs['allowed_programs'] = allowed_programs

            if is_currently_iap(
            ) and enums.Program.WINTER_SCHOOL in allowed_programs:
                kwargs['initial'][
                    'program'] = enums.Program.WINTER_SCHOOL.value
            else:
                # The first program may not be open to the leader.
                # We restrict choices, so ensure leader can lead this program.
                allowed_program = next(iter(allowed_programs))
                kwargs['initial']['program'] = allowed_program.value
        return kwargs

    def get_success_url(self):
        return reverse('view_trip', args=(self.object.pk, ))

    def get_initial(self):
        """ Default with trip creator among leaders. """
        initial = super().get_initial().copy()
        # It's possible for WSC to create trips while not being a leader
        if perm_utils.is_leader(self.request.user):
            initial['leaders'] = [self.request.participant]
        return initial

    def form_valid(self, form):
        """ After is_valid(), assign creator from User, add empty waitlist. """
        creator = self.request.participant
        trip = form.save(commit=False)
        trip.creator = creator
        trip.activity = trip.get_legacy_activity()
        return super().form_valid(form)

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#9
0
class AllTripsMedicalView(ListView):
    model = models.Trip
    template_name = 'trips/all/medical.html'
    context_object_name = 'trips'

    def get_queryset(self):
        trips = super().get_queryset().order_by('trip_date')
        today = local_date()
        return trips.filter(trip_date__gte=today)

    def get_context_data(self, **kwargs):
        context_data = super().get_context_data(**kwargs)
        context_data['wimps'] = wimp.active_wimps()
        return context_data

    @method_decorator(group_required('WSC', 'WIMP'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#10
0
class CreateTripView(CreateView):
    model = models.Trip
    form_class = forms.TripForm
    template_name = 'trips/create.html'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['initial'] = kwargs.get('initial', {})
        if not self.request.user.is_superuser:
            allowed_activities = self.request.participant.allowed_activities
            kwargs['allowed_activities'] = allowed_activities

            if is_winter_school() and 'winter_school' in allowed_activities:
                kwargs['initial']['activity'] = 'winter_school'
            else:
                # The first activity may not be open to the leader.
                # We restrict choices, so ensure leader can lead this activity.
                kwargs['initial']['activity'] = kwargs['allowed_activities'][0]
        return kwargs

    def get_success_url(self):
        return reverse('view_trip', args=(self.object.pk, ))

    def get_initial(self):
        """ Default with trip creator among leaders. """
        initial = super().get_initial().copy()
        # It's possible for WSC to create trips while not being a leader
        if perm_utils.is_leader(self.request.user):
            initial['leaders'] = [self.request.participant]
        return initial

    def form_valid(self, form):
        """ After is_valid(), assign creator from User, add empty waitlist. """
        creator = self.request.participant
        trip = form.save(commit=False)
        trip.creator = creator
        return super().form_valid(form)

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#11
0
class AllLeadersView(ListView):
    model = models.Participant
    context_object_name = 'leaders'
    template_name = 'leaders/all.html'

    def get_queryset(self):
        """ Returns all leaders with active ratings. """
        return models.Participant.leaders.get_queryset()

    def get_context_data(self, **kwargs):
        context_data = super().get_context_data(**kwargs)

        context_data['activities'] = [(activity_enum.value,
                                       activity_enum.label)
                                      for activity_enum in enums.Activity
                                      if activity_enum != enums.Activity.CABIN]
        return context_data

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#12
0
class AllLeadersView(ListView):
    model = models.Participant
    context_object_name = 'leaders'
    template_name = 'leaders/all.html'

    def get_queryset(self):
        """ Returns all leaders with active ratings. """
        return models.Participant.leaders.get_queryset()

    def get_context_data(self, **kwargs):
        context_data = super().get_context_data(**kwargs)

        closed_activities = models.LeaderRating.CLOSED_ACTIVITY_CHOICES
        activities = [(val, label) for (val, label) in closed_activities
                      if val != 'cabin']
        context_data['activities'] = activities
        return context_data

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#13
0
class AllTripsMedicalView(ListView, TripMedical):
    model = models.Trip
    template_name = 'trips/all/medical.html'
    context_object_name = 'trips'

    def get_queryset(self):
        trips = super().get_queryset().order_by('trip_date')
        today = local_date()
        return trips.filter(trip_date__gte=today)

    def get_context_data(self, **kwargs):
        context_data = super().get_context_data(**kwargs)
        by_trip = (self.get_trip_info(trip) for trip in self.get_queryset())
        all_trips = [(c['trip'], c['participants'], c['trip_leaders'],
                      c['cars'], c['info_form']) for c in by_trip]
        context_data['all_trips'] = all_trips
        return context_data

    @method_decorator(group_required('WSC', 'WIMP'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#14
0
class RawMembershipStatsView(View):
    @staticmethod
    def _all_members_info() -> Iterator[Dict[str, Union[str, int]]]:
        for info in geardb_utils.membership_information().values():
            flat_info: Dict[str, Union[str, int]] = {
                'last_known_affiliation': info.last_known_affiliation,
                'num_rentals': info.num_rentals,
            }

            # TODO (Python 3.11, PEP 655): Could TypedDict w/ NotRequired fields
            # Alternatively, could just fix the janky JS to handle.
            if info.trips_information:
                flat_info.update(info.trips_information._asdict())
            yield flat_info

    def get(self, request, *args, **kwargs):
        return JsonResponse({'members': list(self._all_members_info())})

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        # TODO: Restrict to BOD only
        return super().dispatch(request, *args, **kwargs)
示例#15
0
class LeaderSignUpView(BaseSignUpView):
    model = models.LeaderSignUp
    form_class = forms.LeaderSignUpForm

    def get_errors(self, signup):
        errors = super().get_errors(signup)
        trip = signup.trip
        if not signup.participant.can_lead(trip.program_enum):
            errors.append(f"Can't lead {trip.get_program_display()} trips!")
        if not trip.allow_leader_signups:
            errors.append("Trip is not currently accepting leader signups.")
        if models.LeaderSignUp.objects.filter(
            trip=signup.trip, participant=signup.participant
        ).exists():
            errors.append(
                "Already signed up as a leader on this trip! "
                "Contact the trip organizer to be re-added."
            )
        return errors

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
示例#16
0
class ReviewTripView(DetailView):
    model = models.Trip
    template_name = 'trips/review.html'
    success_msg = "Thanks for your feedback!"

    object: models.Trip

    @property
    def posted_feedback(self):
        """Convert named fields of POST data to participant -> feedback mapping.

        If the form data was garbled (intentionally or otherwise), this method
        will raise ValueError or TypeError (on either 'split' or `int`)
        """
        for key, comments in self.request.POST.items():
            if not (key.startswith("par_") or key.startswith("flake_")):
                continue

            feedback_type, par_pk = key.split('_')
            showed_up = feedback_type == 'par'

            yield int(par_pk), comments.strip(), showed_up

    def post(self, request, *args, **kwargs):
        """Create or update all feedback passed along in form data."""
        trip = self.object = self.get_object()
        if trip.feedback_window_passed:
            messages.warning(
                self.request,
                "Trip feedback window has passed. Feedback may not be updated.",
            )
            return redirect(reverse('review_trip', args=(trip.pk, )))

        leader = self.request.participant

        try:
            posted_feedback = list(self.posted_feedback)
        except (TypeError, ValueError):
            # This should never happen, but look at doing this more nicely?
            return HttpResponseBadRequest("Invalid form contents")

        # Create or update feedback for all feedback passed in the form
        existing_feedback = {
            feedback.participant.pk: feedback
            for feedback in self.get_existing_feedback()
        }
        for pk, comments, showed_up in posted_feedback:
            blank_feedback = showed_up and not comments
            existing = existing_feedback.get(pk)

            if existing and blank_feedback:
                existing.delete()
                continue

            if existing is not None:
                feedback = existing
            elif blank_feedback:
                continue  # Don't create new feedback saying nothing useful
            else:
                kwargs = {
                    'leader': leader,
                    'trip': trip,
                    'participant': models.Participant.objects.get(pk=pk),
                }
                feedback = models.Feedback.objects.create(**kwargs)

            feedback.comments = comments
            feedback.showed_up = showed_up
            feedback.save()

        messages.success(self.request, self.success_msg)
        return redirect(reverse('home'))

    @property
    def trip_participants(self):
        accepted_signups = self.object.signup_set.filter(on_trip=True)
        accepted_signups = accepted_signups.select_related('participant')
        return [signup.participant for signup in accepted_signups]

    def get_existing_feedback(self):
        leader = self.request.participant
        return models.Feedback.everything.filter(trip=self.object,
                                                 leader=leader)

    @property
    def feedback_list(self):
        feedback = self.get_existing_feedback()
        par_comments = dict(feedback.values_list('participant__pk',
                                                 'comments'))
        return [(par, par_comments.get(par.pk, ''))
                for par in self.trip_participants]

    def get_context_data(self, **kwargs):
        today = local_date()
        trip = self.object = self.get_object()
        return {
            "trip": trip,
            "feedback_window_passed": trip.feedback_window_passed,
            "trip_completed": today >= trip.trip_date,
            "feedback_required":
            trip.program_enum == enums.Program.WINTER_SCHOOL,
            "feedback_list": self.feedback_list,
        }

    @method_decorator(group_required('leaders'))
    def dispatch(self, request, *args, **kwargs):
        trip = self.get_object()
        if not perm_utils.leader_on_trip(request.participant, trip, False):
            return render(request, 'not_your_trip.html', {'trip': trip})
        return super().dispatch(request, *args, **kwargs)
示例#17
0
     name='help-rentals',
 ),
 url(
     r'^help/participants/weather/$',
     TemplateView.as_view(template_name='help/participants/weather.html'),
     name='help-weather',
 ),
 url(
     r'^help/participants/maps/$',
     TemplateView.as_view(template_name='help/participants/maps.html'),
     name='help-maps',
 ),
 # Trip Logistics (for leaders)
 url(
     r'^help/leaders/trip_admin/$',
     group_required('leaders', 'WSC')(TemplateView.as_view(
         template_name='help/leaders/trip_admin.html')),
     name='help-trip_admin',
 ),
 url(
     r'^help/leaders/checklist/$',
     group_required('leaders', 'WSC')(
         TemplateView.as_view(template_name='help/leaders/checklist.html')),
     name='help-checklist',
 ),
 url(
     r'^help/leaders/example_emails/$',
     group_required('leaders', 'WSC')(TemplateView.as_view(
         template_name='help/leaders/example_emails.html')),
     name='help-example_emails',
 ),
 url(
示例#18
0
 ),
 url(
     r'^help/participants/weather/$',
     TemplateView.as_view(template_name='help/participants/weather.html'),
     name='help-weather',
 ),
 url(
     r'^help/participants/maps/$',
     TemplateView.as_view(template_name='help/participants/maps.html'),
     name='help-maps',
 ),
 # Trip Logistics (for leaders)
 url(
     r'^help/leaders/trip_admin/$',
     group_required('leaders', 'WSC')(
         TemplateView.as_view(template_name='help/leaders/trip_admin.html')
     ),
     name='help-trip_admin',
 ),
 url(
     r'^help/leaders/checklist/$',
     group_required('leaders', 'WSC')(
         TemplateView.as_view(template_name='help/leaders/checklist.html')
     ),
     name='help-checklist',
 ),
 url(
     r'^help/leaders/example_emails/$',
     group_required('leaders', 'WSC')(
         TemplateView.as_view(template_name='help/leaders/example_emails.html')
     ),
示例#19
0
    url(r'^help/participants/personal_info/$',
        TemplateView.as_view(
            template_name='help/participants/personal_info.html'),
        name='help-personal_info'),
    url(r'^help/participants/lottery/$',
        TemplateView.as_view(template_name='help/participants/lottery.html'),
        name='help-lottery'),
    url(r'^help/participants/signups/$',
        TemplateView.as_view(template_name='help/participants/signups.html'),
        name='help-signups'),
    url(r'^help/participants/leading_trips/$',
        TemplateView.as_view(
            template_name='help/participants/leading_trips.html'),
        name='help-leading_trips'),
    url(r'^help/leaders/feedback/$',
        group_required('leaders', 'WSC')(
            TemplateView.as_view(template_name='help/leaders/feedback.html')),
        name='help-feedback'),
    url(r'^help/leaders/trip_admin/$',
        group_required('leaders', 'WSC')(TemplateView.as_view(
            template_name='help/leaders/trip_admin.html')),
        name='help-trip_admin'),
    url(r'^help/wsc/wsc/$',
        group_required('WSC')(
            TemplateView.as_view(template_name='help/wsc/wsc.html')),
        name='help-wsc'),

    # API (must have account in system)
    url(r'^trips/(?P<pk>\d+)/overflow.json$',
        api_views.CheckTripOverflowView.as_view(),
        name='json-check_trip_overflow'),
    url(r'^leaders.json/(?:(?P<activity>.+)/)?$',