Esempio n. 1
0
    def test_accessing_a_view_with_proper_permissions(self):
        """
        If a user tries to access a page for which his company has access and
        that user's roles include the denoted activities, they should be
        allowed to visit that page.
        """

        response = requires(self.activity.name)(dummy_view)(self.request)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, self.user.email)
Esempio n. 2
0
    def test_accessing_a_view_with_proper_permissions(self):
        """
        If a user tries to access a page for which his company has access and
        that user's roles include the denoted activities, they should be
        allowed to visit that page.
        """

        response = requires(self.activity.name)(dummy_view)(self.request)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, self.user.email)
Esempio n. 3
0
    def test_user_with_wrong_activities(self):
        """
        When a user's roles don't include all of the activities required by a
        view, they should see a permission denied error.
        """

        self.user.roles.first().activities.clear()
        response = requires(self.activity.name)(dummy_view)(self.request)

        self.assertEqual(response.status_code, 403)
        self.assertEqual(type(response), MissingActivity)
Esempio n. 4
0
    def test_user_with_wrong_activities(self):
        """
        When a user's roles don't include all of the activities required by a
        view, they should see a permission denied error.
        """

        self.user.roles.first().activities.clear()
        response = requires(self.activity.name)(dummy_view)(self.request)

        self.assertEqual(response.status_code, 403)
        self.assertEqual(type(response), MissingActivity)
Esempio n. 5
0
    def test_user_with_wrong_number_of_activities(self):
        """
        A user's roles should have all activities required by a decorated view,
        not just a subset of them.
        """

        activity = ActivityFactory(app_access=self.app_access)
        response = requires(
            self.activity.name, activity.name)(dummy_view)(self.request)

        self.assertEqual(response.status_code, 403)
        self.assertEqual(type(response), MissingActivity)
Esempio n. 6
0
    def test_user_with_wrong_number_of_activities(self):
        """
        A user's roles should have all activities required by a decorated view,
        not just a subset of them.
        """

        activity = ActivityFactory(app_access=self.app_access)
        response = requires(self.activity.name,
                            activity.name)(dummy_view)(self.request)

        self.assertEqual(response.status_code, 403)
        self.assertEqual(type(response), MissingActivity)
Esempio n. 7
0
    def test_company_with_wrong_app_access(self):
        """
        When a company doesn't have the right app-level access, a user
        shouldn't see that app's view, even if that user has a role with the
        right activities.
        """

        self.company.app_access.clear()
        response = requires([self.activity.name])(dummy_view)(self.request)

        self.assertEqual(response.status_code, 403)
        self.assertEqual(type(response), MissingAppAccess)
Esempio n. 8
0
    def test_user_with_extra_activities(self):
        """
        A user should be able to access a view even if the roles include
        activities not required by the view.
        """

        activity = ActivityFactory(app_access=self.app_access)
        self.role.activities.add(activity)
        response = requires(self.activity.name)(dummy_view)(self.request)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, self.user.email)
Esempio n. 9
0
    def test_user_with_extra_activities(self):
        """
        A user should be able to access a view even if the roles include
        activities not required by the view.
        """

        activity = ActivityFactory(app_access=self.app_access)
        self.role.activities.add(activity)
        response = requires(self.activity.name)(dummy_view)(self.request)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, self.user.email)
Esempio n. 10
0
    def test_company_with_wrong_app_access(self):
        """
        When a company doesn't have the right app-level access, a user
        shouldn't see that app's view, even if that user has a role with the
        right activities.
        """

        self.company.app_access.clear()
        with self.assertRaises(MissingAppLevelAccess) as cm:
            response = requires(self.activity.name)(dummy_view)(self.request)

        self.assertEqual(
            cm.exception.message,
            "%s doesn't have sufficient app-level access." % self.company.name)
Esempio n. 11
0
    def test_company_with_wrong_app_access(self):
        """
        When a company doesn't have the right app-level access, a user
        shouldn't see that app's view, even if that user has a role with the
        right activities.
        """

        self.company.app_access.clear()
        with self.assertRaises(MissingAppLevelAccess) as cm:
            response = requires(self.activity.name)(dummy_view)(self.request)

        self.assertEqual(
            cm.exception.message,
            "%s doesn't have sufficient app-level access." % self.company.name)
Esempio n. 12
0
    def test_invalid_callback(self):
        """
        When an invalid callback is declared, we should see an error.
        """
        def callback(request):
            raise Http404("Required activities missing.")

        with self.assertRaises(TypeError) as cm:
            response = requires(
                self.activity.name,
                # we misspelled access here, so the callback is invalid
                acess_callback=callback)(dummy_view)(self.request)

        # the erroneous callback should be listed in the output
        self.assertIn("- acess_callback", cm.exception.message)
Esempio n. 13
0
    def test_invalid_callback(self):
        """
        When an invalid callback is declared, we should see an error.
        """

        def callback(request):
            raise Http404("Required activities missing.")

        with self.assertRaises(TypeError) as cm:
            response = requires(
                self.activity.name,
                # we misspelled access here, so the callback is invalid
                acess_callback=callback)(dummy_view)(self.request)

        # the erroneous callback should be listed in the output
        self.assertIn("- acess_callback", cm.exception.message)
Esempio n. 14
0
    def test_activity_callback(self):
        """
        When app access is sufficient and a callback is supplied, the response
        of that callback should be returned rather than a `MissingAppAccess`
        response.
        """

        self.user.roles.first().activities.clear()

        def callback(request):
            raise Http404("Required activities missing.")

        with self.assertRaises(Http404) as cm:
            response = requires(
                self.activity.name,
                activity_callback=callback)(dummy_view)(self.request)

        self.assertEqual(cm.exception.message, "Required activities missing.")
Esempio n. 15
0
    def test_access_callback(self):
        """
        When app access is sufficient and a callback is supplied, the response
        of that callback should be returned rather than a
        `MissingAppLevelAccess` response.
        """

        self.company.app_access.clear()

        def callback(request):
            raise Http404("This app doesn't exist.")

        with self.assertRaises(Http404) as cm:
            response = requires(
                self.activity.name,
                access_callback=callback)(dummy_view)(self.request)

        self.assertEqual(cm.exception.message, "This app doesn't exist.")
Esempio n. 16
0
    def test_access_callback(self):
        """
        When app access is sufficient and a callback is supplied, the response
        of that callback should be returned rather than a
        `MissingAppLevelAccess` response.
        """

        self.company.app_access.clear()

        def callback(request):
            raise Http404("This app doesn't exist.")

        with self.assertRaises(Http404) as cm:
            response = requires(self.activity.name,
                                access_callback=callback)(dummy_view)(
                                    self.request)

        self.assertEqual(cm.exception.message, "This app doesn't exist.")
Esempio n. 17
0
    def test_activity_callback(self):
        """
        When app access is sufficient and a callback is supplied, the response
        of that callback should be returned rather than a `MissingAppAccess`
        response.
        """

        self.user.roles.first().activities.clear()

        def callback(request):
            raise Http404("Required activities missing.")

        with self.assertRaises(Http404) as cm:
            response = requires(self.activity.name,
                                activity_callback=callback)(dummy_view)(
                                    self.request)

        self.assertEqual(cm.exception.message, "Required activities missing.")
Esempio n. 18
0
class ReportView(View):
    """
    View for managing report objects.

    A GET request will fetch a report, where as a POST will generate a new
    report.
    """

    app = 'mypartners'
    model = 'contactrecord'

    @method_decorator(
        requires('read partner', 'read contact', 'read communication record'))
    def dispatch(self, *args, **kwargs):
        return super(ReportView, self).dispatch(*args, **kwargs)

    def get(self, request, **kwargs):
        """
        Get a report by ID and return interesting numbers as a JSON
        response. The only expected query parameter is 'id'.

        Query String Parameters:
            :id: The id of the report to retrieve

        Outputs:
            Renders a json object with counts for email, calls, searches,
            meetings, applications, interviews, hires, communications,
            referrals, and contacts. All these are integers except for
            contacts, which is a list of objects, each of which has a name,
            email, referral count, and communications count.
        """

        report_id = request.GET.get('id', 0)
        report = get_object_or_404(Report, pk=report_id)

        if report.model == "contactrecord":
            records = report.queryset
            ctx = json.dumps({
                'emails':
                records.emails,
                'calls':
                records.calls,
                'searches':
                records.searches,
                'meetings':
                records.meetings,
                'applications':
                records.applications,
                'interviews':
                records.interviews,
                'hires':
                records.hires,
                'communications':
                records.communication_activity.count(),
                'referrals':
                records.referrals,
                'contacts':
                list(records.contacts)
            })
            status = 200
        elif report.results:
            ctx = report.json
            status = 200
        else:
            ctx = "Report %s has no results. Please regenerate." % report.name
            status = 503

        return HttpResponse(ctx,
                            status=status,
                            content_type='application/json; charset=utf-8')

    def post(self, request, app='mypartners', model='contactrecords'):
        """
        Create a report by querying on a specific model.

        The request's POST data is parsed for parameters to pass to the model's
        `from_search` method.

        Inputs:
            :app: The app to which the model belongs.
            :model: The model to query on

        Query String Parameters:
            :csrfmiddlewaretoken: Used to prevent Cross Site Request Forgery.
            :report_name: What to name the report. Spaces are converted to
                          underscores.
            :filters: A JSON string representing th exact query to be run.
            :values: Fields to include in report output.

        Outputs:
           An HttpResponse indicating success or failure of report creation.
        """

        company = get_company_or_404(request)
        name = request.POST.get('report_name', str(datetime.now()))
        filters = request.POST.get('filters', "{}")

        records = get_model(app, model).objects.from_search(company, filters)

        contents = serialize('json', records)
        results = ContentFile(contents)
        report, _ = Report.objects.get_or_create(name=name,
                                                 created_by=request.user,
                                                 owner=company,
                                                 app=app,
                                                 model=model,
                                                 filters=filters)

        report.results.save('%s-%s.json' % (name, report.pk), results)

        return HttpResponse(name, content_type='text/plain')
Esempio n. 19
0
class OfflinePurchaseFormView(PostajobModelFormMixin, RequestFormViewBase):
    form_class = OfflinePurchaseForm
    model = OfflinePurchase
    display_name = 'Offline Purchase'

    success_url = reverse_lazy('offlinepurchase')
    add_name = 'offlinepurchase_add'
    update_name = 'offlinepurchase_update'
    delete_name = 'offlinepurchase_delete'

    @method_decorator(requires("delete offline purchase"))
    def delete(self, request):
        if self.object.redeemed_on:
            raise Http404("postajob.views.OfflinePurchaseFormView: "
                          "can't delete redeemed OfflinePurchases")
        return super(OfflinePurchaseFormView, self).delete(request)

    @method_decorator(user_is_allowed())
    def dispatch(self, *args, **kwargs):
        """
        Decorators on this function will be run on every request that
        goes through this class.

        """
        return super(OfflinePurchaseFormView, self).dispatch(*args, **kwargs)

    def get_success_url(self):
        if resolve(self.request.path).url_name == self.add_name:
            kwargs = {
                'pk': self.object.pk,
            }
            return reverse('offline_purchase_success', kwargs=kwargs)
        return self.success_url

    def set_object(self, request):
        """
        Attempting to determine what happens to Products in an already-redeemed
        OfflinePurchase is nearly impossible, so OfflinePurchases can
        only be added or deleted.

        """
        acceptable_names = [self.add_name, self.delete_name]
        if resolve(request.path).url_name not in acceptable_names:
            raise Http404("postajob.views.OfflinePurchaseFormView: "
                          "OfflinePurchases can only be added or deleted")
        return super(OfflinePurchaseFormView, self).set_object(request)

    def get(self, *args, **kwargs):
        company = get_company_or_404(self.request)
        if not can_modify(self.request.user, company, kwargs,
                          "update offline purchase",
                          "create offline purchase"):
            return MissingActivity()

        return super(OfflinePurchaseFormView, self).get(*args, **kwargs)

    def post(self, *args, **kwargs):
        company = get_company_or_404(self.request)
        if not can_modify(self.request.user, company, kwargs,
                          "update offline purchase",
                          "create offline purchase"):
            return MissingActivity()

        return super(OfflinePurchaseFormView, self).post(*args, **kwargs)

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

        return context