def delete_embargo(request, foia): """Remove an embargo from the FOIA""" foia.embargo = False foia.save(comment='removed embargo') logger.info('%s unembargoed %s', request.user, foia) new_action(request.user, 'unembargoed', target=foia) return
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
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 comm = self.communications.create( from_user=user, to_user=self.get_to_user(), date=datetime.now(), response=False, communication=render_to_string('message/communication/payment.txt', { 'amount': amount, 'payable_to': payable_to, })) self.submit(payment=True, snail=True, amount=amount) # 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
def _flag(self, request, foia): """Allow a user to notify us of a problem with the request""" text = request.POST.get('text') if request.user.is_authenticated() and text: FlaggedTask.objects.create(user=request.user, text=text, foia=foia) messages.success(request, 'Problem succesfully reported') new_action(request.user, 'flagged', target=foia) return redirect(foia)
def _follow_up(self, request, foia): """Handle submitting follow ups""" success_msg = 'Your follow up has been sent.' has_perm = foia.has_perm(request.user, 'followup') comm_sent = self._new_comm(request, foia, has_perm, success_msg) if comm_sent: new_action(request.user, 'followed up on', target=foia) return redirect(foia)
def _follow_up(self, request, foia): """Handle submitting follow ups""" can_follow_up = foia.editable_by(request.user) or request.user.is_staff test = can_follow_up and foia.status != 'started' success_msg = 'Your follow up has been sent.' comm_sent = self._new_comm(request, foia, test, success_msg) if comm_sent: new_action(request.user, 'followed up on', target=foia) return redirect(foia)
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)
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() task.models.CrowdfundTask.objects.create(crowdfund=self) verb = 'ended' if succeeded: logging.info('Crowdfund %d reached its goal.', self.id) verb = 'succeeded' new_action(self, verb) return
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) return redirection
def _thank(self, request, foia): """Handle submitting a thank you follow up""" test = foia.editable_by(request.user) and foia.is_thankable() success_msg = 'Your thank you has been sent.' comm_sent = self._new_comm(request, foia, test, success_msg, thanks=True) if comm_sent: new_action(request.user, verb='thanked', target=foia.agency) return redirect(foia)
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.') return
def _submit_request(request, foia): """Submit request for user""" if not foia.user == request.user: messages.error(request, 'Only a request\'s owner may submit it.') elif not request.user.profile.make_request(): error_msg = ('You do not have any requests remaining. ' 'Please purchase more requests and then resubmit.') messages.error(request, error_msg) else: foia.submit() request.session['ga'] = 'request_submitted' messages.success(request, 'Your request was submitted.') new_action(request.user, 'submitted', target=foia) return redirect(foia)
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.')
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'))
def setUp(self): agency = AgencyFactory() self.owner = UserFactory() self.follower = UserFactory() self.request = FOIARequestFactory(user=self.owner, agency=agency) follow(self.follower, self.request) self.action = new_action(agency, 'completed', target=self.request)
def crowdfund_request(request, idx, **kwargs): """Crowdfund a request""" # pylint: disable=unused-argument foia = FOIARequest.objects.get(pk=idx) owner_or_staff = request.user == foia.user or request.user.is_staff # check for unauthorized access if not owner_or_staff: messages.error(request, 'You may only crowdfund your own requests.') return redirect(foia) if foia.has_crowdfund(): messages.error(request, 'You may only run one crowdfund per request.') return redirect(foia) if foia.status != 'payment': messages.error(request, 'You may only crowfund when payment is required.') 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) return redirect(foia) elif request.method == 'GET': # create crowdfund form default_crowdfund_duration = 30 date_due = datetime.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_to_response('forms/foia/crowdfund.html', {'form': form}, context_instance=RequestContext(request))
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) if not form.is_valid(): messages.error(request, 'You did not submit an appeal.') return redirect(foia) communication = foia.appeal(form.cleaned_data['text']) 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)
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)
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
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 = datetime.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}, )
def test_for_object(self): """Notifications should be filterable by a single object.""" foia = factories.FOIARequestFactory() _action = new_action(factories.UserFactory(), 'submitted', target=foia) object_notification = factories.NotificationFactory(user=self.user, action=_action) object_notifications = Notification.objects.for_object(foia) ok_(object_notification in object_notifications, 'A notification for the object should be in the set returned.') ok_(self.notification not in object_notifications, 'A notification not including the object should not be in the set returned.')
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())
def test_idential_different_requests(self): """An identical action on a different request should not mark anything as read.""" other_request = FOIARequestFactory(user=self.owner, agency=self.request.agency) other_action = new_action(self.request.agency, 'completed', target=other_request) unread_count = self.owner.notifications.get_unread().count() self.request.notify(self.action) eq_(self.owner.notifications.get_unread().count(), unread_count + 1, 'The user should have one unread notification.') other_request.notify(other_action) eq_(self.owner.notifications.get_unread().count(), unread_count + 2, 'The user should have two unread notifications.')
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. """ from muckrock.foia.models.communication import FOIACommunication from muckrock.task.models import SnailMailTask # We mark the request as processing self.status = 'submitted' self.date_processing = date.today() self.save() # We create the payment communication and a snail mail task for it. payable_to = self.agency.payable_to if self.agency else None comm = FOIACommunication.objects.create( foia=self, from_who='MuckRock.com', to_who=self.get_to_who(), date=datetime.now(), delivered='mail', response=False, full_html=False, autogenerated=False, communication=render_to_string('message/communication/payment.txt', { 'amount': amount, 'payable_to': payable_to })) SnailMailTask.objects.create(communication=comm, category='p', user=user, amount=amount) # 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
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)
def save(self, *args, **kwargs): """Update the questions answer date when you save the answer""" is_new = True if self.pk is None else False super(Answer, self).save(*args, **kwargs) self.question.answer_date = self.date self.question.save() if is_new: action = new_action(self.user, 'answered', action_object=self, target=self.question) # Notify the question's owner and its followers about the new answer notify(self.question.user, action) notify(followers(self.question), action)
def test_get_question(self): """Try getting the detail page for a Question with an unread notification.""" question = QuestionFactory() view = QuestionDetail.as_view() # Create a notification for the question action = new_action(UserFactory(), 'answered', target=question) notification = notify(self.user, action)[0] ok_(not notification.read, 'The notification should be unread.') # Try getting the view as the user response = http_get_response(question.get_absolute_url(), view, self.user, pk=question.pk, slug=question.slug) eq_(response.status_code, 200, 'The view should respond 200 OK.') # Check that the notification has been read. notification.refresh_from_db() ok_(notification.read, 'The notification should be marked as read.')
def test_get_foia(self): """Try getting the detail page for a FOIA Request with an unread notification.""" agency = AgencyFactory() foia = FOIARequestFactory(agency=agency) view = FOIARequestDetail.as_view() # Create a notification for the request action = new_action(agency, 'completed', target=foia) notification = notify(self.user, action)[0] ok_(not notification.read, 'The notification should be unread.') # Try getting the view as the user response = http_get_response(foia.get_absolute_url(), view, self.user, idx=foia.pk, slug=foia.slug, jidx=foia.jurisdiction.pk, jurisdiction=foia.jurisdiction.slug) eq_(response.status_code, 200, 'The view should response 200 OK.') # Check that the notification has been read. notification.refresh_from_db() ok_(notification.read, 'The notification should be marked as read.')
def setUp(self): self.action = new_action(UserFactory(), 'acted')
def setUp(self): self.user = factories.UserFactory() self.action = new_action(self.user, 'acted') self.notification = factories.NotificationFactory()