diff --git a/src/newsreader/accounts/forms.py b/src/newsreader/accounts/forms.py new file mode 100644 index 0000000..7a29f99 --- /dev/null +++ b/src/newsreader/accounts/forms.py @@ -0,0 +1,9 @@ +from django import forms + +from newsreader.accounts.models import User + + +class UserSettingsForm(forms.ModelForm): + class Meta: + model = User + fields = ("first_name", "last_name") diff --git a/src/newsreader/accounts/templates/accounts/password_change.html b/src/newsreader/accounts/templates/accounts/password_change.html new file mode 100644 index 0000000..1ece1dd --- /dev/null +++ b/src/newsreader/accounts/templates/accounts/password_change.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% load static i18n %} + +{% block content %} +
+
+ {% csrf_token %} + +
+

{% trans "Password change" %}

+
+ +
+ {{ form }} +
+
+ Cancel + +
+
+
+{% endblock %} diff --git a/src/newsreader/accounts/templates/accounts/settings.html b/src/newsreader/accounts/templates/accounts/settings.html new file mode 100644 index 0000000..29a2ee9 --- /dev/null +++ b/src/newsreader/accounts/templates/accounts/settings.html @@ -0,0 +1,42 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +
+
+ {% csrf_token %} + +
+

{% trans "User settings" %}

+
+ + {{ form.non_field_errors }} + +
+
+ + {{ form.first_name.errors }} + {{ form.first_name }} +
+ +
+ + {{ form.last_name.errors }} + {{ form.last_name }} +
+
+ +
+
+ Cancel + + + {% trans "Change password" %} + + + +
+
+
+
+{% endblock %} diff --git a/src/newsreader/accounts/tests/test_views.py b/src/newsreader/accounts/tests/test_views.py new file mode 100644 index 0000000..d3ac77c --- /dev/null +++ b/src/newsreader/accounts/tests/test_views.py @@ -0,0 +1,29 @@ +from django.test import TestCase +from django.urls import reverse + +from newsreader.accounts.models import User +from newsreader.accounts.tests.factories import UserFactory + + +class UserSettingsViewTestCase(TestCase): + def setUp(self): + self.user = UserFactory(password="test") + self.client.force_login(self.user) + + def test_simple(self): + response = self.client.get(reverse("accounts:settings")) + + self.assertEquals(response.status_code, 200) + + def test_user_credential_change(self): + response = self.client.post( + reverse("accounts:settings"), + {"first_name": "First name", "last_name": "Last name"}, + ) + + user = User.objects.get() + + self.assertRedirects(response, reverse("accounts:settings")) + + self.assertEquals(user.first_name, "First name") + self.assertEquals(user.last_name, "Last name") diff --git a/src/newsreader/accounts/urls.py b/src/newsreader/accounts/urls.py index 8605233..d42ae13 100644 --- a/src/newsreader/accounts/urls.py +++ b/src/newsreader/accounts/urls.py @@ -1,3 +1,4 @@ +from django.contrib.auth.decorators import login_required from django.urls import path from newsreader.accounts.views import ( @@ -6,6 +7,7 @@ from newsreader.accounts.views import ( ActivationView, LoginView, LogoutView, + PasswordChangeView, PasswordResetCompleteView, PasswordResetConfirmView, PasswordResetDoneView, @@ -13,6 +15,7 @@ from newsreader.accounts.views import ( RegistrationClosedView, RegistrationCompleteView, RegistrationView, + SettingsView, ) @@ -52,5 +55,10 @@ urlpatterns = [ PasswordResetCompleteView.as_view(), name="password-reset-complete", ), - # TODO: create password change views + path( + "password-change/", + login_required(PasswordChangeView.as_view()), + name="password-change", + ), + path("settings/", login_required(SettingsView.as_view()), name="settings"), ] diff --git a/src/newsreader/accounts/views.py b/src/newsreader/accounts/views.py index 28ae92d..c0342b2 100644 --- a/src/newsreader/accounts/views.py +++ b/src/newsreader/accounts/views.py @@ -2,15 +2,17 @@ from django.contrib.auth import views as django_views from django.shortcuts import render from django.urls import reverse_lazy from django.views.generic import TemplateView +from django.views.generic.edit import FormView, ModelFormMixin from registration.backends.default import views as registration_views +from newsreader.accounts.forms import UserSettingsForm +from newsreader.accounts.models import User + class LoginView(django_views.LoginView): template_name = "accounts/login.html" - - def get_success_url(self): - return reverse_lazy("index") + success_url = reverse_lazy("index") class LogoutView(django_views.LogoutView): @@ -89,3 +91,25 @@ class PasswordResetConfirmView(django_views.PasswordResetConfirmView): class PasswordResetCompleteView(django_views.PasswordResetCompleteView): template_name = "password-reset/password_reset_complete.html" + + +class PasswordChangeView(django_views.PasswordChangeView): + template_name = "accounts/password_change.html" + success_url = reverse_lazy("accounts:settings") + + +class SettingsView(ModelFormMixin, FormView): + template_name = "accounts/settings.html" + success_url = reverse_lazy("accounts:settings") + form_class = UserSettingsForm + model = User + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + return super().get(request, *args, **kwargs) + + def get_object(self, **kwargs): + return self.request.user + + def get_form_kwargs(self): + return {**super().get_form_kwargs(), "instance": self.request.user} diff --git a/src/newsreader/js/pages/categories/App.js b/src/newsreader/js/pages/categories/App.js index 95ab396..691aaed 100644 --- a/src/newsreader/js/pages/categories/App.js +++ b/src/newsreader/js/pages/categories/App.js @@ -80,7 +80,7 @@ class App extends React.Component { const pageHeader = ( <>

Categories

- + Create category diff --git a/src/newsreader/news/collection/templates/collection/rules.html b/src/newsreader/news/collection/templates/collection/rules.html index ee6d539..32b6f24 100644 --- a/src/newsreader/news/collection/templates/collection/rules.html +++ b/src/newsreader/news/collection/templates/collection/rules.html @@ -1,7 +1,5 @@ {% extends "base.html" %} -{% load i18n %} - -{% load static %} +{% load i18n static %} {% block content %}
diff --git a/src/newsreader/scss/components/form/_settings-form.scss b/src/newsreader/scss/components/form/_settings-form.scss new file mode 100644 index 0000000..fc38d70 --- /dev/null +++ b/src/newsreader/scss/components/form/_settings-form.scss @@ -0,0 +1,9 @@ +.settings-form { + &__section:last-child { + & .settings-form__fieldset { + display: flex; + flex-direction: row; + justify-content: space-between; + } + } +} diff --git a/src/newsreader/scss/components/form/index.scss b/src/newsreader/scss/components/form/index.scss index 547da89..1555ae9 100644 --- a/src/newsreader/scss/components/form/index.scss +++ b/src/newsreader/scss/components/form/index.scss @@ -11,3 +11,5 @@ @import "password-reset-form"; @import "password-reset-confirm-form"; + +@import "settings-form"; diff --git a/src/newsreader/scss/components/section/_text-section.scss b/src/newsreader/scss/components/section/_text-section.scss new file mode 100644 index 0000000..88e3e72 --- /dev/null +++ b/src/newsreader/scss/components/section/_text-section.scss @@ -0,0 +1,11 @@ +.text-section { + @extend .section; + + width: 70%; + border-radius: 5px; + + padding: 10px; + + background-color: $white; +} + diff --git a/src/newsreader/scss/components/section/index.scss b/src/newsreader/scss/components/section/index.scss index 4fb6763..0e02686 100644 --- a/src/newsreader/scss/components/section/index.scss +++ b/src/newsreader/scss/components/section/index.scss @@ -1 +1,2 @@ @import "section"; +@import "text-section"; diff --git a/src/newsreader/scss/elements/button/_mixins.scss b/src/newsreader/scss/elements/button/_mixins.scss index 06a912c..75b70e3 100644 --- a/src/newsreader/scss/elements/button/_mixins.scss +++ b/src/newsreader/scss/elements/button/_mixins.scss @@ -1,3 +1,3 @@ @mixin button-padding { - padding: 10px 50px; + padding: 7px 40px; } diff --git a/src/newsreader/scss/pages/index.scss b/src/newsreader/scss/pages/index.scss index 27f0bc6..ddfaf85 100644 --- a/src/newsreader/scss/pages/index.scss +++ b/src/newsreader/scss/pages/index.scss @@ -10,3 +10,5 @@ @import "rule/index"; @import "rules/index"; + +@import "settings/index"; diff --git a/src/newsreader/scss/pages/settings/index.scss b/src/newsreader/scss/pages/settings/index.scss new file mode 100644 index 0000000..28837cd --- /dev/null +++ b/src/newsreader/scss/pages/settings/index.scss @@ -0,0 +1,12 @@ +#settings--page { + .settings-form__fieldset:last-child { + & span { + display: flex; + flex-direction: row; + + & >:first-child { + margin: 0 5px; + } + } + } +} diff --git a/src/newsreader/templates/base.html b/src/newsreader/templates/base.html index 1e54729..3f677c0 100644 --- a/src/newsreader/templates/base.html +++ b/src/newsreader/templates/base.html @@ -17,7 +17,7 @@ - + {% if request.user.is_superuser %} {% endif %}