def _wrapped_view(request, *args, **kwargs): LOGGER.debug("Enters djaoapp.decorators.requires_provider_only") site = get_current_site() organization = kwargs.get('organization', None) if site.db_name: # We have a separate database so it is OK for a manager # of the site to access registered ``Organization`` which # are not subscribed yet. if _has_valid_access(request, [get_current_broker()], strength): return view_func(request, *args, **kwargs) try: app = get_current_app() #pylint:disable=unused-variable redirect_url, matched, session = check_matched( request, app, prefixes=DEFAULT_PREFIXES) if redirect_url: if isinstance(redirect_url, six.string_types): return http.HttpResponseRedirect(redirect_url) raise PermissionDenied() except NoRuleMatch: # By default, we are looking for provider. slug = kwargs.get('charge', organization) redirect_url = _fail_provider_only( request, organization=slug, roledescription=roledescription, strength=strength) if redirect_url: return redirect_or_denied(request, redirect_url, redirect_field_name=redirect_field_name, descr=_("%(auth)s is not a manager of one of"\ " %(organization)s providers.") % {'auth': request.user, 'organization': slug}) return view_func(request, *args, **kwargs)
def _wrapped_view(request, *args, **kwargs): LOGGER.debug("Enters djaoapp.decorators.requires_self_provider") site = get_current_site() if site.db_name: # We have a separate database so it is OK for a manager # of the site to access profiles of ``User`` which # are not subscribed yet. if _has_valid_access(request, [get_current_broker()], strength): return view_func(request, *args, **kwargs) try: app = get_current_app() #pylint:disable=unused-variable redirect_url, matched, session = check_matched( request, app, prefixes=DEFAULT_PREFIXES) if redirect_url: if isinstance(redirect_url, six.string_types): return http.HttpResponseRedirect(redirect_url) raise PermissionDenied() except NoRuleMatch: redirect_url = _fail_self_provider(request, user=kwargs.get( 'user', None), strength=strength) if redirect_url: return redirect_or_denied(request, redirect_url, redirect_field_name=redirect_field_name, descr=_("%(auth)s has neither a direct"\ " relation to an organization connected to %(user)s nor a connection to one"\ " of the providers to such organization.") % { 'auth': request.user, 'user': kwargs.get('user', None)}) return view_func(request, *args, **kwargs)
def _wrapped_view(request, *args, **kwargs): try: app = get_current_app() redirect_url, _, _ = check_matched( request, app, prefixes=[ '/api/billing/', '/api/metrics/', '/api/profile/', '/api/users/', '/billing/', '/metrics/', '/profile/', '/users/' ]) if redirect_url: if isinstance(redirect_url, six.string_types): return http.HttpResponseRedirect(redirect_url) raise PermissionDenied() except NoRuleMatch: slug = kwargs.get('charge', kwargs.get('organization', None)) redirect_url = _fail_direct(request, organization=slug, roledescription=roledescription, strength=strength) if redirect_url: return redirect_or_denied( request, redirect_url, redirect_field_name=redirect_field_name, descr="%(user)s is not a direct manager '\ ' of %(organization)s." % { 'user': request.user, 'organization': slug }) return view_func(request, *args, **kwargs)
def get(self, request, *args, **kwargs): #pylint:disable=unused-argument,no-self-use context = {} app = get_current_app() try: storage = get_default_storage(request, account=app.account) # The following statement will raise an Exception # when we are dealing with a ``FileSystemStorage``. location = "s3://%s/%s" % (storage.bucket_name, storage.location) aws_region = context.get('aws_region', None) context.update(aws_bucket_context(request, location, aws_upload_role=app.role_name, aws_external_id=app.external_id, aws_region=aws_region, acls=['private', 'public-read'])) if request.query_params.get('public', False): context.update({ 'policy': context['public_read_aws_policy'], 'signature': context['public_read_aws_policy_signature'], }) else: context.update({ 'policy': context['private_aws_policy'], 'signature': context['private_aws_policy_signature'], }) except AttributeError: LOGGER.debug("doesn't look like we have a S3Storage.") serializer = self.get_serializer(data=context) serializer.is_valid(raise_exception=True) return Response(serializer.validated_data)
def fail_self_provider(request, user=None, roledescription=None): """ Same decorator as saas.requires_self_provider with the added permissions that managers of the site database itself are also able to access profiles of registered yet unsubscribed ``Organization``. """ site = get_current_site() if site.db_name and site.db_name != DEFAULT_DB_ALIAS: # We have a separate database so it is OK for a manager # of the site to access registered ``Organization`` which # are not subscribed yet. if _has_valid_access(request, [get_current_broker()]): return False try: app = get_current_app() #pylint:disable=unused-variable redirect, matched, session = check_matched(request, app, prefixes=DEFAULT_PREFIXES) except NoRuleMatch: # By default, we are looking for provider. redirect = fail_self_provider_default(request, user=user, roledescription=roledescription) return redirect
def _wrapped_view(request, *args, **kwargs): site = get_current_site() if site.db_name: # We have a separate database so it is OK for a manager # of the site to access profiles of ``User`` which # are not subscribed yet. if _has_valid_access(request, [get_current_broker()], strength): return view_func(request, *args, **kwargs) try: app = get_current_app() redirect_url, _, _ = check_matched( request, app, prefixes=[ '/api/billing/', '/api/metrics/', '/api/profile/', '/api/users/', '/billing/', '/metrics/', '/profile/', '/users/' ]) if redirect_url: if isinstance(redirect_url, six.string_types): return http.HttpResponseRedirect(redirect_url) raise PermissionDenied() except NoRuleMatch: if _fail_self_provider(request, user=kwargs.get('user', None), strength=strength): raise PermissionDenied("%(auth)s has neither a direct"\ " relation to an organization connected to %(user)s nor a connection to one"\ "of the providers to such organization." % { 'auth': request.user, 'user': kwargs.get('user', None)}) return view_func(request, *args, **kwargs)
def get_context_data(self, **kwargs): context = super(DjaoAppMixin, self).get_context_data(**kwargs) context.update({'edit_perm': self.edit_perm}) # XXX generic_navbar.html if self.organization: if not Plan.objects.filter( organization=self.organization).exists(): context.update({'next_url': reverse('saas_cart_plan_list')}) # URLs for user if self.request.user.is_authenticated(): urls = { 'user': { 'logout': reverse('logout'), 'profile': reverse('users_profile', args=(self.request.user, )), } } else: urls = { 'user': { 'login': reverse('login'), 'login_github': reverse('social:begin', args=('github', )), 'login_google': reverse('social:begin', args=('google-oauth2', )), 'login_twitter': reverse('social:begin', args=('twitter', )), 'password_reset': reverse('password_reset'), 'register': reverse('registration_register'), } } # URLs for provider app = get_current_app() # ``app.account`` is guarenteed to be in the same database as ``app``. # ``site.account`` is always in the *default* database, which is not # the expected database ``Organization`` are typically queried from. provider = app.account if not fail_direct(self.request, organization=provider): urls.update({ 'provider': { 'dashboard': reverse('saas_dashboard', args=(provider, )), } }) if 'urls' in context: for key, val in six.iteritems(urls): if key in context['urls']: context['urls'][key].update(val) else: context['urls'].update({key: val}) else: context.update({'urls': urls}) return context
def fail_direct(request, organization=None, roledescription=None): try: app = get_current_app() #pylint:disable=unused-variable redirect, matched, session = check_matched(request, app, prefixes=DEFAULT_PREFIXES) except NoRuleMatch: redirect = fail_direct_default(request, organization=organization, roledescription=roledescription) return redirect
def fail_edit_perm(request, account=None): """ Returns ``True`` if the request user does not have edit permissions. """ result = True # The context processor will be called from the e-mail sender # which might not be associated to a request. if request is not None: if account is None: account = get_current_app().account result = not bool(_valid_manager(request, [account])) return result
def get_context_data(self, **kwargs): context = super(PricingView, self).get_context_data(**kwargs) if self.edit_perm: app = get_current_app() if app.show_edit_tools: context.update({ 'show_show_edit_tools': app.show_edit_tools, 'plan': Plan() }) if not self.object_list.exists(): messages.info(self.request, _("No Plans yet."\ " Click the 'Add Plan' button to create one.")) return context
def djaoapp_urls(request, account=None, base=None): if account is None: account = get_current_app().account urls = { 'pricing': build_absolute_uri(request, location='/pricing/', site=settings.APP_NAME), 'cart': build_absolute_uri(request, location='/billing/%s/cart/' % account, site=settings.APP_NAME) } if base: urls.update({ 'app': build_absolute_uri(request, location='/app/%s/' % base, site="%s-master" % settings.DB_NAME) }) # XXX Hack for correct domain return urls
def fail_authenticated(request, verification_key=None): """ Decorator for views that checks that the user is authenticated. ``django.contrib.auth.decorators.login_required`` will automatically redirect to the login page. We wante to redirect to the activation page when required, as well as raise a ``PermissionDenied`` instead when Content-Type is showing we are dealing with an API request. """ try: app = get_current_app() #pylint:disable=unused-variable redirect, matched, session = check_matched(request, app, prefixes=DEFAULT_PREFIXES) except NoRuleMatch: redirect = fail_authenticated_default(request) if redirect: if verification_key: contact = Contact.objects.filter( Q(email_verification_key=verification_key) | Q(phone_verification_key=verification_key)).first() if not contact: # Not a `Contact`, let's try `Role`. role_model = get_role_model() try: role = role_model.objects.filter( Q(grant_key=verification_key) | Q(request_key=verification_key)).get() contact, _ = Contact.objects.prepare_email_verification( role.user, role.user.email) verification_key = contact.email_verification_key except role_model.DoesNotExist: pass if contact and has_invalid_password(contact.user): redirect = request.build_absolute_uri( reverse('registration_activate', args=(verification_key, ))) return redirect
def _wrapped_view(request, *args, **kwargs): LOGGER.debug("Enters djaoapp.decorators.requires_direct") try: app = get_current_app() #pylint:disable=unused-variable redirect_url, matched, session = check_matched(request, app, prefixes=DEFAULT_PREFIXES) if redirect_url: if isinstance(redirect_url, six.string_types): return http.HttpResponseRedirect(redirect_url) raise PermissionDenied() except NoRuleMatch: slug = kwargs.get('charge', kwargs.get('organization', None)) redirect_url = _fail_direct(request, organization=slug, roledescription=roledescription, strength=strength) if redirect_url: return redirect_or_denied(request, redirect_url, redirect_field_name=redirect_field_name, descr=_("%(auth)s is not a direct manager"\ " of %(organization)s.") % {'auth': request.user, 'organization': slug}) return view_func(request, *args, **kwargs)
def get(self, request, *args, **kwargs): context = {} app = get_current_app() try: # The following statement will raise an Exception # when we are dealing with a ``FileSystemStorage``. _ = get_storage_class().bucket_name bucket_name = get_bucket_name(app) media_prefix = get_media_prefix(app) aws_region = context.get('aws_region', None) context.update( aws_bucket_context(request, bucket_name, aws_upload_role=app.role_name, aws_external_id=app.external_id, aws_region=aws_region, acls=['private', 'public-read'])) if request.query_params.get('public', False): context.update({ 'policy': context['public_read_aws_policy'], 'signature': context['public_read_aws_policy_signature'], }) else: context.update({ 'policy': context['private_aws_policy'], 'signature': context['private_aws_policy_signature'], }) context.update({'media_prefix': media_prefix}) except AttributeError: LOGGER.debug("doesn't look like we have a S3Storage.") serializer = CredentialsSerializer(data=context) serializer.is_valid(raise_exception=True) return Response(serializer.validated_data)
def _wrapped_view(request, *args, **kwargs): site = get_current_site() organization = kwargs.get('organization', None) if site.db_name: # We have a separate database so it is OK for a manager # of the site to access registered ``Organization`` which # are not subscribed yet. if _has_valid_access(request, [get_current_broker()], strength): return view_func(request, *args, **kwargs) try: app = get_current_app() redirect_url, _, _ = check_matched( request, app, prefixes=[ '/api/billing/', '/api/metrics/', '/api/profile/', '/api/users/', '/billing/', '/metrics/', '/profile/', '/users/' ]) if redirect_url: if isinstance(redirect_url, six.string_types): return http.HttpResponseRedirect(redirect_url) raise PermissionDenied() except NoRuleMatch: # By default, we are looking for provider. slug = kwargs.get('charge', organization) redirect_url = _fail_provider_only( request, organization=slug, roledescription=roledescription, strength=strength) if redirect_url: return redirect_or_denied(request, redirect_url, "%(user)s is not a manager of one of"\ " %(slug)s providers." % {'user': request.user, 'slug': slug}) return view_func(request, *args, **kwargs)
def inject_edition_tools(response, request, context=None, body_top_template_name=None, body_bottom_template_name=None): """ If the ``request.user`` has editable permissions, this method injects the edition tools into the html *content* and return a BeautifulSoup object of the resulting content + tools. If the response is editable according to the proxy rules, this method returns a BeautifulSoup object of the content such that ``PageMixin`` inserts the edited page elements. """ #pylint:disable=too-many-locals if context is None: context = {} dj_urls = {} edit_urls = {} provider_urls = {} site = get_current_site() app = get_current_app() # ``app.account`` is guarenteed to be in the same database as ``app``. # ``site.account`` is always in the *default* database, which is not # the expected database ``Organization`` are typically queried from. provider = app.account enable_code_editor = False edit_urls = { 'api_medias': reverse('uploaded_media_elements', kwargs={'path': ''}), 'api_sitecss': reverse('edit_sitecss'), 'api_less_overrides': reverse('pages_api_less_overrides'), 'api_sources': reverse('pages_api_sources'), 'api_page_elements': reverse('page_elements'), 'api_plans': reverse('saas_api_plans', args=(provider, )), 'plan_update_base': reverse('saas_plan_base', args=(provider, )) } if not fail_edit_perm(request, account=provider): body_bottom_template_name = "pages/_body_bottom.html" try: # The following statement will raise an Exception # when we are dealing with a ``FileSystemStorage``. _ = get_storage_class().bucket_name edit_urls.update({'media_upload': reverse('api_credentials')}) except AttributeError: LOGGER.debug("doesn't look like we have a S3Storage.") enable_code_editor = is_streetside(site) if not has_bank_account(provider): provider_urls = { 'bank': reverse('saas_update_bank', args=(provider, )) } body_top_template_name = "pages/_body_top_connect_processor.html" elif is_testing(site): if enable_code_editor: dj_urls = djaoapp_urls(request, account=provider, base=site.as_base()) body_top_template_name = "pages/_body_top_streetside_cart.html" else: dj_urls = djaoapp_urls(request, account=provider) body_top_template_name = "pages/_body_top_mallspace_cart.html" # XXX ``is_streetside(site)`` shouldn't disable all edit functionality. # Just the edition of templates. body_bottom_template_name = "pages/_body_bottom_edit_tools.html" elif not has_bank_account(provider) or is_testing(site): body_top_template_name = "pages/_body_top.html" if not (body_top_template_name or body_bottom_template_name): return None context.update({ 'ENABLE_CODE_EDITOR': enable_code_editor, 'FEATURE_DEBUG': settings.FEATURES_DEBUG, 'urls': { 'provider': provider_urls, 'djaodjin': dj_urls, 'edit': edit_urls } }) context.update(csrf(request)) return pages_inject_edition_tools( response, request, context=context, body_top_template_name=body_top_template_name, body_bottom_template_name=body_bottom_template_name)
def inject_edition_tools(response, request, context=None, body_top_template_name=None, body_bottom_template_name=None): """ If the ``request.user`` has editable permissions, this method injects the edition tools into the html *content* and return a BeautifulSoup object of the resulting content + tools. If the response is editable according to the proxy rules, this method returns a BeautifulSoup object of the content such that ``PageMixin`` inserts the edited page elements. """ #pylint:disable=too-many-locals,too-many-nested-blocks,too-many-statements content_type = response.get('content-type', '') if not content_type.startswith('text/html'): return None if not is_authenticated(request): return None if context is None: context = {} # ``app.account`` is guarenteed to be in the same database as ``app``. # ``site.account`` is always in the *default* database, which is not # the expected database ``Organization`` are typically queried from. app = get_current_app() provider = app.account soup = None if app.show_edit_tools and get_role_model().objects.valid_for( organization=provider, user=request.user): edit_urls = { 'api_medias': reverse('uploaded_media_elements', kwargs={'path': ''}), 'api_sitecss': reverse('edit_sitecss'), 'api_less_overrides': reverse('pages_api_less_overrides'), 'api_sources': reverse('pages_api_sources'), 'api_page_element_base': reverse('api_page_element', kwargs={'path': ''}), 'api_plans': reverse('saas_api_plans', args=(provider, )), 'plan_update_base': reverse('saas_plan_base', args=(provider, )) } try: # The following statement will raise an Exception # when we are dealing with a ``FileSystemStorage``. _ = get_storage_class().bucket_name edit_urls.update( {'media_upload': reverse('api_credentials_organization')}) except AttributeError: LOGGER.debug("doesn't look like we have a S3Storage.") # XXX sites which are hosted on a same domain shouldn't disable # all edit functionality, just the edition of base templates. site = get_current_site() enable_code_editor = is_domain_site(site) if enable_code_editor: dj_urls = djaoapp_urls(request, account=provider, base=site.as_base()) body_bottom_template_name = "pages/_body_bottom_edit_tools.html" else: dj_urls = djaoapp_urls(request, account=provider) body_bottom_template_name = "pages/_body_bottom.html" context.update({ 'ENABLE_CODE_EDITOR': enable_code_editor, 'FEATURE_DEBUG': settings.FEATURES_DEBUG, 'urls': { 'djaodjin': dj_urls, 'edit': edit_urls } }) context.update(csrf(request)) soup = pages_inject_edition_tools( response, request, context=context, body_top_template_name=body_top_template_name, body_bottom_template_name=body_bottom_template_name) # Insert the authenticated user information and roles on organization. if not soup: soup = BeautifulSoup(response.content, 'html5lib') if soup and soup.body: # Implementation Note: we have to use ``.body.next`` here # because html5lib "fixes" our HTML by adding missing # html/body tags. Furthermore if we use #``soup.body.insert(1, BeautifulSoup(body_top, 'html.parser'))`` # instead, later on ``soup.find_all(class_=...)`` returns # an empty set though ``soup.prettify()`` outputs the full # expected HTML text. auth_user = soup.body.find(class_='header-menubar') user_menu_template = '_menubar.html' if auth_user and user_menu_template: serializer_class = import_string(rules_settings.SESSION_SERIALIZER) serializer = serializer_class(request) path_parts = reversed(request.path.split('/')) top_accessibles = [] has_broker_role = False active_organization = None for role, organizations in six.iteritems(serializer.data['roles']): for organization in organizations: if organization['slug'] == request.user.username: # Personal Organization continue db_obj = get_organization_model().objects.get( slug=organization['slug']) # XXX Remove query. if db_obj.is_provider: settings_location = reverse( 'saas_dashboard', args=(organization['slug'], )) else: settings_location = reverse( 'saas_organization_profile', args=(organization['slug'], )) app_location = reverse('organization_app', args=(organization['slug'], )) if organization['slug'] in path_parts: active_organization = TopAccessibleOrganization( organization['slug'], organization['printable_name'], settings_location, role, app_location) if is_broker(organization['slug']): has_broker_role = True top_accessibles += [ TopAccessibleOrganization( organization['slug'], organization['printable_name'], settings_location, role, app_location) ] if not active_organization and has_broker_role: active_organization = get_broker() context.update({'active_organization': active_organization}) context.update({'top_accessibles': top_accessibles}) template = loader.get_template(user_menu_template) user_menu = render_template(template, context, request).strip() auth_user.clear() els = BeautifulSoup(user_menu, 'html5lib').body.ul.children for elem in els: auth_user.append(BeautifulSoup(str(elem), 'html5lib')) return soup
def get_context_data(self, **kwargs): context = super(ExtraMixin, self).get_context_data(**kwargs) # Flags used in saas/_body_top_template.html to show how processor # handles cards and charges. # if broker not configured # return configure_broker() # if broker in testmode # return configure_broker_livemode() # if provider not connected # return connect_provider() # if provider in testmode # return connect_provider_livemode() app = get_current_app() # ``app.account`` is guarenteed to be in the same database as ``app``. # ``site.account`` is always in the *default* database, which is not # the expected database ``Organization`` are typically queried from. # XXX Relying on settings instead of saas_settings to cut down # on imports. `requires_provider_keys` matches definition # in `saas.backends.stripe_processor.base.StripeBackend`. broker_pub_key = getattr(settings, 'STRIPE_PUB_KEY', None) processor_backend_mode = settings.SAAS.get('PROCESSOR', STRIPE_CONNECT_LOCAL).get( 'MODE', STRIPE_CONNECT_LOCAL) requires_provider_keys = (processor_backend_mode in (STRIPE_CONNECT_FORWARD, STRIPE_CONNECT_REMOTE) and not self._is_platform(app.account)) provider_pub_key = app.account.processor_pub_key processor_hint = None if not broker_pub_key: processor_hint = 'configure_broker' elif requires_provider_keys and not provider_pub_key: processor_hint = 'connect_provider' elif not broker_pub_key.startswith('pk_live_'): processor_hint = 'configure_broker_livemode' elif (requires_provider_keys and not provider_pub_key.startswith('pk_live_')): processor_hint = 'connect_provider_livemode' context.update({'processor_hint': processor_hint}) self.update_context_urls( context, { 'provider': { 'bank': reverse('saas_update_bank', args=(app.account, )) } }) if not is_broker(self.organization): if 'urls' in context: if 'pages' in context['urls']: del context['urls']['pages'] if 'rules' in context['urls']: del context['urls']['rules'] # XXX might be overkill to always add ``site`` even though # it is only used in ``templates/saas/users/roles.html`` at this point. context.update({'site': get_current_site()}) self.update_context_urls( context, { 'profile_redirect': reverse('accounts_profile'), }) # `ExtraMixin.get_context_data` is called before # `OrganizationMixin.get_context_data` had an opportunity to # add the organization to the `context`, so we call # `OrganizationMixin.organization` here. hmmm. attached_user = self.organization.attached_user() if attached_user: self.update_context_urls( context, { 'user': { # The following are copy/pasted # from `signup.UserProfileView` # to be used in the personal profile page. 'api_generate_keys': reverse('api_generate_keys', args=(attached_user, )), 'api_profile': reverse('api_user_profile', args=(attached_user, )), 'api_password_change': reverse('api_user_password_change', args=(attached_user, )), 'api_contact': reverse('api_contact', args=(attached_user.username, )), #XXX 'api_pubkey': reverse('api_pubkey', args=(attached_user, )), 'password_change': reverse('password_change', args=(attached_user, )), # For sidebar menu items on personal profiles. 'accessibles': reverse('saas_user_product_list', args=(attached_user, )), 'notifications': reverse('users_notifications', args=(attached_user, )), 'profile': reverse('users_profile', args=(attached_user, )), } }) # XXX we can't enable this code until we remove references # to `User = get_user_model()` in signup.compat. #if has_valid_password(attached_user): # self.update_context_urls(context, {'user': { # 'api_activate': reverse( # 'api_user_activate', args=(attached_user,)), # }}) # XXX temporarily until djaodjin-saas v0.5 is released. #if not is_broker(self.organization): # self.update_context_urls(context, { # 'rules': {'app': None}, # 'pages': {'theme_base': None}, # }) return context