Commit 6290d67a authored by Birin Sanchez's avatar Birin Sanchez

* Add a profile configuration page where user can set billing email

  and recovery email.
* Specify role=all when querying customers through Woo REST API.
Signed-off-by: Birin Sanchez's avatarBirin Sanchez <birin.sanchez@puri.sm>
parent 0458b149
...@@ -155,6 +155,7 @@ SPDX-License-Identifier: AGPL-3.0 ...@@ -155,6 +155,7 @@ SPDX-License-Identifier: AGPL-3.0
<ul> <ul>
<li><a href="{% url 'password_change' %}">{% trans "Change password" %}</a></li> <li><a href="{% url 'password_change' %}">{% trans "Change password" %}</a></li>
<li><a href="{% url 'profile_configure' username %}">{% trans "Profile settings" %}</a></li>
</ul> </ul>
</article> </article>
......
...@@ -24,7 +24,8 @@ from ldapregister.forms import RegistrationForm ...@@ -24,7 +24,8 @@ from ldapregister.forms import RegistrationForm
from ldapregister.views import LdhLoginView from ldapregister.views import LdhLoginView
from cart.views import CartRegistrationView from cart.views import CartRegistrationView
from purist.views import Recovery, PasswordChange, PasswordChangeDone from purist.views import Recovery, PasswordChange, \
PasswordChangeDone, ProfileConfigureView
from invitation.views import InvitationRegistrationView from invitation.views import InvitationRegistrationView
# #
...@@ -48,6 +49,8 @@ urlpatterns = [ ...@@ -48,6 +49,8 @@ urlpatterns = [
limitmonitor.views.toggle_tunnel, name='toggle_tunnel'), limitmonitor.views.toggle_tunnel, name='toggle_tunnel'),
url(r'^accounts/profile/new_invitation', url(r'^accounts/profile/new_invitation',
limitmonitor.views.new_invitation, name='new_invitation'), limitmonitor.views.new_invitation, name='new_invitation'),
url(r'^accounts/profile/configure/(?P<username>.+)/$',
ProfileConfigureView.as_view(), name='profile_configure'),
# url(r'^accounts/register/$', RegistrationView.as_view(form_class=RegistrationForm), name='registration_register'), # url(r'^accounts/register/$', RegistrationView.as_view(form_class=RegistrationForm), name='registration_register'),
url(r'^accounts/login/$', LdhLoginView.as_view(), name='auth_login'), url(r'^accounts/login/$', LdhLoginView.as_view(), name='auth_login'),
url(r'^accounts/recover/$', Recovery.as_view(), name='password_reset_recover'), url(r'^accounts/recover/$', Recovery.as_view(), name='password_reset_recover'),
......
...@@ -4,6 +4,7 @@ from django.contrib.auth.forms import PasswordChangeForm \ ...@@ -4,6 +4,7 @@ from django.contrib.auth.forms import PasswordChangeForm \
as BasePasswordChangeForm as BasePasswordChangeForm
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from password_reset.forms import PasswordRecoveryForm as BasePasswordRecoveryForm from password_reset.forms import PasswordRecoveryForm as BasePasswordRecoveryForm
from .models import User
class PasswordRecoveryForm(BasePasswordRecoveryForm): class PasswordRecoveryForm(BasePasswordRecoveryForm):
...@@ -40,3 +41,21 @@ class PasswordChangeForm(BasePasswordChangeForm): ...@@ -40,3 +41,21 @@ class PasswordChangeForm(BasePasswordChangeForm):
self.user.set_woocommerce_password(raw_password=password, self.user.set_woocommerce_password(raw_password=password,
woocommerce_id=None) woocommerce_id=None)
return self.user return self.user
class ProfileConfigureForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'billing_email']
labels = {
'email': _('Recovery email'),
'billing_email': _('Billing email'),
}
widgets = {
'email': forms.EmailInput(attrs={'size': '100%'}),
'billing_email': forms.EmailInput(attrs={'size': '100%'}),
}
def save(self, commit=True):
self.instance.set_woocommerce_billing_email()
return super(ProfileConfigureForm, self).save(commit)
# -*- coding: utf-8 -*-
# Generated by Django 1.11.18 on 2019-04-25 07:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('purist', '0004_add_account_type_field'),
]
operations = [
migrations.AddField(
model_name='user',
name='billing_email',
field=models.EmailField(default='', max_length=254),
),
]
...@@ -85,6 +85,7 @@ class User(AbstractUser): ...@@ -85,6 +85,7 @@ class User(AbstractUser):
tunnel_password = models.CharField(max_length=250, default=None, null=True) tunnel_password = models.CharField(max_length=250, default=None, null=True)
account_type = EnumIntegerField(enum=AccountType, account_type = EnumIntegerField(enum=AccountType,
default=AccountType.UNDEFINED) default=AccountType.UNDEFINED)
billing_email = models.EmailField(default='', null=False)
@classmethod @classmethod
def normalize_username(cls, username): def normalize_username(cls, username):
...@@ -165,7 +166,7 @@ class User(AbstractUser): ...@@ -165,7 +166,7 @@ class User(AbstractUser):
def get_woocommerce_id(self): def get_woocommerce_id(self):
query = "customers?email=" + self.get_identity() query = "customers?role=all&email=" + self.get_identity()
json = self.woo_get_json(query) json = self.woo_get_json(query)
if json is not None and len(json) == 1: if json is not None and len(json) == 1:
...@@ -218,6 +219,32 @@ class User(AbstractUser): ...@@ -218,6 +219,32 @@ class User(AbstractUser):
def get_identity(self): def get_identity(self):
return self.get_username() + "@" + settings.SITE_DOMAIN.lower() return self.get_username() + "@" + settings.SITE_DOMAIN.lower()
def get_woocommerce_billing_email(self):
query = "customers?role=all&email=" + self.get_identity()
json = self.woo_get_json(query)
if json is not None and len(json) == 1:
billing_email = json[0]["billing"]["email"]
if billing_email != '':
return billing_email
return None
def set_woocommerce_billing_email(self, woocommerce_id=None):
data = {
"billing": {
"email": self.billing_email
},
}
if woocommerce_id is None:
woocommerce_id = self.get_woocommerce_id()
query = "customers/" + str(woocommerce_id)
return self.woo_put_json(query, data)
def save(self, force_insert=False, force_update=False, using=None, update_fields=None): def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
# save django user # save django user
......
<!DOCTYPE html>
{% load static %}
{% load i18n %}
<!--
Keel (LDH middleware)
Copyright 2017-2018 Purism SPC
https://source.puri.sm/liberty/ldh_middleware
SPDX-License-Identifier: AGPL-3.0
-->
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{% static 'layout.css' %}"/>
<link rel="stylesheet" href="{% static 'theme.css' %}"/>
<title>{% trans "Profile Settings" %}</title>
<link rel="icon" sizes="960x960" href="{% static 'favicon.png' %}"/>
<meta name="application-name" content="{{ site_title }}"/>
<meta charset="UTF-8"/>
</head>
<body>
<header>
<div id="title_box">
<a href="{% url 'home' %}"><img class="logo" src="{% static 'logo.png' %}" alt="{{ site_title }}"/></a>
<div id="title_text">
<h1>{% trans "Profile Settings" %}</h1>
</div>
</div>
<div id="log_state">
{% if request.user.is_authenticated %}
{% trans "Logged in as" %} {{ username }}<br/>
<a href="{% url 'profile' %}">{% trans "Profile" %}</a> |
{% if request.user.is_superuser %}
<a href="{% url 'admin:index' %}">{% trans "Admin" %}</a> |
{% endif %}
<a href="{% url 'auth_logout' %}">{% trans "Log out" %}</a>
{% else %}
{% trans "You are not logged in." %}<br/>
<a href="{% url 'auth_login' %}">{% trans "Log in" %}</a>
<!--
{% trans "or" %}
<a href="{% url 'registration_register' %}">{% trans "register." %}</a>
-->
{% endif %}
</div>
</header>
<hr/>
<main class="col-wrapper form">
<article class="col-1">
<form action="" method="post">{% csrf_token %}
{{ form.as_ul }}
<input type="submit" value={% trans "Save" %}>
</form>
<a href="{% url 'profile' %}">{% trans "Back to profile" %}</a>
</main>
<footer>
<div id="footer_block">
<p>
<em>{{ site_title }}</em> provided by <a href="{{ site_provider_link }}">{{ site_provider }}</a><br />
Code shared under AGPL-3.0-or-later
(<a href="https://source.puri.sm/liberty/ldh_middleware">project</a>,
<a href="{% url 'download-zip' %}">source</a>,
<a href="{% url 'jslicense' %}" rel="jslicense">javascript</a>)
</p>
</div>
</footer>
</body>
</html>
...@@ -8,12 +8,14 @@ from django.http import Http404, FileResponse ...@@ -8,12 +8,14 @@ from django.http import Http404, FileResponse
from password_reset.views import Recover from password_reset.views import Recover
from .serializers import UserSerializer from .serializers import UserSerializer
from .forms import PasswordRecoveryForm, PasswordChangeForm from .forms import PasswordRecoveryForm, PasswordChangeForm, \
ProfileConfigureForm
from django.contrib.auth.views import PasswordChangeView \ from django.contrib.auth.views import PasswordChangeView \
as BasePasswordChangeView as BasePasswordChangeView
from django.contrib.auth.views import PasswordChangeDoneView \ from django.contrib.auth.views import PasswordChangeDoneView \
as BasePasswordChangeDoneView as BasePasswordChangeDoneView
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.views.generic.edit import UpdateView
class UserDetail(APIView): class UserDetail(APIView):
...@@ -65,6 +67,28 @@ class PasswordChange(BasePasswordChangeView): ...@@ -65,6 +67,28 @@ class PasswordChange(BasePasswordChangeView):
return context return context
class ProfileConfigureView(UpdateView):
template_name = 'purist/profile_configure.html'
form_class = ProfileConfigureForm
success_url = reverse_lazy('profile')
model = User
slug_field = 'username'
slug_url_kwarg = 'username'
def get_context_data(self, **kwargs):
context = super(ProfileConfigureView, self).get_context_data(**kwargs)
context['username'] = self.request.user.get_username()
context['site_title'] = settings.SITE_TITLE
context['site_provider'] = settings.SITE_PROVIDER
return context
def get_initial(self):
# Prepopulate form fields with values from User Model and
# WooCommerce
return {"email": self.object.email,
"billing_email": self.object.get_woocommerce_billing_email()}
def home(request): def home(request):
render_data = { render_data = {
"username": request.user.get_username(), "username": request.user.get_username(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment