mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	Merge branch 'inventree:master' into matmair/issue2279
This commit is contained in:
		| @@ -16,6 +16,7 @@ | ||||
|         {% 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" %} | ||||
|         {% include "InvenTree/settings/setting.html" with key="LOGIN_ENFORCE_MFA" %} | ||||
|         <tr> | ||||
|             <th><h5>{% trans 'Signup' %}</h5></th> | ||||
|             <td colspan='4'></td> | ||||
|   | ||||
| @@ -42,193 +42,317 @@ | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <div class='panel-heading'> | ||||
|     <div class='d-flex flex-span'> | ||||
| <div class="row"> | ||||
|     <div class='panel-heading'> | ||||
|         <div class='d-flex flex-span'> | ||||
|         <h4>{% trans "Email" %}</h4> | ||||
|         {% include "spacer.html" %} | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| <div class='row'> | ||||
|     <div class='col-sm-6'> | ||||
|         {% if user.emailaddress_set.all %} | ||||
|         <p>{% trans 'The following email addresses are associated with your account:' %}</p> | ||||
|     <div class="col-sm-6"> | ||||
|     {% if user.emailaddress_set.all %} | ||||
|     <p>{% trans 'The following email addresses are associated with your account:' %}</p> | ||||
|  | ||||
|         <form action="{% url 'account_email' %}" class="email_list" method="post"> | ||||
|     <form action="{% url 'account_email' %}" class="email_list" method="post"> | ||||
|         {% csrf_token %} | ||||
|             <fieldset class="blockLabels"> | ||||
|         <fieldset class="blockLabels"> | ||||
|  | ||||
|             {% for emailaddress in user.emailaddress_set.all %} | ||||
|             <div> | ||||
|                 <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}}"/> | ||||
|                          | ||||
|                         {% if emailaddress.primary %} | ||||
|                         <b>{{ emailaddress.email }}</b> | ||||
|                         {% else %} | ||||
|                         {{ emailaddress.email }} | ||||
|                         {% endif %} | ||||
|                     </label> | ||||
|                     {% if emailaddress.verified %} | ||||
|                     <span class='badge badge-right rounded-pill bg-success'>{% trans "Verified" %}</span> | ||||
|             <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}}" /> | ||||
|  | ||||
|                     {% if emailaddress.primary %} | ||||
|                     <b>{{ emailaddress.email }}</b> | ||||
|                     {% else %} | ||||
|                     <span class='badge badge-right rounded-pill bg-warning'>{% trans "Unverified" %}</span> | ||||
|                     {{ emailaddress.email }} | ||||
|                     {% endif %} | ||||
|                     {% if emailaddress.primary %}<span class='badge badge-right rounded-pill bg-primary'>{% trans "Primary" %}</span>{% endif %} | ||||
|                 </div> | ||||
|                 </label> | ||||
|  | ||||
|                 {% if emailaddress.verified %} | ||||
|                 <span class='badge badge-right rounded-pill bg-success'>{% trans "Verified" %}</span> | ||||
|                 {% else %} | ||||
|                 <span class='badge badge-right rounded-pill bg-warning'>{% trans "Unverified" %}</span> | ||||
|                 {% endif %} | ||||
|                 {% if emailaddress.primary %}<span class='badge badge-right rounded-pill bg-primary'>{% trans "Primary" %}</span>{% endif %} | ||||
|             </div> | ||||
|             </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_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> | ||||
|                 <button class="btn btn-primary primaryAction" type="submit" name="action_remove">{% trans 'Remove' %}</button> | ||||
|             </div> | ||||
|  | ||||
|         </fieldset> | ||||
|     </form> | ||||
|  | ||||
|     {% else %} | ||||
|     <div class='alert alert-block alert-danger'> | ||||
|         <strong>{% trans 'Warning:'%}</strong> | ||||
|         {% trans "You currently do not have any email address set up. You should really add an email address so you can receive notifications, reset your password, etc." %} | ||||
|     </div> | ||||
|  | ||||
|     {% endif %} | ||||
|     </div> | ||||
|  | ||||
|     {% if can_add_email %} | ||||
|     <div class="col-sm-6"> | ||||
|     <h5>{% trans "Add Email Address" %}</h5> | ||||
|  | ||||
|     <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 Email" %}</button> | ||||
|     </form> | ||||
|     </div> | ||||
|     {% endif %} | ||||
| </div> | ||||
|  | ||||
| <div class="row"> | ||||
|     <div class='panel-heading'> | ||||
|         <h4>{% trans "Social Accounts" %}</h4> | ||||
|     </div> | ||||
|  | ||||
|     <div class="col-md-6"> | ||||
|         {% 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><strong>{% trans 'Warning:'%}</strong> | ||||
|             {% trans "You currently do not have any email address set up. You should really add an email address so you can receive notifications, reset your password, etc." %} | ||||
|         </p> | ||||
|  | ||||
|         <p>{% trans 'You currently have no social network accounts connected to this account.' %}</p> | ||||
|         {% endif %} | ||||
|     </div> | ||||
|  | ||||
|     <div class="col-md-6"> | ||||
|         <h5>{% trans 'Add a 3rd Party Account' %}</h5> | ||||
|         <div> | ||||
|             {% include "socialaccount/snippets/provider_list.html" with process="connect" %} | ||||
|         </div> | ||||
|         {% include "socialaccount/snippets/login_extra.html" %} | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| <div class="row"> | ||||
|     <div class='panel-heading'> | ||||
|         <h4>{% trans "Multifactor" %}</h4> | ||||
|     </div> | ||||
|  | ||||
|     <div class="col-md-6"> | ||||
|     {% if user.staticdevice_set.all or user.totpdevice_set.all %} | ||||
|     <p>{% trans 'You have these factors available:' %}</p> | ||||
|  | ||||
|     <table class="table table-striped"> | ||||
|         <thead> | ||||
|             <th>Type</th> | ||||
|             <th>Name</th> | ||||
|         </thead> | ||||
|         <tbody> | ||||
|         {% for token in user.totpdevice_set.all %} | ||||
|         <tr> | ||||
|             <td>{% trans 'TOTP' %}</td> | ||||
|             <td>{{ token.name }}</td> | ||||
|         </tr> | ||||
|         {% endfor %} | ||||
|         {% for token in user.staticdevice_set.all %} | ||||
|         <tr> | ||||
|             <td>{% trans 'Static' %}</td> | ||||
|             <td>{{ token.name }}</td> | ||||
|         </tr> | ||||
|         {% endfor %} | ||||
|         </tbody> | ||||
|     </table> | ||||
|  | ||||
|     {% else %} | ||||
|     <p><strong>{% trans 'Warning:'%}</strong> | ||||
|         {% trans "You currently do not have any factors set up." %} | ||||
|     </p> | ||||
|  | ||||
|     {% endif %} | ||||
|     </div> | ||||
|  | ||||
|     <div class="col-md-6"> | ||||
|     <h5>{% trans "Change factors" %}</h5> | ||||
|     <a href="{% url 'two-factor-setup' %}" class="btn btn-primary {% if user.staticdevice_set.all and user.totpdevice_set.all %}disabled{% endif %}" role="button">{% trans "Setup multifactor" %}</a> | ||||
|     {% if user.staticdevice_set.all or user.totpdevice_set.all %} | ||||
|     <a href="{% url 'two-factor-remove' %}" class="btn btn-primary" role="button">{% trans "Remove multifactor" %}</a> | ||||
|     {% endif %} | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| <div class='row'> | ||||
|     <div class='panel-heading'> | ||||
|         <h4>{% trans "Theme Settings" %}</h4> | ||||
|     </div> | ||||
|  | ||||
|     <div class='col-sm-6'> | ||||
|         {% if can_add_email %} | ||||
|         <h5>{% trans "Add Email Address" %}</h5> | ||||
|  | ||||
|         <form method="post" action="{% url 'account_email' %}" class="add_email"> | ||||
|         <form action='{% url "settings-appearance" %}' method='post'> | ||||
|             {% csrf_token %} | ||||
|  | ||||
|             <label for="id_email" class=" requiredField"> | ||||
|                 E-mail<span class="asteriskField">*</span> | ||||
|             <input name='next' type='hidden' value='{% url "settings" %}'> | ||||
|             <label for='theme' class=' requiredField'> | ||||
|                 {% trans "Select theme" %} | ||||
|             </label> | ||||
|             <div id="div_id_email" class="form-group input-group mb-3"> | ||||
|                 <div class='input-group-prepend'><span class='input-group-text'>@</span></div> | ||||
|                 <input type="email" name="email" placeholder='{% trans "Enter e-mail address" %}' class="textinput textInput form-control" required="" id="id_email"> | ||||
|             <div class='form-group input-group mb-3'> | ||||
|                 <select id='theme' name='theme' class='select form-control'> | ||||
|                     {% get_available_themes as themes %} | ||||
|                     {% for theme in themes %} | ||||
|                     <option value='{{ theme.key }}'>{{ theme.name }}</option> | ||||
|                     {% endfor %} | ||||
|                 </select> | ||||
|                 <div class='input-group-append'> | ||||
|                     <button class="btn btn-primary" name="action_add" type="submit">{% trans "Add Email" %}</button> | ||||
|                     <input type="submit" value="{% trans 'Set Theme' %}" class="btn btn-primary"> | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|         </form> | ||||
|     {% endif %} | ||||
|     </div> | ||||
| </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 class="row"> | ||||
|     <div class='panel-heading'> | ||||
|         <h4>{% trans "Language Settings" %}</h4> | ||||
|     </div> | ||||
|     {% endwith %} | ||||
|     {% endfor %} | ||||
|  | ||||
|     <div> | ||||
|     <button class="btn btn-primary" type="submit">{% trans 'Remove' %}</button> | ||||
|     </div> | ||||
|      | ||||
|     </fieldset> | ||||
|      | ||||
|     <div class="col"> | ||||
|         <form action="{% url 'set_language' %}" method="post"> | ||||
|             {% csrf_token %} | ||||
|             <input name="next" type="hidden" value="{% url 'settings' %}"> | ||||
|             <label for='language' class=' requiredField'> | ||||
|                 {% trans "Select language" %} | ||||
|             </label> | ||||
|             <div class='form-group input-group mb-3'> | ||||
|                 <select name="language" class="select form-control w-25"> | ||||
|                     {% get_current_language as LANGUAGE_CODE %} | ||||
|                     {% get_available_languages as LANGUAGES %} | ||||
|                     {% get_language_info_list for LANGUAGES as languages %} | ||||
|                     {% if 'alllang' in request.GET %}{% define True as ALL_LANG %}{% endif %} | ||||
|                     {% for language in languages %} | ||||
|                         {% define language.code as lang_code %} | ||||
|                         {% define locale_stats|keyvalue:lang_code as lang_translated %} | ||||
|                         {% if lang_translated > 10 or lang_code == 'en' or lang_code == LANGUAGE_CODE %}{% define True as use_lang %}{% else %}{% define False as use_lang %}{% endif %} | ||||
|                         {% if ALL_LANG or use_lang  %} | ||||
|                         <option value="{{ lang_code }}"{% if lang_code == LANGUAGE_CODE %} selected{% endif %}> | ||||
|                             {{ language.name_local }} ({{ lang_code }})  | ||||
|                             {% if lang_translated %} | ||||
|                                 {% blocktrans %}{{ lang_translated }}% translated{% endblocktrans %} | ||||
|                             {% else %} | ||||
|                                 {% if lang_code == 'en' %}-{% else %}{% trans 'No translations available' %}{% endif %} | ||||
|                             {% endif %} | ||||
|                         </option> | ||||
|                         {% endif %} | ||||
|                     {% endfor %} | ||||
|                 </select> | ||||
|                 <div class='input-group-append'> | ||||
|                     <input type="submit" value="{% trans 'Set Language' %}" class="btn btn btn-primary"> | ||||
|                 </div> | ||||
|                 <p>{% trans "Some languages are not complete" %} | ||||
|                 {% if ALL_LANG %} | ||||
|                 . <a href="{% url 'settings' %}">{% trans "Show only sufficent" %}</a> | ||||
|                 {% else %} | ||||
|                 and hidden. <a href="?alllang">{% trans "Show them too" %}</a> | ||||
|                 {% endif %} | ||||
|                 </p> | ||||
|             </div> | ||||
|     </form> | ||||
|      | ||||
|     {% else %} | ||||
|     <div class='alert alert-block alert-warning'> | ||||
|         {% trans "There are no social network accounts connected to your InvenTree account" %} | ||||
|     </div> | ||||
|     {% endif %} | ||||
|  | ||||
|     <br> | ||||
|     <h4>{% trans 'Add a 3rd Party Account' %}</h4> | ||||
|     <div> | ||||
|     {% include "socialaccount/snippets/provider_list.html" with process="connect" %} | ||||
|     <div class="col-sm-6"> | ||||
|         <h4>{% trans "Help the translation efforts!" %}</h4> | ||||
|         <p>{% blocktrans with link="https://crowdin.com/project/inventree" %}Native language translation of the | ||||
|             InvenTree web application is <a href="{{link}}">community contributed via crowdin</a>. Contributions are | ||||
|             welcomed and encouraged.{% endblocktrans %}</p> | ||||
|     </div> | ||||
|     {% include "socialaccount/snippets/login_extra.html" %} | ||||
|     <br> | ||||
|  | ||||
| </div> | ||||
|  | ||||
| <div class='panel-heading'> | ||||
|     <div class='d-flex flex-wrap'> | ||||
|         <h4>{% trans "Active Sessions" %}</h4> | ||||
|         {% include "spacer.html" %} | ||||
|         <div class='btn-group' role='group'> | ||||
|             {% if session_list.count > 1 %} | ||||
|             <form method="post" action="{% url 'session_delete_other' %}"> | ||||
|                 {% csrf_token %} | ||||
|                 <button type="submit" class="btn btn-sm btn-default btn-danger" title='{% trans "Log out active sessions (except this one)" %}'> | ||||
|                     {% trans "Log Out Active Sessions" %} | ||||
|                 </button> | ||||
|             </form> | ||||
|             {% endif %} | ||||
| <div class="row"> | ||||
|     <div class='panel-heading'> | ||||
|         <div class='d-flex flex-wrap'> | ||||
|             <h4>{% trans "Active Sessions" %}</h4> | ||||
|             {% include "spacer.html" %} | ||||
|             <div class='btn-group' role='group'> | ||||
|                 {% if session_list.count > 1 %} | ||||
|                 <form method="post" action="{% url 'session_delete_other' %}"> | ||||
|                     {% csrf_token %} | ||||
|                     <button type="submit" class="btn btn-sm btn-default btn-danger" title='{% trans "Log out active sessions (except this one)" %}'> | ||||
|                         {% trans "Log Out Active Sessions" %} | ||||
|                     </button> | ||||
|                 </form> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| <div> | ||||
|     {% trans "<em>unknown on unknown</em>" as unknown_on_unknown %} | ||||
|     {% trans "<em>unknown</em>" as unknown %} | ||||
|     <table class="table table-striped table-condensed"> | ||||
|     <thead> | ||||
|         <tr> | ||||
|         <th>{% trans "IP Address" %}</th> | ||||
|         <th>{% trans "Device" %}</th> | ||||
|         <th>{% trans "Last Activity" %}</th> | ||||
|         </tr> | ||||
|     </thead> | ||||
|     {% for object in session_list %} | ||||
|         <tr {% if object.session_key == session_key %}class="active"{% endif %}> | ||||
|         <td>{{ object.ip }}</td> | ||||
|         <td>{{ object.user_agent|device|default_if_none:unknown_on_unknown|safe }}</td> | ||||
|         <td> | ||||
|             {% if object.session_key == session_key %} | ||||
|             {% blocktrans with time=object.last_activity|timesince %}{{ time }} ago (this session){% endblocktrans %} | ||||
|             {% else %} | ||||
|             {% blocktrans with time=object.last_activity|timesince %}{{ time }} ago{% endblocktrans %} | ||||
|             {% endif %} | ||||
|         </td> | ||||
|         </tr> | ||||
|     {% endfor %} | ||||
|     </table> | ||||
|     <div> | ||||
|         {% trans "<em>unknown on unknown</em>" as unknown_on_unknown %} | ||||
|         {% trans "<em>unknown</em>" as unknown %} | ||||
|         <table class="table table-striped table-condensed"> | ||||
|         <thead> | ||||
|             <tr> | ||||
|             <th>{% trans "IP Address" %}</th> | ||||
|             <th>{% trans "Device" %}</th> | ||||
|             <th>{% trans "Last Activity" %}</th> | ||||
|             </tr> | ||||
|         </thead> | ||||
|         {% for object in session_list %} | ||||
|             <tr {% if object.session_key == session_key %}class="active"{% endif %}> | ||||
|             <td>{{ object.ip }}</td> | ||||
|             <td>{{ object.user_agent|device|default_if_none:unknown_on_unknown|safe }}</td> | ||||
|             <td> | ||||
|                 {% if object.session_key == session_key %} | ||||
|                 {% blocktrans with time=object.last_activity|timesince %}{{ time }} ago (this session){% endblocktrans %} | ||||
|                 {% else %} | ||||
|                 {% blocktrans with time=object.last_activity|timesince %}{{ time }} ago{% endblocktrans %} | ||||
|                 {% endif %} | ||||
|             </td> | ||||
|             </tr> | ||||
|         {% endfor %} | ||||
|         </table> | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block js_ready %} | ||||
| (function() { | ||||
|   var message = "{% trans 'Do you really want to remove the selected email address?' %}"; | ||||
|   var actions = document.getElementsByName('action_remove'); | ||||
|   if (actions.length) { | ||||
|     actions[0].addEventListener("click", function(e) { | ||||
|       if (! confirm(message)) { | ||||
|         e.preventDefault(); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| var message = "{% trans 'Do you really want to remove the selected email address?' %}"; | ||||
| var actions = document.getElementsByName('action_remove'); | ||||
| if (actions.length) { | ||||
| actions[0].addEventListener("click", function(e) { | ||||
| if (! confirm(message)) { | ||||
| e.preventDefault(); | ||||
| } | ||||
| }); | ||||
| } | ||||
| })(); | ||||
| {% endblock %} | ||||
							
								
								
									
										15
									
								
								InvenTree/templates/allauth_2fa/authenticate.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								InvenTree/templates/allauth_2fa/authenticate.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| {% extends "account/base.html" %} | ||||
| {% load i18n crispy_forms_tags %} | ||||
|  | ||||
| {% block content %} | ||||
| <h1>{% trans "Two-Factor Authentication" %}</h1> | ||||
|  | ||||
| <form method="post" class="login"> | ||||
|   {% csrf_token %} | ||||
|   {{ form|crispy }} | ||||
|  | ||||
|   <button type="submit" class="btn btn-primary"> | ||||
|     {% trans 'Authenticate' %} | ||||
|   </button> | ||||
| </form> | ||||
| {% endblock %} | ||||
							
								
								
									
										33
									
								
								InvenTree/templates/allauth_2fa/backup_tokens.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								InvenTree/templates/allauth_2fa/backup_tokens.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| {% extends "account/base.html" %} | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block content %} | ||||
| <h3> | ||||
|   {% trans "Two-Factor Authentication Backup Tokens" %} | ||||
| </h3> | ||||
|  | ||||
| {% if backup_tokens %} | ||||
|   {% if reveal_tokens %} | ||||
|     <ul> | ||||
|       {% for token in backup_tokens %} | ||||
|         <li>{{ token.token }}</li> | ||||
|       {% endfor %} | ||||
|     </ul> | ||||
|   {% else %} | ||||
|     {% trans 'Backup tokens have been generated, but are not revealed here for security reasons. Press the button below to generate new ones.' %} | ||||
|   {% endif %} | ||||
| {% else %} | ||||
|   {% trans 'No tokens. Press the button below to generate some.' %} | ||||
| {% endif %} | ||||
|  | ||||
| <br> | ||||
| <form method="post"> | ||||
|   {% csrf_token %} | ||||
|   <button type="submit" class="btn btn-primary w-100"> | ||||
|     {% trans 'Generate backup tokens' %} | ||||
|   </button> | ||||
| </form> | ||||
| <br> | ||||
| <a href="{% url 'settings' %}" class="btn btn-secondary w-100 btn-sm">{% trans "back to settings" %}</a> | ||||
|  | ||||
| {% endblock %} | ||||
							
								
								
									
										18
									
								
								InvenTree/templates/allauth_2fa/remove.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								InvenTree/templates/allauth_2fa/remove.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| {% extends "account/base.html" %} | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block content %} | ||||
| <h3> | ||||
|   {% trans "Disable Two-Factor Authentication" %} | ||||
| </h3> | ||||
|  | ||||
| <p>{% trans "Are you sure?" %}</p> | ||||
|  | ||||
| <form method="post"> | ||||
|   {% csrf_token %} | ||||
|   <button type="submit" class="btn btn-danger w-100"> | ||||
|     {% trans 'Disable Two-Factor' %} | ||||
|   </button> | ||||
| </form> | ||||
|  | ||||
| {% endblock %} | ||||
							
								
								
									
										42
									
								
								InvenTree/templates/allauth_2fa/setup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								InvenTree/templates/allauth_2fa/setup.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| {% extends "account/base.html" %} | ||||
| {% load i18n crispy_forms_tags %} | ||||
|  | ||||
| {% block content %} | ||||
| <h3> | ||||
|   {% trans "Setup Two-Factor Authentication" %} | ||||
| </h3> | ||||
|  | ||||
| <h4> | ||||
|   {% trans 'Step 1' %}: | ||||
| </h4> | ||||
|  | ||||
| <p> | ||||
|   {% trans 'Scan the QR code below with a token generator of your choice (for instance Google Authenticator).' %} | ||||
| </p> | ||||
|  | ||||
| <div class="bg-light rounded"> | ||||
| <img src="{{ qr_code_url }}" class="mx-auto d-block"/> | ||||
| </div> | ||||
| <br> | ||||
|  | ||||
| <h4> | ||||
|   {% trans 'Step 2' %}: | ||||
| </h4> | ||||
|  | ||||
| <p> | ||||
|   {% trans 'Input a token generated by the app:' %} | ||||
| </p> | ||||
|  | ||||
| <form method="post"> | ||||
|   {% csrf_token %} | ||||
|   {{ form|crispy }} | ||||
|  | ||||
|   <button type="submit" class="btn btn-primary btn-block w-100"> | ||||
|     {% trans 'Verify' %} | ||||
|   </button> | ||||
| </form> | ||||
|  | ||||
| <div> | ||||
| <a href="{% url 'settings' %}" class="btn btn-secondary w-100 btn-sm mt-3">{% trans "back to settings" %}</a> | ||||
| </div> | ||||
| {% endblock %} | ||||
| @@ -175,7 +175,6 @@ function enableBreadcrumbTree(options) { | ||||
|  | ||||
|                 for (var i = 0; i < data.length; i++) { | ||||
|                     node = data[i]; | ||||
|                     node.nodes = []; | ||||
|                     nodes[node.pk] = node; | ||||
|                     node.selectable = false; | ||||
|  | ||||
| @@ -193,10 +192,17 @@ function enableBreadcrumbTree(options) { | ||||
|                     node = data[i]; | ||||
|  | ||||
|                     if (node.parent != null) { | ||||
|                         nodes[node.parent].nodes.push(node); | ||||
|                         if (nodes[node.parent].nodes) { | ||||
|                             nodes[node.parent].nodes.push(node); | ||||
|                         } else { | ||||
|                             nodes[node.parent].nodes = [node]; | ||||
|                         } | ||||
|  | ||||
|                         if (node.state.expanded) { | ||||
|                             nodes[node.parent].state.expanded = true; | ||||
|                             while (node.parent != null) { | ||||
|                                 nodes[node.parent].state.expanded = true; | ||||
|                                 node = nodes[node.parent]; | ||||
|                             } | ||||
|                         } | ||||
|                          | ||||
|                     } else { | ||||
| @@ -212,7 +218,6 @@ function enableBreadcrumbTree(options) { | ||||
|                     collapseIcon: 'fa fa-chevron-down', | ||||
|                 }); | ||||
|  | ||||
|                 setBreadcrumbTreeState(label, state); | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| @@ -220,26 +225,11 @@ function enableBreadcrumbTree(options) { | ||||
|     $('#breadcrumb-tree-toggle').click(function() { | ||||
|         // Add callback to "collapse" and "expand" the sidebar | ||||
|  | ||||
|         // By default, the menu is "expanded" | ||||
|         var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded'; | ||||
|         // Toggle treeview visibilty | ||||
|         $('#breadcrumb-tree-collapse').toggle(); | ||||
|          | ||||
|         // We wish to "toggle" the state! | ||||
|         setBreadcrumbTreeState(label, state == 'expanded' ? 'collapsed' : 'expanded'); | ||||
|     }); | ||||
|  | ||||
|     // Set the initial state (default = expanded) | ||||
|     var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded'; | ||||
|  | ||||
|     function setBreadcrumbTreeState(label, state) { | ||||
|  | ||||
|         if (state == 'collapsed') { | ||||
|             $('#breadcrumb-tree-collapse').hide(100); | ||||
|         } else { | ||||
|             $('#breadcrumb-tree-collapse').show(100); | ||||
|         } | ||||
|  | ||||
|         localStorage.setItem(`inventree-tree-state-${label}`, state); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| /* globals | ||||
|     constructForm, | ||||
|     exportFormatOptions, | ||||
|     imageHoverIcon, | ||||
|     inventreeGet, | ||||
|     inventreePut, | ||||
| @@ -14,6 +15,8 @@ | ||||
| */ | ||||
|  | ||||
| /* exported | ||||
|     downloadBomTemplate, | ||||
|     exportBom, | ||||
|     newPartFromBomWizard, | ||||
|     loadBomTable, | ||||
|     loadUsedInTable, | ||||
| @@ -21,12 +24,121 @@ | ||||
|     removeColFromBomWizard, | ||||
| */ | ||||
|  | ||||
| /* BOM management functions. | ||||
|  * Requires follwing files to be loaded first: | ||||
|  * - api.js | ||||
|  * - part.js | ||||
|  * - modals.js | ||||
| function downloadBomTemplate(options={}) { | ||||
|  | ||||
|     var format = options.format; | ||||
|  | ||||
|     if (!format) { | ||||
|         format = inventreeLoad('bom-export-format', 'csv'); | ||||
|     } | ||||
|  | ||||
|     constructFormBody({}, { | ||||
|         title: '{% trans "Download BOM Template" %}', | ||||
|         fields: { | ||||
|             format: { | ||||
|                 label: '{% trans "Format" %}', | ||||
|                 help_text: '{% trans "Select file format" %}', | ||||
|                 required: true, | ||||
|                 type: 'choice', | ||||
|                 value: format, | ||||
|                 choices: exportFormatOptions(), | ||||
|             } | ||||
|         }, | ||||
|         onSubmit: function(fields, opts) { | ||||
|             var format = getFormFieldValue('format', fields['format'], opts); | ||||
|  | ||||
|             // Save the format for next time | ||||
|             inventreeSave('bom-export-format', format); | ||||
|  | ||||
|             // Hide the modal | ||||
|             $(opts.modal).modal('hide'); | ||||
|  | ||||
|             // Download the file | ||||
|             location.href = `{% url "bom-upload-template" %}?format=${format}`; | ||||
|  | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Export BOM (Bill of Materials) for the specified Part instance | ||||
|  */ | ||||
| function exportBom(part_id, options={}) { | ||||
|  | ||||
|     constructFormBody({}, { | ||||
|         title: '{% trans "Export BOM" %}', | ||||
|         fields: { | ||||
|             format: { | ||||
|                 label: '{% trans "Format" %}', | ||||
|                 help_text: '{% trans "Select file format" %}', | ||||
|                 required: true, | ||||
|                 type: 'choice', | ||||
|                 value: inventreeLoad('bom-export-format', 'csv'), | ||||
|                 choices: exportFormatOptions(), | ||||
|             }, | ||||
|             cascading: { | ||||
|                 label: '{% trans "Cascading" %}', | ||||
|                 help_text: '{% trans "Download cascading / multi-level BOM" %}', | ||||
|                 type: 'boolean', | ||||
|                 value: inventreeLoad('bom-export-cascading', true), | ||||
|             }, | ||||
|             levels: { | ||||
|                 label: '{% trans "Levels" %}', | ||||
|                 help_text: '{% trans "Select maximum number of BOM levels to export (0 = all levels)" %}', | ||||
|                 type: 'integer', | ||||
|                 value: 0, | ||||
|                 min_value: 0, | ||||
|             }, | ||||
|             parameter_data: { | ||||
|                 label: '{% trans "Include Parameter Data" %}', | ||||
|                 help_text: '{% trans "Include part  parameter data in exported BOM" %}', | ||||
|                 type: 'boolean', | ||||
|                 value: inventreeLoad('bom-export-parameter_data', false), | ||||
|             }, | ||||
|             stock_data: { | ||||
|                 label: '{% trans "Include Stock Data" %}', | ||||
|                 help_text: '{% trans "Include part stock data in exported BOM" %}', | ||||
|                 type: 'boolean', | ||||
|                 value: inventreeLoad('bom-export-stock_data', false), | ||||
|             }, | ||||
|             manufacturer_data: { | ||||
|                 label: '{% trans "Include Manufacturer Data" %}', | ||||
|                 help_text: '{% trans "Include part manufacturer data in exported BOM" %}', | ||||
|                 type: 'boolean', | ||||
|                 value: inventreeLoad('bom-export-manufacturer_data', false), | ||||
|             }, | ||||
|             supplier_data: { | ||||
|                 label: '{% trans "Include Supplier Data" %}', | ||||
|                 help_text: '{% trans "Include part supplier data in exported BOM" %}', | ||||
|                 type: 'boolean', | ||||
|                 value: inventreeLoad('bom-export-supplier_data', false), | ||||
|             } | ||||
|         }, | ||||
|         onSubmit: function(fields, opts) { | ||||
|  | ||||
|             // Extract values from the form | ||||
|             var field_names = ['format', 'cascading', 'levels', 'parameter_data', 'stock_data', 'manufacturer_data', 'supplier_data']; | ||||
|  | ||||
|             var url = `/part/${part_id}/bom-download/?`; | ||||
|  | ||||
|             field_names.forEach(function(fn) { | ||||
|                 var val = getFormFieldValue(fn, fields[fn], opts); | ||||
|  | ||||
|                 // Update user preferences | ||||
|                 inventreeSave(`bom-export-${fn}`, val); | ||||
|  | ||||
|                 url += `${fn}=${val}&`; | ||||
|             }); | ||||
|  | ||||
|             $(opts.modal).modal('hide'); | ||||
|  | ||||
|             // Redirect to the BOM file download | ||||
|             location.href = url; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| function bomItemFields() { | ||||
|   | ||||
| @@ -811,7 +811,9 @@ function updateFieldValue(name, value, field, options) { | ||||
|  | ||||
|     switch (field.type) { | ||||
|     case 'boolean': | ||||
|         el.prop('checked', value); | ||||
|         if (value == true || value.toString().toLowerCase() == 'true') { | ||||
|             el.prop('checked'); | ||||
|         } | ||||
|         break; | ||||
|     case 'related field': | ||||
|         // Clear? | ||||
| @@ -2034,8 +2036,15 @@ function constructInputOptions(name, classes, type, parameters) { | ||||
|     } | ||||
|  | ||||
|     if (parameters.value != null) { | ||||
|         // Existing value? | ||||
|         opts.push(`value='${parameters.value}'`); | ||||
|         if (parameters.type == 'boolean') { | ||||
|             // Special consideration of a boolean (checkbox) value | ||||
|             if (parameters.value == true || parameters.value.toString().toLowerCase() == 'true') { | ||||
|                 opts.push('checked'); | ||||
|             } | ||||
|         } else { | ||||
|             // Existing value? | ||||
|             opts.push(`value='${parameters.value}'`); | ||||
|         } | ||||
|     } else if (parameters.default != null) { | ||||
|         // Otherwise, a defualt value? | ||||
|         opts.push(`value='${parameters.default}'`); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user