summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2023-03-08 18:46:23 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2023-03-08 18:48:15 +0100
commitf5796cb2bf4e3bbe3a71b9cdf9320aea690ddfd9 (patch)
treeafb4925208a6ee8abc889d035ebd36ed39ca3128 /ishtar_common
parent4a1ebdc182c6e332fa46d47cea9ee6e3f8f9b646 (diff)
downloadIshtar-f5796cb2bf4e3bbe3a71b9cdf9320aea690ddfd9.tar.bz2
Ishtar-f5796cb2bf4e3bbe3a71b9cdf9320aea690ddfd9.zip
UI: show/hide password on login
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms_common.py14
-rw-r--r--ishtar_common/static/js/bootstrap-show-password/bootstrap-show-password.min.js2
-rw-r--r--ishtar_common/templates/base.html1
-rw-r--r--ishtar_common/urls_registration.py31
-rw-r--r--ishtar_common/views.py6
5 files changed, 46 insertions, 8 deletions
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 4286ae9fd..eb7e03f3a 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -32,6 +32,8 @@ import zipfile
from django import forms
from django.conf import settings
from django.contrib.auth.models import User
+from django.contrib.auth.forms import AuthenticationForm as AuthAuthenticationForm, \
+ UsernameField
from django.contrib.contenttypes.models import ContentType
from django.core import validators
from django.core.cache import cache
@@ -135,6 +137,18 @@ def get_person_field(label=_("Person"), required=True, person_types=None):
)
+class AuthenticationForm(AuthAuthenticationForm):
+ username = UsernameField(widget=forms.TextInput(
+ attrs={'autofocus': True, 'class': 'no-append'})
+ )
+ password = forms.CharField(
+ label=_("Password"),
+ strip=False,
+ widget=forms.PasswordInput(
+ attrs={'autocomplete': 'off', 'data-toggle': 'password'})
+ )
+
+
class NewItemForm(forms.Form):
def __init__(self, *args, **kwargs):
self.limits = {}
diff --git a/ishtar_common/static/js/bootstrap-show-password/bootstrap-show-password.min.js b/ishtar_common/static/js/bootstrap-show-password/bootstrap-show-password.min.js
index a944d22c1..317ed06d3 100644
--- a/ishtar_common/static/js/bootstrap-show-password/bootstrap-show-password.min.js
+++ b/ishtar_common/static/js/bootstrap-show-password/bootstrap-show-password.min.js
@@ -3,4 +3,4 @@
* https://github.com/wenzhixin/bootstrap-show-password
* version: 1.0.3
*/
-!function(e){"use strict";var t=function(e){var t=arguments,s=!0,i=1;return e=e.replace(/%s/g,function(){var e=t[i++];return"undefined"==typeof e?(s=!1,""):e}),s?e:""},s=function(t,s){this.options=s,this.$element=e(t),this.isShown=!1,this.init()};s.DEFAULTS={placement:"after",white:!1,message:"Click here to show/hide password",eyeClass:"glyphicon",eyeOpenClass:"glyphicon-eye-open",eyeCloseClass:"glyphicon-eye-close"},s.prototype.init=function(){var s,i;"before"===this.options.placement?(s="insertBefore",i="input-prepend"):(this.options.placement="after",s="insertAfter",i="input-append"),this.$element.wrap(t('<div class="%s input-group" />',i)),this.$text=e('<input type="text" />')[s](this.$element).attr("class",this.$element.attr("class")).attr("style",this.$element.attr("style")).attr("placeholder",this.$element.attr("placeholder")).css("display",this.$element.css("display")).val(this.$element.val()).hide(),this.$element.prop("readonly")&&this.$text.prop("readonly",!0),this.$icon=e(['<span tabindex="100" title="'+this.options.message+'" class="add-on input-group-addon">','<i class="icon-eye-open'+(this.options.white?" icon-white":"")+" "+this.options.eyeClass+" "+this.options.eyeOpenClass+'"></i>',"</span>"].join(""))[s](this.$text).css("cursor","pointer"),this.$text.off("keyup").on("keyup",e.proxy(function(){this.isShown&&this.$element.val(this.$text.val()).trigger("change")},this)),this.$icon.off("click").on("click",e.proxy(function(){this.$text.val(this.$element.val()).trigger("change"),this.toggle()},this))},s.prototype.toggle=function(e){this[this.isShown?"hide":"show"](e)},s.prototype.show=function(t){var s=e.Event("show.bs.password",{relatedTarget:t});this.$element.trigger(s),this.isShown=!0,this.$element.hide(),this.$text.show(),this.$icon.find("i").removeClass("icon-eye-open "+this.options.eyeOpenClass).addClass("icon-eye-close "+this.options.eyeCloseClass),this.$text[this.options.placement](this.$element)},s.prototype.hide=function(t){var s=e.Event("hide.bs.password",{relatedTarget:t});this.$element.trigger(s),this.isShown=!1,this.$element.show(),this.$text.hide(),this.$icon.find("i").removeClass("icon-eye-close "+this.options.eyeCloseClass).addClass("icon-eye-open "+this.options.eyeOpenClass),this.$element[this.options.placement](this.$text)},s.prototype.val=function(e){return"undefined"==typeof e?this.$element.val():(this.$element.val(e).trigger("change"),this.$text.val(e),void 0)};var i=e.fn.password;e.fn.password=function(){var t,i=arguments[0],n=arguments,o=["show","hide","toggle","val"];return this.each(function(){var a=e(this),h=a.data("bs.password"),r=e.extend({},s.DEFAULTS,a.data(),"object"==typeof i&&i);if("string"==typeof i){if(e.inArray(i,o)<0)throw"Unknown method: "+i;t=h[i](n[1])}else h?h.init(r):(h=new s(a,r),a.data("bs.password",h))}),t?t:this},e.fn.password.Constructor=s,e.fn.password.noConflict=function(){return e.fn.password=i,this},e(function(){e('[data-toggle="password"]').password()})}(window.jQuery); \ No newline at end of file
+!function(e){"use strict";var t=function(e){var t=arguments,s=!0,i=1;return e=e.replace(/%s/g,function(){var e=t[i++];return"undefined"==typeof e?(s=!1,""):e}),s?e:""},s=function(t,s){this.options=s,this.$element=e(t),this.isShown=!1,this.init()};s.DEFAULTS={placement:"after",white:!1,message:"Click here to show/hide password",eyeClass:"fa",eyeOpenClass:"fa-eye",eyeCloseClass:"fa-eye-slash"},s.prototype.init=function(){var s,i;"before"===this.options.placement?(s="insertBefore",i="input-prepend"):(this.options.placement="after",s="insertAfter",i=""),this.$element.wrap(t('<div class="%sinput-group" />',i)),this.$text=e('<input type="text" />')[s](this.$element).attr("class",this.$element.attr("class")).attr("style",this.$element.attr("style")).attr("placeholder",this.$element.attr("placeholder")).css("display",this.$element.css("display")).val(this.$element.val()).hide(),this.$element.prop("readonly")&&this.$text.prop("readonly",!0),this.$icon=e(['<div tabindex="100" title="'+this.options.message+'" class="input-group-append">','<span class="input-group-text"><i class="icon-eye-open'+(this.options.white?" icon-white":"")+" "+this.options.eyeClass+" "+this.options.eyeOpenClass+'"></i></span>',"</div>"].join(""))[s](this.$text).css("cursor","pointer"),this.$text.off("keyup").on("keyup",e.proxy(function(){this.isShown&&this.$element.val(this.$text.val()).trigger("change")},this)),this.$icon.off("click").on("click",e.proxy(function(){this.$text.val(this.$element.val()).trigger("change"),this.toggle()},this))},s.prototype.toggle=function(e){this[this.isShown?"hide":"show"](e)},s.prototype.show=function(t){var s=e.Event("show.bs.password",{relatedTarget:t});this.$element.trigger(s),this.isShown=!0,this.$element.hide(),this.$text.show(),this.$icon.find("i").removeClass("icon-eye-open "+this.options.eyeOpenClass).addClass("icon-eye-close "+this.options.eyeCloseClass),this.$text[this.options.placement](this.$element)},s.prototype.hide=function(t){var s=e.Event("hide.bs.password",{relatedTarget:t});this.$element.trigger(s),this.isShown=!1,this.$element.show(),this.$text.hide(),this.$icon.find("i").removeClass("icon-eye-close "+this.options.eyeCloseClass).addClass("icon-eye-open "+this.options.eyeOpenClass),this.$element[this.options.placement](this.$text)},s.prototype.val=function(e){return"undefined"==typeof e?this.$element.val():(this.$element.val(e).trigger("change"),this.$text.val(e),void 0)};var i=e.fn.password;e.fn.password=function(){var t,i=arguments[0],n=arguments,o=["show","hide","toggle","val"];return this.each(function(){var a=e(this),h=a.data("bs.password"),r=e.extend({},s.DEFAULTS,a.data(),"object"==typeof i&&i);if("string"==typeof i){if(e.inArray(i,o)<0)throw"Unknown method: "+i;t=h[i](n[1])}else h?h.init(r):(h=new s(a,r),a.data("bs.password",h))}),t?t:this},e.fn.password.Constructor=s,e.fn.password.noConflict=function(){return e.fn.password=i,this},e(function(){e('[data-toggle="password"]').password()})}(window.jQuery);
diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html
index 3fa049215..53ef4f35a 100644
--- a/ishtar_common/templates/base.html
+++ b/ishtar_common/templates/base.html
@@ -15,6 +15,7 @@
<script language="javascript" type="text/javascript" src="{{STATIC_URL}}popper.min.js?ver={{VERSION}}"></script>
<script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}jquery-ui.js?ver={{VERSION}}"></script>
<script language="javascript" type="text/javascript" src="{{STATIC_URL}}bootstrap/bootstrap.js?ver={{VERSION}}"></script>
+ <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/bootstrap-show-password/bootstrap-show-password.min.js?ver={{VERSION}}"></script>
<script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/papaparse.min.js?ver={{VERSION}}"></script>
<script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/chosen/chosen.jquery.min.js?ver={{VERSION}}"></script>
{# <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/prettyPhoto/js/jquery.prettyPhoto.js?ver={{VERSION}}"></script> #}
diff --git a/ishtar_common/urls_registration.py b/ishtar_common/urls_registration.py
index 36795b113..0a18ff060 100644
--- a/ishtar_common/urls_registration.py
+++ b/ishtar_common/urls_registration.py
@@ -1,11 +1,15 @@
-from django.conf.urls import include, url
+from django.conf.urls import url
+from django.urls import path
from django.views.generic.base import TemplateView
try:
- from registration import views # debian
+ from registration import views as registration_views # debian
except ModuleNotFoundError:
- from django_registration import views # pip
+ from django_registration import views as registration_views # pip
+from django.contrib.auth import views as auth_views
+
+from ishtar_common import views
urlpatterns = [
url(r'^accounts/activate/complete/$',
@@ -18,10 +22,10 @@ urlpatterns = [
# the view; that way it can return a sensible "invalid key"
# message instead of a confusing 404.
url(r'^accounts/activate/(?P<activation_key>\w+)/$',
- views.ActivationView.as_view(),
+ registration_views.ActivationView.as_view(),
name='registration_activate'),
url(r'^accounts/register/$',
- views.RegistrationView.as_view(),
+ registration_views.RegistrationView.as_view(),
name='registration_register'),
url(r'^accounts/register/complete/$',
TemplateView.as_view(
@@ -33,5 +37,20 @@ urlpatterns = [
template_name='registration/registration_closed.html'
),
name='registration_disallowed'),
- url("^accounts/", include('django.contrib.auth.urls')),
+ # url("^accounts/", include('django.contrib.auth.urls')),
+ path('accounts/login/', views.LoginView.as_view(), name='login'),
+ path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'),
+
+ path('accounts/password_change/', auth_views.PasswordChangeView.as_view(),
+ name='password_change'),
+ path('accounts/password_change/done/', auth_views.PasswordChangeDoneView.as_view(),
+ name='password_change_done'),
+
+ path('accounts/password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
+ path('accounts/password_reset/done/', auth_views.PasswordResetDoneView.as_view(),
+ name='password_reset_done'),
+ path('accounts/reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(),
+ name='password_reset_confirm'),
+ path('accounts/reset/done/', auth_views.PasswordResetCompleteView.as_view(),
+ name='password_reset_complete'),
] \ No newline at end of file
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index f9f84b533..b6b58fe05 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -31,7 +31,7 @@ from django.apps import apps
from django.conf import settings
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required
-from django.contrib.auth.views import redirect_to_login
+from django.contrib.auth.views import redirect_to_login, LoginView as AuthLoginView
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
@@ -167,6 +167,10 @@ def index(request):
return render(request, "index.html", dct)
+class LoginView(AuthLoginView):
+ form_class = forms.AuthenticationForm
+
+
person_search_wizard = wizards.PersonSearch.as_view(
[("general-person_search", forms.PersonFormSelection)],
label=_("Person search"),