def perform_destroy(self, instance): # We will archive the user record to keep audit foreign keys # in place but we delete the roles on organizations # for that user to make sure access rights for the archive profile # are fully gone. get_role_model().objects.filter(user=instance).delete() super(UserProfileAPIView, self).perform_destroy(instance)
def _wrapped_view(request, *args, **kwargs): LOGGER.debug("Enters djaoapp.decorators.requires_authenticated") redirect_url = fail_authenticated(request) if redirect_url: verification_key = kwargs.get('verification_key', None) if verification_key: contact = Contact.objects.filter( 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.update_or_create_token( role.user) verification_key = contact.verification_key except role_model.DoesNotExist: pass if contact and has_invalid_password(contact.user): redirect_url = request.build_absolute_uri( reverse('registration_activate', args=(verification_key, ))) return redirect_or_denied( request, redirect_url, redirect_field_name=redirect_field_name) return view_func(request, *args, **kwargs)
def user_activated_notice(sender, user, verification_key, request, **kwargs): """ A new user has activated his account. We have a complete profile and active email address now. """ for role in get_role_model().objects.filter(grant_key=verification_key): role.grant_key = None role.save() broker = get_broker() site = get_current_site() recipients, bcc = _notified_recipients(broker) app = get_current_app() LOGGER.debug( "[signal] user_activated_notice(user=%s, verification_key=%s)", user, verification_key) if SEND_EMAIL: get_email_backend(connection=app.get_connection()).send( from_email=app.get_from_email(), recipients=recipients, bcc=bcc, template='notification/user_activated.eml', context={ 'request': request, 'broker': get_broker(), 'app': app, 'user': get_user_context(user), 'urls': { 'user': { 'profile': site.as_absolute_uri( reverse('users_profile', args=(user, ))) } } })
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. """ redirect = fail_authenticated_default(request) if redirect: if verification_key: contact = Contact.objects.filter( 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.update_or_create_token( role.user) verification_key = contact.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
class RoleListAPIView(RoleListBaseAPIView): """ Lists roles of a specific type Lists the specified role assignments for an organization. **Tags: rbac **Examples .. code-block:: http GET /api/profile/cowork/roles/manager/ HTTP/1.1 responds .. code-block:: json { "count": 1, "next": null, "previous": null, "results": [ { "created_at": "2018-01-01T00:00:00Z", "role_description": { "name": "Manager", "slug": "manager", "organization": { "slug": "cowork", "full_name": "ABC Corp.", "printable_name": "ABC Corp.", "created_at": "2018-01-01T00:00:00Z", "email": "*****@*****.**" } }, "user": { "slug": "alice", "email": "*****@*****.**", "full_name": "Alice Doe", "created_at": "2018-01-01T00:00:00Z" }, "request_key": "1", "grant_key": null } ] } """ serializer_class = RoleSerializer queryset = get_role_model().objects.all().select_related('user__contact')
def fail_active_roles(request): """ User with active roles only """ role_model = get_role_model() redirect_to = reverse('saas_user_product_list', args=(request.user, )) if request.path == redirect_to: # Prevents URL redirect loops return False if role_model.objects.filter(user=request.user, grant_key__isnull=False).exists(): # We have some invites pending so let's first stop # by the user accessibles page. return redirect_to return False
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 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