diff --git a/MANIFEST.in b/MANIFEST.in index f507731..07426af 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,6 +3,7 @@ include setup.py recursive-include adjutant_ui/content/default/templates * recursive-include adjutant_ui/content/forgotpassword/templates * recursive-include adjutant_ui/content/project_users/templates * +recursive-include adjutant_ui/content/signup/templates * recursive-include adjutant_ui/content/tasks/templates * recursive-include adjutant_ui/content/token/templates * recursive-include adjutant_ui/static * diff --git a/adjutant_ui/api/adjutant.py b/adjutant_ui/api/adjutant.py index 26d8d4d..ee9f853 100644 --- a/adjutant_ui/api/adjutant.py +++ b/adjutant_ui/api/adjutant.py @@ -258,6 +258,17 @@ def forgotpassword_submit(request, data): raise +def signup_submit(request, data): + headers = {"Content-Type": "application/json"} + try: + return post(request, 'openstack/sign-up', + data=json.dumps(data), + headers=headers) + except Exception as e: + LOG.error(e) + raise + + def task_list(request, filters={}, page=1): tasks_per_page = utils.get_page_size(request) tasklist = [] diff --git a/adjutant_ui/content/forgot_password/forms.py b/adjutant_ui/content/forgot_password/forms.py index f75a4d6..3f5862d 100644 --- a/adjutant_ui/content/forgot_password/forms.py +++ b/adjutant_ui/content/forgot_password/forms.py @@ -27,17 +27,18 @@ USERNAME_IS_EMAIL = True class ForgotPasswordForm(hforms.SelfHandlingForm): - username = forms.CharField(max_length=255, label=_("User Name")) - email = forms.EmailField( - label=_("Email"), - widget=forms.TextInput(attrs={"autofocus": "autofocus"}) - ) + username = forms.CharField( + max_length=255, label=_("User Name"), + widget=forms.TextInput(attrs={"autofocus": "autofocus"})) + email = forms.EmailField(label=_("Email")) def __init__(self, *args, **kwargs): super(ForgotPasswordForm, self).__init__(*args, **kwargs) if (hasattr(settings, 'USERNAME_IS_EMAIL') and getattr(settings, 'USERNAME_IS_EMAIL')): self.fields.pop('username') + self.fields['email'].widget = forms.TextInput( + attrs={"autofocus": "autofocus"}) def clean(self, *args, **kwargs): # validate username and email? diff --git a/adjutant_ui/content/forgot_password/templates/forgot_password/_forgot_password_form.html b/adjutant_ui/content/forgot_password/templates/forgot_password/_forgot_password_form.html index b1af447..4d6b234 100644 --- a/adjutant_ui/content/forgot_password/templates/forgot_password/_forgot_password_form.html +++ b/adjutant_ui/content/forgot_password/templates/forgot_password/_forgot_password_form.html @@ -42,6 +42,9 @@ {% trans "Submit" %} {% trans "Submit" %} + + {% trans "Back to login" %} +
{% endblock %} diff --git a/adjutant_ui/content/project_users/views.py b/adjutant_ui/content/project_users/views.py index c4505d9..58469d3 100644 --- a/adjutant_ui/content/project_users/views.py +++ b/adjutant_ui/content/project_users/views.py @@ -55,7 +55,7 @@ class UpdateUserView(forms.ModalFormView): def get_object(self): try: return adjutant.user_get(self.request, - self.kwargs['user_id']) + self.kwargs['user_id']) except Exception: msg = _('Unable to retrieve user.') url = reverse('horizon:management:project_users:index') diff --git a/adjutant_ui/content/signup/__init__.py b/adjutant_ui/content/signup/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/adjutant_ui/content/signup/forms.py b/adjutant_ui/content/signup/forms.py new file mode 100644 index 0000000..4cdac88 --- /dev/null +++ b/adjutant_ui/content/signup/forms.py @@ -0,0 +1,58 @@ +# Copyright (c) 2016 Catalyst IT Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.conf import settings +from django import forms +from django import http +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms as hforms +from horizon.utils import functions as utils + +from adjutant_ui.api import adjutant + + +class SignupForm(hforms.SelfHandlingForm): + username = forms.CharField( + max_length=255, label=_("User Name"), + widget=forms.TextInput(attrs={"autofocus": "autofocus"})) + email = forms.EmailField(label=_("Email")) + project_name = forms.CharField(label=_("Project Name"), max_length=64) + setup_network = forms.BooleanField( + label=_("Create Default Network"), + help_text=_("Create a basic network during account creation so that " + "you can deploy VMs immediately."), + required=False, + initial=True) + + def __init__(self, *args, **kwargs): + super(SignupForm, self).__init__(*args, **kwargs) + if (hasattr(settings, 'USERNAME_IS_EMAIL') and + getattr(settings, 'USERNAME_IS_EMAIL')): + self.fields.pop('username') + self.fields['email'].widget = forms.TextInput( + attrs={"autofocus": "autofocus"}) + + def handle(self, request, data): + submit_response = adjutant.signup_submit( + request, data) + if submit_response.ok: + return True + + # Send the user back to the login page. + msg = _("The signup service is currently unavailable. " + "Please try again later.") + response = http.HttpResponseRedirect(settings.LOGOUT_URL) + utils.add_logout_reason(self.request, response, msg) + return response diff --git a/adjutant_ui/content/signup/panel.py b/adjutant_ui/content/signup/panel.py new file mode 100644 index 0000000..a954594 --- /dev/null +++ b/adjutant_ui/content/signup/panel.py @@ -0,0 +1,23 @@ +# Copyright (c) 2016 Catalyst IT Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.utils.translation import ugettext_lazy as _ + +import horizon + + +class SignupPanel(horizon.Panel): + name = _('Sign Up') + slug = 'signup' + nav = False diff --git a/adjutant_ui/content/signup/templates/auth/_login_page.html b/adjutant_ui/content/signup/templates/auth/_login_page.html new file mode 100644 index 0000000..3cebe6f --- /dev/null +++ b/adjutant_ui/content/signup/templates/auth/_login_page.html @@ -0,0 +1,7 @@ +{% overextends 'auth/_login_page.html' %} +{% load i18n %} + +{% block login_footer %} + {{ block.super }} +

Don't have an account? Sign up.

+{% endblock %} diff --git a/adjutant_ui/content/signup/templates/signup/_index.html b/adjutant_ui/content/signup/templates/signup/_index.html new file mode 100644 index 0000000..447c0d3 --- /dev/null +++ b/adjutant_ui/content/signup/templates/signup/_index.html @@ -0,0 +1,23 @@ +{% extends 'signup/_signup_form.html' %} + +{% load url from future %} +{% load i18n %} + +{% block pre_login %} +
+
+
+ {{ block.super }} +{% endblock %} + +{% block login_header %} + {% include 'auth/_splash.html' %} + {{ block.super }} +{% endblock %} + +{% block post_login %} + {{ block.super }} +
+
+
+{% endblock %} diff --git a/adjutant_ui/content/signup/templates/signup/_signup_form.html b/adjutant_ui/content/signup/templates/signup/_signup_form.html new file mode 100644 index 0000000..90bd764 --- /dev/null +++ b/adjutant_ui/content/signup/templates/signup/_signup_form.html @@ -0,0 +1,54 @@ +{% load i18n %} + +{% block pre_login %} +
+ {% csrf_token %} +{% endblock %} + +
+ +
+ {% block login_header %} + + {% endblock %} +
+ +
+ {% block login_body %} + {% comment %} + These fake fields are required to prevent Chrome v34+ from autofilling form. + {% endcomment %} + {% if HORIZON_CONFIG.password_autocomplete != "on" %} + + {%endif%} +
+ {% include "horizon/common/_form_fields.html" %} +
+ {% endblock %} +
+ + +
+ +{% block post_login%} +
+{% endblock %} diff --git a/adjutant_ui/content/signup/templates/signup/_submitted.html b/adjutant_ui/content/signup/templates/signup/_submitted.html new file mode 100644 index 0000000..1f04fe6 --- /dev/null +++ b/adjutant_ui/content/signup/templates/signup/_submitted.html @@ -0,0 +1,20 @@ +{% extends 'signup/_sent_text.html' %} + +{% block pre_login %} +
+
+
+ {{ block.super }} +{% endblock %} + +{% block login_header %} + {% include 'auth/_splash.html' %} + {{ block.super }} +{% endblock %} + +{% block post_login %} + {{ block.super }} +
+
+
+{% endblock %} diff --git a/adjutant_ui/content/signup/templates/signup/_submitted_text.html b/adjutant_ui/content/signup/templates/signup/_submitted_text.html new file mode 100644 index 0000000..50973db --- /dev/null +++ b/adjutant_ui/content/signup/templates/signup/_submitted_text.html @@ -0,0 +1,34 @@ +{% load i18n %} + +{% block pre_login %} +
+ {% csrf_token %} +{% endblock %} + +
+ +
+ {% block login_header %} + + {% endblock %} +
+ +
+ {% block login_body %} + {% trans "Your signup request has been submitted. An email will be sent once an administator approves your request." %} + {% endblock %} +
+ + +
+ +{% block post_login%} +
+{% endblock %} diff --git a/adjutant_ui/content/signup/templates/signup/index.html b/adjutant_ui/content/signup/templates/signup/index.html new file mode 100644 index 0000000..8bd2311 --- /dev/null +++ b/adjutant_ui/content/signup/templates/signup/index.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% load i18n %} + + +{% block title %}{% trans "Sign Up" %}{% endblock %} + +{% block body_id %}splash{% endblock %} + +{% block content %} + {% include 'signup/_index.html' %} +{% endblock %} diff --git a/adjutant_ui/content/signup/templates/signup/submitted.html b/adjutant_ui/content/signup/templates/signup/submitted.html new file mode 100644 index 0000000..2c84d60 --- /dev/null +++ b/adjutant_ui/content/signup/templates/signup/submitted.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% load i18n %} +{% block title %}{% trans "Signup Submitted" %}{% endblock %} + +{% block body_id %}splash{% endblock %} + +{% block content %} + {% include 'signup/_sent.html' %} +{% endblock %} diff --git a/adjutant_ui/content/signup/urls.py b/adjutant_ui/content/signup/urls.py new file mode 100644 index 0000000..de0e83d --- /dev/null +++ b/adjutant_ui/content/signup/urls.py @@ -0,0 +1,24 @@ +# Copyright (c) 2016 Catalyst IT Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.conf.urls import patterns +from django.conf.urls import url + +from adjutant_ui.content.signup import views + +urlpatterns = patterns( + '', + url(r'^/?$', views.SignupFormView.as_view(), name='index'), + url(r'^submitted/?$', views.signup_sent_view, name='submitted'), +) diff --git a/adjutant_ui/content/signup/views.py b/adjutant_ui/content/signup/views.py new file mode 100644 index 0000000..cdbb84f --- /dev/null +++ b/adjutant_ui/content/signup/views.py @@ -0,0 +1,31 @@ +# Copyright (c) 2016 Catalyst IT Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.shortcuts import render +from django.core.urlresolvers import reverse_lazy + +from horizon import forms + +from adjutant_ui.content.signup import forms as su_forms + + +class SignupFormView(forms.ModalFormView): + form_class = su_forms.SignupForm + submit_url = reverse_lazy("horizon:signup:signup:index") + success_url = reverse_lazy("horizon:signup:signup:submitted") + template_name = 'signup/index.html' + + +def signup_sent_view(request): + return render(request, 'signup/submitted.html') diff --git a/adjutant_ui/dashboards/signup_dash.py b/adjutant_ui/dashboards/signup_dash.py new file mode 100644 index 0000000..ddf8a81 --- /dev/null +++ b/adjutant_ui/dashboards/signup_dash.py @@ -0,0 +1,31 @@ +# Copyright (c) 2014 Catalyst IT Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.utils.translation import ugettext_lazy as _ + +import horizon + +from adjutant_ui.content.signup import panel + + +class SignupDashboard(horizon.Dashboard): + name = _("Sign Up") + slug = "signup" + default_panel = 'signup' + nav = False + public = True + + +horizon.register(SignupDashboard) +SignupDashboard.register(panel.SignupPanel) diff --git a/adjutant_ui/enabled/_6001_adjutant_base.py b/adjutant_ui/enabled/_6001_adjutant_base.py index be6a523..4c80111 100644 --- a/adjutant_ui/enabled/_6001_adjutant_base.py +++ b/adjutant_ui/enabled/_6001_adjutant_base.py @@ -4,5 +4,6 @@ FEATURE = "adjutant-ui-base" # A list of applications to be added to INSTALLED_APPS. ADD_INSTALLED_APPS = [ - 'adjutant_ui' + 'adjutant_ui', + 'overextends', ] diff --git a/adjutant_ui/enabled/_6015_forgot_password.py b/adjutant_ui/enabled/_6015_forgot_password.py index 2712b8e..cec8b98 100644 --- a/adjutant_ui/enabled/_6015_forgot_password.py +++ b/adjutant_ui/enabled/_6015_forgot_password.py @@ -5,5 +5,4 @@ DASHBOARD = 'forgot_password' ADD_INSTALLED_APPS = [ 'adjutant_ui.dashboards.forgot_password_dash', 'adjutant_ui.content.forgot_password', - 'overextends', ] diff --git a/adjutant_ui/enabled/_6025_signup.py b/adjutant_ui/enabled/_6025_signup.py new file mode 100644 index 0000000..0760681 --- /dev/null +++ b/adjutant_ui/enabled/_6025_signup.py @@ -0,0 +1,8 @@ +# The name of the dashboard to be added to HORIZON['dashboards']. Required. +DASHBOARD = 'signup' + +# A list of applications to be added to INSTALLED_APPS. +ADD_INSTALLED_APPS = [ + 'adjutant_ui.dashboards.signup_dash', + 'adjutant_ui.content.signup', +]