mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
commit
19a8c712d4
@ -13,7 +13,12 @@ from crispy_forms.helper import FormHelper
|
|||||||
from crispy_forms.layout import Layout, Field
|
from crispy_forms.layout import Layout, Field
|
||||||
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div
|
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div
|
||||||
|
|
||||||
|
from allauth.account.forms import SignupForm, set_form_field_order
|
||||||
|
from allauth.account.adapter import DefaultAccountAdapter
|
||||||
|
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||||
|
|
||||||
from part.models import PartCategory
|
from part.models import PartCategory
|
||||||
|
from common.models import InvenTreeSetting
|
||||||
|
|
||||||
|
|
||||||
class HelperForm(forms.ModelForm):
|
class HelperForm(forms.ModelForm):
|
||||||
@ -144,7 +149,6 @@ class EditUserForm(HelperForm):
|
|||||||
'username',
|
'username',
|
||||||
'first_name',
|
'first_name',
|
||||||
'last_name',
|
'last_name',
|
||||||
'email'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -204,3 +208,76 @@ class SettingCategorySelectForm(forms.ModelForm):
|
|||||||
css_class='row',
|
css_class='row',
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# override allauth
|
||||||
|
class CustomSignupForm(SignupForm):
|
||||||
|
"""
|
||||||
|
Override to use dynamic settings
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['email_required'] = InvenTreeSetting.get_setting('LOGIN_MAIL_REQUIRED')
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# check for two mail fields
|
||||||
|
if InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_TWICE'):
|
||||||
|
self.fields["email2"] = forms.EmailField(
|
||||||
|
label=_("E-mail (again)"),
|
||||||
|
widget=forms.TextInput(
|
||||||
|
attrs={
|
||||||
|
"type": "email",
|
||||||
|
"placeholder": _("E-mail address confirmation"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# check for two password fields
|
||||||
|
if not InvenTreeSetting.get_setting('LOGIN_SIGNUP_PWD_TWICE'):
|
||||||
|
self.fields.pop("password2")
|
||||||
|
|
||||||
|
# reorder fields
|
||||||
|
set_form_field_order(self, ["username", "email", "email2", "password1", "password2", ])
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
|
||||||
|
# check for two mail fields
|
||||||
|
if InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_TWICE'):
|
||||||
|
email = cleaned_data.get("email")
|
||||||
|
email2 = cleaned_data.get("email2")
|
||||||
|
if (email and email2) and email != email2:
|
||||||
|
self.add_error("email2", _("You must type the same email each time."))
|
||||||
|
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
class RegistratonMixin:
|
||||||
|
"""
|
||||||
|
Mixin to check if registration should be enabled
|
||||||
|
"""
|
||||||
|
def is_open_for_signup(self, request):
|
||||||
|
if InvenTreeSetting.get_setting('EMAIL_HOST', None) and InvenTreeSetting.get_setting('LOGIN_ENABLE_REG', True):
|
||||||
|
return super().is_open_for_signup(request)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class CustomAccountAdapter(RegistratonMixin, DefaultAccountAdapter):
|
||||||
|
"""
|
||||||
|
Override of adapter to use dynamic settings
|
||||||
|
"""
|
||||||
|
def send_mail(self, template_prefix, email, context):
|
||||||
|
"""only send mail if backend configured"""
|
||||||
|
if InvenTreeSetting.get_setting('EMAIL_HOST', None):
|
||||||
|
return super().send_mail(template_prefix, email, context)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class CustomSocialAccountAdapter(RegistratonMixin, DefaultSocialAccountAdapter):
|
||||||
|
"""
|
||||||
|
Override of adapter to use dynamic settings
|
||||||
|
"""
|
||||||
|
def is_auto_signup_allowed(self, request, sociallogin):
|
||||||
|
if InvenTreeSetting.get_setting('LOGIN_SIGNUP_SSO_AUTO', True):
|
||||||
|
return super().is_auto_signup_allowed(request, sociallogin)
|
||||||
|
return False
|
||||||
|
@ -64,15 +64,15 @@ class AuthRequiredMiddleware(object):
|
|||||||
# No authorization was found for the request
|
# No authorization was found for the request
|
||||||
if not authorized:
|
if not authorized:
|
||||||
# A logout request will redirect the user to the login screen
|
# A logout request will redirect the user to the login screen
|
||||||
if request.path_info == reverse_lazy('logout'):
|
if request.path_info == reverse_lazy('account_logout'):
|
||||||
return HttpResponseRedirect(reverse_lazy('login'))
|
return HttpResponseRedirect(reverse_lazy('account_login'))
|
||||||
|
|
||||||
path = request.path_info
|
path = request.path_info
|
||||||
|
|
||||||
# List of URL endpoints we *do not* want to redirect to
|
# List of URL endpoints we *do not* want to redirect to
|
||||||
urls = [
|
urls = [
|
||||||
reverse_lazy('login'),
|
reverse_lazy('account_login'),
|
||||||
reverse_lazy('logout'),
|
reverse_lazy('account_logout'),
|
||||||
reverse_lazy('admin:login'),
|
reverse_lazy('admin:login'),
|
||||||
reverse_lazy('admin:logout'),
|
reverse_lazy('admin:logout'),
|
||||||
]
|
]
|
||||||
@ -80,7 +80,7 @@ class AuthRequiredMiddleware(object):
|
|||||||
if path not in urls and not path.startswith('/api/'):
|
if path not in urls and not path.startswith('/api/'):
|
||||||
# Save the 'next' parameter to pass through to the login view
|
# Save the 'next' parameter to pass through to the login view
|
||||||
|
|
||||||
return redirect('%s?next=%s' % (reverse_lazy('login'), request.path))
|
return redirect('%s?next=%s' % (reverse_lazy('account_login'), request.path))
|
||||||
|
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django.contrib.sites',
|
||||||
|
|
||||||
# InvenTree apps
|
# InvenTree apps
|
||||||
'build.apps.BuildConfig',
|
'build.apps.BuildConfig',
|
||||||
@ -279,6 +280,10 @@ INSTALLED_APPS = [
|
|||||||
'error_report', # Error reporting in the admin interface
|
'error_report', # Error reporting in the admin interface
|
||||||
'django_q',
|
'django_q',
|
||||||
'formtools', # Form wizard tools
|
'formtools', # Form wizard tools
|
||||||
|
|
||||||
|
'allauth', # Base app for SSO
|
||||||
|
'allauth.account', # Extend user with accounts
|
||||||
|
'allauth.socialaccount', # Use 'social' providers
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = CONFIG.get('middleware', [
|
MIDDLEWARE = CONFIG.get('middleware', [
|
||||||
@ -298,7 +303,8 @@ MIDDLEWARE = CONFIG.get('middleware', [
|
|||||||
MIDDLEWARE.append('error_report.middleware.ExceptionProcessor')
|
MIDDLEWARE.append('error_report.middleware.ExceptionProcessor')
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = CONFIG.get('authentication_backends', [
|
AUTHENTICATION_BACKENDS = CONFIG.get('authentication_backends', [
|
||||||
'django.contrib.auth.backends.ModelBackend'
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
|
'allauth.account.auth_backends.AuthenticationBackend', # SSO login via external providers
|
||||||
])
|
])
|
||||||
|
|
||||||
# If the debug toolbar is enabled, add the modules
|
# If the debug toolbar is enabled, add the modules
|
||||||
@ -646,3 +652,34 @@ MESSAGE_TAGS = {
|
|||||||
messages.ERROR: 'alert alert-block alert-danger',
|
messages.ERROR: 'alert alert-block alert-danger',
|
||||||
messages.INFO: 'alert alert-block alert-info',
|
messages.INFO: 'alert alert-block alert-info',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SITE_ID = 1
|
||||||
|
|
||||||
|
# Load the allauth social backends
|
||||||
|
SOCIAL_BACKENDS = CONFIG.get('social_backends', [])
|
||||||
|
for app in SOCIAL_BACKENDS:
|
||||||
|
INSTALLED_APPS.append(app)
|
||||||
|
|
||||||
|
SOCIALACCOUNT_PROVIDERS = CONFIG.get('social_providers', [])
|
||||||
|
|
||||||
|
# settings for allauth
|
||||||
|
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', CONFIG.get('login_confirm_days', 3))
|
||||||
|
|
||||||
|
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', CONFIG.get('login_attempts', 5))
|
||||||
|
|
||||||
|
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
|
||||||
|
|
||||||
|
# override forms / adapters
|
||||||
|
ACCOUNT_FORMS = {
|
||||||
|
'login': 'allauth.account.forms.LoginForm',
|
||||||
|
'signup': 'InvenTree.forms.CustomSignupForm',
|
||||||
|
'add_email': 'allauth.account.forms.AddEmailForm',
|
||||||
|
'change_password': 'allauth.account.forms.ChangePasswordForm',
|
||||||
|
'set_password': 'allauth.account.forms.SetPasswordForm',
|
||||||
|
'reset_password': 'allauth.account.forms.ResetPasswordForm',
|
||||||
|
'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm',
|
||||||
|
'disconnect': 'allauth.socialaccount.forms.DisconnectForm',
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCIALACCOUNT_ADAPTER = 'InvenTree.forms.CustomSocialAccountAdapter'
|
||||||
|
ACCOUNT_ADAPTER = 'InvenTree.forms.CustomAccountAdapter'
|
||||||
|
@ -111,6 +111,10 @@ class URLTest(TestCase):
|
|||||||
if url.startswith("admin:"):
|
if url.startswith("admin:"):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# TODO can this be more elegant?
|
||||||
|
if url.startswith("account_"):
|
||||||
|
return
|
||||||
|
|
||||||
if pk:
|
if pk:
|
||||||
# We will assume that there is at least one item in the database
|
# We will assume that there is at least one item in the database
|
||||||
reverse(url, kwargs={"pk": 1})
|
reverse(url, kwargs={"pk": 1})
|
||||||
|
@ -8,7 +8,6 @@ Passes URL lookup downstream to each app as required.
|
|||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth import views as auth_views
|
|
||||||
|
|
||||||
from company.urls import company_urls
|
from company.urls import company_urls
|
||||||
from company.urls import manufacturer_part_urls
|
from company.urls import manufacturer_part_urls
|
||||||
@ -38,7 +37,7 @@ from rest_framework.documentation import include_docs_urls
|
|||||||
|
|
||||||
from .views import auth_request
|
from .views import auth_request
|
||||||
from .views import IndexView, SearchView, DatabaseStatsView
|
from .views import IndexView, SearchView, DatabaseStatsView
|
||||||
from .views import SettingsView, EditUserView, SetPasswordView
|
from .views import SettingsView, EditUserView, SetPasswordView, CustomEmailView, CustomConnectionsView, CustomPasswordResetFromKeyView
|
||||||
from .views import CurrencyRefreshView
|
from .views import CurrencyRefreshView
|
||||||
from .views import AppearanceSelectView, SettingCategorySelectView
|
from .views import AppearanceSelectView, SettingCategorySelectView
|
||||||
from .views import DynamicJsView
|
from .views import DynamicJsView
|
||||||
@ -143,9 +142,6 @@ urlpatterns = [
|
|||||||
|
|
||||||
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
|
|
||||||
url(r'^login/?', auth_views.LoginView.as_view(), name='login'),
|
|
||||||
url(r'^logout/', auth_views.LogoutView.as_view(template_name='registration/logged_out.html'), name='logout'),
|
|
||||||
|
|
||||||
url(r'^settings/', include(settings_urls)),
|
url(r'^settings/', include(settings_urls)),
|
||||||
|
|
||||||
url(r'^edit-user/', EditUserView.as_view(), name='edit-user'),
|
url(r'^edit-user/', EditUserView.as_view(), name='edit-user'),
|
||||||
@ -154,7 +150,6 @@ urlpatterns = [
|
|||||||
url(r'^admin/error_log/', include('error_report.urls')),
|
url(r'^admin/error_log/', include('error_report.urls')),
|
||||||
url(r'^admin/shell/', include('django_admin_shell.urls')),
|
url(r'^admin/shell/', include('django_admin_shell.urls')),
|
||||||
url(r'^admin/', admin.site.urls, name='inventree-admin'),
|
url(r'^admin/', admin.site.urls, name='inventree-admin'),
|
||||||
url(r'accounts/', include('django.contrib.auth.urls')),
|
|
||||||
|
|
||||||
url(r'^index/', IndexView.as_view(), name='index'),
|
url(r'^index/', IndexView.as_view(), name='index'),
|
||||||
url(r'^search/', SearchView.as_view(), name='search'),
|
url(r'^search/', SearchView.as_view(), name='search'),
|
||||||
@ -166,6 +161,13 @@ urlpatterns = [
|
|||||||
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
||||||
|
|
||||||
url(r'^markdownx/', include('markdownx.urls')),
|
url(r'^markdownx/', include('markdownx.urls')),
|
||||||
|
|
||||||
|
# Single Sign On / allauth
|
||||||
|
# overrides of urlpatterns
|
||||||
|
url(r'^accounts/email/', CustomEmailView.as_view(), name='account_email'),
|
||||||
|
url(r'^accounts/social/connections/', CustomConnectionsView.as_view(), name='socialaccount_connections'),
|
||||||
|
url(r"^accounts/password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$", CustomPasswordResetFromKeyView.as_view(), name="account_reset_password_from_key"),
|
||||||
|
url(r'^accounts/', include('allauth.urls')), # included urlpatterns
|
||||||
]
|
]
|
||||||
|
|
||||||
# Server running in "DEBUG" mode?
|
# Server running in "DEBUG" mode?
|
||||||
|
@ -17,13 +17,19 @@ from django.urls import reverse_lazy
|
|||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic import ListView, DetailView, CreateView, FormView, DeleteView, UpdateView
|
from django.views.generic import ListView, DetailView, CreateView, FormView, DeleteView, UpdateView
|
||||||
from django.views.generic.base import RedirectView, TemplateView
|
from django.views.generic.base import RedirectView, TemplateView
|
||||||
|
|
||||||
from djmoney.contrib.exchange.models import ExchangeBackend, Rate
|
from djmoney.contrib.exchange.models import ExchangeBackend, Rate
|
||||||
|
from allauth.account.forms import AddEmailForm
|
||||||
|
from allauth.socialaccount.forms import DisconnectForm
|
||||||
|
from allauth.account.models import EmailAddress
|
||||||
|
from allauth.account.views import EmailView, PasswordResetFromKeyView
|
||||||
|
from allauth.socialaccount.views import ConnectionsView
|
||||||
|
|
||||||
from common.settings import currency_code_default, currency_codes
|
from common.settings import currency_code_default, currency_codes
|
||||||
|
|
||||||
from part.models import Part, PartCategory
|
from part.models import Part, PartCategory
|
||||||
@ -810,9 +816,47 @@ class SettingsView(TemplateView):
|
|||||||
except:
|
except:
|
||||||
ctx["locale_stats"] = {}
|
ctx["locale_stats"] = {}
|
||||||
|
|
||||||
|
# Forms and context for allauth
|
||||||
|
ctx['add_email_form'] = AddEmailForm
|
||||||
|
ctx["can_add_email"] = EmailAddress.objects.can_add_email(self.request.user)
|
||||||
|
|
||||||
|
# Form and context for allauth social-accounts
|
||||||
|
ctx["request"] = self.request
|
||||||
|
ctx['social_form'] = DisconnectForm(request=self.request)
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
class AllauthOverrides(LoginRequiredMixin):
|
||||||
|
"""
|
||||||
|
Override allauths views to always redirect to success_url
|
||||||
|
"""
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
# always redirect to settings
|
||||||
|
return HttpResponseRedirect(self.success_url)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomEmailView(AllauthOverrides, EmailView):
|
||||||
|
"""
|
||||||
|
Override of allauths EmailView to always show the settings but leave the functions allow
|
||||||
|
"""
|
||||||
|
success_url = reverse_lazy("settings")
|
||||||
|
|
||||||
|
|
||||||
|
class CustomConnectionsView(AllauthOverrides, ConnectionsView):
|
||||||
|
"""
|
||||||
|
Override of allauths ConnectionsView to always show the settings but leave the functions allow
|
||||||
|
"""
|
||||||
|
success_url = reverse_lazy("settings")
|
||||||
|
|
||||||
|
|
||||||
|
class CustomPasswordResetFromKeyView(PasswordResetFromKeyView):
|
||||||
|
"""
|
||||||
|
Override of allauths PasswordResetFromKeyView to always show the settings but leave the functions allow
|
||||||
|
"""
|
||||||
|
success_url = reverse_lazy("account_login")
|
||||||
|
|
||||||
|
|
||||||
class CurrencyRefreshView(RedirectView):
|
class CurrencyRefreshView(RedirectView):
|
||||||
"""
|
"""
|
||||||
POST endpoint to refresh / update exchange rates
|
POST endpoint to refresh / update exchange rates
|
||||||
|
@ -830,6 +830,50 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'default': True,
|
'default': True,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# login / SSO
|
||||||
|
'LOGIN_ENABLE_PWD_FORGOT': {
|
||||||
|
'name': _('Enable password forgot'),
|
||||||
|
'description': _('Enable password forgot function on the login-pages'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
'LOGIN_ENABLE_REG': {
|
||||||
|
'name': _('Enable registration'),
|
||||||
|
'description': _('Enable self-registration for users on the login-pages'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
'LOGIN_ENABLE_SSO': {
|
||||||
|
'name': _('Enable SSO'),
|
||||||
|
'description': _('Enable SSO on the login-pages'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
'LOGIN_MAIL_REQUIRED': {
|
||||||
|
'name': _('E-Mail required'),
|
||||||
|
'description': _('Require user to supply mail on signup'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
'LOGIN_SIGNUP_SSO_AUTO': {
|
||||||
|
'name': _('Auto-fill SSO users'),
|
||||||
|
'description': _('Automatically fill out user-details from SSO account-data'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
'LOGIN_SIGNUP_MAIL_TWICE': {
|
||||||
|
'name': _('Mail twice'),
|
||||||
|
'description': _('On signup ask users twice for their mail'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
'LOGIN_SIGNUP_PWD_TWICE': {
|
||||||
|
'name': _('Password twice'),
|
||||||
|
'description': _('On signup ask users twice for their password'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -141,6 +141,14 @@ static_root: '/home/inventree/data/static'
|
|||||||
# - git
|
# - git
|
||||||
# - ssh
|
# - ssh
|
||||||
|
|
||||||
|
# Login configuration
|
||||||
|
# How long do confirmation mail last?
|
||||||
|
# Use environment variable INVENTREE_LOGIN_CONFIRM_DAYS
|
||||||
|
#login_confirm_days: 3
|
||||||
|
# How many wrong login attempts are permitted?
|
||||||
|
# Use environment variable INVENTREE_LOGIN_ATTEMPTS
|
||||||
|
#login_attempts: 5
|
||||||
|
|
||||||
# Permit custom authentication backends
|
# Permit custom authentication backends
|
||||||
#authentication_backends:
|
#authentication_backends:
|
||||||
# - 'django.contrib.auth.backends.ModelBackend'
|
# - 'django.contrib.auth.backends.ModelBackend'
|
||||||
@ -157,3 +165,14 @@ static_root: '/home/inventree/data/static'
|
|||||||
# - 'django.contrib.messages.middleware.MessageMiddleware'
|
# - 'django.contrib.messages.middleware.MessageMiddleware'
|
||||||
# - 'django.middleware.clickjacking.XFrameOptionsMiddleware'
|
# - 'django.middleware.clickjacking.XFrameOptionsMiddleware'
|
||||||
# - 'InvenTree.middleware.AuthRequiredMiddleware'
|
# - 'InvenTree.middleware.AuthRequiredMiddleware'
|
||||||
|
|
||||||
|
# Add SSO login-backends
|
||||||
|
# social_backends:
|
||||||
|
# - 'allauth.socialaccount.providers.keycloak'
|
||||||
|
|
||||||
|
# Add specific settings
|
||||||
|
# social_providers:
|
||||||
|
# keycloak:
|
||||||
|
# KEYCLOAK_URL: 'https://keycloak.custom/auth'
|
||||||
|
# KEYCLOAK_REALM: 'master'
|
||||||
|
|
||||||
|
@ -351,6 +351,12 @@ def object_link(url_name, pk, ref):
|
|||||||
return mark_safe('<b><a href="{}">{}</a></b>'.format(ref_url, ref))
|
return mark_safe('<b><a href="{}">{}</a></b>'.format(ref_url, ref))
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def mail_configured():
|
||||||
|
""" Return if mail is configured """
|
||||||
|
return bool(settings.EMAIL_HOST)
|
||||||
|
|
||||||
|
|
||||||
class I18nStaticNode(StaticNode):
|
class I18nStaticNode(StaticNode):
|
||||||
"""
|
"""
|
||||||
custom StaticNode
|
custom StaticNode
|
||||||
|
31
InvenTree/templates/InvenTree/settings/login.html
Normal file
31
InvenTree/templates/InvenTree/settings/login.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% extends "panel.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
{% block label %}login{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Login Settings" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
<tbody>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_REG" icon="fa-info-circle" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_SSO" icon="fa-info-circle" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_PWD_FORGOT" icon="fa-info-circle" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_MAIL_REQUIRED" icon="fa-info-circle" %}
|
||||||
|
<tr>
|
||||||
|
<td>{% trans 'Signup' %}</td>
|
||||||
|
<td colspan='4'></td>
|
||||||
|
</tr>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_SIGNUP_MAIL_TWICE" icon="fa-info-circle" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_SIGNUP_PWD_TWICE" icon="fa-info-circle" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="LOGIN_SIGNUP_SSO_AUTO" icon="fa-info-circle" %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -68,6 +68,12 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Login" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-login'>
|
||||||
|
<span class='fas fa-fingerprint'></span> {% trans "Login" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class='list-group-item' title='{% trans "Barcodes" %}'>
|
<li class='list-group-item' title='{% trans "Barcodes" %}'>
|
||||||
<a href='#' class='nav-toggle' id='select-barcodes'>
|
<a href='#' class='nav-toggle' id='select-barcodes'>
|
||||||
<span class='fas fa-qrcode'></span> {% trans "Barcodes" %}
|
<span class='fas fa-qrcode'></span> {% trans "Barcodes" %}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
|
|
||||||
{% include "InvenTree/settings/global.html" %}
|
{% include "InvenTree/settings/global.html" %}
|
||||||
|
{% include "InvenTree/settings/login.html" %}
|
||||||
{% include "InvenTree/settings/barcode.html" %}
|
{% include "InvenTree/settings/barcode.html" %}
|
||||||
{% include "InvenTree/settings/currencies.html" %}
|
{% include "InvenTree/settings/currencies.html" %}
|
||||||
{% include "InvenTree/settings/report.html" %}
|
{% include "InvenTree/settings/report.html" %}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
{% load socialaccount %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block label %}account{% endblock %}
|
{% block label %}account{% endblock %}
|
||||||
|
|
||||||
@ -10,6 +12,8 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% mail_configured as mail_conf %}
|
||||||
|
|
||||||
<div class='btn-group' style='float: right;'>
|
<div class='btn-group' style='float: right;'>
|
||||||
<div class='btn btn-primary' type='button' id='edit-user' title='{% trans "Edit User Information" %}'>
|
<div class='btn btn-primary' type='button' id='edit-user' title='{% trans "Edit User Information" %}'>
|
||||||
<span class='fas fa-user-cog'></span> {% trans "Edit" %}
|
<span class='fas fa-user-cog'></span> {% trans "Edit" %}
|
||||||
@ -32,12 +36,119 @@
|
|||||||
<td>{% trans "Last Name" %}</td>
|
<td>{% trans "Last Name" %}</td>
|
||||||
<td>{{ user.last_name }}</td>
|
<td>{{ user.last_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>{% trans "Email Address" %}</td>
|
|
||||||
<td>{{ user.email }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<h4>{% trans "E-Mail" %}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{% if user.emailaddress_set.all %}
|
||||||
|
<p>{% trans 'The following e-mail addresses are associated with your account:' %}</p>
|
||||||
|
|
||||||
|
<form action="{% url 'account_email' %}" class="email_list" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<fieldset class="blockLabels">
|
||||||
|
|
||||||
|
{% for emailaddress in user.emailaddress_set.all %}
|
||||||
|
<div class="ctrlHolder">
|
||||||
|
<label for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
|
||||||
|
|
||||||
|
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %}checked="checked"{%endif %} value="{{emailaddress.email}}"/>
|
||||||
|
|
||||||
|
{{ emailaddress.email }}
|
||||||
|
{% if emailaddress.verified %}
|
||||||
|
<span class="verified">{% trans "Verified" %}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="unverified">{% trans "Unverified" %}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if emailaddress.primary %}<span class="primary">{% trans "Primary" %}</span>{% endif %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="buttonHolder">
|
||||||
|
<button class="btn btn-primary secondaryAction" type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
|
||||||
|
<button class="btn btn-primary secondaryAction" type="submit" name="action_send" {% if not mail_conf %}disabled{% endif %}>{% trans 'Re-send Verification' %}</button>
|
||||||
|
<button class="btn btn-primary primaryAction" type="submit" name="action_remove" >{% trans 'Remove' %}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<p><strong>{% trans 'Warning:'%}</strong>
|
||||||
|
{% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if can_add_email %}
|
||||||
|
<br>
|
||||||
|
<h4>{% trans "Add E-mail Address" %}</h4>
|
||||||
|
|
||||||
|
<form method="post" action="{% url 'account_email' %}" class="add_email">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ add_email_form|crispy }}
|
||||||
|
<button class="btn btn-primary" name="action_add" type="submit">{% trans "Add E-mail" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<h4>{% trans "Social Accounts" %}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{% if social_form.accounts %}
|
||||||
|
<p>{% blocktrans %}You can sign in to your account using any of the following third party accounts:{% endblocktrans %}</p>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" action="{% url 'socialaccount_connections' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
{% if social_form.non_field_errors %}
|
||||||
|
<div id="errorMsg">{{ social_form.non_field_errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for base_account in social_form.accounts %}
|
||||||
|
{% with base_account.get_provider_account as account %}
|
||||||
|
<div>
|
||||||
|
<label for="id_account_{{ base_account.id }}">
|
||||||
|
<input id="id_account_{{ base_account.id }}" type="radio" name="account" value="{{ base_account.id }}"/>
|
||||||
|
<span class="socialaccount_provider {{ base_account.provider }} {{ account.get_brand.id }}">
|
||||||
|
<span class='brand-icon' brand_name='{{account.get_brand.id}}'></span>{{account.get_brand.name}}</span>
|
||||||
|
{{ account }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-primary" type="submit">{% trans 'Remove' %}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<p>{% trans 'You currently have no social network accounts connected to this account.' %}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<h4>{% trans 'Add a 3rd Party Account' %}</h4>
|
||||||
|
<div>
|
||||||
|
{% include "socialaccount/snippets/provider_list.html" with process="connect" %}
|
||||||
|
</div>
|
||||||
|
{% include "socialaccount/snippets/login_extra.html" %}
|
||||||
|
<br>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class='panel-heading'>
|
<div class='panel-heading'>
|
||||||
<h4>{% trans "Theme Settings" %}</h4>
|
<h4>{% trans "Theme Settings" %}</h4>
|
||||||
</div>
|
</div>
|
||||||
@ -105,4 +216,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
(function() {
|
||||||
|
var message = "{% trans 'Do you really want to remove the selected e-mail address?' %}";
|
||||||
|
var actions = document.getElementsByName('action_remove');
|
||||||
|
if (actions.length) {
|
||||||
|
actions[0].addEventListener("click", function(e) {
|
||||||
|
if (! confirm(message)) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,6 +1,5 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -12,57 +11,79 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
<!-- CSS -->
|
<!-- CSS -->
|
||||||
|
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
||||||
|
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
<link rel="stylesheet" href="{% get_color_theme_css user.get_username %}">
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.login-error {
|
|
||||||
color: #F88;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>
|
<title>
|
||||||
{% inventree_title %}
|
{% inventree_title %} | {% block head_title %}{% endblock %}
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
|
{% block extra_head %}
|
||||||
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class='login-screen'>
|
<body class='login-screen'>
|
||||||
|
<!--
|
||||||
|
Background Image Attribution: https://unsplash.com/photos/Ixvv3YZkd7w
|
||||||
|
-->
|
||||||
|
|
||||||
<div class='main body-wrapper login-screen'>
|
<div class='main body-wrapper login-screen'>
|
||||||
|
|
||||||
<div class='login-container'>
|
<div class='login-container'>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class='container-fluid'>
|
<div class='container-fluid'>
|
||||||
|
|
||||||
<div class='clearfix content-heading login-header'>
|
<div class='clearfix content-heading login-header'>
|
||||||
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
||||||
<span><h3>{% inventree_title %} </h3></span>
|
<span><h3>{% inventree_title %}</h3></span>
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class='container-fluid'>
|
|
||||||
|
|
||||||
<p>{% trans "Forgotten your password?" %}</p>
|
|
||||||
<p>{% trans "Enter your email address below." %}</p>
|
|
||||||
<p>{% trans "An email will be sent with password reset instructions." %}</p>
|
|
||||||
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ form.as_p }}
|
|
||||||
<button class="btn btn-primary" type="submit">{% trans "Send email" %}</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class='container-fluid'>{% block content %}{% endblock %}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
{% block extra_body %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
</body>
|
{% include 'notification.html' %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
|
||||||
|
<!-- general InvenTree -->
|
||||||
|
<script type='text/javascript' src="{% static 'script/inventree/notification.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- dynamic javascript templates -->
|
||||||
|
<script type='text/javascript' src="{% url 'inventree.js' %}"></script>
|
||||||
|
|
||||||
|
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type='text/javascript'>
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
// notifications
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
showAlertOrCache('alert-info', '{{message}}', true);
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
showCachedAlerts();
|
||||||
|
|
||||||
|
inventreeDocReady();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
31
InvenTree/templates/account/email_confirm.html
Normal file
31
InvenTree/templates/account/email_confirm.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% extends "account/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load account %}
|
||||||
|
|
||||||
|
{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{% trans "Confirm E-mail Address" %}</h1>
|
||||||
|
|
||||||
|
{% if confirmation %}
|
||||||
|
|
||||||
|
{% user_display confirmation.email_address.user as user_display %}
|
||||||
|
|
||||||
|
<p>{% blocktrans with confirmation.email_address.email as email %}Please confirm that <a href="mailto:{{ email }}">{{ email }}</a> is an e-mail address for user {{ user_display }}.{% endblocktrans %}</p>
|
||||||
|
|
||||||
|
<form method="post" action="{% url 'account_confirm_email' confirmation.key %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">{% trans 'Confirm' %}</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{% url 'account_email' as email_url %}
|
||||||
|
|
||||||
|
<p>{% blocktrans %}This e-mail confirmation link expired or is invalid. Please <a href="{{ email_url }}">issue a new e-mail confirmation request</a>.{% endblocktrans %}</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
52
InvenTree/templates/account/login.html
Normal file
52
InvenTree/templates/account/login.html
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{% extends "account/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n account socialaccount crispy_forms_tags inventree_extras %}
|
||||||
|
|
||||||
|
{% block head_title %}{% trans "Sign In" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% settings_value 'LOGIN_ENABLE_REG' as enable_reg %}
|
||||||
|
{% settings_value 'LOGIN_ENABLE_PWD_FORGOT' as enable_pwd_forgot %}
|
||||||
|
{% settings_value 'LOGIN_ENABLE_SSO' as enable_sso %}
|
||||||
|
{% mail_configured as mail_conf %}
|
||||||
|
|
||||||
|
<h1>{% trans "Sign In" %}</h1>
|
||||||
|
|
||||||
|
{% if enable_reg %}
|
||||||
|
{% get_providers as socialaccount_providers %}
|
||||||
|
{% if socialaccount_providers %}
|
||||||
|
<p>{% blocktrans with site.name as site_name %}Please sign in with one
|
||||||
|
of your existing third party accounts or <a class="btn btn-primary btn-small" href="{{ signup_url }}">sign up</a>
|
||||||
|
for a account and sign in below:{% endblocktrans %}</p>
|
||||||
|
{% else %}
|
||||||
|
<p>{% blocktrans %}If you have not created an account yet, then please
|
||||||
|
<a href="{{ signup_url }}">sign up</a> first.{% endblocktrans %}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form class="login" method="POST" action="{% url 'account_login' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
{% if redirect_field_value %}
|
||||||
|
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="btn-toolbar">
|
||||||
|
<button class="btn btn-primary col-md-8" type="submit">{% trans "Sign In" %}</button>
|
||||||
|
{% if mail_conf and enable_pwd_forgot %}
|
||||||
|
<a class="btn btn-primary" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if enable_sso %}
|
||||||
|
<br>
|
||||||
|
<h4 class="text-center">{% trans 'or use SSO' %}</h4>
|
||||||
|
<div>
|
||||||
|
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
|
||||||
|
</div>
|
||||||
|
{% include "socialaccount/snippets/login_extra.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
21
InvenTree/templates/account/logout.html
Normal file
21
InvenTree/templates/account/logout.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{% extends "account/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block head_title %}{% trans "Sign Out" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{% trans "Sign Out" %}</h1>
|
||||||
|
|
||||||
|
<p>{% trans 'Are you sure you want to sign out?' %}</p>
|
||||||
|
|
||||||
|
<form method="post" action="{% url 'account_logout' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% if redirect_field_value %}
|
||||||
|
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
|
||||||
|
{% endif %}
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">{% trans 'Sign Out' %}</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
30
InvenTree/templates/account/password_reset.html
Normal file
30
InvenTree/templates/account/password_reset.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{% extends "account/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n account crispy_forms_tags inventree_extras %}
|
||||||
|
|
||||||
|
{% block head_title %}{% trans "Password Reset" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% settings_value 'LOGIN_ENABLE_PWD_FORGOT' as enable_pwd_forgot %}
|
||||||
|
{% mail_configured as mail_conf %}
|
||||||
|
|
||||||
|
<h1>{% trans "Password Reset" %}</h1>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% include "account/snippets/already_logged_in.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if mail_conf and enable_pwd_forgot %}
|
||||||
|
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p>
|
||||||
|
|
||||||
|
<form method="POST" action="{% url 'account_reset_password' %}" class="password_reset">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<input type="submit" class="btn btn-primary btn-block" value="{% trans 'Reset My Password' %}" />
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<div class='alert alert-block alert-danger'>
|
||||||
|
<p>{% trans "This function is currently disabled. Please contact an administrator." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
23
InvenTree/templates/account/password_reset_from_key.html
Normal file
23
InvenTree/templates/account/password_reset_from_key.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{% extends "account/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n crispy_forms_tags %}
|
||||||
|
{% block head_title %}{% trans "Change Password" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}</h1>
|
||||||
|
|
||||||
|
{% if token_fail %}
|
||||||
|
{% url 'account_reset_password' as passwd_reset_url %}
|
||||||
|
<p>{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a <a href="{{ passwd_reset_url }}">new password reset</a>.{% endblocktrans %}</p>
|
||||||
|
{% else %}
|
||||||
|
{% if form %}
|
||||||
|
<form method="POST" action="{{ action_url }}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<input type="submit" name="action" class="btn btn-primary btn-block" value="{% trans 'change password' %}"/>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<p>{% trans 'Your password is now changed.' %}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
40
InvenTree/templates/account/signup.html
Normal file
40
InvenTree/templates/account/signup.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{% extends "account/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n crispy_forms_tags inventree_extras %}
|
||||||
|
|
||||||
|
{% block head_title %}{% trans "Signup" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% settings_value 'LOGIN_ENABLE_REG' as enable_reg %}
|
||||||
|
{% settings_value 'LOGIN_ENABLE_SSO' as enable_sso %}
|
||||||
|
|
||||||
|
<h1>{% trans "Sign Up" %}</h1>
|
||||||
|
|
||||||
|
<p>{% blocktrans %}Already have an account? Then please <a href="{{ login_url }}">sign in</a>.{% endblocktrans %}</p>
|
||||||
|
|
||||||
|
{% if enable_reg %}
|
||||||
|
<form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
{% if redirect_field_value %}
|
||||||
|
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
|
||||||
|
{% endif %}
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">{% trans "Sign Up" %}</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if enable_sso %}
|
||||||
|
<br>
|
||||||
|
<h4>{% trans 'Or use a SSO-provider for signup' %}</h4>
|
||||||
|
<div>
|
||||||
|
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
|
||||||
|
</div>
|
||||||
|
{% include "socialaccount/snippets/login_extra.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class='alert alert-block alert-danger'>
|
||||||
|
<p>{% trans "This function is currently disabled. Please contact an administrator." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -177,6 +177,11 @@ function inventreeDocReady() {
|
|||||||
'ui-autocomplete': 'dropdown-menu search-menu',
|
'ui-autocomplete': 'dropdown-menu search-menu',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Generate brand-icons
|
||||||
|
$('.brand-icon').each(function(i, obj) {
|
||||||
|
loadBrandIcon($(this), $(this).attr('brand_name'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFileTransfer(transfer) {
|
function isFileTransfer(transfer) {
|
||||||
@ -275,3 +280,13 @@ function inventreeLoad(name, defaultValue) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadBrandIcon(element, name) {
|
||||||
|
// check if icon exists
|
||||||
|
var icon = window.FontAwesome.icon({prefix: 'fab', iconName: name});
|
||||||
|
|
||||||
|
if (icon) {
|
||||||
|
// add icon to button
|
||||||
|
element.addClass('fab fa-' + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -82,9 +82,9 @@
|
|||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
<li><a href="/admin/"><span class="fas fa-user"></span> {% trans "Admin" %}</a></li>
|
<li><a href="/admin/"><span class="fas fa-user"></span> {% trans "Admin" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="{% url 'logout' %}"><span class="fas fa-sign-out-alt"></span> {% trans "Logout" %}</a></li>
|
<li><a href="{% url 'account_logout' %}"><span class="fas fa-sign-out-alt"></span> {% trans "Logout" %}</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href="{% url 'login' %}"><span class="fas fa-sign-in-alt"></span> {% trans "Login" %}</a></li>
|
<li><a href="{% url 'account_login' %}"><span class="fas fa-sign-in-alt"></span> {% trans "Login" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<hr>
|
<hr>
|
||||||
<li><a href="{% url 'settings' %}"><span class="fas fa-cog"></span> {% trans "Settings" %}</a></li>
|
<li><a href="{% url 'settings' %}"><span class="fas fa-cog"></span> {% trans "Settings" %}</a></li>
|
||||||
|
@ -1,59 +1,10 @@
|
|||||||
{% load static %}
|
{% extends "registration/logged_out.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
{% load inventree_extras %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
{% block content %}
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<!-- Required meta tags -->
|
<p>{% translate "You were logged out successfully." %}</p>
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
|
|
||||||
<!-- CSS -->
|
<p><a href="{% url 'admin:index' %}">{% translate 'Log in again' %}</a></p>
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
{% endblock %}
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.login-error {
|
|
||||||
color: #F88;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>
|
|
||||||
{% inventree_title %}
|
|
||||||
</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class='login-screen'>
|
|
||||||
|
|
||||||
<div class='main body-wrapper login-screen'>
|
|
||||||
|
|
||||||
<div class='login-container'>
|
|
||||||
<div class="row">
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<div class='clearfix content-heading login-header'>
|
|
||||||
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
|
||||||
<span><h3>{% inventree_title %} </h3></span>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<p>{% trans "You have been logged out" %}</p>
|
|
||||||
<p><a href='{% url "login" %}'>{% trans "Return to login screen" %}</a></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load inventree_extras %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<!-- Required meta tags -->
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.login-error {
|
|
||||||
color: #F88;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>
|
|
||||||
{% inventree_title %}
|
|
||||||
</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class='login-screen'>
|
|
||||||
<!--
|
|
||||||
Background Image Attribution: https://unsplash.com/photos/Ixvv3YZkd7w
|
|
||||||
-->
|
|
||||||
|
|
||||||
<div class='main body-wrapper login-screen'>
|
|
||||||
|
|
||||||
<div class='login-container'>
|
|
||||||
<div class="row">
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<div class='clearfix content-heading login-header'>
|
|
||||||
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
|
||||||
<span><h3>{% inventree_title %} </h3></span>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<form method="post" action=''>
|
|
||||||
{% csrf_token %}
|
|
||||||
|
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
|
|
||||||
<div id="div_id_username" class="form-group">
|
|
||||||
<label for="id_username" class="control-label requiredField">{% trans "Username" %}<span class="asteriskField">*</span></label>
|
|
||||||
<div class="controls ">
|
|
||||||
<div class='input-group'>
|
|
||||||
<div class='input-group-addon'>
|
|
||||||
<span class='fas fa-user'></span>
|
|
||||||
</div>
|
|
||||||
<input type="text" name="username" autofocus autocapitalize="none" autocomplete="username" maxlength="150" class="textinput textInput form-control" required id="id_username" placeholder='{% trans "Enter username" %}'>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="div_id_password" class="form-group">
|
|
||||||
<label for="id_password" class="control-label requiredField">{% trans "Password" %}<span class="asteriskField">*</span></label>
|
|
||||||
<div class='controls'>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class='input-group-addon'>
|
|
||||||
<span class='fas fa-key'></span>
|
|
||||||
</div>
|
|
||||||
<input type="password" name="password" autocomplete="current-password" class="textinput textInput form-control" required id="id_password" placeholder='{% trans "Enter password" %}'>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if form.errors %}
|
|
||||||
<div class='login-error'>
|
|
||||||
<strong>{% trans "Username / password combination is incorrect" %}</strong>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<button class='pull-right btn btn-primary login-button' type="submit">{% trans "Login" %}</button>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% if email_configured %}
|
|
||||||
<hr><br>
|
|
||||||
<p>{% trans "Forgotten your password?" %} - <a href='{% url "password_reset" %}'>{% trans "Click here to reset" %}</a></p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,59 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
{% load inventree_extras %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<!-- Required meta tags -->
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.login-error {
|
|
||||||
color: #F88;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>
|
|
||||||
{% inventree_title %}
|
|
||||||
</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class='login-screen'>
|
|
||||||
|
|
||||||
<div class='main body-wrapper login-screen'>
|
|
||||||
|
|
||||||
<div class='login-container'>
|
|
||||||
<div class="row">
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<div class='clearfix content-heading login-header'>
|
|
||||||
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
|
||||||
<span><h3>{% inventree_title %} </h3></span>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<p>{% trans "Password reset complete" %}</p>
|
|
||||||
<p><a href='{% url "login" %}'>{% trans "Return to login screen" %}</a></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
@ -1,69 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
{% load inventree_extras %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<!-- Required meta tags -->
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.login-error {
|
|
||||||
color: #F88;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>
|
|
||||||
{% inventree_title %}
|
|
||||||
</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class='login-screen'>
|
|
||||||
|
|
||||||
<div class='main body-wrapper login-screen'>
|
|
||||||
|
|
||||||
<div class='login-container'>
|
|
||||||
<div class="row">
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<div class='clearfix content-heading login-header'>
|
|
||||||
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
|
||||||
<span><h3>{% inventree_title %} </h3></span>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class='container-fluid'>
|
|
||||||
|
|
||||||
{% if validlink %}
|
|
||||||
<h3>{% trans "Change password" %}</h3>
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ form.as_p }}
|
|
||||||
<button class="btn btn-primary" type="submit">{% trans "Change password" %}</button>
|
|
||||||
</form>
|
|
||||||
{% else %}
|
|
||||||
<p>
|
|
||||||
{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
@ -1,65 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
{% load inventree_extras %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<!-- Required meta tags -->
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.login-error {
|
|
||||||
color: #F88;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>
|
|
||||||
{% inventree_title %}
|
|
||||||
</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class='login-screen'>
|
|
||||||
|
|
||||||
<div class='main body-wrapper login-screen'>
|
|
||||||
|
|
||||||
<div class='login-container'>
|
|
||||||
<div class="row">
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<div class='clearfix content-heading login-header'>
|
|
||||||
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
|
|
||||||
<span><h3>{% inventree_title %} </h3></span>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class='container-fluid'>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<a href='{% url "login" %}'>{% trans "Return to login screen" %}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
@ -0,0 +1,17 @@
|
|||||||
|
{% load socialaccount %}
|
||||||
|
|
||||||
|
{% get_providers as socialaccount_providers %}
|
||||||
|
|
||||||
|
{% for provider in socialaccount_providers %}
|
||||||
|
{% if provider.id == "openid" %}
|
||||||
|
{% for brand in provider.get_brands %}
|
||||||
|
<a title="{{brand.name}}"
|
||||||
|
class="btn btn-primary socialaccount_provider {{provider.id}} {{brand.id}}"
|
||||||
|
href="{% provider_login_url provider.id openid=brand.openid_url process=process %}"
|
||||||
|
><span class='brand-icon' brand_name='{{provider.id}}'></span> {{brand.name}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
<a title="{{provider.name}}" class="btn btn-primary socialaccount_provider {{provider.id}}"
|
||||||
|
href="{% provider_login_url provider.id process=process scope=scope auth_params=auth_params %}"
|
||||||
|
><span class='brand-icon' brand_name='{{provider.id}}'></span> {{provider.name}}</a>
|
||||||
|
{% endfor %}
|
@ -67,7 +67,12 @@ class RuleSet(models.Model):
|
|||||||
'report_billofmaterialsreport',
|
'report_billofmaterialsreport',
|
||||||
'report_purchaseorderreport',
|
'report_purchaseorderreport',
|
||||||
'report_salesorderreport',
|
'report_salesorderreport',
|
||||||
|
'account_emailaddress',
|
||||||
|
'account_emailconfirmation',
|
||||||
|
'sites_site',
|
||||||
|
'socialaccount_socialaccount',
|
||||||
|
'socialaccount_socialapp',
|
||||||
|
'socialaccount_socialtoken',
|
||||||
],
|
],
|
||||||
'part_category': [
|
'part_category': [
|
||||||
'part_partcategory',
|
'part_partcategory',
|
||||||
|
@ -68,7 +68,9 @@ RUN apk add --no-cache git make bash \
|
|||||||
# PostgreSQL support
|
# PostgreSQL support
|
||||||
postgresql postgresql-contrib postgresql-dev libpq \
|
postgresql postgresql-contrib postgresql-dev libpq \
|
||||||
# MySQL/MariaDB support
|
# MySQL/MariaDB support
|
||||||
mariadb-connector-c mariadb-dev mariadb-client
|
mariadb-connector-c mariadb-dev mariadb-client \
|
||||||
|
# Required for python cryptography support
|
||||||
|
rust cargo
|
||||||
|
|
||||||
# Install required base-level python packages
|
# Install required base-level python packages
|
||||||
COPY requirements.txt requirements.txt
|
COPY requirements.txt requirements.txt
|
||||||
|
@ -35,5 +35,6 @@ python-barcode[images]==0.13.1 # Barcode generator
|
|||||||
qrcode[pil]==6.1 # QR code generator
|
qrcode[pil]==6.1 # QR code generator
|
||||||
django-q==1.3.4 # Background task scheduling
|
django-q==1.3.4 # Background task scheduling
|
||||||
django-formtools==2.3 # Form wizard tools
|
django-formtools==2.3 # Form wizard tools
|
||||||
|
django-allauth==0.45.0 # SSO for external providers via OpenID
|
||||||
|
|
||||||
inventree # Install the latest version of the InvenTree API python library
|
inventree # Install the latest version of the InvenTree API python library
|
||||||
|
Loading…
Reference in New Issue
Block a user