mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
Breakout (most) user stuff to separate module
The model remains in RIGS for now, as it's pretty painful to move...
This commit is contained in:
57
users/forms.py
Normal file
57
users/forms.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import simplejson
|
||||
from captcha.fields import ReCaptchaField
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm,
|
||||
UserChangeForm, UserCreationForm)
|
||||
from django.core import serializers
|
||||
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
||||
from django.utils import formats
|
||||
from registration.forms import RegistrationFormUniqueEmail
|
||||
from RIGS import models
|
||||
|
||||
|
||||
# Registration
|
||||
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||
captcha = ReCaptchaField()
|
||||
|
||||
class Meta:
|
||||
model = models.Profile
|
||||
fields = ('username', 'email', 'first_name', 'last_name', 'initials')
|
||||
|
||||
def clean_initials(self):
|
||||
"""
|
||||
Validate that the supplied initials are unique.
|
||||
"""
|
||||
if models.Profile.objects.filter(initials__iexact=self.cleaned_data['initials']):
|
||||
raise forms.ValidationError("These initials are already in use. Please supply different initials.")
|
||||
return self.cleaned_data['initials']
|
||||
|
||||
|
||||
class CheckApprovedForm(AuthenticationForm):
|
||||
def confirm_login_allowed(self, user):
|
||||
if user.is_approved or user.is_superuser:
|
||||
return AuthenticationForm.confirm_login_allowed(self, user)
|
||||
else:
|
||||
raise forms.ValidationError("Your account hasn't been approved by an administrator yet. Please check back in a few minutes!")
|
||||
|
||||
|
||||
# Embedded Login form - remove the autofocus
|
||||
class EmbeddedAuthenticationForm(CheckApprovedForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['username'].widget.attrs.pop('autofocus', None)
|
||||
|
||||
|
||||
class PasswordReset(PasswordResetForm):
|
||||
captcha = ReCaptchaField(label='Captcha')
|
||||
|
||||
|
||||
class ProfileCreationForm(UserCreationForm):
|
||||
class Meta(UserCreationForm.Meta):
|
||||
model = models.Profile
|
||||
|
||||
|
||||
class ProfileChangeForm(UserChangeForm):
|
||||
class Meta(UserChangeForm.Meta):
|
||||
model = models.Profile
|
||||
15
users/regbackend.py
Normal file
15
users/regbackend.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from RIGS.models import Profile
|
||||
from users.forms import ProfileRegistrationFormUniqueEmail
|
||||
from registration.signals import user_registered
|
||||
|
||||
|
||||
def user_created(sender, user, request, **kwargs):
|
||||
form = ProfileRegistrationFormUniqueEmail(request.POST)
|
||||
user.first_name = form.data['first_name']
|
||||
user.last_name = form.data['last_name']
|
||||
user.initials = form.data['initials']
|
||||
# user.phone = form.data['phone']
|
||||
user.save()
|
||||
|
||||
|
||||
user_registered.connect(user_created)
|
||||
12
users/templates/profile_button.html
Normal file
12
users/templates/profile_button.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{# pass in variable "profile" to this template #}
|
||||
|
||||
<button title="{{profile.name}}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover focus' data-toggle="popover" data-content='
|
||||
<img src="{{profile.profile_picture}}" class="img-responsive img-rounded center-block" style="max-width:4em" />
|
||||
<dl class="dl-vertical">
|
||||
<dt>Email</dt>
|
||||
<dd>{{profile.email}}</dd>
|
||||
|
||||
<dt>Phone</dt>
|
||||
<dd>{{profile.phone}}</dd>
|
||||
</dl>
|
||||
'>{{profile.first_name}}</button>
|
||||
150
users/templates/profile_detail.html
Normal file
150
users/templates/profile_detail.html
Normal file
@@ -0,0 +1,150 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
|
||||
{% block title %}RIGS Profile {{object.pk}}{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#urlParamForm').change(function(){
|
||||
url = "?";
|
||||
$('#urlParamForm *').filter(':input').each(function(index, value){
|
||||
defaultVal = $(value).data('default');
|
||||
param = $(value).val();
|
||||
val = $(value).prop('checked');
|
||||
|
||||
if(val != defaultVal){
|
||||
url = url+param+"="+val+"&";
|
||||
}
|
||||
});
|
||||
ics_url = $('#cal-url').data('url') + url.substring(0, url.length - 1);
|
||||
$('#cal-url').text(ics_url);
|
||||
|
||||
gcal_url = $('#gcal-link').data('url') + encodeURIComponent(url.substring(0, url.length - 1));
|
||||
$('#gcal-link').attr('href',gcal_url);
|
||||
});
|
||||
|
||||
$('#urlParamForm').change(); //Do the initial setting
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Profile: {{object.name}}</h3>
|
||||
{% if not request.is_ajax %}
|
||||
<div class="row py-3">
|
||||
{% if object.pk == user.pk %}
|
||||
<div>
|
||||
<div class="btn-group">
|
||||
<a href="{% url 'profile_update_self' %}" class="btn btn-light">
|
||||
Edit Profile <i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a href="{% url 'password_change' %}" class="btn btn-light">
|
||||
Change Password <span class="fas fa-lock"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="row no-gutters">
|
||||
<div class="col-md-3">
|
||||
<img src="{{object.profile_picture}}" class="card-img img-fluid" />
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-5">First Name</dt>
|
||||
<dd class="col-7">{{object.first_name}}</dd>
|
||||
|
||||
<dt class="col-5">Last Name</dt>
|
||||
<dd class="col-7">{{object.last_name}}</dd>
|
||||
|
||||
<dt class="col-5">Email</dt>
|
||||
<dd class="col-7">{{object.email}}</dd>
|
||||
|
||||
<dt class="col-5">Last Login</dt>
|
||||
<dd class="col-7">{{object.last_login|date:"d/m/Y H:i"}}</dd>
|
||||
|
||||
<dt class="col-5">Date Joined</dt>
|
||||
<dd class="col-7">{{object.date_joined|date:"d/m/Y H:i"}}</dd>
|
||||
|
||||
<dt class="col-5">Initials</dt>
|
||||
<dd class="col-7">{{object.initials}}</dd>
|
||||
|
||||
<dt class="col-5">Phone</dt>
|
||||
<dd class="col-7">{% if object.phone %}}<a href="tel:{{ object.phone }}">{% endif %}{{object.phone}}{% if object.phone %}}</a>{% endif %}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if not request.is_ajax and object.pk == user.pk %}
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4>Personal iCal Details</h4>
|
||||
<dl class="row">
|
||||
<dt class="col-4">API Key</dt>
|
||||
<dd class="col-5">
|
||||
{% if user.api_key %}
|
||||
{{user.api_key}}
|
||||
{% else %}
|
||||
No API Key Generated
|
||||
{% endif %}
|
||||
</dd>
|
||||
<a href="{% url 'reset_api_key' %}" class="btn btn-secondary col-3">
|
||||
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
|
||||
<span class="fas fa-redo"></span>
|
||||
</a>
|
||||
|
||||
<dt class="col-4">Calendar Options</dt>
|
||||
<dd class="col-8">
|
||||
<form class="form-inline" id="urlParamForm">
|
||||
<div class="form-group">
|
||||
<label class="checkbox-inline mr-3">
|
||||
<input type="checkbox" value="rig" data-default="true" checked> Rigs
|
||||
</label>
|
||||
<label class="checkbox-inline mx-3">
|
||||
<input type="checkbox" value="non-rig" data-default="true" checked> Non-Rigs
|
||||
</label>
|
||||
<label class="checkbox-inline mx-3">
|
||||
<input type="checkbox" value="dry-hire" data-default="true" checked> Dry-Hires
|
||||
</label>
|
||||
<label class="checkbox-inline mx-3">
|
||||
<input type="checkbox" value="cancelled" data-default="false" > Cancelled
|
||||
</label>
|
||||
<label class="checkbox-inline mx-3">
|
||||
<input type="checkbox" value="provisional" data-default="true" checked> Provisional
|
||||
</label>
|
||||
<label class="checkbox-inline mx-3">
|
||||
<input type="checkbox" value="confirmed" data-default="true" checked> Confirmed/Booked
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</dd>
|
||||
<dt class="col-4">Calendar URL</dt>
|
||||
<dd class="col-8">
|
||||
{% if user.api_key %}
|
||||
<pre id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></pre>
|
||||
<small><a id="gcal-link" data-url="https://support.google.com/calendar/answer/37100" href="">Click here</a> for instructions on adding to google calendar.<br/>
|
||||
To sync from google calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
|
||||
{% else %}
|
||||
<pre>No API Key Generated</pre>
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h4>Events</h4>
|
||||
{% with object.latest_events as events %}
|
||||
{% include 'event_table.html' %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
71
users/templates/profile_form.html
Normal file
71
users/templates/profile_form.html
Normal file
@@ -0,0 +1,71 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Update Profile {{object.name}}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-10 col-sm-offset-1">
|
||||
{% include 'form_errors.html' %}
|
||||
<h3>Update Profile</h3>
|
||||
<div class="col-sm-6">
|
||||
<form action="{{form.action|default:request.path}}" method="post" class="form-horizontal">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="{{form.first_name.id_for_label}}" class="col-sm-4 control-label">{{form.first_name.label}}</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.first_name class+="form-control" placeholder=form.first_name.label %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{form.last_name.id_for_label}}" class="col-sm-4 control-label">{{form.last_name.label}}</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.last_name class+="form-control" placeholder=form.last_name.label %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{form.email.id_for_label}}" class="col-sm-4 control-label">{{form.email.label}}</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.email type="email" class+="form-control" placeholder=form.email.label %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{form.initials.id_for_label}}" class="col-sm-4 control-label">{{form.initials.label}}</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.initials class+="form-control" placeholder=form.initials.label %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{form.phone.id_for_label}}" class="col-sm-4 control-label">{{form.phone.label}}</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.phone type="tel" class+="form-control" placeholder=form.phone.label %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input class="btn btn-primary pull-right" type="submit"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 col-sm-offset-2">
|
||||
<div class="center-block">
|
||||
<a href="https://gravatar.com/">
|
||||
<img src="{{object.profile_picture}}" class="img-responsive img-rounded" />
|
||||
<div class="text-center">
|
||||
Images hosted by Gravatar
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
10
users/templates/registration/activation_complete.html
Normal file
10
users/templates/registration/activation_complete.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
|
||||
{% block title %}Activation Complete{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert alert-success">
|
||||
<h2>Activation Complete</h2>
|
||||
<p>Your user account is now awaiting administrator approval. Won't be long!</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
7
users/templates/registration/activation_email.txt
Normal file
7
users/templates/registration/activation_email.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
Welcome {{ user }},
|
||||
|
||||
Thank you for registering on {{ site }}
|
||||
|
||||
To continue the registration process please visit http://{{ site.domain }}{% url 'registration_activate' activation_key=activation_key %}.
|
||||
This link will be active for the next {{ expiration_days }} days.
|
||||
@@ -0,0 +1 @@
|
||||
{{ user|safe }} activation required
|
||||
10
users/templates/registration/logged_out.html
Normal file
10
users/templates/registration/logged_out.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
|
||||
{% block title %}Logout Successful{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert alert-success">
|
||||
<h2>Logout Successful</h2>
|
||||
<p>You have successfully been logged out of RIGS</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
10
users/templates/registration/login.html
Normal file
10
users/templates/registration/login.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="text-center">
|
||||
<h1>R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></h1>
|
||||
</div>
|
||||
{% include 'registration/loginform.html' %}
|
||||
{% endblock %}
|
||||
34
users/templates/registration/login_embed.html
Normal file
34
users/templates/registration/login_embed.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends 'base_embed.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="text-center">
|
||||
<h1>R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></h1>
|
||||
</div>
|
||||
|
||||
|
||||
{% include 'form_errors.html' %}
|
||||
|
||||
|
||||
<div class="col-sm-6 col-sm-offset-3 col-lg-4 col-lg-offset-4">
|
||||
|
||||
<form id="loginForm" action="" method="post" role="form" target="_self">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="id_username">{{ form.username.label }}</label>
|
||||
{% render_field form.username class+="form-control" placeholder=form.username.label %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.password.id_for_label }}">{{ form.password.label }}</label>
|
||||
{% render_field form.password class+="form-control" placeholder=form.password.label %}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<input type="submit" value="Login" class="btn btn-primary"/>
|
||||
</div>
|
||||
<input type="hidden" name="next" value="{{ next }}"/>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
20
users/templates/registration/loginform.html
Normal file
20
users/templates/registration/loginform.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% load widget_tweaks %}
|
||||
{% include 'form_errors.html' %}
|
||||
<div class="col-sm-6 offset-sm-3 col-lg-4 offset-lg-4">
|
||||
<form action="{% url 'login' %}" method="post" role="form" target="_self">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="id_username">{{ form.username.label }}</label>
|
||||
{% render_field form.username class+="form-control" placeholder=form.username.label autofocus="" %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.password.id_for_label }}">{{ form.password.label }}</label>
|
||||
{% render_field form.password class+="form-control" placeholder=form.password.label %}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<a href="{% url 'registration_register' %}" class="btn">Register</a>
|
||||
<a href="{% url 'password_reset' %}" class="btn">Forgotten Password</a>
|
||||
<input type="submit" id="id_submit" value="Login" class="btn btn-primary"/>
|
||||
<input type="hidden" name="next" value="{{ next }}"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
20
users/templates/registration/password_change_done.html
Normal file
20
users/templates/registration/password_change_done.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends "base_rigs.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||
› {% trans 'Password reset' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% trans 'Password change successful' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-12">
|
||||
<h1>{% trans 'Password change successful' %}</h1>
|
||||
|
||||
<p>{% trans "Your password has been changed" %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
33
users/templates/registration/password_change_form.html
Normal file
33
users/templates/registration/password_change_form.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{% extends "base_rigs.html" %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
|
||||
{% block title %}Change Password{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="col-sm-10 col-sm-offset-1">
|
||||
<h3>Change Password</h3>
|
||||
{% if form.errors or supplement_form.errors %}
|
||||
<div class="alert alert-danger">
|
||||
Please correct the error(s) below.
|
||||
{{form.errors}}
|
||||
{{supplement_form.errors}}
|
||||
</div>
|
||||
{% endif %}
|
||||
<p>Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly.</p>
|
||||
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<form action="" method="post" class="form-horizontal" role="form">{% csrf_token %}
|
||||
{% for field in form %}
|
||||
<div class="form-group">
|
||||
<label for="{{ field.id_for_label }}" class="control-label col-sm-4">{{ field.label }}</label>
|
||||
<div class="controls col-sm-8">
|
||||
{% render_field field class+="form-control" placeholder=field.label %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p><input type="submit" value="Change Password" class="btn btn-primary pull-right"></p>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
23
users/templates/registration/password_reset_complete.html
Normal file
23
users/templates/registration/password_reset_complete.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "base_rigs.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||
› {% trans 'Password reset' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% trans 'Password reset complete' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-12">
|
||||
<h1>{% trans 'Password reset complete' %}</h1>
|
||||
|
||||
<p>{% trans "Your password has been set. You may go ahead and log in now." %}</p>
|
||||
|
||||
<p><a href="{{ login_url }}">{% trans 'Log in' %}</a></p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
61
users/templates/registration/password_reset_confirm.html
Normal file
61
users/templates/registration/password_reset_confirm.html
Normal file
@@ -0,0 +1,61 @@
|
||||
{% extends "base_rigs.html" %}
|
||||
{% load i18n %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||
› {% trans 'Password reset confirmation' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% trans 'Password reset' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if validlink %}
|
||||
<div class="col-sm-12">
|
||||
|
||||
<h1>{% trans 'Enter new password' %}</h1>
|
||||
|
||||
<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
|
||||
|
||||
<div class="col-sm-8 col-sm-offset-2 well">
|
||||
<form action="" method="post" role="form" class="form-horizontal">{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
{% include 'form_errors.html' %}
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="{{form.new_password1.id_for_label}}" class="col-sm-4 control-label">{{form.new_password1.label}}</label>
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.new_password1 class+="form-control" %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{form.new_password2.id_for_label}}" class="col-sm-4 control-label">{{form.new_password2.label}}</label>
|
||||
<div class="col-sm-8">
|
||||
{% render_field form.new_password2 class+="form-control" %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="pull-right">
|
||||
<div class="form-group">
|
||||
<input type="submit" value="{% trans 'Change my password' %}" class="btn btn-primary" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
<h1>{% trans 'Password reset unsuccessful' %}</h1>
|
||||
|
||||
<p>{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
20
users/templates/registration/password_reset_done.html
Normal file
20
users/templates/registration/password_reset_done.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends "base_rigs.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||
› {% trans 'Password reset' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% trans 'Password reset successful' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-12">
|
||||
<h1>{% trans 'Password reset successful' %}</h1>
|
||||
|
||||
<p>{% trans "We've e-mailed you instructions for setting your password to the e-mail address you submitted. You should be receiving it shortly." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
14
users/templates/registration/password_reset_email.html
Normal file
14
users/templates/registration/password_reset_email.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{% load i18n %}{% autoescape off %}
|
||||
{% blocktrans %}You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
|
||||
|
||||
{% trans "Please go to the following page and choose a new password:" %}
|
||||
{% block reset_link %}
|
||||
{{ protocol }}://{{ domain }}{% url 'auth_password_reset_confirm' uidb64=uid token=token %}
|
||||
{% endblock %}
|
||||
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
|
||||
|
||||
{% trans "Thanks for using our site!" %}
|
||||
|
||||
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
|
||||
|
||||
{% endautoescape %}
|
||||
35
users/templates/registration/password_reset_form.html
Normal file
35
users/templates/registration/password_reset_form.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% load i18n %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Password reset{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-12">
|
||||
<h1>Password Reset</h1>
|
||||
|
||||
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>
|
||||
|
||||
<div class="col-sm-8 col-sm-offset-2 well">
|
||||
<form action="" method="POST" role="form" class="form-horizontal">{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
{% include 'form_errors.html' %}
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="{{form.email.id_for_label}}" class="col-sm-2 control-label">{{form.email.label}}</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.email type="email" class+="form-control" %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-10 col-md-8 col-md-offset-2">
|
||||
{{ form.captcha }}
|
||||
</div>
|
||||
<div class="col-sm-2 text-right">
|
||||
<input type="submit" value="Submit" class="btn btn-primary" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
10
users/templates/registration/registration_complete.html
Normal file
10
users/templates/registration/registration_complete.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
|
||||
{% block title %}Registration complete{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert alert-success">
|
||||
<h2>Thanks for registering</h2>
|
||||
<p>Thanks for registering with RIGS, further details will be emailed to you.</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
29
users/templates/registration/registration_form.html
Normal file
29
users/templates/registration/registration_form.html
Normal file
@@ -0,0 +1,29 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% load widget_tweaks %}
|
||||
{% block title %}Registration{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-10 col-sm-offset-1">
|
||||
<h3>New User Registration</h3>
|
||||
{% if form.errors or supplement_form.errors %}
|
||||
<div class="alert alert-danger">
|
||||
{{form.errors}}
|
||||
{{supplement_form.errors}}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<form action="" method="post" class="form-horizontal" role="form">{% csrf_token %}
|
||||
{% for field in form %}
|
||||
<div class="form-group">
|
||||
<label for="{{ field.id_for_label }}" class="control-label col-sm-4">{{ field.label }}</label>
|
||||
<div class="controls col-sm-8">
|
||||
{% render_field field class+="form-control" placeholder=field.label %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p><input type="submit" value="Register" class="btn btn-primary pull-right"></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
29
users/urls.py
Normal file
29
users/urls.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from django.urls import path
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.conf import settings
|
||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.contrib.auth.views import LoginView
|
||||
from registration.backends.default.views import RegistrationView
|
||||
from PyRIGS.decorators import permission_required_with_403
|
||||
from users import regbackend, forms, views
|
||||
|
||||
urlpatterns = [
|
||||
path('user/', include('django.contrib.auth.urls')),
|
||||
path('user/', include('registration.backends.default.urls')),
|
||||
path('user/register/', RegistrationView.as_view(form_class=forms.ProfileRegistrationFormUniqueEmail),
|
||||
name="registration_register"),
|
||||
path('user/login/', LoginView.as_view(authentication_form=forms.CheckApprovedForm), name='login'),
|
||||
path('user/login/embed/', xframe_options_exempt(views.LoginEmbed.as_view()), name='login_embed'),
|
||||
# User editing
|
||||
path('user/edit/', login_required(views.ProfileUpdateSelf.as_view()),
|
||||
name='profile_update_self'),
|
||||
path('user/reset_api_key', login_required(views.ResetApiKey.as_view(permanent=False)),
|
||||
name='reset_api_key'),
|
||||
path('user/', login_required(views.ProfileDetail.as_view()), name='profile_detail'),
|
||||
path('user/<pk>/',
|
||||
permission_required_with_403('RIGS.view_profile')(views.ProfileDetail.as_view()),
|
||||
name='profile_detail'),
|
||||
]
|
||||
79
users/views.py
Normal file
79
users/views.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.http import HttpResponse
|
||||
from django.urls import reverse_lazy, reverse, NoReverseMatch
|
||||
from django.views import generic
|
||||
from django.contrib.auth.views import LoginView
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.core import serializers
|
||||
from django.conf import settings
|
||||
import simplejson
|
||||
from django.contrib import messages
|
||||
import datetime
|
||||
import pytz
|
||||
import operator
|
||||
from registration.views import RegistrationView
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
|
||||
from RIGS import models, forms
|
||||
from assets import models as asset_models
|
||||
from functools import reduce
|
||||
|
||||
# This view should be exempt from requiring CSRF token.
|
||||
# Then we can check for it and show a nice error
|
||||
# Don't worry, django.contrib.auth.views.login will
|
||||
# check for it before logging the user in
|
||||
class LoginEmbed(LoginView):
|
||||
template_name = 'registration/login_embed.html'
|
||||
|
||||
@csrf_exempt
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.method == "POST":
|
||||
csrf_cookie = request.COOKIES.get('csrftoken', None)
|
||||
|
||||
if csrf_cookie is None:
|
||||
messages.warning(request, 'Cookies do not seem to be enabled. Try logging in using a new tab.')
|
||||
request.method = 'GET' # Render the page without trying to login
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ProfileDetail(generic.DetailView):
|
||||
template_name = "profile_detail.html"
|
||||
model = models.Profile
|
||||
|
||||
def get_queryset(self):
|
||||
try:
|
||||
pk = self.kwargs['pk']
|
||||
except KeyError:
|
||||
pk = self.request.user.id
|
||||
self.kwargs['pk'] = pk
|
||||
|
||||
return self.model.objects.filter(pk=pk)
|
||||
|
||||
|
||||
class ProfileUpdateSelf(generic.UpdateView):
|
||||
template_name = "profile_form.html"
|
||||
model = models.Profile
|
||||
fields = ['first_name', 'last_name', 'email', 'initials', 'phone']
|
||||
|
||||
def get_queryset(self):
|
||||
pk = self.request.user.id
|
||||
self.kwargs['pk'] = pk
|
||||
|
||||
return self.model.objects.filter(pk=pk)
|
||||
|
||||
def get_success_url(self):
|
||||
url = reverse_lazy('profile_detail')
|
||||
return url
|
||||
|
||||
|
||||
class ResetApiKey(generic.RedirectView):
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
self.request.user.api_key = self.request.user.make_api_key()
|
||||
|
||||
self.request.user.save()
|
||||
|
||||
return reverse_lazy('profile_detail')
|
||||
Reference in New Issue
Block a user