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)
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)
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)
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)
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)
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)
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)
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)
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.")
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.")
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.")
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.")
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')
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