In my app I have 3 kind of users with different permissions. HR, Employees and candidate.
I would like to be able to create a User employee providing only its email ans set it as inactive And when the employee sign in into the app he setup a his first name, last name and a password and become Active on the app
I am starting in django and have really no idea how to do it;
I started the authentication process using the documentation and I get to :
views.py :
from django.shortcuts import render
from .forms import HRForm, CandidateForm, EmployeeForm
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.backends import ModelBackend
from .models import MyUser
def registerEmployee(request):
registered = False
if request.method == "POST":
Employee_form = EmployeeForm(data=request.POST)
if Employee_form.is_valid():
user = Employee_form.save()
user.set_password(user.password)
user.is_employee = True
user.save()
registered = True
else:
print("Error!")
else:
Employee_form = EmployeeForm()
return render(request,'Employee_registration_form.html',
{'Employee_form':Employee_form,
'registered':registered})
Could you please help me or give me direction to dive in ?
Thx you ;)
For activating/deactivating a user you could use:
user.is_active = False/True
For creating the user I recommend the following article:
https://medium.com/#ramykhuffash/django-authentication-with-just-an-email-and-password-no-username-required-33e47976b517
Related
My Django app has an option for login/register using CustomForm (inherited from the UserCreationForm) as well as Outh. Now the problem is if a user has already signed up using the CustomForm and if the next time he tries to log in using google Oauth then instead of logging in, google Oauth is redirecting to some other signup form (not created by me) which looks like:
But as the user is already registered, if he enters the same username/email here then it displays says username taken. So how can I resolve this issue? I mean I want the user to be able to login using Oauth even if he has signed up using the CustomForm, how can I implement that? Or even if I ask the user to fill this form to be able to use OAuth login, the problem is that his email/username are already present in the db, so he won't be able to sign up using this form.
Edit:
If that's difficult to implement then instead how can I just show a message when the user tries to login using oauth after signing up with the CustomForm, something like "You signed up using username rather than google account", rather than taking him to the socialaccount signup form?
My register function in views.py:
def register(request):
if request.method == 'POST':
form = CustomForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('login')
else:
return redirect('register')
else:
return render(request, 'accounts/register.html')
forms.py looks something like this:
class CustomForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ("username", "email")
You can use pre_social_login signal
from allauth.exceptions import ImmediateHttpResponse
from allauth.socialaccount.signals import pre_social_login
from allauth.account.utils import perform_login
from allauth.utils import get_user_model
from django.dispatch import receiver
from django.shortcuts import redirect
from django.conf import settings
#receiver(pre_social_login)
def link_to_local_user(sender, request, sociallogin, **kwargs):
email_address = sociallogin.account.extra_data['email']
User = get_user_model()
users = User.objects.filter(email=email_address)
if users:
perform_login(request, users[0], email_verification=settings.EMAIL_VERIFICATION)
raise ImmediateHttpResponse(redirect(settings.LOGIN_REDIRECT_URL))
See https://github.com/pennersr/django-allauth/issues/215
the following code throws attribute error
''Database' object has no attribute 'exists''.
from django.shortcuts import render
from django.views import View
from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect
import pyrebase
from django.contrib import auth
import json
import requests
from . import services
from .models import Product
authe = services.firebase_key().auth()
database = services.firebase_key().database()
def Login(request):
return render(request, "Login.html")
def postsign(request):
data = services.get_products()
print(data)
context = {'data': data}
number = request.POST.get('number')
password = request.POST.get("password")
if database.child("users").child(number).exists():
user = database.child("users").child(number).get().val()
if user['number'] == number:
if user['password'] == password:
return render(request,"Welcome.html",context)
I need to check if the number exists in the database or not since I want the existing users to log in using numbers and passwords.
Check if child exist in Python using Pyrebase, should be something similar, see official docs here
if not database.child('users').shallow().get().val():
print("users does not exist")
else:
print("users exist")
You can try below.
if database.child('users').child(number).shallow().get().val():
print("user exists")
else:
print("user does not exist")
I am currently building a small project using Django, I have noticed a problem that a logged in user was getting access to the other users page by simply changing the id in the url i.e
This is the url of currently logged in user
http://localhost:8000/home/myBooks/7/
by changing that id from 7 to 6
i.e
http://localhost:8000/home/myBooks/6/
He was getting access to that page,I have used #login_required for functional based views and LoginRequiredMixin for class based views ,but they are not helping, what else I need to do to prevent this problem?
My app/views.py:
from django.shortcuts import render,redirect
from django.http import HttpResponse
from django.views.generic.edit import FormView
from . forms import BookForm
from django.contrib.auth.models import User
from . models import UserBooks
from django.contrib.auth.models import User
from django.views import generic
from django.contrib.auth.decorators import login_required
from .models import UserBooks
from django.shortcuts import get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin
#login_required
def HomeView(request):
return render(request,'home/homepage.html')
class BookDetailsView (LoginRequiredMixin,generic.DetailView):
model=UserBooks
template_name='home/bookdetails.html'
class BooksView (LoginRequiredMixin,generic.DetailView):
model=User
template_name='home/mybooks.html'
#login_required
def addBooks(request):
if (request.method=='POST'):
form=BookForm(data=request.POST)
if(form.is_valid()):
u=UserBooks()
u.book_name=form.cleaned_data['book_name']
u.book_author=form.cleaned_data['book_author']
u.book_ISBN=form.cleaned_data['book_ISBN']
u.book_status=True
u.book_genre=form.cleaned_data['book_genre']
u.username=request.user.username
u.user_id = User.objects.get(username=request.user.username)
u.save()
return redirect('/')
else:
form = BookForm()
return render (request,'home/addbooks.html',{'form':form})
my apps/models.py:
from django.db import models
from django.contrib.auth.models import User
class UserBooks(models.Model):
user_id = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
username = models.CharField(max_length=200)
book_name = models.CharField(max_length=200)
book_author = models.CharField(max_length=200)
book_ISBN=models.CharField(max_length=200)
book_genre = models.CharField(max_length=200)
book_status=models.BooleanField(default=False)
class Meta:
unique_together = (("username", "book_ISBN"),)
def __str__(self):
return self.book_name
my apps/urls.py:
from django.urls import path
from . import views
app_name='home'
urlpatterns=[
path('',views.HomeView,name='home'),
path('addBooks/',views.addBooks,name='addBooks'),
path('myBooks/<int:pk>/',views.BooksView.as_view(),name='myBooks'),
path('<int:pk>/', views.BookDetailsView.as_view(), name='myBooks'),
]
If your view should always show the detail for the current user, don't put the ID in the URL at all; get the logged-in user directly within the view.
class BooksView(LoginRequiredMixin, generic.DetailView):
model = User
template_name ='home/mybooks.html'
def get_object(self):
return self.request.user
...
path('myBooks/',views.BooksView.as_view(),name='myBooks'),
class BooksView(LoginRequiredMixin, DetailView):
...
def get(self, request, *args, **kwargs):
current_user = User.objects.get(id=self.request.user.pk)
if current_user.pk == kwargs['pk']:
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('profile-url')
Here I assume that if you are logged in user and you try to check another user profile by giving id in url. So I add a get method which will check is requested URL id is for the current user (books/7/ is 7 is current user id) if not then redirect to an URL, for example, otherwise redirects to another url. You can get some idea. This may not help you exactly.
If you have just started to develop the app, then it is okay to use pks inside of urls. However, when it comes to a real working app it can lead to some security problems.
As you wrote, one can simply change the url and get some private data.
Other problems can be:
The number of users in the database can be easily counted by iteration through your urls.
The user can be easily detected by his id. Knowing it one can easily get some private data.
If you will decide to change ids in your db, then all the external links will be broken...and etc.
Considering that I suggest an approach in which you use ids internally. For external usage (urls, links) you can use uuids.
To do that you just need additional field into your model:
import uuid
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
And here is the example url:
url(r'^myBooks/(?P<user_uuid>\b[0-9A-Fa-f]{8}\b(-\b[0-9A-Fa-f]{4}\b){3}-\b[0-9A-Fa-f]{12}\b)/$',
After you switch to uuids it will be almost impossible to "hack" the url.
UPDATE!
The activation code is stored in the database, but I can not call it as a function of activation
Gives an error message:
TypeError at /account/activation/18d2ecbee1fd15440bbcfdf942c071a2f5b8d0ff/
activation() got an unexpected keyword argument 'activation_key'
forms.py
from django import forms
from django.contrib.auth.models import User
class EmailForm(forms.Form):
email = forms.EmailField(widget=forms.EmailInput(
attrs={'class': 'form-control input-lg',
'placeholder': 'Ваш E-mail'}))
views.py
import datetime
import hashlib
import random
from django.conf import settings
from django.contrib.auth import authenticate, logout, login
from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail
from django.http import HttpResponseRedirect, HttpResponse
from django.http import Http404
from django.shortcuts import render
from forms import *
from models import *
def register(request):
if request.method == "POST":
form = EmailForm(request.POST)
if form.is_valid():
form_email = form.cleaned_data['email']
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
activation_key = hashlib.sha1(salt+form_email).hexdigest()
key_expires = datetime.datetime.today() + datetime.timedelta(2)
subject = 'Activation your e-mail'
from_email = settings.EMAIL_HOST_USER
to_email = [form_email]
message_email = "Hi, i'm link activate e-mail! \
http://127.0.0.1:8000/account/activation/%s" % activation_key
send_mail(subject,
message_email,
from_email,
to_email,
fail_silently=True)
code = ActivationEmail.objects.create(activation_key=activation_key)
code.save()
return render(request, 'registration/activate.html', locals())
else:
form = EmailForm()
return render(request, 'registration/register.html', locals())
def activation(request, code):
try:
active = ActivationEmail.objects.get(activation_key=code)
except ActivationEmail.DoesNotExist:
active = None
active.validated = True
if not active:
raise Http404
print "USER WAS HERE?!"
return HttpResponseRedirect('/account/wizard/')
urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns('',
url(r'^register/', views.register, name='registration'),
url(r'^activation/(?P<activation_key>\w+)/', views.activation, name='activation'),
url(r'^login/$', views.user_login, name='login'),
url(r'^logout/$', views.user_logout, name='logout'),
Just can not figure out how to do next; (
You will need to
1- You will need to create a new table to store the activation keys, such that you can create a new entry before sending the email
2.- On the user clicking the activation link, that link should be sufficient for you to find the record you created before sending the email
3.- If everything matches, then set a user.is_active type thing on your user model.
But all that said, you are reinventing the wheel here. There are several top notch packages you can use with this and more. I would recommend django-allauth with also give you social login support (e.g. facebook). If you just want the activation portion, there is an older package called django-registration. There are a few others if you search around, but the point is you don't need to implement this (and you probably don't want to mess around with registration if you are not an expert)
I have to change the "is_staff" option from views.py file to disabling the Django-admin page but i am not able to figure out this following issue.
Whenever i tried to write "user.is_staff" then it sound that there is not any option to choose it (is_staff) whereas is_active is present. is this problem of importing?
Following are the content which i am importing:
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.models import User
from django.http import HttpResponseForbidden, HttpResponse
from django.shortcuts import get_object_or_404
from django.views.generic.list_detail import object_detail
from django.views.generic.simple import direct_to_template
from django.utils.translation import ugettext as _
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
Following code i wrote in views.py:
def user_change_status(request, id):
user = User.objects.get(pk=id)
if user.is_staff:
user.is_staff = False
else:
user.is_active = True
return HttpResponse('')
Whole scenario is that i have a template which is showing the list of all user with his/her is_staff option (True/ False). What i want when superuser will select any of user is_staff option it become change and the page will redirect on the same page.
After editing:
Two method are defined in views.py:
def user_change_status(request, id):
user = User.objects.get(pk=id)
if user.is_active:
user.is_staff = False
else:
user.is_staff = True
user.save()
value2 = user.is_staff
return HttpResponse(value2)
and another one is `
def user_block(request, id):
user = User.objects.get(pk=id)
if user.is_active:
user.is_active = False
else:
user.is_active = True
user.save()
value1 = user.is_active
return HttpResponse('value1')
I want to change the is_staff value and is_active value. Method user_change_status is not working whereas user_block does.
Python is a dynamic language. In particular, it's not Java or C++. As a rule, IDEs do very badly in autocompleting in dynamic languages.
It's a complete mistake to take any notice of what your IDE does or doesn't offer as autocomplete options. Sometimes it'll get it right, other times it won't. Sometimes it'll offer options that aren't members of the object at all.
Use the documentation, not your IDE.
user_change_status removes the is_staff for active users, but enables the is_staff for inactive users, is this what you wanted to do ? Is it not about toggling the is_staff value, actually ?
I ask since the user_block toggles the is_active value.
If so, you should replace
if user.is_active:
user.is_staff = False
with
if user.is_staff:
user.is_staff = False