Submit form from Paypal script after approved payment in Django - django

I have a user registration form and I would like the user to pay in order to register for my app.
I have the frontend paypal set up for the payment as well as the user registration with a submit button but I do not know how to integrate the two.
<div id="paypal-button-container"></div>
<script src="https://www.paypal.com/sdk/js?client-id=sb&currency=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '00.01'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
// Show a success message to the buyer
alert('Transaction completed by ' + details.payer.name.given_name + '!');
});
}
}).render('#paypal-button-container');
</script>
<button class="w3-button w3-blue w3-padding-large" type="submit">
Buy Now
</button>
</form>
I would like the submit button to be used in the 'onapprove' part of the script but I am not sure how. Alternatively I was thinking of calling my 'buy' function from the views
def buy(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
data = form.cleaned_data
email = f"{data['email']}"
username = f"{data['username']}"
form.instance.username = username
form.save()
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/buy.html', {'form': form})
The other thing is that the system would have to check that the form inputs are unique and valid before payment. Would it just be best to have the redirect the user to the registration page following a successful payment?
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
username = forms.CharField(max_length=20)
class Meta:
model = User
fields = ['email', 'username', 'password1', 'password2']

You can use onClick to check the values are valid before proceeding with payment: https://developer.paypal.com/docs/checkout/integration-features/validation/
Combine that with a proper server integration that transmits the values in a fetch body when creating or capturing the order, so your server can store them then.
For that server integration you need to create two routes, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return JSON data.
Pair those routes with the following button approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server , plus your onClick function

Related

Customize django-otp email template

I'm doing two-factor authentication (2FA) in my Django app and using django-otp package. I want to send my custom email to users. I followed the official documentation and added my custom settings as follow:
# django-otp template
OTP_EMAIL_SUBJECT = _('Please confirm your login attempt')
OTP_EMAIL_BODY_TEMPLATE_PATH = 'account/email/login_confirmation_otp.html'
The above settings are working and it's sending the email in text/plain content type but I want text/html content type.
The following code is sending the email:
def generate_challenge(self, extra_context=None):
"""
Generates a random token and emails it to the user.
:param extra_context: Additional context variables for rendering the
email template.
:type extra_context: dict
"""
self.generate_token(valid_secs=settings.OTP_EMAIL_TOKEN_VALIDITY)
context = {'token': self.token, **(extra_context or {})}
if settings.OTP_EMAIL_BODY_TEMPLATE:
body = Template(settings.OTP_EMAIL_BODY_TEMPLATE).render(Context(context))
else:
body = get_template(settings.OTP_EMAIL_BODY_TEMPLATE_PATH).render(context)
send_mail(settings.OTP_EMAIL_SUBJECT,
body,
settings.OTP_EMAIL_SENDER,
[self.email or self.user.email])
message = "sent by email"
return message
in django_otp/plugins/otp_email/models.py. I want to override generate_challenge() function and add html_message in send_email() function but don't know how to do it?

how to use action object and target in django notifications

i"m working on a project with django something blogging like webapp. I'm using django notifications for my websites notification. i'm recieving notifications if someone comment on my post or like the post. However i can't go to the specific post from the notifications by clicking the notification.
my views.py :
#login_required
def like_post(request):
# posts = get_object_or_404(Post, id=request.POST.get('post_id'))
posts = get_object_or_404(post, id=request.POST.get('id'))
# posts.likes.add for the particular posts and the post_id for the post itself its belongs to the post without any pk
is_liked = False
if posts.likes.filter(id=request.user.id).exists():
posts.likes.remove(request.user)
is_liked = False
else:
posts.likes.add(request.user)
is_liked = True
notify.send(request.user, recipient=posts.author, actor=request.user, verb='liked your post.', nf_type='liked_by_one_user')
context = {'posts':posts, 'is_liked': is_liked, 'total_likes': posts.total_likes(),}
if request.is_ajax():
html = render_to_string('blog/like_section.html', context, request=request)
return JsonResponse({'form': html})
From the project's readme, we can see that the Notification model allows you to store extra data in a JSON field. To enable this, you'll first need to add this to your settings file
DJANGO_NOTIFICATIONS_CONFIG = { 'USE_JSONFIELD': True}
After doing so you can store the url of the target object in the field by passing it as a kwarg to the notify.send signal
notify.send(request.user, recipient=posts.author, actor=request.user, verb='liked your post.', nf_type='liked_by_one_user', url=object_url)
You should note however that doing it this way would result in a broken link should you change your url conf so an alternative way of doing it would be to create a view that will return the target objects url which you can call while rendering the notifications.

Post request in Django results in broken pipe

I'm trying to make a post request from a react frontend to a django backend to log a user in, and redirect to a new page. The issue I'm having is that even though the request reaches the server and I can get the data when it comes time for django to redirect, the redirect does not happen and their is an output in the console that says "Broken pipe from ('127.0.0.1', 64989)". I've done some research online about this issue, but I still can't figure out how to fix it. However, everything works fine when I use a an html form element with an action and method type. Below I have shared my code.
React Frontend
handleSubmit = () => {
let csrfToken = Cookies.get('csrftoken')
let endpoint = this.state.isLoggingIn ? LOGIN_ENDPOINT : REGISTER_ENDPOINT;
axios({
url: endpoint,
method: "POST",
data: {
username: this.state.username,
password: this.state.password,
displayName: this.state.displayName,
},
headers: {"X-CSRFToken": csrfToken},
responseType: "json",
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
}
Django Backend
def login_view(request):
if request.method == 'POST':
#username = request.POST.get('username') <= I use this and below, to get data sent via a form with an action and method set.
#password = request.POST.get('password')
body_unicode = request.body.decode('utf-8')
data = simplejson.loads(body_unicode)
username = data['username']
password = data['password']
user = authenticate(username=username, password=password)
print user
if user is not None and user.is_active:
login(request, user)
return redirect('chat_app:chat')
else:
return JsonResponse({'message': 'Check you username or password'})
else:
return render(request, 'frontend/chat_app/home.html')
Following works but is not what I want
With this method I can get the data from the input fields (not shown here)
authenticate the user and redirect them properly. However, I do not want to
use this method because I want to pass back any error messages to the submitFunction() that had been called, or process any other data, in the same page that had made the call.
<form method="POST" action={ENDPOINT}>
<input
type="hidden"
name="csrfmiddlewaretoken"
value={csrftoken}
/>
....

How does userena with Django track if user signed in?

With normal Django user handeling, you would save a session to the user once he/she is logged in. However, after reading the userena views.py file for signin, I couldn't see how the user is tracked so that once they log in, the site would now they are logged in. I put the code from userena below:
def signin(request, auth_form=AuthenticationForm,
template_name='userena/signin_form.html',
redirect_field_name=REDIRECT_FIELD_NAME,
redirect_signin_function=signin_redirect, extra_context=None):
"""
Signin using email or username with password.
Signs a user in by combining email/username with password. If the
combination is correct and the user :func:`is_active` the
:func:`redirect_signin_function` is called with the arguments
``REDIRECT_FIELD_NAME`` and an instance of the :class:`User` whois is
trying the login. The returned value of the function will be the URL that
is redirected to.
A user can also select to be remembered for ``USERENA_REMEMBER_DAYS``.
:param auth_form:
Form to use for signing the user in. Defaults to the
:class:`AuthenticationForm` supplied by userena.
:param template_name:
String defining the name of the template to use. Defaults to
``userena/signin_form.html``.
:param redirect_field_name:
Form field name which contains the value for a redirect to the
successing page. Defaults to ``next`` and is set in
``REDIRECT_FIELD_NAME`` setting.
:param redirect_signin_function:
Function which handles the redirect. This functions gets the value of
``REDIRECT_FIELD_NAME`` and the :class:`User` who has logged in. It
must return a string which specifies the URI to redirect to.
:param extra_context:
A dictionary containing extra variables that should be passed to the
rendered template. The ``form`` key is always the ``auth_form``.
**Context**
``form``
Form used for authentication supplied by ``auth_form``.
"""
form = auth_form
if request.method == 'POST':
form = auth_form(request.POST, request.FILES)
if form.is_valid():
identification, password, remember_me = (form.cleaned_data['identification'],
form.cleaned_data['password'],
form.cleaned_data['remember_me'])
user = authenticate(identification=identification,
password=password)
if user.is_active:
login(request, user)
if remember_me:
request.session.set_expiry(userena_settings.USERENA_REMEMBER_ME_DAYS[1] * 86400)
else: request.session.set_expiry(0)
if userena_settings.USERENA_USE_MESSAGES:
messages.success(request, _('You have been signed in.'),
fail_silently=True)
# Whereto now?
redirect_to = redirect_signin_function(
request.REQUEST.get(redirect_field_name), user)
return redirect(redirect_to)
else:
return redirect(reverse('userena_disabled',
kwargs={'username': user.username}))
if not extra_context: extra_context = dict()
extra_context.update({
'form': form,
'next': request.REQUEST.get(redirect_field_name),
})
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)
The user is first authenticated using
user = authenticate(identification=identification,password=password)
which can be found here https://github.com/django/django/blob/master/django/contrib/auth/backends.py
This method checks if the user exists, and checks whether the password is correct.
If all goes well, the login method is called
login(request, user)
which can be found here
https://github.com/django/django/blob/master/django/contrib/auth/views.py
As you can see, these are two methods that are shipped with Django, and act as the sort of 'default' authentication package for Django.
Your site knows that a user is logged in because you'll probably be using Middleware (specifically SessionMiddleware and AuthenticationMiddleware), which attach a session and a user object to the request. The login method mentioned above saves the user ID to the session.
For more details see https://docs.djangoproject.com/en/dev/topics/auth/#authentication-in-web-requests
Concerning your comment:
You could render your template using RequestContext, or have your views return a TemplateResponse.
See https://docs.djangoproject.com/en/dev/ref/template-response/#using-templateresponse-and-simpletemplateresponse
This passes the user object to the template processor.
Then, in your template you could do something like this:
{% if user.is_authenticated %}
<p>Welcome {{ user.first_name }}</p>
{% else %}
<p>Please log in</p>
{% endif %}
Also see https://docs.djangoproject.com/en/dev/topics/auth/#id8
In my opinion it is indeed very well possible to put a modified version of this in your base.html. For example to show a login button if the user is not logged in, and replace it by a button that brings the user to his/her profile page when the user is logged in.

How to get the currently logged in user's user id in Django?

How to get the currently logged-in user's id?
in models.py:
class Game(models.model):
name = models.CharField(max_length=255)
owner = models.ForeignKey(User, related_name='game_user', verbose_name='Owner')
in views.py:
gta = Game.objects.create(name="gta", owner=?)
First make sure you have SessionMiddleware and AuthenticationMiddleware middlewares added to your MIDDLEWARE_CLASSES setting.
The current user is in request object, you can get it by:
def sample_view(request):
current_user = request.user
print current_user.id
request.user will give you a User object representing the currently logged-in user. If a user isn't currently logged in, request.user will be set to an instance of AnonymousUser. You can tell them apart with the field is_authenticated, like so:
if request.user.is_authenticated:
# Do something for authenticated users.
else:
# Do something for anonymous users.
You can access Current logged in user by using the following code:
request.user.id
Assuming you are referring to Django's Auth User, in your view:
def game(request):
user = request.user
gta = Game.objects.create(name="gta", owner=user)
FROM WITHIN THE TEMPLATES
This is how I usually get current logged in user and their id in my templates.
<p>Your Username is : {{user}} </p>
<p>Your User Id is : {{user.id}} </p>
I wrote this in an ajax view, but it is a more expansive answer giving the list of currently logged in and logged out users.
The is_authenticated attribute always returns True for my users, which I suppose is expected since it only checks for AnonymousUsers, but that proves useless if you were to say develop a chat app where you need logged in users displayed.
This checks for expired sessions and then figures out which user they belong to based on the decoded _auth_user_id attribute:
def ajax_find_logged_in_users(request, client_url):
"""
Figure out which users are authenticated in the system or not.
Is a logical way to check if a user has an expired session (i.e. they are not logged in)
:param request:
:param client_url:
:return:
"""
# query non-expired sessions
sessions = Session.objects.filter(expire_date__gte=timezone.now())
user_id_list = []
# build list of user ids from query
for session in sessions:
data = session.get_decoded()
# if the user is authenticated
if data.get('_auth_user_id'):
user_id_list.append(data.get('_auth_user_id'))
# gather the logged in people from the list of pks
logged_in_users = CustomUser.objects.filter(id__in=user_id_list)
list_of_logged_in_users = [{user.id: user.get_name()} for user in logged_in_users]
# Query all logged in staff users based on id list
all_staff_users = CustomUser.objects.filter(is_resident=False, is_active=True, is_superuser=False)
logged_out_users = list()
# for some reason exclude() would not work correctly, so I did this the long way.
for user in all_staff_users:
if user not in logged_in_users:
logged_out_users.append(user)
list_of_logged_out_users = [{user.id: user.get_name()} for user in logged_out_users]
# return the ajax response
data = {
'logged_in_users': list_of_logged_in_users,
'logged_out_users': list_of_logged_out_users,
}
print(data)
return HttpResponse(json.dumps(data))
This is how I usually get current logged in user and their id in my templates.
<p>Your Username is : {{user|default: Unknown}} </p>
<p>Your User Id is : {{user.id|default: Unknown}} </p>
Just go on your profile.html template and add a HTML tag named paragraph there,
<p>User-ID: {% user.id %}</p>