#101 Team sharing form

* adds team sharing field to share form
* splits sharing logic into user based and teams based
* adds TeamAdmin for admin backend
* adds validity check on Team name -> only unused names shall be valid
pull/122/head
mpeltriaux 3 years ago
parent 071bdea099
commit e152dfd4d7

@ -109,8 +109,8 @@ class APIV1CreateTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
self.eco_account.share_with(self.superuser) self.eco_account.share_with_user(self.superuser)
url = reverse("api:v1:deduction") url = reverse("api:v1:deduction")
json_file_path = "api/tests/v1/create/deduction_create_post_body.json" json_file_path = "api/tests/v1/create/deduction_create_post_body.json"

@ -57,7 +57,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase):
""" """
test_intervention = self.create_dummy_intervention() test_intervention = self.create_dummy_intervention()
test_intervention.share_with(self.superuser) test_intervention.share_with_user(self.superuser)
url = reverse("api:v1:intervention", args=(str(test_intervention.id),)) url = reverse("api:v1:intervention", args=(str(test_intervention.id),))
self._test_delete_object(test_intervention, url) self._test_delete_object(test_intervention, url)
@ -68,7 +68,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase):
""" """
test_comp = self.create_dummy_compensation() test_comp = self.create_dummy_compensation()
test_comp.share_with(self.superuser) test_comp.share_with_user(self.superuser)
url = reverse("api:v1:compensation", args=(str(test_comp.id),)) url = reverse("api:v1:compensation", args=(str(test_comp.id),))
self._test_delete_object(test_comp, url) self._test_delete_object(test_comp, url)
@ -79,7 +79,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase):
""" """
test_acc = self.create_dummy_eco_account() test_acc = self.create_dummy_eco_account()
test_acc.share_with(self.superuser) test_acc.share_with_user(self.superuser)
url = reverse("api:v1:ecoaccount", args=(str(test_acc.id),)) url = reverse("api:v1:ecoaccount", args=(str(test_acc.id),))
self._test_delete_object(test_acc, url) self._test_delete_object(test_acc, url)
@ -90,7 +90,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase):
""" """
test_ema = self.create_dummy_ema() test_ema = self.create_dummy_ema()
test_ema.share_with(self.superuser) test_ema.share_with_user(self.superuser)
url = reverse("api:v1:ema", args=(str(test_ema.id),)) url = reverse("api:v1:ema", args=(str(test_ema.id),))
self._test_delete_object(test_ema, url) self._test_delete_object(test_ema, url)
@ -101,7 +101,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase):
""" """
test_deduction = self.create_dummy_deduction() test_deduction = self.create_dummy_deduction()
test_deduction.intervention.share_with(self.superuser) test_deduction.intervention.share_with_user(self.superuser)
url = reverse("api:v1:deduction", args=(str(test_deduction.id),)) url = reverse("api:v1:deduction", args=(str(test_deduction.id),))
response = self._run_delete_request(url) response = self._run_delete_request(url)

@ -64,7 +64,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
url = reverse("api:v1:intervention", args=(str(self.intervention.id),)) url = reverse("api:v1:intervention", args=(str(self.intervention.id),))
geojson = self._test_get_object(self.intervention, url) geojson = self._test_get_object(self.intervention, url)
self._assert_geojson_format(geojson) self._assert_geojson_format(geojson)
@ -91,7 +91,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
self.compensation.intervention = self.intervention self.compensation.intervention = self.intervention
self.compensation.save() self.compensation.save()
@ -119,7 +119,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.eco_account.share_with(self.superuser) self.eco_account.share_with_user(self.superuser)
url = reverse("api:v1:ecoaccount", args=(str(self.eco_account.id),)) url = reverse("api:v1:ecoaccount", args=(str(self.eco_account.id),))
geojson = self._test_get_object(self.eco_account, url) geojson = self._test_get_object(self.eco_account, url)
@ -148,7 +148,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.ema.share_with(self.superuser) self.ema.share_with_user(self.superuser)
url = reverse("api:v1:ema", args=(str(self.ema.id),)) url = reverse("api:v1:ema", args=(str(self.ema.id),))
geojson = self._test_get_object(self.ema, url) geojson = self._test_get_object(self.ema, url)
@ -172,7 +172,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.deduction.intervention.share_with(self.superuser) self.deduction.intervention.share_with_user(self.superuser)
url = reverse("api:v1:deduction", args=(str(self.deduction.id),)) url = reverse("api:v1:deduction", args=(str(self.deduction.id),))
_json = self._test_get_object(self.deduction, url) _json = self._test_get_object(self.deduction, url)

@ -52,7 +52,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
modified_on = self.intervention.modified modified_on = self.intervention.modified
url = reverse("api:v1:intervention", args=(str(self.intervention.id),)) url = reverse("api:v1:intervention", args=(str(self.intervention.id),))
json_file_path = "api/tests/v1/update/intervention_update_put_body.json" json_file_path = "api/tests/v1/update/intervention_update_put_body.json"
@ -79,7 +79,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
""" """
self.compensation.intervention = self.intervention self.compensation.intervention = self.intervention
self.compensation.save() self.compensation.save()
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
modified_on = self.compensation.modified modified_on = self.compensation.modified
url = reverse("api:v1:compensation", args=(str(self.compensation.id),)) url = reverse("api:v1:compensation", args=(str(self.compensation.id),))
@ -108,7 +108,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.eco_account.share_with(self.superuser) self.eco_account.share_with_user(self.superuser)
modified_on = self.eco_account.modified modified_on = self.eco_account.modified
url = reverse("api:v1:ecoaccount", args=(str(self.eco_account.id),)) url = reverse("api:v1:ecoaccount", args=(str(self.eco_account.id),))
@ -139,7 +139,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.ema.share_with(self.superuser) self.ema.share_with_user(self.superuser)
modified_on = self.ema.modified modified_on = self.ema.modified
url = reverse("api:v1:ema", args=(str(self.ema.id),)) url = reverse("api:v1:ema", args=(str(self.ema.id),))
@ -168,8 +168,8 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
Returns: Returns:
""" """
self.deduction.intervention.share_with(self.superuser) self.deduction.intervention.share_with_user(self.superuser)
self.deduction.account.share_with(self.superuser) self.deduction.account.share_with_user(self.superuser)
url = reverse("api:v1:deduction", args=(str(self.deduction.id),)) url = reverse("api:v1:deduction", args=(str(self.deduction.id),))
json_file_path = "api/tests/v1/update/deduction_update_put_body.json" json_file_path = "api/tests/v1/update/deduction_update_put_body.json"

@ -292,7 +292,7 @@ class AbstractModelShareAPIView(AbstractAPIView):
id__in=obj.shared_users id__in=obj.shared_users
) )
new_users_objs = obj.shared_users.union(new_users_to_be_added) new_users_objs = obj.shared_users.union(new_users_to_be_added)
obj.share_with_list(new_users_objs) obj.share_with_user_list(new_users_objs)
return True return True

@ -400,7 +400,7 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
comment=comment, comment=comment,
legal=legal legal=legal
) )
acc.share_with(user) acc.share_with_user(user)
# Add the log entry to the main objects log list # Add the log entry to the main objects log list
acc.log.add(action) acc.log.add(action)

@ -103,7 +103,7 @@ class CompensationViewTestCase(BaseViewTestCase):
client = Client() client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([]) self.superuser.groups.set([])
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
# Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference # Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference
# to a user without access, since the important permissions are missing # to a user without access, since the important permissions are missing
@ -143,7 +143,7 @@ class CompensationViewTestCase(BaseViewTestCase):
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([]) self.superuser.groups.set([])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
# Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference # Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference
# to a user having shared access, since all important permissions are missing # to a user having shared access, since all important permissions are missing
@ -185,7 +185,7 @@ class CompensationViewTestCase(BaseViewTestCase):
group = self.groups.get(name=DEFAULT_GROUP) group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group]) self.superuser.groups.set([group])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -221,7 +221,7 @@ class CompensationViewTestCase(BaseViewTestCase):
group = self.groups.get(name=DEFAULT_GROUP) group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group]) self.superuser.groups.set([group])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,

@ -25,7 +25,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
super().setUp() super().setUp()
# Give the user shared access to the dummy intervention -> inherits the access to the compensation # Give the user shared access to the dummy intervention -> inherits the access to the compensation
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
# Make sure the intervention itself would be fine with valid data # Make sure the intervention itself would be fine with valid data
self.intervention = self.fill_out_intervention(self.intervention) self.intervention = self.fill_out_intervention(self.intervention)

@ -78,7 +78,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase):
client = Client() client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([]) self.superuser.groups.set([])
self.eco_account.share_with_list([self.superuser]) self.eco_account.share_with_user_list([self.superuser])
# Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference # Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference
# to a user without access, since the important permissions are missing # to a user without access, since the important permissions are missing
@ -119,7 +119,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase):
client = Client() client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([]) self.superuser.groups.set([])
self.eco_account.share_with_list([]) self.eco_account.share_with_user_list([])
# Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference # Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference
# to a user having shared access, since all important permissions are missing # to a user having shared access, since all important permissions are missing
@ -163,7 +163,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase):
group = self.groups.get(name=DEFAULT_GROUP) group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group]) self.superuser.groups.set([group])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.eco_account.share_with_list([self.superuser]) self.eco_account.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -200,7 +200,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase):
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
group = self.groups.get(name=DEFAULT_GROUP) group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group]) self.superuser.groups.set([group])
self.eco_account.share_with_list([]) self.eco_account.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,

@ -27,7 +27,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
# Add user to conservation office group and give shared access to the account # Add user to conservation office group and give shared access to the account
self.superuser.groups.add(self.groups.get(name=DEFAULT_GROUP)) self.superuser.groups.add(self.groups.get(name=DEFAULT_GROUP))
self.superuser.groups.add(self.groups.get(name=ETS_GROUP)) self.superuser.groups.add(self.groups.get(name=ETS_GROUP))
self.eco_account.share_with_list([self.superuser]) self.eco_account.share_with_user_list([self.superuser])
def test_new(self): def test_new(self):
""" Test the creation of an EcoAccount """ Test the creation of an EcoAccount
@ -73,7 +73,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
Returns: Returns:
""" """
self.eco_account.share_with(self.superuser) self.eco_account.share_with_user(self.superuser)
url = reverse("compensation:acc:edit", args=(self.eco_account.id,)) url = reverse("compensation:acc:edit", args=(self.eco_account.id,))
pre_edit_log_count = self.eco_account.log.count() pre_edit_log_count = self.eco_account.log.count()
@ -129,7 +129,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
""" """
# Add proper privilege for the user # Add proper privilege for the user
self.eco_account.share_with(self.superuser) self.eco_account.share_with_user(self.superuser)
pre_record_log_count = self.eco_account.log.count() pre_record_log_count = self.eco_account.log.count()
# Prepare url and form data # Prepare url and form data
@ -178,7 +178,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
""" """
# Give user shared access to the dummy intervention, which will be needed here # Give user shared access to the dummy intervention, which will be needed here
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
pre_deduction_acc_log_count = self.eco_account.log.count() pre_deduction_acc_log_count = self.eco_account.log.count()
pre_deduction_int_log_count = self.intervention.log.count() pre_deduction_int_log_count = self.intervention.log.count()
@ -231,7 +231,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
def test_edit_deduction(self): def test_edit_deduction(self):
test_surface = self.eco_account.get_available_rest()[0] test_surface = self.eco_account.get_available_rest()[0]
self.eco_account.set_recorded(self.superuser) self.eco_account.set_recorded(self.superuser)
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
self.eco_account.refresh_from_db() self.eco_account.refresh_from_db()
self.assertIn(self.superuser, self.intervention.is_shared_with(self.superuser)) self.assertIn(self.superuser, self.intervention.is_shared_with(self.superuser))
@ -281,8 +281,8 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
"confirm": True, "confirm": True,
} }
intervention.share_with(self.superuser) intervention.share_with_user(self.superuser)
account.share_with(self.superuser) account.share_with_user(self.superuser)
pre_edit_intervention_log_count = intervention.log.count() pre_edit_intervention_log_count = intervention.log.count()
pre_edit_account_log_count = account.log.count() pre_edit_account_log_count = account.log.count()

@ -64,7 +64,7 @@ class PaymentViewTestCase(BaseViewTestCase):
client = Client() client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([]) self.superuser.groups.set([])
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
# Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference # Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference
# to a user without access, since the important permissions are missing # to a user without access, since the important permissions are missing
@ -91,7 +91,7 @@ class PaymentViewTestCase(BaseViewTestCase):
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([]) self.superuser.groups.set([])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
# Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference # Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference
# to a user having shared access, since all important permissions are missing # to a user having shared access, since all important permissions are missing
@ -120,7 +120,7 @@ class PaymentViewTestCase(BaseViewTestCase):
group = self.groups.get(name=DEFAULT_GROUP) group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group]) self.superuser.groups.set([group])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.new_url, self.new_url,
@ -143,7 +143,7 @@ class PaymentViewTestCase(BaseViewTestCase):
group = self.groups.get(name=DEFAULT_GROUP) group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group]) self.superuser.groups.set([group])
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
success_urls = [ success_urls = [
] ]

@ -21,7 +21,7 @@ class PaymentWorkflowTestCase(BaseWorkflowTestCase):
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() super().setUp()
# Give the user shared access to the dummy intervention # Give the user shared access to the dummy intervention
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
self.payment = Payment.objects.get_or_create( self.payment = Payment.objects.get_or_create(
intervention=self.intervention, intervention=self.intervention,

@ -796,7 +796,7 @@ def share_view(request: HttpRequest, id: str, token: str):
request, request,
_("{} has been shared with you").format(obj.identifier) _("{} has been shared with you").format(obj.identifier)
) )
obj.share_with(user) obj.share_with_user(user)
return redirect("compensation:acc:detail", id=id) return redirect("compensation:acc:detail", id=id)
else: else:
messages.error( messages.error(

@ -80,7 +80,7 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin):
) )
# Add the creating user to the list of shared users # Add the creating user to the list of shared users
acc.share_with(user) acc.share_with_user(user)
# Add the log entry to the main objects log list # Add the log entry to the main objects log list
acc.log.add(action) acc.log.add(action)

@ -110,7 +110,7 @@ class EmaViewTestCase(CompensationViewTestCase):
# Sharing does not have any effect in here, since the default group will prohibit further functionality access # Sharing does not have any effect in here, since the default group will prohibit further functionality access
# to this user # to this user
self.ema.share_with_list([self.superuser]) self.ema.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -160,7 +160,7 @@ class EmaViewTestCase(CompensationViewTestCase):
# Sharing does not have any effect in here, since the default group will prohibit further functionality access # Sharing does not have any effect in here, since the default group will prohibit further functionality access
# to this user # to this user
self.ema.share_with_list([]) self.ema.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -203,7 +203,7 @@ class EmaViewTestCase(CompensationViewTestCase):
groups = self.groups.filter(Q(name=ETS_GROUP)|Q(name=DEFAULT_GROUP)) groups = self.groups.filter(Q(name=ETS_GROUP)|Q(name=DEFAULT_GROUP))
self.superuser.groups.set(groups) self.superuser.groups.set(groups)
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.ema.share_with_list([self.superuser]) self.ema.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -243,7 +243,7 @@ class EmaViewTestCase(CompensationViewTestCase):
groups = self.groups.filter(Q(name=ETS_GROUP)|Q(name=DEFAULT_GROUP)) groups = self.groups.filter(Q(name=ETS_GROUP)|Q(name=DEFAULT_GROUP))
self.superuser.groups.set(groups) self.superuser.groups.set(groups)
# Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state # Sharing is inherited by base intervention for compensation. Therefore configure the interventions share state
self.ema.share_with_list([]) self.ema.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,

@ -621,7 +621,7 @@ def share_view(request: HttpRequest, id: str, token: str):
request, request,
_("{} has been shared with you").format(obj.identifier) _("{} has been shared with you").format(obj.identifier)
) )
obj.share_with(user) obj.share_with_user(user)
return redirect("ema:detail", id=id) return redirect("ema:detail", id=id)
else: else:
messages.error( messages.error(

@ -253,7 +253,7 @@ class NewInterventionForm(BaseForm):
intervention.log.add(action) intervention.log.add(action)
# Add the performing user as the first user having access to the data # Add the performing user as the first user having access to the data
intervention.share_with(user) intervention.share_with_user(user)
return intervention return intervention

@ -115,7 +115,7 @@ class ShareModalForm(BaseModalForm):
def _add_teams_to_field(self): def _add_teams_to_field(self):
form_data = { form_data = {
"teams": [] "team_select": self.instance.teams.all()
} }
self.load_initial_data(form_data) self.load_initial_data(form_data)

@ -144,7 +144,7 @@ class InterventionViewTestCase(BaseViewTestCase):
# Add user to default group # Add user to default group
default_group = Group.objects.get(name=DEFAULT_GROUP) default_group = Group.objects.get(name=DEFAULT_GROUP)
self.superuser.groups.set([default_group]) self.superuser.groups.set([default_group])
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -190,7 +190,7 @@ class InterventionViewTestCase(BaseViewTestCase):
# Add user to default group # Add user to default group
default_group = Group.objects.get(name=DEFAULT_GROUP) default_group = Group.objects.get(name=DEFAULT_GROUP)
self.superuser.groups.set([default_group]) self.superuser.groups.set([default_group])
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -236,7 +236,7 @@ class InterventionViewTestCase(BaseViewTestCase):
# Add user to zb group # Add user to zb group
zb_group = self.groups.get(name=ZB_GROUP) zb_group = self.groups.get(name=ZB_GROUP)
self.superuser.groups.set([zb_group]) self.superuser.groups.set([zb_group])
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -282,7 +282,7 @@ class InterventionViewTestCase(BaseViewTestCase):
# Add user to zb group # Add user to zb group
zb_group = self.groups.get(name=ZB_GROUP) zb_group = self.groups.get(name=ZB_GROUP)
self.superuser.groups.set([zb_group]) self.superuser.groups.set([zb_group])
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -328,7 +328,7 @@ class InterventionViewTestCase(BaseViewTestCase):
# Add user to ets group # Add user to ets group
ets_group = Group.objects.get(name=ETS_GROUP) ets_group = Group.objects.get(name=ETS_GROUP)
self.superuser.groups.set([ets_group]) self.superuser.groups.set([ets_group])
self.intervention.share_with_list([self.superuser]) self.intervention.share_with_user_list([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -374,7 +374,7 @@ class InterventionViewTestCase(BaseViewTestCase):
# Add user to default group # Add user to default group
ets_group = Group.objects.get(name=ETS_GROUP) ets_group = Group.objects.get(name=ETS_GROUP)
self.superuser.groups.set([ets_group]) self.superuser.groups.set([ets_group])
self.intervention.share_with_list([]) self.intervention.share_with_user_list([])
success_urls = [ success_urls = [
self.index_url, self.index_url,

@ -30,7 +30,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
super().setUp() super().setUp()
# Recreate a new (bare minimum) intervention before each test # Recreate a new (bare minimum) intervention before each test
self.intervention = self.create_dummy_intervention() self.intervention = self.create_dummy_intervention()
self.intervention.share_with(self.superuser) self.intervention.share_with_user(self.superuser)
def test_new(self): def test_new(self):
""" """
@ -365,7 +365,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
if self.eco_account.recorded is None: if self.eco_account.recorded is None:
rec_action = UserActionLogEntry.get_recorded_action(self.superuser) rec_action = UserActionLogEntry.get_recorded_action(self.superuser)
self.eco_account.recorded = rec_action self.eco_account.recorded = rec_action
self.eco_account.share_with_list([self.superuser]) self.eco_account.share_with_user_list([self.superuser])
self.eco_account.save() self.eco_account.save()
num_all_deducs = EcoAccountDeduction.objects.count() num_all_deducs = EcoAccountDeduction.objects.count()

@ -432,7 +432,7 @@ def share_view(request: HttpRequest, id: str, token: str):
request, request,
_("{} has been shared with you").format(intervention.identifier) _("{} has been shared with you").format(intervention.identifier)
) )
intervention.share_with(user) intervention.share_with_user(user)
return redirect("intervention:detail", id=id) return redirect("intervention:detail", id=id)
else: else:
messages.error( messages.error(

@ -378,6 +378,7 @@ class CheckableObjectMixin(models.Model):
class ShareableObjectMixin(models.Model): class ShareableObjectMixin(models.Model):
# Users having access on this object # Users having access on this object
users = models.ManyToManyField("user.User", help_text="Users having access (data shared with)") users = models.ManyToManyField("user.User", help_text="Users having access (data shared with)")
teams = models.ManyToManyField("user.Team", help_text="Teams having access (data shared with)")
access_token = models.CharField( access_token = models.CharField(
max_length=255, max_length=255,
null=True, null=True,
@ -435,9 +436,36 @@ class ShareableObjectMixin(models.Model):
Returns: Returns:
""" """
return self.users.filter(id=user.id) directly_shared = self.users.filter(id=user.id).exists()
team_shared = self.teams.filter(
users__in=[user]
).exists()
is_shared = directly_shared or team_shared
return is_shared
def share_with(self, user): def share_with_team(self, team):
""" Adds team to list of shared access teans
Args:
team (Team): The team to be added to the object
Returns:
"""
self.teams.add(team)
def share_with_team_list(self, team_list: list):
""" Sets the list of shared access teams
Args:
team_list (list): The teams to be added to the object
Returns:
"""
self.teams.set(team_list)
def share_with_user(self, user):
""" Adds user to list of shared access users """ Adds user to list of shared access users
Args: Args:
@ -449,7 +477,7 @@ class ShareableObjectMixin(models.Model):
if not self.is_shared_with(user): if not self.is_shared_with(user):
self.users.add(user) self.users.add(user)
def share_with_list(self, user_list: list): def share_with_user_list(self, user_list: list):
""" Sets the list of shared access users """ Sets the list of shared access users
Args: Args:
@ -472,24 +500,32 @@ class ShareableObjectMixin(models.Model):
from user.models import User from user.models import User
form_data = form.cleaned_data form_data = form.cleaned_data
keep_accessing_users = form_data["users"] # Fetch selected teams and find out which user IDs are in removed teams -> mails need to be sent
accessing_teams = form_data["team_select"]
removed_team_users = self.teams.all().exclude(
id__in=accessing_teams
).values_list("users__id", flat=True)
new_accessing_users = list(form_data["user_select"].values_list("id", flat=True)) new_accessing_users = list(form_data["user_select"].values_list("id", flat=True))
keep_accessing_users = form_data["users"]
accessing_users = keep_accessing_users + new_accessing_users accessing_users = keep_accessing_users + new_accessing_users
users = User.objects.filter( users = User.objects.filter(
id__in=accessing_users id__in=accessing_users
) )
removed_users = self.users.all().exclude( removed_users = self.users.all().exclude(
id__in=accessing_users id__in=accessing_users
).values("id") ).values_list("id", flat=True)
removed_users = removed_users.union(removed_team_users)
# Send mails # Send mails
for user in removed_users: for user_id in removed_users:
celery_send_mail_shared_access_removed.delay(self.identifier, self.title, user["id"]) celery_send_mail_shared_access_removed.delay(self.identifier, self.title, user_id)
for user in new_accessing_users: for user_id in new_accessing_users:
celery_send_mail_shared_access_given.delay(self.identifier, self.title, user) celery_send_mail_shared_access_given.delay(self.identifier, self.title, user_id)
# Set new shared users # Set new shared users
self.share_with_list(users) self.share_with_user_list(users)
self.share_with_team_list(accessing_teams)
@property @property
def shared_users(self) -> QuerySet: def shared_users(self) -> QuerySet:

Binary file not shown.

@ -7,8 +7,8 @@
#: compensation/forms/modalForms.py:47 compensation/forms/modalForms.py:63 #: compensation/forms/modalForms.py:47 compensation/forms/modalForms.py:63
#: compensation/forms/modalForms.py:356 compensation/forms/modalForms.py:463 #: compensation/forms/modalForms.py:356 compensation/forms/modalForms.py:463
#: intervention/forms/forms.py:54 intervention/forms/forms.py:156 #: intervention/forms/forms.py:54 intervention/forms/forms.py:156
#: intervention/forms/forms.py:168 intervention/forms/modalForms.py:127 #: intervention/forms/forms.py:168 intervention/forms/modalForms.py:148
#: intervention/forms/modalForms.py:140 intervention/forms/modalForms.py:153 #: intervention/forms/modalForms.py:161 intervention/forms/modalForms.py:174
#: konova/filters/mixins.py:53 konova/filters/mixins.py:54 #: konova/filters/mixins.py:53 konova/filters/mixins.py:54
#: konova/filters/mixins.py:81 konova/filters/mixins.py:82 #: konova/filters/mixins.py:81 konova/filters/mixins.py:82
#: konova/filters/mixins.py:94 konova/filters/mixins.py:95 #: konova/filters/mixins.py:94 konova/filters/mixins.py:95
@ -26,7 +26,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-17 13:42+0100\n" "POT-Creation-Date: 2022-02-18 09:35+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -64,7 +64,7 @@ msgstr "Verantwortliche Stelle"
#: compensation/forms/forms.py:165 intervention/forms/forms.py:64 #: compensation/forms/forms.py:165 intervention/forms/forms.py:64
#: intervention/forms/forms.py:81 intervention/forms/forms.py:97 #: intervention/forms/forms.py:81 intervention/forms/forms.py:97
#: intervention/forms/forms.py:113 intervention/forms/modalForms.py:49 #: intervention/forms/forms.py:113 intervention/forms/modalForms.py:49
#: user/forms.py:196 #: intervention/forms/modalForms.py:63 user/forms.py:196
msgid "Click for selection" msgid "Click for selection"
msgstr "Auswählen..." msgstr "Auswählen..."
@ -221,7 +221,7 @@ msgstr "Abbuchungen"
#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:36 #: compensation/templates/compensation/detail/eco_account/includes/states-before.html:36
#: ema/templates/ema/detail/includes/states-after.html:36 #: ema/templates/ema/detail/includes/states-after.html:36
#: ema/templates/ema/detail/includes/states-before.html:36 #: ema/templates/ema/detail/includes/states-before.html:36
#: intervention/forms/modalForms.py:338 #: intervention/forms/modalForms.py:359
msgid "Surface" msgid "Surface"
msgstr "Fläche" msgstr "Fläche"
@ -284,8 +284,8 @@ msgid "Type"
msgstr "Typ" msgstr "Typ"
#: analysis/templates/analysis/reports/includes/old_data/amount.html:24 #: analysis/templates/analysis/reports/includes/old_data/amount.html:24
#: compensation/tables.py:89 intervention/forms/modalForms.py:349 #: compensation/tables.py:89 intervention/forms/modalForms.py:370
#: intervention/forms/modalForms.py:356 intervention/tables.py:88 #: intervention/forms/modalForms.py:377 intervention/tables.py:88
#: intervention/templates/intervention/detail/view.html:19 #: intervention/templates/intervention/detail/view.html:19
#: konova/templates/konova/includes/quickstart/interventions.html:4 #: konova/templates/konova/includes/quickstart/interventions.html:4
#: templates/navbars/navbar.html:22 #: templates/navbars/navbar.html:22
@ -295,7 +295,7 @@ msgstr "Eingriff"
#: analysis/templates/analysis/reports/includes/old_data/amount.html:34 #: analysis/templates/analysis/reports/includes/old_data/amount.html:34
#: compensation/tables.py:266 #: compensation/tables.py:266
#: compensation/templates/compensation/detail/eco_account/view.html:20 #: compensation/templates/compensation/detail/eco_account/view.html:20
#: intervention/forms/modalForms.py:322 intervention/forms/modalForms.py:329 #: intervention/forms/modalForms.py:343 intervention/forms/modalForms.py:350
#: konova/templates/konova/includes/quickstart/ecoaccounts.html:4 #: konova/templates/konova/includes/quickstart/ecoaccounts.html:4
#: templates/navbars/navbar.html:34 #: templates/navbars/navbar.html:34
msgid "Eco-account" msgid "Eco-account"
@ -364,7 +364,7 @@ msgstr "Kompensation XY; Flur ABC"
#: ema/templates/ema/detail/includes/actions.html:34 #: ema/templates/ema/detail/includes/actions.html:34
#: ema/templates/ema/detail/includes/deadlines.html:34 #: ema/templates/ema/detail/includes/deadlines.html:34
#: ema/templates/ema/detail/includes/documents.html:34 #: ema/templates/ema/detail/includes/documents.html:34
#: intervention/forms/forms.py:180 intervention/forms/modalForms.py:152 #: intervention/forms/forms.py:180 intervention/forms/modalForms.py:173
#: intervention/templates/intervention/detail/includes/documents.html:34 #: intervention/templates/intervention/detail/includes/documents.html:34
#: intervention/templates/intervention/detail/includes/payments.html:34 #: intervention/templates/intervention/detail/includes/payments.html:34
#: intervention/templates/intervention/detail/includes/revocation.html:38 #: intervention/templates/intervention/detail/includes/revocation.html:38
@ -484,7 +484,7 @@ msgid "Due on which date"
msgstr "Zahlung wird an diesem Datum erwartet" msgstr "Zahlung wird an diesem Datum erwartet"
#: compensation/forms/modalForms.py:64 compensation/forms/modalForms.py:357 #: compensation/forms/modalForms.py:64 compensation/forms/modalForms.py:357
#: intervention/forms/modalForms.py:154 konova/forms.py:395 #: intervention/forms/modalForms.py:175 konova/forms.py:395
msgid "Additional comment, maximum {} letters" msgid "Additional comment, maximum {} letters"
msgstr "Zusätzlicher Kommentar, maximal {} Zeichen" msgstr "Zusätzlicher Kommentar, maximal {} Zeichen"
@ -512,7 +512,7 @@ msgstr "Zusatzbezeichnung"
msgid "Select an additional biotope type" msgid "Select an additional biotope type"
msgstr "Zusatzbezeichnung wählen" msgstr "Zusatzbezeichnung wählen"
#: compensation/forms/modalForms.py:197 intervention/forms/modalForms.py:340 #: compensation/forms/modalForms.py:197 intervention/forms/modalForms.py:361
msgid "in m²" msgid "in m²"
msgstr "" msgstr ""
@ -540,7 +540,7 @@ msgstr "Fristart wählen"
#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:31 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:31
#: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:31 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:31
#: ema/templates/ema/detail/includes/deadlines.html:31 #: ema/templates/ema/detail/includes/deadlines.html:31
#: intervention/forms/modalForms.py:126 #: intervention/forms/modalForms.py:147
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
@ -752,7 +752,7 @@ msgstr "Menge"
#: intervention/templates/intervention/detail/includes/documents.html:39 #: intervention/templates/intervention/detail/includes/documents.html:39
#: intervention/templates/intervention/detail/includes/payments.html:39 #: intervention/templates/intervention/detail/includes/payments.html:39
#: intervention/templates/intervention/detail/includes/revocation.html:43 #: intervention/templates/intervention/detail/includes/revocation.html:43
#: templates/log.html:10 user/templates/user/team/index.html:33 #: templates/log.html:10 user/templates/user/team/index.html:32
msgid "Action" msgid "Action"
msgstr "Aktionen" msgstr "Aktionen"
@ -1000,14 +1000,14 @@ msgstr "Zuletzt bearbeitet"
#: compensation/templates/compensation/detail/compensation/view.html:100 #: compensation/templates/compensation/detail/compensation/view.html:100
#: compensation/templates/compensation/detail/eco_account/view.html:83 #: compensation/templates/compensation/detail/eco_account/view.html:83
#: ema/templates/ema/detail/view.html:76 intervention/forms/modalForms.py:56 #: ema/templates/ema/detail/view.html:76 intervention/forms/modalForms.py:70
#: intervention/templates/intervention/detail/view.html:116 #: intervention/templates/intervention/detail/view.html:116
msgid "Shared with" msgid "Shared with"
msgstr "Freigegeben für" msgstr "Freigegeben für"
#: compensation/templates/compensation/detail/eco_account/includes/controls.html:15 #: compensation/templates/compensation/detail/eco_account/includes/controls.html:15
#: ema/templates/ema/detail/includes/controls.html:15 #: ema/templates/ema/detail/includes/controls.html:15
#: intervention/forms/modalForms.py:70 #: intervention/forms/modalForms.py:84
#: intervention/templates/intervention/detail/includes/controls.html:15 #: intervention/templates/intervention/detail/includes/controls.html:15
msgid "Share" msgid "Share"
msgstr "Freigabe" msgstr "Freigabe"
@ -1325,10 +1325,22 @@ msgid "Send this link to users who you want to have writing access on the data"
msgstr "Andere Nutzer erhalten über diesen Link Zugriff auf die Daten" msgstr "Andere Nutzer erhalten über diesen Link Zugriff auf die Daten"
#: intervention/forms/modalForms.py:41 #: intervention/forms/modalForms.py:41
msgid "Add team to share with"
msgstr "Team hinzufügen"
#: intervention/forms/modalForms.py:43
msgid ""
"Multiple selection possible - You can only select teams which do not already "
"have access."
msgstr ""
"Mehrfachauswahl möglich - Sie können nur Teams wählen, für die der Eintrag "
"noch nicht freigegeben wurde."
#: intervention/forms/modalForms.py:55
msgid "Add user to share with" msgid "Add user to share with"
msgstr "Nutzer direkt hinzufügen" msgstr "Nutzer direkt hinzufügen"
#: intervention/forms/modalForms.py:43 #: intervention/forms/modalForms.py:57
msgid "" msgid ""
"Multiple selection possible - You can only select users which do not already " "Multiple selection possible - You can only select users which do not already "
"have access. Enter the full username." "have access. Enter the full username."
@ -1336,46 +1348,46 @@ msgstr ""
"Mehrfachauswahl möglich - Sie können nur Nutzer wählen, für die der Eintrag " "Mehrfachauswahl möglich - Sie können nur Nutzer wählen, für die der Eintrag "
"noch nicht freigegeben wurde. Geben Sie den ganzen Nutzernamen an." "noch nicht freigegeben wurde. Geben Sie den ganzen Nutzernamen an."
#: intervention/forms/modalForms.py:59 #: intervention/forms/modalForms.py:73
msgid "Remove check to remove access for this user" msgid "Remove check to remove access for this user"
msgstr "Wählen Sie die Nutzer ab, die keinen Zugriff mehr haben sollen" msgstr "Wählen Sie die Nutzer ab, die keinen Zugriff mehr haben sollen"
#: intervention/forms/modalForms.py:71 #: intervention/forms/modalForms.py:85
msgid "Share settings for {}" msgid "Share settings for {}"
msgstr "Freigabe Einstellungen für {}" msgstr "Freigabe Einstellungen für {}"
#: intervention/forms/modalForms.py:128 #: intervention/forms/modalForms.py:149
msgid "Date of revocation" msgid "Date of revocation"
msgstr "Datum des Widerspruchs" msgstr "Datum des Widerspruchs"
#: intervention/forms/modalForms.py:139 #: intervention/forms/modalForms.py:160
#: intervention/templates/intervention/detail/includes/revocation.html:35 #: intervention/templates/intervention/detail/includes/revocation.html:35
msgid "Document" msgid "Document"
msgstr "Dokument" msgstr "Dokument"
#: intervention/forms/modalForms.py:142 #: intervention/forms/modalForms.py:163
msgid "Must be smaller than 15 Mb" msgid "Must be smaller than 15 Mb"
msgstr "Muss kleiner als 15 Mb sein" msgstr "Muss kleiner als 15 Mb sein"
#: intervention/forms/modalForms.py:167 #: intervention/forms/modalForms.py:188
#: intervention/templates/intervention/detail/includes/revocation.html:18 #: intervention/templates/intervention/detail/includes/revocation.html:18
msgid "Add revocation" msgid "Add revocation"
msgstr "Widerspruch hinzufügen" msgstr "Widerspruch hinzufügen"
#: intervention/forms/modalForms.py:224 #: intervention/forms/modalForms.py:245
msgid "Checked intervention data" msgid "Checked intervention data"
msgstr "Eingriffsdaten geprüft" msgstr "Eingriffsdaten geprüft"
#: intervention/forms/modalForms.py:230 #: intervention/forms/modalForms.py:251
msgid "Checked compensations data and payments" msgid "Checked compensations data and payments"
msgstr "Kompensationen und Zahlungen geprüft" msgstr "Kompensationen und Zahlungen geprüft"
#: intervention/forms/modalForms.py:239 #: intervention/forms/modalForms.py:260
#: intervention/templates/intervention/detail/includes/controls.html:19 #: intervention/templates/intervention/detail/includes/controls.html:19
msgid "Run check" msgid "Run check"
msgstr "Prüfung vornehmen" msgstr "Prüfung vornehmen"
#: intervention/forms/modalForms.py:240 konova/forms.py:514 #: intervention/forms/modalForms.py:261 konova/forms.py:514
msgid "" msgid ""
"I, {} {}, confirm that all necessary control steps have been performed by " "I, {} {}, confirm that all necessary control steps have been performed by "
"myself." "myself."
@ -1383,23 +1395,23 @@ msgstr ""
"Ich, {} {}, bestätige, dass die notwendigen Kontrollschritte durchgeführt " "Ich, {} {}, bestätige, dass die notwendigen Kontrollschritte durchgeführt "
"wurden:" "wurden:"
#: intervention/forms/modalForms.py:324 #: intervention/forms/modalForms.py:345
msgid "Only recorded accounts can be selected for deductions" msgid "Only recorded accounts can be selected for deductions"
msgstr "Nur verzeichnete Ökokonten können für Abbuchungen verwendet werden." msgstr "Nur verzeichnete Ökokonten können für Abbuchungen verwendet werden."
#: intervention/forms/modalForms.py:351 #: intervention/forms/modalForms.py:372
msgid "Only shared interventions can be selected" msgid "Only shared interventions can be selected"
msgstr "Nur freigegebene Eingriffe können gewählt werden" msgstr "Nur freigegebene Eingriffe können gewählt werden"
#: intervention/forms/modalForms.py:364 #: intervention/forms/modalForms.py:385
msgid "New Deduction" msgid "New Deduction"
msgstr "Neue Abbuchung" msgstr "Neue Abbuchung"
#: intervention/forms/modalForms.py:365 #: intervention/forms/modalForms.py:386
msgid "Enter the information for a new deduction from a chosen eco-account" msgid "Enter the information for a new deduction from a chosen eco-account"
msgstr "Geben Sie die Informationen für eine neue Abbuchung ein." msgstr "Geben Sie die Informationen für eine neue Abbuchung ein."
#: intervention/forms/modalForms.py:408 #: intervention/forms/modalForms.py:429
msgid "" msgid ""
"Eco-account {} is not recorded yet. You can only deduct from recorded " "Eco-account {} is not recorded yet. You can only deduct from recorded "
"accounts." "accounts."
@ -1407,7 +1419,7 @@ msgstr ""
"Ökokonto {} ist noch nicht verzeichnet. Abbuchungen können nur von " "Ökokonto {} ist noch nicht verzeichnet. Abbuchungen können nur von "
"verzeichneten Ökokonten erfolgen." "verzeichneten Ökokonten erfolgen."
#: intervention/forms/modalForms.py:418 #: intervention/forms/modalForms.py:439
msgid "" msgid ""
"The account {} has not enough surface for a deduction of {} m². There are " "The account {} has not enough surface for a deduction of {} m². There are "
"only {} m² left" "only {} m² left"
@ -2273,7 +2285,7 @@ msgstr "* sind Pflichtfelder."
msgid "New entry" msgid "New entry"
msgstr "Neuer Eintrag" msgstr "Neuer Eintrag"
#: templates/generic_index.html:41 user/templates/user/team/index.html:23 #: templates/generic_index.html:41 user/templates/user/team/index.html:22
msgid "New" msgid "New"
msgstr "Neu" msgstr "Neu"
@ -2406,7 +2418,7 @@ msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
msgid "Team name" msgid "Team name"
msgstr "Team Name" msgstr "Team Name"
#: user/forms.py:179 user/templates/user/team/index.html:31 #: user/forms.py:179 user/templates/user/team/index.html:30
msgid "Description" msgid "Description"
msgstr "Beschreibung" msgstr "Beschreibung"
@ -2434,19 +2446,23 @@ msgstr ""
"Sie werden standardmäßig der Administrator dieses Teams. Sie müssen sich " "Sie werden standardmäßig der Administrator dieses Teams. Sie müssen sich "
"selbst nicht zur Liste der Mitglieder hinzufügen." "selbst nicht zur Liste der Mitglieder hinzufügen."
#: user/forms.py:230 #: user/forms.py:218 user/forms.py:279
msgid "Name already taken. Try another."
msgstr "Name bereits vergeben. Probieren Sie einen anderen."
#: user/forms.py:249
msgid "Admin" msgid "Admin"
msgstr "Administrator" msgstr "Administrator"
#: user/forms.py:231 #: user/forms.py:250
msgid "Administrators manage team details and members" msgid "Administrators manage team details and members"
msgstr "Administratoren verwalten die Teamdaten und Mitglieder" msgstr "Administratoren verwalten die Teamdaten und Mitglieder"
#: user/forms.py:244 #: user/forms.py:263
msgid "Selected admin ({}) needs to be a member of this team." msgid "Selected admin ({}) needs to be a member of this team."
msgstr "Gewählter Administrator ({}) muss ein Mitglied des Teams sein." msgstr "Gewählter Administrator ({}) muss ein Mitglied des Teams sein."
#: user/forms.py:256 user/templates/user/team/index.html:52 #: user/forms.py:291 user/templates/user/team/index.html:51
msgid "Edit team" msgid "Edit team"
msgstr "Team bearbeiten" msgstr "Team bearbeiten"
@ -2466,7 +2482,7 @@ msgstr "Gelöscht"
msgid "Show contact data" msgid "Show contact data"
msgstr "Zeige Kontaktdaten" msgstr "Zeige Kontaktdaten"
#: user/templates/user/index.html:13 user/templates/user/team/index.html:30 #: user/templates/user/index.html:13 user/templates/user/team/index.html:29
msgid "Name" msgid "Name"
msgstr "" msgstr ""
@ -2515,20 +2531,20 @@ msgstr ""
msgid "Manage teams" msgid "Manage teams"
msgstr "" msgstr ""
#: user/templates/user/index.html:69 user/templates/user/team/index.html:19 #: user/templates/user/index.html:69 user/templates/user/team/index.html:18
#: user/views.py:142 #: user/views.py:142
msgid "Teams" msgid "Teams"
msgstr "" msgstr ""
#: user/templates/user/team/index.html:21 #: user/templates/user/team/index.html:20
msgid "Add new team" msgid "Add new team"
msgstr "Neues Team hinzufügen" msgstr "Neues Team hinzufügen"
#: user/templates/user/team/index.html:32 #: user/templates/user/team/index.html:31
msgid "Members" msgid "Members"
msgstr "Mitglieder" msgstr "Mitglieder"
#: user/templates/user/team/index.html:55 #: user/templates/user/team/index.html:54
msgid "Remove team" msgid "Remove team"
msgstr "Team entfernen" msgstr "Team entfernen"

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from user.models import UserNotification, UserActionLogEntry, User from user.models import UserNotification, UserActionLogEntry, User, Team
class UserNotificationAdmin(admin.ModelAdmin): class UserNotificationAdmin(admin.ModelAdmin):
@ -64,7 +64,20 @@ class UserActionLogEntryAdmin(admin.ModelAdmin):
] ]
class TeamAdmin(admin.ModelAdmin):
list_display = [
"name",
"description",
"admin",
]
search_fields = [
"name",
"description",
]
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
admin.site.register(Team, TeamAdmin)
# Outcommented for a cleaner admin backend on production # Outcommented for a cleaner admin backend on production
#admin.site.register(UserNotification, UserNotificationAdmin) #admin.site.register(UserNotification, UserNotificationAdmin)

@ -206,6 +206,25 @@ class NewTeamModalForm(BaseModalForm):
self.action_url = reverse("user:team-new") self.action_url = reverse("user:team-new")
self.cancel_redirect = reverse("user:team-index") self.cancel_redirect = reverse("user:team-index")
def _is_name_valid(self):
name = self.cleaned_data.get("name", None)
teams_with_same_name = Team.objects.filter(
name=name
)
name_valid = not teams_with_same_name.exists()
if not name_valid:
self.add_error(
"name",
_("Name already taken. Try another.")
)
return name_valid
def is_valid(self):
super_valid = super().is_valid()
name_valid = self._is_name_valid()
return super_valid and name_valid
def save(self): def save(self):
with transaction.atomic(): with transaction.atomic():
team = Team.objects.create( team = Team.objects.create(
@ -246,6 +265,22 @@ class EditTeamModalForm(NewTeamModalForm):
return _is_valid return _is_valid
def _is_name_valid(self):
name = self.cleaned_data.get("name", None)
teams_with_same_name = Team.objects.filter(
name=name
).exclude(
id=self.instance.id
)
name_valid = not teams_with_same_name.exists()
if not name_valid:
self.add_error(
"name",
_("Name already taken. Try another.")
)
return name_valid
def is_valid(self): def is_valid(self):
super_valid = super().is_valid() super_valid = super().is_valid()
admin_valid = self.__is_admin_valid() admin_valid = self.__is_admin_valid()

Loading…
Cancel
Save