Dispatch a similar URL to different apps depending on user status - django

I have 2 apps, Registration and Albums. If the user visits the '/' or '/home' then they should see either the registration/login form or their album management page depending on whether the user is logged in or not.
Is there an established best practice for how to dispatch a similar URL between 2 different apps? Is there a way to build this so that either App does not need to know about the other?
Thanks!

If your needs are restricted to showing a login form if the user is not logged in vs showing the "home page" when the user is not logged in, I'd recommend that you use the "login required" decorator.
from django.contrib.auth.decorators import login_required
#login_required
def show_home(request):
"""
Show home page...
"""
...
This decorator can be applied at the view level ( as shown above ) or in urls.py ( as shown below ):
url(r'^reports/', login_required(ListView.as_view(
template_name="...",
queryset = ...,
context_object_name = ...
))),
The second pattern is commonly used with generic views and class based views.
Both solutions presuppose that you are hooking into Django's built in login / registration apparatus ( with customized templates and customized views where needed ). If you are using a custom registration / auth framework, it will still be a good idea to use a decorator pattern.

If you set LOGIN_URL to /registration/login, and decorate your / view with #login_required, then they will automatically be redirected.

when user signs-in add a variable to session and check it on the / or /home request.

Related

Django allauth - Signing up a new user while already logged in

I'm trying to customize allauth's default SignUpView and SignUpForm to allow me to create other users while already logged in. The default behavior prevents me from doing this: in other words, I can only sign up for a new account if I'm not authenticated.
How do I override this behavior?
I presume I'll have to override the SignupView in views.py but I'm not sure what to look for... I played around with RedirectAuthenticatedUserMixin, but to no avail.
Forms.py
from allauth.account.forms import SignupForm
class SubUserForm(SignupForm):
USER_TYPES = [
(2,'customer'),
(3,'vendor'),
(4,'supplier')
]
first_name = forms.CharField(max_length=45)
last_name = forms.CharField(max_length=45)
user_type = forms.CharField(widget=forms.Select(choices=USER_TYPES))
Views.py
from allauth.account.views import SignupView
class SubUserSignupView(SignupView):
template_name = 'accounts/new_user_signup_form.html'
form_class = SubUserForm
view_name = 'sub_user_signup'
sub_user_signup = SubUserSignupView.as_view()
urls.py
urlpatterns = [
path('sub_user/',views.sub_user_signup,name='sub_user_signup'),
]
To put in context
My app allows for a 'parent' user to sign up multiple 'children' users (called 'subuser' in the code above) using allauth. In my case, an organization can create several customers, merchants, suppliers, etc. When a parent user creates a child user, a verification email is sent to the child user, who then activates his account and is prompted to enter a password. I use 2 signup forms; the default allauth signup (for parent accounts), and a customized signup form (for children accounts), which also extends from allauth.
Although the registration flow above works well, a parent user can only sign up new children users (trigger email verification) when logged out. I'm struggling to identify what I need to prevent this from happening.
Navigate to the allauth directory, under app settings, set this to False
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS (=True)
The default behaviour is to redirect authenticated users to LOGIN_REDIRECT_URL when they try accessing login/signup pages.
By changing this setting to False, logged in users will not be redirected when they access login/signup pages.
This also worked
Navigate to the allauth folder, under views find SignupView.
Deleting the redirectAuthenticatedUsermixin works
New issue is that you are logged in as the new user, fixing that currently.
First of all, this article maybe useful:
https://tech.serhatteker.com/post/2020-06/custom-signup-view-in-django-allauth/
The reason you can only sign up for a new account if you're not authenticated is because of this Allauth's mixin: RedirectAuthenticatedUserMixin (as suggested by Anthony M).
So, you have to override this mixin and the allauth's signup view with your own code.
It is very important that you register the url before allauth urls.
Hope it helps.

How can I set up site-wide password protection and privilege requirements on views with Django?

My Django app is meant for internal use at the company I work at; however, it needs to be set up such that only certain employees with login credentials can access any of the web pages. Furthermore, I need to be able to customize the views so that only accounts with the right privileges can access them. How would I go about this?
My gut instinct is to use the same password protection and privilege system that the admin site uses since my project is basically just meant for viewing and editing the database easily. However, Google doesn't seem to turn up any information on how to do this, and I've only been working with Django for a month and half so I don't quite have the chops to figure this out myself. Is there a way to use the admin site's password protection and privilege system or is it inaccessible?
If staff privileges are enough this can easily be done using the staff_member_required view decorator. All you need is to apply the decorator to your view
staff_member_required Example:
from django.contrib.admin.views.decorators import staff_member_required
#staff_member_required
def random_view(request):
#If the user does not have staff privileges he will be redirected to a login page
If you are looking to test more specific privileges you should use the user_passes_test decorator. See: Django User Passes Test Decorator
You apply the decorator to your view and pass a function as a parameter that validates if a user should have access to that page, if the function returns True access is given normally, otherwise the user will be redirected.
user_passes_test Example:
from django.contrib.auth.decorators import user_passes_test
def user_is_author(user)
#your test goes here, pseudo code example ignore syntax.
return user.is_author
#user_passes_test(user_is_author)
def random_view(request):
#if user passed the test the view will work normally

Django REST - Serialize User.get_all_permissions

I am building an application with a Django Rest backend, and a VueJS front end and am working through authorization and authentication. I have the authentication working well, but am a bit stuck on letting the front end (VueJS) know what the user has authorization to do in terms of Add/Change/View/Delete for a model. For example, if a user cannot add a customer, I don't want to show the 'Add Customer button'.
Working through the Django docs, and solutions on StackOverflow, I believe the simplest way is to send the user's permissions from Django to VueJS.
The 'best'/'simplest' way I can see to get the permissions is with the following:
userModel = User.objects.get(request.user)
return User.get_all_permissions(userModel)
Where I am stuck is exactly where to put this logic and how to serialize it. Does the above belong in the View, Serializer, other? Up until now, I have only been working with Models (ModelSerializers and ModelViews), but I don't believe this falls into this category.
Thanks in advance...
You should add this logic to views, because the views are used to implement these kinds of logic.
Actually, you don't want to use serializers here, because of the response of .get_all_permissions() method is already in serialized form
Apart from that, your provided code is not good (it's clearly bad). It should be as below,
return request.user.get_all_permissions()
because, you'll get current logged-in user's instance through request.user, to get his/her permissions, you all need to call the get_all_permissions() method
Example
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
#permission_classes(IsAuthenticated, )
#api_view()
def my_view(request):
logged_in_user = request.user
return Response(data=logged_in_user.get_all_permissions())

How to Redirect to user profile in django? i am using Django registration Redux

I am working on an app where the user will be able to login to his profile. I am using Django-registration-redux. I am using the below code to inculde in my project.
LOGIN_REDIRECT_URL = '/profile/view/(?P<pk>[0-9]+)/'
I want to redirect the user to his profile after logging in. I know that is not the way you can actually call an url in settings file. any solution for the problem?
I believe you can use https://docs.djangoproject.com/en/dev/ref/urlresolvers/#reverse-lazy to add URL resolution to a setting.
You don't need to pass the user pk to the view. You can get this value and every other data field of the user from request.user object.
As stated in Django docs, you could do something like this:
def profile(request):
if request.user.is_authenticated:
# Do something for logged-in users.
request.user.do_something()
[...]
else:
# Do something for anonymous users like redirect to registration
pass

Django Redirect after Successful Login

I have a requirement that whenever I login or attempt to request a view that has a login_decorator then the next page be a page where I am required to ask the user to select a business entity (irreespective of the original view requested).
Let's say that the page is http://127.0.0.1:8999/APP/business_unit
To achieve this I configured the following in my settings.py
LOGIN_REDIRECT_URL='/APP/business_unit_selector'
Now when i try to access http://127.0.0.1:8999/APP/range_list
the page goes to http://127.0.0.1:8999/APP/login?next=/APP/range_list I was expecting that the next page after login be /APP/business_unit
but instead, the next page was /APP/range_list
The browser address bar has http://127.0.0.1:8999/APP/login?next=/APP/range_list
Is it possible to achieve what I am trying in Django?
LOGIN_REDIRECT_URL is used unly when next is unspecified. In your test request there is next=/APP/range_list - and that address is used to redirect user after login.
Probably the easiest and most effective solution is to make your own decorator, similar to login_required which redirects to /APP/business_unit_selector&next=<redirect_url> if unit is not selected, and apply it together with login_required. It is not the most efficient solution in terms of redirects number, but is quite clean, and doesn't mess up the login page.
You will also have to handle next parameter in your business_unit_selector view, if you like to achieve natural flow.
Your decorator should be something like
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.utils.http import urlquote
import functools
def business_unit_required(view):
#login_required # probably you want to incorporate it here
#functools.wraps(view)
def wrapped(request, *args, **kwargs):
if not 'selected_business_unit' in request.session:
return redirect('%s?next=%s' % (
reverse('business_unit_selector'),
urlquote(request.get_full_path())))
return view(request, *args, **kwargs)
return wrapped
The reason that http://127.0.0.1:8999/APP/login?next=/APP/range_list is redirecting you to range_list after logging in, is because with next= you are overriding what is specified in your settings file, LOGIN_REDIRECT_URL='/APP/business_unit_selector'.
If I understand correctly you need to user to choose a business entity after logging in.
A couple solutions that come to mind are as follows:
1.) Don't use a separate forms for login and business entity. Instead combine them.
Username
Password
Business Entity
2.) You can also specify in your view if the user doesn't have a buisness entity ResponseRedirect("/APP/business_unit_selector")
docs here