Example #1
0
    def pay(self, user, amount):
        """
        Users can make payments for request fees.
        Upon payment, we create a snail mail task and we set the request to a processing status.
        Payments are always snail mail, because we need to mail the check to the agency.
        Since collaborators may make payments, we do not assume the user is the request creator.
        Returns the communication that was generated.
        """
        # We create the payment communication and a snail mail task for it.
        payable_to = self.agency.payable_to if self.agency else None
        text = render_to_string('message/communication/payment.txt', {
            'amount': amount,
            'payable_to': payable_to,
        })

        comm = self.create_out_communication(
            from_user=user,
            text=text,
            user=user,
            payment=True,
            snail=True,
            amount=amount,
            # we include the latest pdf here under the assumption
            # it is the invoice
            include_latest_pdf=True,
        )

        # We perform some logging and activity generation
        logger.info('%s has paid %0.2f for request %s', user.username, amount,
                    self.title)
        utils.new_action(user, 'paid fees', target=self)
        # We return the communication we generated, in case the caller wants to do anything with it
        return comm
Example #2
0
 def _user_follow_up(self, request, foia):
     """Handle follow ups for non-admins"""
     has_perm = foia.has_perm(request.user, 'followup')
     contact_info_form = ContactInfoForm(request.POST, foia=foia)
     has_contact_perm = (request.user.is_authenticated
                         and request.user.profile.is_advanced())
     contact_valid = contact_info_form.is_valid()
     use_contact_info = (
         has_contact_perm
         and contact_info_form.cleaned_data.get('use_contact_information'))
     comm_sent = self._new_comm(
         request,
         foia,
         has_perm and (not use_contact_info or contact_valid),
         'Your follow up has been sent.',
         contact_info=contact_info_form.cleaned_data
         if use_contact_info else None,
     )
     if use_contact_info:
         foia.add_contact_info_note(
             request.user,
             contact_info_form.cleaned_data,
         )
     if comm_sent:
         new_action(request.user, 'followed up on', target=foia)
     return redirect(foia.get_absolute_url() + '#')
Example #3
0
def _admin_follow_up(request, foia):
    """Handle follow ups for admins"""
    form = FOIAAdminFixForm(
        request.POST, prefix="admin_fix", request=request, foia=foia
    )
    if form.is_valid():
        foia.update_address(
            form.cleaned_data["via"],
            email=form.cleaned_data["email"],
            other_emails=form.cleaned_data["other_emails"],
            fax=form.cleaned_data["fax"],
        )
        snail = form.cleaned_data["via"] == "snail"
        foia.create_out_communication(
            from_user=form.cleaned_data["from_user"],
            text=form.cleaned_data["comm"],
            user=request.user,
            snail=snail,
            subject=form.cleaned_data["subject"],
        )
        messages.success(request, "Your follow up has been sent.")
        new_action(request.user, "followed up on", target=foia)
        return _get_redirect(request, foia)
    else:
        raise FoiaFormError("admin_fix_form", form)
Example #4
0
 def _user_follow_up(self, request, foia):
     """Handle follow ups for non-admins"""
     has_perm = foia.has_perm(request.user, 'followup')
     contact_info_form = ContactInfoForm(request.POST,
                                         foia=foia,
                                         prefix='followup')
     has_contact_perm = request.user.has_perm('foia.set_info_foiarequest')
     contact_valid = contact_info_form.is_valid()
     use_contact_info = (
         has_contact_perm
         and contact_info_form.cleaned_data.get('use_contact_information'))
     comm_sent = self._new_comm(
         request,
         foia,
         has_perm and (not use_contact_info or contact_valid),
         'Your follow up has been sent.',
         contact_info=contact_info_form.cleaned_data
         if use_contact_info else None,
     )
     if use_contact_info:
         foia.add_contact_info_note(
             request.user,
             contact_info_form.cleaned_data,
         )
     if comm_sent:
         new_action(request.user, 'followed up on', target=foia)
         mixpanel_event(
             request,
             'Follow Up',
             foia.mixpanel_data({
                 'Use Contact Info': use_contact_info,
             }),
         )
     return redirect(foia.get_absolute_url() + '#')
Example #5
0
 def test_unidentical_notification(self):
     """A new notification shoudl not mark any with unidentical language as read."""
     first_action = new_action(self.request.agency,
                               "completed",
                               target=self.request)
     second_action = new_action(self.request.agency,
                                "rejected",
                                target=self.request)
     third_action = new_action(self.owner, "completed", target=self.request)
     unread_count = self.owner.notifications.get_unread().count()
     self.request.notify(first_action)
     eq_(
         self.owner.notifications.get_unread().count(),
         unread_count + 1,
         "The user should have one unread notification.",
     )
     self.request.notify(second_action)
     eq_(
         self.owner.notifications.get_unread().count(),
         unread_count + 2,
         "The user should have two unread notifications.",
     )
     self.request.notify(third_action)
     eq_(
         self.owner.notifications.get_unread().count(),
         unread_count + 3,
         "The user should have three unread notifications.",
     )
Example #6
0
 def remove_member(self, request):
     """Removes a single member from an organization"""
     organization = self.get_object()
     try:
         user_pk = request.POST['member']
         user = User.objects.select_related('profile').get(pk=user_pk)
     except (KeyError, User.DoesNotExist):
         messages.error(request, 'No member selected to remove.')
         return
     # let members remove themselves from the organization, but nobody else
     removing_self = user == request.user
     user_is_owner = organization.owner == request.user
     if removing_self or user_is_owner or request.user.is_staff:
         if organization.remove_member(user):
             new_action(request.user,
                        'removed',
                        action_object=user,
                        target=organization)
             logging.info('%s %s %s from %s.', request.user, 'removed',
                          user, organization)
             if removing_self:
                 msg = 'You are no longer a member.'
             else:
                 msg = 'You removed membership from %s.' % user.first_name
             messages.success(request, msg)
     else:
         messages.error(
             request, 'You do not have permission to remove this member.')
     return
Example #7
0
def _user_follow_up(request, foia):
    """Handle follow ups for non-admins"""
    has_perm = foia.has_perm(request.user, "followup")
    contact_info_form = ContactInfoForm(request.POST, foia=foia, prefix="followup")
    has_contact_perm = request.user.has_perm("foia.set_info_foiarequest")
    contact_valid = contact_info_form.is_valid()
    use_contact_info = has_contact_perm and contact_info_form.cleaned_data.get(
        "use_contact_information"
    )
    comm_sent = _new_comm(
        request,
        foia,
        has_perm and (not use_contact_info or contact_valid),
        "Your follow up has been sent.",
        contact_info=contact_info_form.cleaned_data if use_contact_info else None,
    )
    if use_contact_info:
        foia.add_contact_info_note(request.user, contact_info_form.cleaned_data)
    if comm_sent:
        new_action(request.user, "followed up on", target=foia)
        mixpanel_event(
            request,
            "Follow Up",
            foia.mixpanel_data({"Use Contact Info": use_contact_info}),
        )
    return _get_redirect(request, foia)
Example #8
0
 def _admin_follow_up(self, request, foia):
     """Handle follow ups for admins"""
     form = FOIAAdminFixForm(
         request.POST,
         prefix='admin_fix',
         request=request,
         foia=foia,
     )
     if form.is_valid():
         foia.update_address(
             form.cleaned_data['via'],
             email=form.cleaned_data['email'],
             other_emails=form.cleaned_data['other_emails'],
             fax=form.cleaned_data['fax'],
         )
         snail = form.cleaned_data['via'] == 'snail'
         foia.create_out_communication(
             from_user=form.cleaned_data['from_user'],
             text=form.cleaned_data['comm'],
             user=request.user,
             snail=snail,
             subject=form.cleaned_data['subject'],
         )
         messages.success(request, 'Your follow up has been sent.')
         new_action(request.user, 'followed up on', target=foia)
         return redirect(foia.get_absolute_url() + '#')
     else:
         self.admin_fix_form = form
         raise FoiaFormError
Example #9
0
 def form_valid(self, form):
     """Saves relationship and sends action before returning URL"""
     redirection = super(ProjectCrowdfundView, self).form_valid(form)
     crowdfund = self.object
     project = self.get_project()
     relationship = ProjectCrowdfunds.objects.create(
         project=project, crowdfund=crowdfund
     )
     new_action(
         self.request.user,
         "began crowdfunding",
         action_object=relationship.crowdfund,
         target=relationship.project,
     )
     crowdfund.send_intro_email(self.request.user)
     mixpanel_event(
         self.request,
         "Launch Project Crowdfund",
         self._project_mixpanel_properties(
             project,
             {
                 "Name": crowdfund.name,
                 "Payment Capped": crowdfund.payment_capped,
                 "Payment Required": float(crowdfund.payment_required),
                 "Date Due": crowdfund.date_due.isoformat(),
             },
         ),
     )
     return redirection
Example #10
0
def thanks(request, foia):
    """Handle submitting a thank you follow up"""
    success_msg = "Your thank you has been sent."
    has_perm = foia.has_perm(request.user, "thank")
    comm_sent = _new_comm(request, foia, has_perm, success_msg, thanks=True)
    if comm_sent:
        new_action(request.user, verb="thanked", target=foia.agency)
    return _get_redirect(request, foia)
Example #11
0
def crowdfund_request(request, idx, **kwargs):
    """Crowdfund a request"""
    # pylint: disable=unused-argument
    # select for update locks this request in order to prevent a race condition
    # allowing multiple crowdfunds to be created for it
    foia = get_object_or_404(
        FOIARequest.objects.select_for_update().select_related(
            "agency__jurisdiction", "composer"
        ),
        pk=idx,
    )
    # check for unauthorized access
    if not foia.has_perm(request.user, "crowdfund"):
        messages.error(request, "You may not crowdfund this request.")
        return redirect(foia)
    if request.method == "POST":
        # save crowdfund object
        form = CrowdfundForm(request.POST)
        if form.is_valid():
            crowdfund = form.save()
            foia.crowdfund = crowdfund
            foia.save(comment="added a crowdfund")
            messages.success(request, "Your crowdfund has started, spread the word!")
            new_action(
                request.user, "began crowdfunding", action_object=crowdfund, target=foia
            )
            crowdfund.send_intro_email(request.user)
            mixpanel_event(
                request,
                "Launch Request Crowdfund",
                foia.mixpanel_data(
                    {
                        "Name": crowdfund.name,
                        "Payment Capped": crowdfund.payment_capped,
                        "Payment Required": float(crowdfund.payment_required),
                        "Date Due": crowdfund.date_due.isoformat(),
                    }
                ),
            )
            return redirect(foia)

    elif request.method == "GET":
        # create crowdfund form
        default_crowdfund_duration = 30
        date_due = timezone.now() + timedelta(default_crowdfund_duration)
        initial = {
            "name": "Crowdfund Request: %s" % str(foia),
            "description": "Help cover the request fees needed to free these docs!",
            "payment_required": foia.get_stripe_amount(),
            "date_due": date_due,
            "foia": foia,
        }
        form = CrowdfundForm(initial=initial)
        mixpanel_event(request, "Start Request Crowdfund", foia.mixpanel_data())

    return render(request, "forms/foia/crowdfund.html", {"form": form})
Example #12
0
 def close_crowdfund(self, succeeded=False):
     """Close the crowdfund and create a new task for it once it reaches its goal."""
     self.closed = True
     self.save()
     self.crowdfundtask_set.create()
     verb = "ended"
     if succeeded:
         logger.info("Crowdfund %d reached its goal.", self.id)
         verb = "succeeded"
     new_action(self, verb)
Example #13
0
 def create_embargo(request, foia):
     """Apply an embargo to the FOIA"""
     if foia.has_perm(request.user, "embargo"):
         foia.embargo = True
         foia.save(comment="added embargo")
         logger.info("%s embargoed %s", request.user, foia)
         new_action(request.user, "embargoed", target=foia)
         fine_tune_embargo(request, foia)
     else:
         logger.error("%s was forbidden from embargoing %s", request.user, foia)
         messages.error(request, "You cannot embargo requests.")
Example #14
0
 def _thank(self, request, foia):
     """Handle submitting a thank you follow up"""
     success_msg = 'Your thank you has been sent.'
     has_perm = foia.has_perm(request.user, 'thank')
     comm_sent = self._new_comm(request,
                                foia,
                                has_perm,
                                success_msg,
                                thanks=True)
     if comm_sent:
         new_action(request.user, verb='thanked', target=foia.agency)
     return redirect(foia.get_absolute_url() + '#')
Example #15
0
def crowdfund_request(request, idx, **kwargs):
    """Crowdfund a request"""
    # pylint: disable=unused-argument
    # select for update locks this request in order to prevent a race condition
    # allowing multiple crowdfunds to be created for it
    foia = FOIARequest.objects.select_for_update().get(pk=idx)
    # check for unauthorized access
    if not foia.has_perm(request.user, 'crowdfund'):
        messages.error(request, 'You may not crowdfund this request.')
        return redirect(foia)
    if request.method == 'POST':
        # save crowdfund object
        form = CrowdfundForm(request.POST)
        if form.is_valid():
            crowdfund = form.save()
            foia.crowdfund = crowdfund
            foia.save(comment='added a crowdfund')
            messages.success(
                request, 'Your crowdfund has started, spread the word!'
            )
            new_action(
                request.user,
                'began crowdfunding',
                action_object=crowdfund,
                target=foia
            )
            crowdfund.send_intro_email(request.user)
            return redirect(foia)

    elif request.method == 'GET':
        # create crowdfund form
        default_crowdfund_duration = 30
        date_due = timezone.now() + timedelta(default_crowdfund_duration)
        initial = {
            'name':
                u'Crowdfund Request: %s' % unicode(foia),
            'description':
                'Help cover the request fees needed to free these docs!',
            'payment_required':
                foia.get_stripe_amount(),
            'date_due':
                date_due,
            'foia':
                foia
        }
        form = CrowdfundForm(initial=initial)

    return render(
        request,
        'forms/foia/crowdfund.html',
        {'form': form},
    )
Example #16
0
 def form_valid(self, form):
     """Saves relationship and sends action before returning URL"""
     redirection = super(ProjectCrowdfundView, self).form_valid(form)
     crowdfund = self.object
     project = self.get_project()
     relationship = ProjectCrowdfunds.objects.create(project=project,
                                                     crowdfund=crowdfund)
     new_action(self.request.user,
                'began crowdfunding',
                action_object=relationship.crowdfund,
                target=relationship.project)
     crowdfund.send_intro_email(self.request.user)
     return redirection
Example #17
0
 def _flag(self, request, foia):
     """Allow a user to notify us of a problem with the request"""
     form = FOIAFlagForm(request.POST)
     has_perm = foia.has_perm(request.user, 'flag')
     if has_perm and form.is_valid():
         FlaggedTask.objects.create(
             user=request.user,
             foia=foia,
             text=form.cleaned_data['text'],
             category=form.cleaned_data['category'],
         )
         messages.success(request, 'Problem succesfully reported')
         new_action(request.user, 'flagged', target=foia)
     return redirect(foia.get_absolute_url() + '#')
Example #18
0
def flag(request, foia):
    """Allow a user to notify us of a problem with the request"""
    form = FOIAFlagForm(request.POST, all_choices=True)
    if form.is_valid():
        FlaggedTask.objects.create(
            user=request.user if request.user.is_authenticated else None,
            foia=foia,
            text=form.cleaned_data["text"],
            category=form.cleaned_data["category"],
        )
        messages.success(request, "Problem succesfully reported")
        if request.user.is_authenticated:
            new_action(request.user, "flagged", target=foia)
    return _get_redirect(request, foia)
Example #19
0
 def _appeal(self, request, foia):
     """Handle submitting an appeal, then create an Appeal from the returned
     communication.
     """
     form = AppealForm(request.POST)
     has_perm = foia.has_perm(request.user, 'appeal')
     contact_info_form = ContactInfoForm(
         request.POST,
         foia=foia,
         prefix='appeal',
         appeal=True,
     )
     has_contact_perm = request.user.has_perm('foia.set_info_foiarequest')
     contact_valid = contact_info_form.is_valid()
     use_contact_info = (
         has_contact_perm
         and contact_info_form.cleaned_data.get('use_contact_information'))
     if not has_perm:
         messages.error(request,
                        'You do not have permission to submit an appeal.')
         return redirect(foia.get_absolute_url() + '#')
     if not form.is_valid():
         messages.error(request, 'You did not submit an appeal.')
         return redirect(foia.get_absolute_url() + '#')
     if foia.attachments_over_size_limit(request.user):
         messages.error(request,
                        'Total attachment size must be less than 20MB')
         return redirect(foia.get_absolute_url() + '#')
     if use_contact_info and not contact_valid:
         messages.error(request, 'Invalid contact information')
         return redirect(foia.get_absolute_url() + '#')
     communication = foia.appeal(
         form.cleaned_data['text'],
         request.user,
         contact_info=contact_info_form.cleaned_data
         if use_contact_info else None,
     )
     base_language = form.cleaned_data['base_language']
     appeal = Appeal.objects.create(communication=communication)
     appeal.base_language.set(base_language)
     new_action(request.user, 'appealed', target=foia)
     messages.success(request, 'Your appeal has been sent.')
     if use_contact_info:
         foia.add_contact_info_note(
             request.user,
             contact_info_form.cleaned_data,
         )
     return redirect(foia.get_absolute_url() + '#')
Example #20
0
class NotificationFactory(factory.django.DjangoModelFactory):
    """A factory for creating Notification test objects."""
    class Meta:
        model = Notification

    user = factory.SubFactory(UserFactory)
    action = factory.LazyAttribute(lambda obj: new_action(obj.user, 'acted'))
Example #21
0
 def test_basic(self):
     """An action only needs an actor and a verb."""
     actor = UserFactory()
     verb = 'acted'
     action = new_action(actor, verb)
     ok_(isinstance(action, Action), 'An Action should be returned.')
     eq_(action.actor, actor)
     eq_(action.verb, verb)
Example #22
0
 def setUp(self):
     agency = AgencyFactory()
     self.owner = UserFactory()
     self.follower = UserFactory()
     self.request = FOIARequestFactory(composer__user=self.owner,
                                       agency=agency)
     follow(self.follower, self.request)
     self.action = new_action(agency, "completed", target=self.request)
Example #23
0
 def add_members(self, request):
     """Grants organization membership to a list of users"""
     organization = self.get_object()
     if not organization.is_owned_by(
             request.user) and not request.user.is_staff:
         messages.error(request,
                        'You cannot add members this organization.')
         return
     form = AddMembersForm(request.POST)
     if form.is_valid():
         new_members = form.cleaned_data['members']
         new_member_count = len(new_members)
         existing_member_count = organization.members.count()
         if new_member_count + existing_member_count > organization.max_users:
             difference = (new_member_count +
                           existing_member_count) - organization.max_users
             seat = 'seats' if difference > 1 else 'seat'
             messages.error(
                 request,
                 'You will need to purchase %d %s.' % (difference, seat))
             return
         if not organization.active:
             messages.error(
                 request,
                 'You may not add members to an inactive organization.')
             return
         members_added = 0
         for member in new_members:
             try:
                 if organization.add_member(member):
                     new_action(request.user,
                                'added',
                                action_object=member,
                                target=organization)
                     logging.info('%s %s %s to %s.', request.user, 'added',
                                  member, organization)
                     members_added += 1
             except AttributeError as exception:
                 messages.error(request, exception)
         if members_added > 0:
             members_plural = 'members' if members_added > 1 else 'member'
             messages.success(
                 request,
                 'You added %d %s.' % (members_added, members_plural))
     return
Example #24
0
 def create_agency_notifications(self):
     """Create the notifications for when an agency creates a new comm"""
     if self.foia and self.foia.agency:
         action = new_action(self.foia.agency,
                             'sent a communication',
                             action_object=self,
                             target=self.foia)
         self.foia.notify(action)
     if self.foia:
         self.foia.update(self.anchor())
Example #25
0
 def test_send_notification(self):
     """The email should send if there are notifications."""
     # generate an action on an actor the user follows
     agency = AgencyFactory()
     foia = FOIARequestFactory(agency=agency)
     action = new_action(agency, "completed", target=foia)
     notify(self.user, action)
     # generate the email, which should contain the generated action
     email = self.digest(user=self.user, interval=self.interval)
     eq_(email.activity["count"], 1, "There should be activity.")
     eq_(email.send(), 1, "The email should send.")
Example #26
0
 def _appeal(self, request, foia):
     """Handle submitting an appeal, then create an Appeal from the returned
     communication.
     """
     form = AppealForm(request.POST)
     has_perm = foia.has_perm(request.user, 'appeal')
     if not has_perm:
         messages.error(request,
                        'You do not have permission to submit an appeal.')
         return redirect(foia.get_absolute_url() + '#')
     if not form.is_valid():
         messages.error(request, 'You did not submit an appeal.')
         return redirect(foia.get_absolute_url() + '#')
     communication = foia.appeal(form.cleaned_data['text'], request.user)
     base_language = form.cleaned_data['base_language']
     appeal = Appeal.objects.create(communication=communication)
     appeal.base_language.set(base_language)
     new_action(request.user, 'appealed', target=foia)
     messages.success(request, 'Your appeal has been sent.')
     return redirect(foia.get_absolute_url() + '#')
Example #27
0
 def test_digest_follow_requests(self):
     """Digests should include information on requests I follow."""
     # generate an action on a request the user owns
     other_user = UserFactory()
     foia = FOIARequestFactory(composer__user=other_user)
     agency = AgencyFactory()
     action = new_action(agency, "rejected", target=foia)
     notify(self.user, action)
     # generate the email, which should contain the generated action
     email = self.digest(user=self.user, interval=self.interval)
     eq_(email.activity["count"], 1, "There should be activity.")
     eq_(email.send(), 1, "The email should send.")
Example #28
0
def appeal(request, foia):
    """Handle submitting an appeal, then create an Appeal from the returned
    communication.
    """
    form = AppealForm(request.POST)
    has_perm = foia.has_perm(request.user, "appeal")
    contact_info_form = ContactInfoForm(
        request.POST, foia=foia, prefix="appeal", appeal=True
    )
    has_contact_perm = request.user.has_perm("foia.set_info_foiarequest")
    contact_valid = contact_info_form.is_valid()
    use_contact_info = has_contact_perm and contact_info_form.cleaned_data.get(
        "use_contact_information"
    )
    if not has_perm:
        messages.error(request, "You do not have permission to submit an appeal.")
        return _get_redirect(request, foia)
    if not form.is_valid():
        messages.error(request, "You did not submit an appeal.")
        return _get_redirect(request, foia)
    if foia.attachments_over_size_limit(request.user):
        messages.error(request, "Total attachment size must be less than 20MB")
        return _get_redirect(request, foia)
    if use_contact_info and not contact_valid:
        messages.error(request, "Invalid contact information")
        return _get_redirect(request, foia)
    communication = foia.appeal(
        form.cleaned_data["text"],
        request.user,
        contact_info=contact_info_form.cleaned_data if use_contact_info else None,
    )
    base_language = form.cleaned_data["base_language"]
    appeal_ = Appeal.objects.create(communication=communication)
    appeal_.base_language.set(base_language)
    new_action(request.user, "appealed", target=foia)
    messages.success(request, "Your appeal has been sent.")
    if use_contact_info:
        foia.add_contact_info_note(request.user, contact_info_form.cleaned_data)
    return _get_redirect(request, foia)
Example #29
0
 def save(self, *args, **kwargs):
     """Creates an action if question is newly asked"""
     is_new = True if self.pk is None else False
     super(Question, self).save(*args, **kwargs)
     if is_new:
         action = new_action(self.user, 'asked', target=self)
         # Notify users who subscribe to new question notifications
         new_question_subscribers = Profile.objects.filter(
             new_question_notifications=True)
         users_to_notify = [
             profile.user for profile in new_question_subscribers
         ]
         notify(users_to_notify, action)
Example #30
0
 def save(self, *args, **kwargs):
     """Creates an action if question is newly asked"""
     # pylint: disable=signature-differs
     is_new = self.pk is None
     super(Question, self).save(*args, **kwargs)
     if is_new:
         action = new_action(self.user, "asked", target=self)
         # Notify users who subscribe to new question notifications
         new_question_subscribers = Profile.objects.filter(
             new_question_notifications=True)
         users_to_notify = [
             profile.user for profile in new_question_subscribers
         ]
         notify(users_to_notify, action)