Merge pull request #203 from pierotofy/defaultuser

Welcome screen to create a default admin
pull/210/head
Piero Toffanin 2017-06-09 14:45:54 -04:00 zatwierdzone przez GitHub
commit fa63913040
7 zmienionych plików z 356 dodań i 8 usunięć

Wyświetl plik

@ -50,7 +50,6 @@ docker-machine ip
Linux / Mac, users can connect to 127.0.0.1.
* Open a Web Browser to `http://<yourDockerMachineIp>:8000`
* Log in with the default credentials: "admin:admin"
To stop WebODM press CTRL+C or run:

Wyświetl plik

@ -50,11 +50,6 @@ def boot():
# Add permission to view processing nodes
default_group.permissions.add(Permission.objects.get(codename="view_processingnode"))
# Check super user
if User.objects.filter(is_superuser=True).count() == 0:
User.objects.create_superuser('admin', 'admin@example.com', 'admin')
logger.info("Created superuser")
# Unlock any Task that might have been locked
Task.objects.filter(processing_lock=True).update(processing_lock=False)

Wyświetl plik

@ -3,6 +3,7 @@
{% block page-wrapper %}
<section class="main">
<div class="content">
{% block registration_header %}{% endblock %}
<div class="col-sm-12 col-md-6 col-md-offset-3 top-buffer">
{% block registration_content %}{% endblock %}
</div>

Wyświetl plik

@ -0,0 +1,241 @@
{% extends 'registration/registration_base.html' %}
{% load i18n %}
{% block registration_header %}
{% if not firstuserform.errors %}
<canvas id="canvas" style="position: absolute; top: 0; left: 0;"></canvas>
<script type="text/javascript">
// Confetti animation
(function () {
// globals
var canvas;
var ctx;
var W;
var H;
var mp = 150; //max particles
var particles = [];
var angle = 0;
var tiltAngle = 0;
var confettiActive = true;
var animationComplete = true;
var deactivationTimerHandler;
var reactivationTimerHandler;
var animationHandler;
// objects
var particleColors = {
colorOptions: ["DodgerBlue", "OliveDrab", "Gold", "pink", "SlateBlue", "lightblue", "Violet", "PaleGreen", "SteelBlue", "SandyBrown", "Chocolate", "Crimson"],
colorIndex: 0,
colorIncrementer: 0,
colorThreshold: 10,
getColor: function () {
if (this.colorIncrementer >= 10) {
this.colorIncrementer = 0;
this.colorIndex++;
if (this.colorIndex >= this.colorOptions.length) {
this.colorIndex = 0;
}
}
this.colorIncrementer++;
return this.colorOptions[this.colorIndex];
}
}
function confettiParticle(color) {
this.x = Math.random() * W; // x-coordinate
this.y = (Math.random() * H) - H; //y-coordinate
this.r = RandomFromTo(10, 30); //radius;
this.d = (Math.random() * mp) + 10; //density;
this.color = color;
this.tilt = Math.floor(Math.random() * 10) - 10;
this.tiltAngleIncremental = (Math.random() * 0.07) + .05;
this.tiltAngle = 0;
this.draw = function () {
ctx.beginPath();
ctx.lineWidth = this.r / 2;
ctx.strokeStyle = this.color;
ctx.moveTo(this.x + this.tilt + (this.r / 4), this.y);
ctx.lineTo(this.x + this.tilt, this.y + this.tilt + (this.r / 4));
return ctx.stroke();
}
}
$(document).ready(function () {
SetGlobals();
InitializeButton();
InitializeConfetti();
$(window).resize(function () {
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W;
canvas.height = H;
});
});
function InitializeButton() {
$("input").click(DeactivateConfetti);
}
function SetGlobals() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W;
canvas.height = H;
}
function InitializeConfetti() {
particles = [];
animationComplete = false;
for (var i = 0; i < mp; i++) {
var particleColor = particleColors.getColor();
particles.push(new confettiParticle(particleColor));
}
StartConfetti();
}
function Draw() {
ctx.clearRect(0, 0, W, H);
var results = [];
for (var i = 0; i < mp; i++) {
(function (j) {
results.push(particles[j].draw());
})(i);
}
Update();
return results;
}
function RandomFromTo(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
function Update() {
var remainingFlakes = 0;
var particle;
angle += 0.01;
tiltAngle += 0.1;
for (var i = 0; i < mp; i++) {
particle = particles[i];
if (animationComplete) return;
if (!confettiActive && particle.y < -15) {
particle.y = H + 100;
continue;
}
stepParticle(particle, i);
if (particle.y <= H) {
remainingFlakes++;
}
CheckForReposition(particle, i);
}
if (remainingFlakes === 0) {
StopConfetti();
}
}
function CheckForReposition(particle, index) {
if ((particle.x > W + 20 || particle.x < -20 || particle.y > H) && confettiActive) {
if (index % 5 > 0 || index % 2 == 0) //66.67% of the flakes
{
repositionParticle(particle, Math.random() * W, -10, Math.floor(Math.random() * 10) - 20);
} else {
if (Math.sin(angle) > 0) {
//Enter from the left
repositionParticle(particle, -20, Math.random() * H, Math.floor(Math.random() * 10) - 20);
} else {
//Enter from the right
repositionParticle(particle, W + 20, Math.random() * H, Math.floor(Math.random() * 10) - 20);
}
}
}
}
function stepParticle(particle, particleIndex) {
particle.tiltAngle += particle.tiltAngleIncremental;
particle.y += (Math.cos(angle + particle.d) + 3 + particle.r / 2) / 2;
particle.x += Math.sin(angle);
particle.tilt = (Math.sin(particle.tiltAngle - (particleIndex / 3))) * 15;
}
function repositionParticle(particle, xCoordinate, yCoordinate, tilt) {
particle.x = xCoordinate;
particle.y = yCoordinate;
particle.tilt = tilt;
}
function StartConfetti() {
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W;
canvas.height = H;
(function animloop() {
if (animationComplete) return null;
animationHandler = requestAnimFrame(animloop);
return Draw();
})();
}
function ClearTimers() {
clearTimeout(reactivationTimerHandler);
clearTimeout(animationHandler);
}
function DeactivateConfetti() {
confettiActive = false;
ClearTimers();
}
function StopConfetti() {
animationComplete = true;
if (ctx == undefined) return;
ctx.clearRect(0, 0, W, H);
}
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
return window.setTimeout(callback, 1000 / 60);
};
})();
})();
</script>
{% endif %}
{% endblock %}
{% block registration_content %}
{% if firstuserform.errors %}
<div class="alert alert-warning">
<p>{% trans "Uh oh! Could you please check the errors below?" %}</p>
</div>
{% else %}
<h3>{% trans 'Welcome! ☺' %}</h3>
<div style="margin-bottom: 28px;">Before we get started, we need to create an administrator account for you:</div>
{% endif %}
<form action="" method="post" class="form-horizontal" role="form">{% csrf_token %}
{% for field in firstuserform %}
{% include 'registration/form_field.html' %}
{% endfor %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">{% trans 'Create Account' %}</button>
</div>
</div>
</form>
{% endblock %}

Wyświetl plik

@ -0,0 +1,72 @@
from django.contrib.auth.models import User, Group
from django.test import Client
from rest_framework import status
from app.models import Project, Task
from .classes import BootTestCase
from app import scheduler
from django.core.exceptions import ValidationError
class TestWelcome(BootTestCase):
def setUp(self):
Project.objects.all().delete()
# Start with no users
User.objects.all().delete()
def tearDown(self):
pass
def test_first_screen(self):
c = Client()
# User points the browser to the website
res = c.get('/', follow=True)
# User is redirected to the welcome page
self.assertRedirects(res, '/welcome/')
# The welcome page is being rendered by the correct template
self.assertTemplateUsed(res, 'app/welcome.html')
# User cannot create an admin user without password
res = c.post('/welcome/', data={
'username': 'testadminuser',
'password': ''}, follow=True)
self.assertFormError(res, 'firstuserform', 'password', 'This field is required.')
self.assertTrue(User.objects.count() == 0, 'No users were created')
# User can create admin user
res = c.post('/welcome/', data={
'username': 'testadminuser',
'password': 'testadminpass'}, follow=True)
self.assertTrue(User.objects.count() == 1, 'A user was created')
# User was created
user = User.objects.get(username='testadminuser')
self.assertTrue(user.is_superuser, 'The user is a superuser')
self.assertTrue(user.is_staff, 'The user is a staff member')
# Redirect to the dashboard happens
self.assertRedirects(res, '/dashboard/')
# User is automatically logged-in
self.assertTrue(res.context['user'].is_authenticated)
# After a super admin is created, the welcome page is no longer accessible
res = c.get('/welcome/', follow=True)
self.assertRedirects(res, '/dashboard/')
# We cannot create another superuser
res = c.post('/welcome/', data={
'username': 'testadminuser2',
'password': 'testadminpass2'}, follow=True)
self.assertRedirects(res, '/dashboard/')
self.assertTrue(User.objects.filter(username='testadminuser2').count() == 0, 'No users were created')
# If we log-out and try to access the welcome page, we should get the login page
c.logout()
res = c.get('/welcome/', follow=True)
self.assertRedirects(res, '/login/')

Wyświetl plik

@ -6,6 +6,7 @@ from webodm import settings
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^welcome/$', views.welcome, name='welcome'),
url(r'^dashboard/$', views.dashboard, name='dashboard'),
url(r'^map/project/(?P<project_pk>[^/.]+)/task/(?P<task_pk>[^/.]+)/$', views.map, name='map'),
url(r'^map/project/(?P<project_pk>[^/.]+)/$', views.map, name='map'),

Wyświetl plik

@ -1,8 +1,9 @@
import json
from django.contrib.auth import login
from django.contrib.auth.models import User
from django.http import Http404
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from guardian.shortcuts import get_objects_for_user
from nodeodm.models import ProcessingNode
@ -10,9 +11,15 @@ from .models import Project, Task
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
from django import forms
def index(request):
return redirect('dashboard' if request.user.is_authenticated()
# Check first access where the user is expected to
# create an admin account
if User.objects.filter(is_superuser=True).count() == 0:
return redirect('welcome')
return redirect('dashboard' if request.user.is_authenticated()
else 'login')
@login_required
@ -100,6 +107,38 @@ def processing_node(request, processing_node_id):
**get_view_params(request),
})
class FirstUserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'password', )
widgets = {
'password': forms.PasswordInput(),
}
def welcome(request):
if User.objects.filter(is_superuser=True).count() > 0:
return redirect('index')
fuf = FirstUserForm()
if request.method == 'POST':
fuf = FirstUserForm(request.POST)
if fuf.is_valid():
admin_user = fuf.save(commit=False)
admin_user.is_superuser = admin_user.is_staff = True
admin_user.save()
# Log-in automatically
login(request, admin_user, 'django.contrib.auth.backends.ModelBackend')
return redirect('dashboard')
return render(request, 'app/welcome.html',
{
'title': 'Welcome',
'firstuserform': fuf
})
def get_view_params(request):
"""