Compare commits
8 commits
e71c18c46f
...
b11c7ecc21
Author | SHA1 | Date | |
---|---|---|---|
b11c7ecc21 | |||
c28fa71b9d | |||
a285d655a7 | |||
8f719b0d65 | |||
98e114dc79 | |||
0df2b0e0eb | |||
a1d5c1c764 | |||
1754cd609c |
9 changed files with 109 additions and 38 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
@ -33,6 +34,18 @@ class Organization(ServalaModelMixin, models.Model):
|
||||||
user=user, organization=self, role=OrganizationRole.OWNER
|
user=user, organization=self, role=OrganizationRole.OWNER
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_organization(cls, instance, owner):
|
||||||
|
try:
|
||||||
|
instance.origin
|
||||||
|
except Exception:
|
||||||
|
instance.origin = OrganizationOrigin.objects.get(
|
||||||
|
pk=settings.SERVALA_DEFAULT_ORIGIN
|
||||||
|
)
|
||||||
|
instance.save()
|
||||||
|
instance.set_owner(owner)
|
||||||
|
return instance
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Organization")
|
verbose_name = _("Organization")
|
||||||
verbose_name_plural = _("Organizations")
|
verbose_name_plural = _("Organizations")
|
||||||
|
|
11
src/servala/frontend/forms/auth.py
Normal file
11
src/servala/frontend/forms/auth.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from django.forms import Form
|
||||||
|
|
||||||
|
from servala.core.models.user import User
|
||||||
|
|
||||||
|
|
||||||
|
class ServalaSignupForm(Form):
|
||||||
|
company = User._meta.get_field("company").formfield()
|
||||||
|
|
||||||
|
def signup(self, request, user):
|
||||||
|
user.company = self.cleaned_data.get("company")
|
||||||
|
user.save()
|
|
@ -20,6 +20,11 @@
|
||||||
<div id="app">
|
<div id="app">
|
||||||
{% include 'includes/sidebar.html' %}
|
{% include 'includes/sidebar.html' %}
|
||||||
<div id="main">
|
<div id="main">
|
||||||
|
<header class="mb-3">
|
||||||
|
<a href="#" class="burger-btn d-block d-xl-none">
|
||||||
|
<i class="bi bi-justify fs-3"></i>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
<div class="page-heading">
|
<div class="page-heading">
|
||||||
<h3>
|
<h3>
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="form-group{% with classes=field.css_classes %}{% if classes %} {{ classes }}{% endif %}{% endwith %}{% if errors %} is-invalid{% endif %}">
|
<div class="form-group{% if field.field.required %} mandatory{% endif %}{% if errors %} is-invalid{% endif %}">
|
||||||
{% if field.field.widget.input_type != "checkbox" or field.field.widget.allow_multiple_selected %}
|
{% if field.field.widget.input_type != "checkbox" or field.field.widget.allow_multiple_selected %}
|
||||||
<label for="{{ field.auto_id }}" class="{{ label_class }}">
|
<label for="{{ field.auto_id }}" class="form-label">{{ field.label }}</label>
|
||||||
{{ field.label }}
|
|
||||||
{% if not field.field.required %}
|
|
||||||
<span class="optional">{% translate "Optional" %}</span>
|
|
||||||
{% endif %}
|
|
||||||
</label>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if field.use_fieldset %}
|
{% if field.use_fieldset %}
|
||||||
<fieldset {% if field.help_text and field.auto_id and "aria-describedby" not in field.field.widget.attrs %} aria-describedby="{{ field.auto_id }}_helptext"{% endif %}>
|
<fieldset {% if field.help_text and field.auto_id and "aria-describedby" not in field.field.widget.attrs %} aria-describedby="{{ field.auto_id }}_helptext"{% endif %}>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ field }}
|
{{ field }}
|
||||||
{% if field.field.widget.input_type == "checkbox" and not field.field.widget.allow_multiple_selected %}
|
{% if field.field.widget.input_type == "checkbox" and not field.field.widget.allow_multiple_selected %}
|
||||||
<label for="{{ field.auto_id }}">{{ field.label }}</label>
|
<label for="{{ field.auto_id }}" class="form-check-label form-label">{{ field.label }}</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if field.use_fieldset %}</fieldset>{% endif %}
|
{% if field.use_fieldset %}</fieldset>{% endif %}
|
||||||
{% for text in field.errors %}<div class="text-danger">{{ text }}</div>{% endfor %}
|
{% for text in field.errors %}<div class="invalid-feedback">{{ text }}</div>{% endfor %}
|
||||||
{% if field.help_text %}
|
{% if field.help_text %}
|
||||||
<small class="form-text text-muted"
|
<small class="form-text text-muted"
|
||||||
{% if field.auto_id %}id="{{ field.auto_id }}_helptext"{% endif %}>{{ field.help_text|safe }}</small>
|
{% if field.auto_id %}id="{{ field.auto_id }}_helptext"{% endif %}>{{ field.help_text|safe }}</small>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "frontend/base.html" %}
|
{% extends "frontend/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n static %}
|
||||||
{% block html_title %}
|
{% block html_title %}
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
{% translate "Profile" %}
|
{% translate "Profile" %}
|
||||||
|
@ -10,28 +10,63 @@
|
||||||
<h4 class="card-title">{% translate "Account" %}</h4>
|
<h4 class="card-title">{% translate "Account" %}</h4>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block card_content %}
|
{% block content %}
|
||||||
<p>
|
<section>
|
||||||
{% blocktranslate trimmed %}
|
<div class="row match-height">
|
||||||
You are logged in with your VSHN user account. You will be able to change your password and other settings here in the future.
|
<div class="col-md-6 col-12">
|
||||||
{% endblocktranslate %}
|
<div class="card">
|
||||||
</p>
|
<div class="card-header">
|
||||||
<div class="table-responsive">
|
<h4 class="card-title">{% translate "Profile" %}</h4>
|
||||||
<table class="table table-lg">
|
</div>
|
||||||
<tbody>
|
<div class="card-content">
|
||||||
<tr>
|
<div class="card-body">
|
||||||
<th>{% translate "E-mail" %}</th>
|
<div class="table-responsive">
|
||||||
<td>{{ request.user.email }}</td>
|
<table class="table table-lg">
|
||||||
</tr>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "First name" %}</th>
|
<th>{% translate "E-mail" %}</th>
|
||||||
<td>{{ request.user.first_name }}</td>
|
<td>{{ request.user.email }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Last name" %}</th>
|
<th>{% translate "First name" %}</th>
|
||||||
<td>{{ request.user.last_name }}</td>
|
<td>{{ request.user.first_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
<tr>
|
||||||
</table>
|
<th>{% translate "Last name" %}</th>
|
||||||
</div>
|
<td>{{ request.user.last_name }}</td>
|
||||||
{% endblock card_content %}
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% translate "Company" %}</th>
|
||||||
|
<td>{{ request.user.company }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h4 class="card-title">{% translate "Account" %}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
{% blocktranslate trimmed %}
|
||||||
|
You are logged in with your VSHN user account. Change your password and other account data here:
|
||||||
|
{% endblocktranslate %}
|
||||||
|
</p>
|
||||||
|
<a href="{{ account_href }}"
|
||||||
|
class="btn btn-warning btn-lg icon icon-left">
|
||||||
|
<img src="{% static 'img/keycloak.svg' %}" style="height: 30px">
|
||||||
|
<span class="mx-1">{% translate "VSHN Account" %}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock content %}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,3 +8,14 @@ class IndexView(TemplateView):
|
||||||
|
|
||||||
class ProfileView(TemplateView):
|
class ProfileView(TemplateView):
|
||||||
template_name = "frontend/profile.html"
|
template_name = "frontend/profile.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
keycloak_server_url = settings.SOCIALACCOUNT_PROVIDERS["openid_connect"][
|
||||||
|
"APPS"
|
||||||
|
][0]["settings"]["server_url"]
|
||||||
|
account_url = keycloak_server_url.replace(
|
||||||
|
"/.well-known/openid-configuration", "/account"
|
||||||
|
)
|
||||||
|
context["account_href"] = account_url
|
||||||
|
return context
|
||||||
|
|
|
@ -8,8 +8,7 @@ class OrganizationCreateView(FormView):
|
||||||
template_name = "frontend/organizations/create.html"
|
template_name = "frontend/organizations/create.html"
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.save()
|
form.instance.create_organization(form.instance, owner=self.request.user)
|
||||||
form.instance.set_owner(self.request.user)
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
|
|
|
@ -164,6 +164,7 @@ ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
||||||
ACCOUNT_UNIQUE_EMAIL = True
|
ACCOUNT_UNIQUE_EMAIL = True
|
||||||
ACCOUNT_LOGIN_METHODS = {"email"}
|
ACCOUNT_LOGIN_METHODS = {"email"}
|
||||||
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
|
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
|
||||||
|
ACCOUNT_SIGNUP_FORM_CLASS = "servala.frontend.forms.auth.ServalaSignupForm"
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
# Needed to login by username in Django admin, regardless of `allauth`
|
# Needed to login by username in Django admin, regardless of `allauth`
|
||||||
|
|
|
@ -14,12 +14,12 @@ admin.site.index_title = _("Dashboard")
|
||||||
admin.site.login = secure_admin_login(admin.site.login)
|
admin.site.login = secure_admin_login(admin.site.login)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
|
||||||
path("", include((urls, "servala.frontend"), namespace="frontend")),
|
path("", include((urls, "servala.frontend"), namespace="frontend")),
|
||||||
# This adds the allauth urls to the project:
|
# This adds the allauth urls to the project:
|
||||||
# - accounts/keycloak/login/
|
# - accounts/keycloak/login/
|
||||||
# - accounts/keycloak/login/callback/
|
# - accounts/keycloak/login/callback/
|
||||||
path("accounts/", include("allauth.urls")),
|
path("accounts/", include("allauth.urls")),
|
||||||
|
path("admin/", admin.site.urls),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Serve static and media files in development
|
# Serve static and media files in development
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue