parent
							
								
									7a760332fa
								
							
						
					
					
						commit
						e8fae7a6f4
					
				@ -7,11 +7,11 @@ Created on: 27.09.21
 | 
			
		||||
"""
 | 
			
		||||
from dal import autocomplete
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.db.models.fields.files import FieldFile
 | 
			
		||||
 | 
			
		||||
from konova.utils.message_templates import DEDUCTION_ADDED, REVOCATION_ADDED, DEDUCTION_REMOVED, DEDUCTION_EDITED, \
 | 
			
		||||
    REVOCATION_EDITED, FILE_TYPE_UNSUPPORTED, FILE_SIZE_TOO_LARGE
 | 
			
		||||
from user.models import User, UserActionLogEntry
 | 
			
		||||
    REVOCATION_EDITED
 | 
			
		||||
from user.models import User
 | 
			
		||||
from user.models import UserActionLogEntry
 | 
			
		||||
from django.db import transaction
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,6 @@ from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP, LANIS_ZOOM_LUT,
 | 
			
		||||
from konova.tasks import celery_send_mail_shared_access_removed, celery_send_mail_shared_access_given, \
 | 
			
		||||
    celery_send_mail_shared_data_recorded, celery_send_mail_shared_data_unrecorded, \
 | 
			
		||||
    celery_send_mail_shared_data_deleted, celery_send_mail_shared_data_checked
 | 
			
		||||
from user.models import User
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.http import HttpRequest
 | 
			
		||||
from django.utils.timezone import now
 | 
			
		||||
@ -28,7 +27,6 @@ from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_I
 | 
			
		||||
from konova.utils import generators
 | 
			
		||||
from konova.utils.generators import generate_random_string
 | 
			
		||||
from konova.utils.message_templates import CHECKED_RECORDED_RESET, GEOMETRY_CONFLICT_WITH_TEMPLATE
 | 
			
		||||
from user.models import UserActionLogEntry, UserAction
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UuidModel(models.Model):
 | 
			
		||||
@ -50,14 +48,14 @@ class BaseResource(UuidModel):
 | 
			
		||||
    A basic resource model, which defines attributes for every derived model
 | 
			
		||||
    """
 | 
			
		||||
    created = models.ForeignKey(
 | 
			
		||||
        UserActionLogEntry,
 | 
			
		||||
        "user.UserActionLogEntry",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        related_name='+'
 | 
			
		||||
    )
 | 
			
		||||
    modified = models.ForeignKey(
 | 
			
		||||
        UserActionLogEntry,
 | 
			
		||||
        "user.UserActionLogEntry",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
@ -94,9 +92,9 @@ class BaseObject(BaseResource):
 | 
			
		||||
    """
 | 
			
		||||
    identifier = models.CharField(max_length=1000, null=True, blank=True)
 | 
			
		||||
    title = models.CharField(max_length=1000, null=True, blank=True)
 | 
			
		||||
    deleted = models.ForeignKey(UserActionLogEntry, on_delete=models.SET_NULL, null=True, blank=True, related_name='+')
 | 
			
		||||
    deleted = models.ForeignKey("user.UserActionLogEntry", on_delete=models.SET_NULL, null=True, blank=True, related_name='+')
 | 
			
		||||
    comment = models.TextField(null=True, blank=True)
 | 
			
		||||
    log = models.ManyToManyField(UserActionLogEntry, blank=True, help_text="Keeps all user actions of an object", editable=False)
 | 
			
		||||
    log = models.ManyToManyField("user.UserActionLogEntry", blank=True, help_text="Keeps all user actions of an object", editable=False)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
@ -105,7 +103,7 @@ class BaseObject(BaseResource):
 | 
			
		||||
    def set_status_messages(self, request: HttpRequest):
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
 | 
			
		||||
    def mark_as_deleted(self, user: User, send_mail: bool = True):
 | 
			
		||||
    def mark_as_deleted(self, user, send_mail: bool = True):
 | 
			
		||||
        """ Mark an entry as deleted
 | 
			
		||||
 | 
			
		||||
        Does not delete from database but sets a timestamp for being deleted on and which user deleted the object
 | 
			
		||||
@ -116,6 +114,7 @@ class BaseObject(BaseResource):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        if self.deleted:
 | 
			
		||||
            # Nothing to do here
 | 
			
		||||
            return
 | 
			
		||||
@ -133,7 +132,7 @@ class BaseObject(BaseResource):
 | 
			
		||||
 | 
			
		||||
            self.save()
 | 
			
		||||
 | 
			
		||||
    def mark_as_edited(self, performing_user: User, request: HttpRequest = None, edit_comment: str = None):
 | 
			
		||||
    def mark_as_edited(self, performing_user, request: HttpRequest = None, edit_comment: str = None):
 | 
			
		||||
        """ In case the object or a related object changed the log history needs to be updated
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -144,13 +143,14 @@ class BaseObject(BaseResource):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        edit_action = UserActionLogEntry.get_edited_action(performing_user, edit_comment)
 | 
			
		||||
        self.modified = edit_action
 | 
			
		||||
        self.log.add(edit_action)
 | 
			
		||||
        self.save()
 | 
			
		||||
        return edit_action
 | 
			
		||||
 | 
			
		||||
    def add_log_entry(self, action: UserAction, user: User, comment: str):
 | 
			
		||||
    def add_log_entry(self, action, user, comment: str):
 | 
			
		||||
        """ Wraps adding of UserActionLogEntry to log
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -161,6 +161,7 @@ class BaseObject(BaseResource):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        user_action = UserActionLogEntry.objects.create(
 | 
			
		||||
            user=user,
 | 
			
		||||
            action=action,
 | 
			
		||||
@ -229,7 +230,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
    """
 | 
			
		||||
    # Refers to "verzeichnen"
 | 
			
		||||
    recorded = models.OneToOneField(
 | 
			
		||||
        UserActionLogEntry,
 | 
			
		||||
        "user.UserActionLogEntry",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
@ -240,7 +241,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
    def set_unrecorded(self, user: User):
 | 
			
		||||
    def set_unrecorded(self, user):
 | 
			
		||||
        """ Perform unrecording
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -249,6 +250,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        if not self.recorded:
 | 
			
		||||
            return None
 | 
			
		||||
        action = UserActionLogEntry.get_unrecorded_action(user)
 | 
			
		||||
@ -262,7 +264,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
 | 
			
		||||
        return action
 | 
			
		||||
 | 
			
		||||
    def set_recorded(self, user: User):
 | 
			
		||||
    def set_recorded(self, user):
 | 
			
		||||
        """ Perform recording
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -271,6 +273,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        if self.recorded:
 | 
			
		||||
            return None
 | 
			
		||||
        action = UserActionLogEntry.get_recorded_action(user)
 | 
			
		||||
@ -284,7 +287,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
 | 
			
		||||
        return action
 | 
			
		||||
 | 
			
		||||
    def unrecord(self, performing_user: User, request: HttpRequest = None):
 | 
			
		||||
    def unrecord(self, performing_user, request: HttpRequest = None):
 | 
			
		||||
        """ Unrecords a dataset
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -318,7 +321,7 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
class CheckableObjectMixin(models.Model):
 | 
			
		||||
    # Checks - Refers to "Genehmigen" but optional
 | 
			
		||||
    checked = models.OneToOneField(
 | 
			
		||||
        UserActionLogEntry,
 | 
			
		||||
        "user.UserActionLogEntry",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
@ -346,7 +349,7 @@ class CheckableObjectMixin(models.Model):
 | 
			
		||||
        self.save()
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def set_checked(self, user: User) -> UserActionLogEntry:
 | 
			
		||||
    def set_checked(self, user):
 | 
			
		||||
        """ Perform checking
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -355,6 +358,7 @@ class CheckableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        if self.checked:
 | 
			
		||||
            # Nothing to do
 | 
			
		||||
            return
 | 
			
		||||
@ -373,7 +377,7 @@ class CheckableObjectMixin(models.Model):
 | 
			
		||||
 | 
			
		||||
class ShareableObjectMixin(models.Model):
 | 
			
		||||
    # Users having access on this object
 | 
			
		||||
    users = models.ManyToManyField(User, help_text="Users having access (data shared with)")
 | 
			
		||||
    users = models.ManyToManyField("user.User", help_text="Users having access (data shared with)")
 | 
			
		||||
    access_token = models.CharField(
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        null=True,
 | 
			
		||||
@ -420,7 +424,7 @@ class ShareableObjectMixin(models.Model):
 | 
			
		||||
            self.access_token = token
 | 
			
		||||
            self.save()
 | 
			
		||||
 | 
			
		||||
    def is_shared_with(self, user: User):
 | 
			
		||||
    def is_shared_with(self, user):
 | 
			
		||||
        """ Access check
 | 
			
		||||
 | 
			
		||||
        Checks whether a given user has access to this object
 | 
			
		||||
@ -433,7 +437,7 @@ class ShareableObjectMixin(models.Model):
 | 
			
		||||
        """
 | 
			
		||||
        return self.users.filter(id=user.id)
 | 
			
		||||
 | 
			
		||||
    def share_with(self, user: User):
 | 
			
		||||
    def share_with(self, user):
 | 
			
		||||
        """ Adds user to list of shared access users
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
@ -465,6 +469,7 @@ class ShareableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from user.models import User
 | 
			
		||||
        form_data = form.cleaned_data
 | 
			
		||||
 | 
			
		||||
        keep_accessing_users = form_data["users"]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										110
									
								
								user/forms.py
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								user/forms.py
									
									
									
									
									
								
							@ -5,17 +5,17 @@ Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 08.07.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal import autocomplete
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.db import IntegrityError
 | 
			
		||||
from django.db import IntegrityError, transaction
 | 
			
		||||
from django.urls import reverse, reverse_lazy
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from api.models import APIUserToken
 | 
			
		||||
from intervention.inputs import GenerateInput
 | 
			
		||||
from user.models import User
 | 
			
		||||
from user.models import User, UserNotification, Team
 | 
			
		||||
 | 
			
		||||
from konova.forms import BaseForm, BaseModalForm
 | 
			
		||||
from user.models import UserNotification
 | 
			
		||||
from konova.forms import BaseForm, BaseModalForm, RemoveModalForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserNotificationForm(BaseForm):
 | 
			
		||||
@ -160,3 +160,105 @@ class UserAPITokenForm(BaseForm):
 | 
			
		||||
        user.api_token = new_token
 | 
			
		||||
        user.save()
 | 
			
		||||
        return new_token
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NewTeamModalForm(BaseModalForm):
 | 
			
		||||
    name = forms.CharField(
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
        label=_("Team name"),
 | 
			
		||||
        max_length=500,
 | 
			
		||||
        widget=forms.TextInput(
 | 
			
		||||
            attrs={
 | 
			
		||||
                "placeholder": _("Team name"),
 | 
			
		||||
                "class": "form-control",
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    description = forms.CharField(
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
        label=_("Description"),
 | 
			
		||||
        widget=forms.Textarea(
 | 
			
		||||
            attrs={
 | 
			
		||||
                "rows": 5,
 | 
			
		||||
                "class": "form-control"
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    members = forms.ModelMultipleChoiceField(
 | 
			
		||||
        label=_("Manage team members"),
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
        help_text=_("Multiple selection possible - You can only select users which are not already a team member. Enter the full username or e-mail."),
 | 
			
		||||
        required=True,
 | 
			
		||||
        queryset=User.objects.all(),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="share-user-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.form_title = _("Create new team")
 | 
			
		||||
        self.form_caption = _("You will become the administrator for this group by default. You do not need to add yourself to the list of members.")
 | 
			
		||||
        self.action_url = reverse("user:team-new")
 | 
			
		||||
        self.cancel_redirect = reverse("user:team-index")
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        with transaction.atomic():
 | 
			
		||||
            team = Team.objects.create(
 | 
			
		||||
                name=self.cleaned_data.get("name", None),
 | 
			
		||||
                description=self.cleaned_data.get("description", None),
 | 
			
		||||
                admin=self.user,
 | 
			
		||||
            )
 | 
			
		||||
            members = self.cleaned_data.get("members", User.objects.none())
 | 
			
		||||
            if self.user.id not in members:
 | 
			
		||||
                members = members.union(
 | 
			
		||||
                    User.objects.filter(
 | 
			
		||||
                        id=self.user.id
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            team.users.set(members)
 | 
			
		||||
        return team
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditTeamModalForm(NewTeamModalForm):
 | 
			
		||||
    admin = forms.ModelChoiceField(
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
        label=_("Admin"),
 | 
			
		||||
        help_text=_("Administrators manage team details and members"),
 | 
			
		||||
        queryset=User.objects.none(),
 | 
			
		||||
        empty_label=None,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.form_title = _("Edit team")
 | 
			
		||||
        self.form_caption = None
 | 
			
		||||
        self.action_url = reverse("user:team-edit", args=(self.instance.id,))
 | 
			
		||||
        self.cancel_redirect = reverse("user:team-index")
 | 
			
		||||
 | 
			
		||||
        members = self.instance.users.all()
 | 
			
		||||
        self.fields["admin"].queryset = members
 | 
			
		||||
 | 
			
		||||
        form_data = {
 | 
			
		||||
            "members": members,
 | 
			
		||||
            "name": self.instance.name,
 | 
			
		||||
            "description": self.instance.description,
 | 
			
		||||
            "admin": self.instance.admin,
 | 
			
		||||
        }
 | 
			
		||||
        self.load_initial_data(form_data)
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        with transaction.atomic():
 | 
			
		||||
            self.instance.name = self.cleaned_data.get("name", None)
 | 
			
		||||
            self.instance.description = self.cleaned_data.get("description", None)
 | 
			
		||||
            self.instance.save()
 | 
			
		||||
            self.instance.users.set(self.cleaned_data.get("members", []))
 | 
			
		||||
        return self.instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RemoveTeamModalForm(RemoveModalForm):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 15.11.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from .user_action import *
 | 
			
		||||
from .user import *
 | 
			
		||||
from .notification import *
 | 
			
		||||
from .user_action import UserActionLogEntry, UserAction
 | 
			
		||||
from .user import User
 | 
			
		||||
from .notification import UserNotification, UserNotificationEnum
 | 
			
		||||
from .team import Team
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								user/models/team.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								user/models/team.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
from django.db import models
 | 
			
		||||
 | 
			
		||||
from konova.models import UuidModel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Team(UuidModel):
 | 
			
		||||
    """ Groups users in self managed teams. Can be used for multi-sharing of data
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    name = models.CharField(max_length=500, null=True, blank=True)
 | 
			
		||||
    description = models.TextField(null=True, blank=True)
 | 
			
		||||
    users = models.ManyToManyField("user.User", blank=True, related_name="teams")
 | 
			
		||||
    admin = models.ForeignKey("user.User", blank=True, null=True, related_name="+", on_delete=models.SET_NULL)
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
@ -62,6 +62,14 @@
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row mb-2">
 | 
			
		||||
                    <a href="{% url 'user:team-index' %}" title="{% trans 'Manage teams' %}">
 | 
			
		||||
                        <button class="btn btn-default">
 | 
			
		||||
                            {% fa5_icon 'users' %}
 | 
			
		||||
                            <span>{% trans 'Teams' %}</span>
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										67
									
								
								user/templates/user/team/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								user/templates/user/team/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
{% extends 'base.html' %}
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
{% block head %}
 | 
			
		||||
 | 
			
		||||
    {% comment %}
 | 
			
		||||
        dal documentation (django-autocomplete-light) states using form.media for adding needed scripts.
 | 
			
		||||
        This does not work properly with modal forms, as the scripts are not loaded properly inside the modal.
 | 
			
		||||
        Therefore the script linkages from form.media have been extracted and put inside dal/scripts.html to ensure
 | 
			
		||||
        these scripts are loaded when needed.
 | 
			
		||||
    {% endcomment %}
 | 
			
		||||
    {% include 'dal/scripts.html' %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block body %}
 | 
			
		||||
<h4>{% trans 'Teams' %}</h4>
 | 
			
		||||
<div class="col-md">
 | 
			
		||||
    <button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-new' %}" title="{% trans 'Add new team' %}">
 | 
			
		||||
        {% fa5_icon 'plus' %}
 | 
			
		||||
        {% trans 'New' %}
 | 
			
		||||
    </button>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="table-container">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col" class="align-middle">{% trans 'Name' %}</th>
 | 
			
		||||
                <th scope="col" class="align-middle w-20">{% trans 'Description' %}</th>
 | 
			
		||||
                <th scope="col" class="align-middle">{% trans 'Members' %}</th>
 | 
			
		||||
                <th scope="col" class="align-middle">{% trans 'Actions' %}</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
            {% for team in teams %}
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>{{team.name}}</td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        <div class="scroll-150">
 | 
			
		||||
                            {{team.description}}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        {% for member in team.users.all %}
 | 
			
		||||
                            <span class="badge badge-pill rlp-r">{{member.username}}</span>
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        {% if team.admin == user %}
 | 
			
		||||
                            <button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-edit' team.id %}" title="{% trans 'Edit team' %}">
 | 
			
		||||
                                {% fa5_icon 'edit' %}
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-remove' team.id %}" title="{% trans 'Remove team' %}">
 | 
			
		||||
                                {% fa5_icon 'trash' %}
 | 
			
		||||
                            </button>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% with 'btn-modal' as btn_class %}
 | 
			
		||||
    {% include 'modal/modal_form_script.html' %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -15,5 +15,9 @@ urlpatterns = [
 | 
			
		||||
    path("notifications/", notifications_view, name="notifications"),
 | 
			
		||||
    path("token/api", api_token_view, name="api-token"),
 | 
			
		||||
    path("contact/<id>", contact_view, name="contact"),
 | 
			
		||||
    path("team/", index_team_view, name="team-index"),
 | 
			
		||||
    path("team/new", new_team_view, name="team-new"),
 | 
			
		||||
    path("team/<id>/edit", edit_team_view, name="team-edit"),
 | 
			
		||||
    path("team/<id>/remove", remove_team_view, name="team-remove"),
 | 
			
		||||
 | 
			
		||||
]
 | 
			
		||||
@ -1,17 +1,19 @@
 | 
			
		||||
from django.contrib import messages
 | 
			
		||||
from django.contrib.auth.decorators import login_required
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
 | 
			
		||||
from konova.utils.mailer import Mailer
 | 
			
		||||
from konova.utils.message_templates import FORM_INVALID
 | 
			
		||||
from user.models import User
 | 
			
		||||
from django.http import HttpRequest
 | 
			
		||||
from user.models import User, Team
 | 
			
		||||
from django.http import HttpRequest, Http404
 | 
			
		||||
from django.shortcuts import render, redirect, get_object_or_404
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from konova.contexts import BaseContext
 | 
			
		||||
from konova.decorators import any_group_check, default_group_required
 | 
			
		||||
from user.forms import UserNotificationForm, UserContactForm, UserAPITokenForm
 | 
			
		||||
from user.forms import UserNotificationForm, UserContactForm, UserAPITokenForm, NewTeamModalForm, EditTeamModalForm, \
 | 
			
		||||
    RemoveTeamModalForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
@ -128,4 +130,52 @@ def contact_view(request: HttpRequest, id: str):
 | 
			
		||||
        request,
 | 
			
		||||
        template,
 | 
			
		||||
        context
 | 
			
		||||
    )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
def index_team_view(request: HttpRequest):
 | 
			
		||||
    template = "user/team/index.html"
 | 
			
		||||
    user = request.user
 | 
			
		||||
    context = {
 | 
			
		||||
        "teams": user.teams.all(),
 | 
			
		||||
        "tab_title": _("Teams"),
 | 
			
		||||
    }
 | 
			
		||||
    context = BaseContext(request, context).context
 | 
			
		||||
    return render(request, template, context)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
def new_team_view(request: HttpRequest):
 | 
			
		||||
    form = NewTeamModalForm(request.POST or None, request=request)
 | 
			
		||||
    return form.process_request(
 | 
			
		||||
        request,
 | 
			
		||||
        _("New team added"),
 | 
			
		||||
        redirect_url=reverse("user:team-index")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
def edit_team_view(request: HttpRequest, id: str):
 | 
			
		||||
    team = get_object_or_404(Team, id=id)
 | 
			
		||||
    if request.user != team.admin:
 | 
			
		||||
        raise Http404()
 | 
			
		||||
    form = EditTeamModalForm(request.POST or None, instance=team, request=request)
 | 
			
		||||
    return form.process_request(
 | 
			
		||||
        request,
 | 
			
		||||
        _("Team edited"),
 | 
			
		||||
        redirect_url=reverse("user:team-index")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
def remove_team_view(request: HttpRequest, id: str):
 | 
			
		||||
    team = get_object_or_404(Team, id=id)
 | 
			
		||||
    if request.user != team.admin:
 | 
			
		||||
        raise Http404()
 | 
			
		||||
    form = RemoveTeamModalForm(request.POST or None, instance=team, request=request)
 | 
			
		||||
    return form.process_request(
 | 
			
		||||
        request,
 | 
			
		||||
        _("Team removed"),
 | 
			
		||||
        redirect_url=reverse("user:team-index")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user