diff --git a/api/tests/v1/create/test_api_create.py b/api/tests/v1/create/test_api_create.py index 72ece979..51a82e72 100644 --- a/api/tests/v1/create/test_api_create.py +++ b/api/tests/v1/create/test_api_create.py @@ -109,8 +109,8 @@ class APIV1CreateTestCase(BaseAPIV1TestCase): Returns: """ - self.intervention.share_with(self.superuser) - self.eco_account.share_with(self.superuser) + self.intervention.share_with_user(self.superuser) + self.eco_account.share_with_user(self.superuser) url = reverse("api:v1:deduction") json_file_path = "api/tests/v1/create/deduction_create_post_body.json" diff --git a/api/tests/v1/delete/test_api_delete.py b/api/tests/v1/delete/test_api_delete.py index cd016cfa..350fdf26 100644 --- a/api/tests/v1/delete/test_api_delete.py +++ b/api/tests/v1/delete/test_api_delete.py @@ -57,7 +57,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase): """ 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),)) self._test_delete_object(test_intervention, url) @@ -68,7 +68,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase): """ 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),)) self._test_delete_object(test_comp, url) @@ -79,7 +79,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase): """ 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),)) self._test_delete_object(test_acc, url) @@ -90,7 +90,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase): """ 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),)) self._test_delete_object(test_ema, url) @@ -101,7 +101,7 @@ class APIV1DeleteTestCase(BaseAPIV1TestCase): """ 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),)) response = self._run_delete_request(url) diff --git a/api/tests/v1/get/test_api_get.py b/api/tests/v1/get/test_api_get.py index 3c464542..5bfd67a1 100644 --- a/api/tests/v1/get/test_api_get.py +++ b/api/tests/v1/get/test_api_get.py @@ -64,7 +64,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase): Returns: """ - self.intervention.share_with(self.superuser) + self.intervention.share_with_user(self.superuser) url = reverse("api:v1:intervention", args=(str(self.intervention.id),)) geojson = self._test_get_object(self.intervention, url) self._assert_geojson_format(geojson) @@ -91,7 +91,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase): Returns: """ - self.intervention.share_with(self.superuser) + self.intervention.share_with_user(self.superuser) self.compensation.intervention = self.intervention self.compensation.save() @@ -119,7 +119,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase): 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),)) geojson = self._test_get_object(self.eco_account, url) @@ -148,7 +148,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase): Returns: """ - self.ema.share_with(self.superuser) + self.ema.share_with_user(self.superuser) url = reverse("api:v1:ema", args=(str(self.ema.id),)) geojson = self._test_get_object(self.ema, url) @@ -172,7 +172,7 @@ class APIV1GetTestCase(BaseAPIV1TestCase): 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),)) _json = self._test_get_object(self.deduction, url) diff --git a/api/tests/v1/update/test_api_update.py b/api/tests/v1/update/test_api_update.py index e371188c..8689fbe3 100644 --- a/api/tests/v1/update/test_api_update.py +++ b/api/tests/v1/update/test_api_update.py @@ -52,7 +52,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase): Returns: """ - self.intervention.share_with(self.superuser) + self.intervention.share_with_user(self.superuser) modified_on = self.intervention.modified url = reverse("api:v1:intervention", args=(str(self.intervention.id),)) 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.save() - self.intervention.share_with(self.superuser) + self.intervention.share_with_user(self.superuser) modified_on = self.compensation.modified url = reverse("api:v1:compensation", args=(str(self.compensation.id),)) @@ -108,7 +108,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase): Returns: """ - self.eco_account.share_with(self.superuser) + self.eco_account.share_with_user(self.superuser) modified_on = self.eco_account.modified url = reverse("api:v1:ecoaccount", args=(str(self.eco_account.id),)) @@ -139,7 +139,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase): Returns: """ - self.ema.share_with(self.superuser) + self.ema.share_with_user(self.superuser) modified_on = self.ema.modified url = reverse("api:v1:ema", args=(str(self.ema.id),)) @@ -168,8 +168,8 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase): Returns: """ - self.deduction.intervention.share_with(self.superuser) - self.deduction.account.share_with(self.superuser) + self.deduction.intervention.share_with_user(self.superuser) + self.deduction.account.share_with_user(self.superuser) url = reverse("api:v1:deduction", args=(str(self.deduction.id),)) json_file_path = "api/tests/v1/update/deduction_update_put_body.json" diff --git a/api/views/views.py b/api/views/views.py index 35c54fee..db8b8f9e 100644 --- a/api/views/views.py +++ b/api/views/views.py @@ -292,7 +292,7 @@ class AbstractModelShareAPIView(AbstractAPIView): id__in=obj.shared_users ) 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 diff --git a/compensation/forms/forms.py b/compensation/forms/forms.py index 72b1a714..46b235fa 100644 --- a/compensation/forms/forms.py +++ b/compensation/forms/forms.py @@ -400,7 +400,7 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix comment=comment, legal=legal ) - acc.share_with(user) + acc.share_with_user(user) # Add the log entry to the main objects log list acc.log.add(action) diff --git a/compensation/tests/compensation/test_views.py b/compensation/tests/compensation/test_views.py index 27218f2a..1174895c 100644 --- a/compensation/tests/compensation/test_views.py +++ b/compensation/tests/compensation/test_views.py @@ -103,7 +103,7 @@ class CompensationViewTestCase(BaseViewTestCase): client = Client() client.login(username=self.superuser.username, password=self.superuser_pw) 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 # 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) self.superuser.groups.set([]) # 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 # 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) self.superuser.groups.set([group]) # 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 = [ self.index_url, @@ -221,7 +221,7 @@ class CompensationViewTestCase(BaseViewTestCase): group = self.groups.get(name=DEFAULT_GROUP) self.superuser.groups.set([group]) # 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 = [ self.index_url, diff --git a/compensation/tests/compensation/test_workflow.py b/compensation/tests/compensation/test_workflow.py index 7b73be89..5b7decff 100644 --- a/compensation/tests/compensation/test_workflow.py +++ b/compensation/tests/compensation/test_workflow.py @@ -25,7 +25,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase): super().setUp() # 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 self.intervention = self.fill_out_intervention(self.intervention) diff --git a/compensation/tests/ecoaccount/test_views.py b/compensation/tests/ecoaccount/test_views.py index 617f7437..aaa7a4c8 100644 --- a/compensation/tests/ecoaccount/test_views.py +++ b/compensation/tests/ecoaccount/test_views.py @@ -78,7 +78,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase): client = Client() client.login(username=self.superuser.username, password=self.superuser_pw) 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 # to a user without access, since the important permissions are missing @@ -119,7 +119,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase): client = Client() client.login(username=self.superuser.username, password=self.superuser_pw) 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 # 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) self.superuser.groups.set([group]) # 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 = [ self.index_url, @@ -200,7 +200,7 @@ class EcoAccountViewTestCase(CompensationViewTestCase): client.login(username=self.superuser.username, password=self.superuser_pw) group = self.groups.get(name=DEFAULT_GROUP) self.superuser.groups.set([group]) - self.eco_account.share_with_list([]) + self.eco_account.share_with_user_list([]) success_urls = [ self.index_url, diff --git a/compensation/tests/ecoaccount/test_workflow.py b/compensation/tests/ecoaccount/test_workflow.py index afc4111e..1b350e9b 100644 --- a/compensation/tests/ecoaccount/test_workflow.py +++ b/compensation/tests/ecoaccount/test_workflow.py @@ -27,7 +27,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): # 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=ETS_GROUP)) - self.eco_account.share_with_list([self.superuser]) + self.eco_account.share_with_user_list([self.superuser]) def test_new(self): """ Test the creation of an EcoAccount @@ -73,7 +73,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): 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,)) pre_edit_log_count = self.eco_account.log.count() @@ -129,7 +129,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): """ # 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() # 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 - 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_int_log_count = self.intervention.log.count() @@ -231,7 +231,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): def test_edit_deduction(self): test_surface = self.eco_account.get_available_rest()[0] 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.assertIn(self.superuser, self.intervention.is_shared_with(self.superuser)) @@ -281,8 +281,8 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): "confirm": True, } - intervention.share_with(self.superuser) - account.share_with(self.superuser) + intervention.share_with_user(self.superuser) + account.share_with_user(self.superuser) pre_edit_intervention_log_count = intervention.log.count() pre_edit_account_log_count = account.log.count() diff --git a/compensation/tests/payment/test_views.py b/compensation/tests/payment/test_views.py index b1eca5ae..30ffa000 100644 --- a/compensation/tests/payment/test_views.py +++ b/compensation/tests/payment/test_views.py @@ -64,7 +64,7 @@ class PaymentViewTestCase(BaseViewTestCase): client = Client() client.login(username=self.superuser.username, password=self.superuser_pw) 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 # 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) self.superuser.groups.set([]) # 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 # 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) self.superuser.groups.set([group]) # 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 = [ self.new_url, @@ -143,7 +143,7 @@ class PaymentViewTestCase(BaseViewTestCase): group = self.groups.get(name=DEFAULT_GROUP) self.superuser.groups.set([group]) # 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 = [ ] diff --git a/compensation/tests/payment/test_workflow.py b/compensation/tests/payment/test_workflow.py index 790fb619..81259b80 100644 --- a/compensation/tests/payment/test_workflow.py +++ b/compensation/tests/payment/test_workflow.py @@ -21,7 +21,7 @@ class PaymentWorkflowTestCase(BaseWorkflowTestCase): def setUp(self) -> None: super().setUp() # 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( intervention=self.intervention, diff --git a/compensation/views/eco_account.py b/compensation/views/eco_account.py index d291218f..85b13714 100644 --- a/compensation/views/eco_account.py +++ b/compensation/views/eco_account.py @@ -796,7 +796,7 @@ def share_view(request: HttpRequest, id: str, token: str): request, _("{} has been shared with you").format(obj.identifier) ) - obj.share_with(user) + obj.share_with_user(user) return redirect("compensation:acc:detail", id=id) else: messages.error( diff --git a/ema/forms.py b/ema/forms.py index 2f193605..8e6faab7 100644 --- a/ema/forms.py +++ b/ema/forms.py @@ -80,7 +80,7 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin): ) # 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 acc.log.add(action) diff --git a/ema/tests/test_views.py b/ema/tests/test_views.py index 9654e8f3..b2c23e11 100644 --- a/ema/tests/test_views.py +++ b/ema/tests/test_views.py @@ -110,7 +110,7 @@ class EmaViewTestCase(CompensationViewTestCase): # Sharing does not have any effect in here, since the default group will prohibit further functionality access # to this user - self.ema.share_with_list([self.superuser]) + self.ema.share_with_user_list([self.superuser]) success_urls = [ 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 # to this user - self.ema.share_with_list([]) + self.ema.share_with_user_list([]) success_urls = [ self.index_url, @@ -203,7 +203,7 @@ class EmaViewTestCase(CompensationViewTestCase): groups = self.groups.filter(Q(name=ETS_GROUP)|Q(name=DEFAULT_GROUP)) self.superuser.groups.set(groups) # 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 = [ self.index_url, @@ -243,7 +243,7 @@ class EmaViewTestCase(CompensationViewTestCase): groups = self.groups.filter(Q(name=ETS_GROUP)|Q(name=DEFAULT_GROUP)) self.superuser.groups.set(groups) # 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 = [ self.index_url, diff --git a/ema/views.py b/ema/views.py index e9d0acb6..c145511f 100644 --- a/ema/views.py +++ b/ema/views.py @@ -621,7 +621,7 @@ def share_view(request: HttpRequest, id: str, token: str): request, _("{} has been shared with you").format(obj.identifier) ) - obj.share_with(user) + obj.share_with_user(user) return redirect("ema:detail", id=id) else: messages.error( diff --git a/intervention/forms/forms.py b/intervention/forms/forms.py index 1c5cf1c6..94ff9704 100644 --- a/intervention/forms/forms.py +++ b/intervention/forms/forms.py @@ -253,7 +253,7 @@ class NewInterventionForm(BaseForm): intervention.log.add(action) # Add the performing user as the first user having access to the data - intervention.share_with(user) + intervention.share_with_user(user) return intervention diff --git a/intervention/forms/modalForms.py b/intervention/forms/modalForms.py index 978360da..8e44ac2e 100644 --- a/intervention/forms/modalForms.py +++ b/intervention/forms/modalForms.py @@ -115,7 +115,7 @@ class ShareModalForm(BaseModalForm): def _add_teams_to_field(self): form_data = { - "teams": [] + "team_select": self.instance.teams.all() } self.load_initial_data(form_data) diff --git a/intervention/tests/test_views.py b/intervention/tests/test_views.py index f12ee7a3..a049f3e7 100644 --- a/intervention/tests/test_views.py +++ b/intervention/tests/test_views.py @@ -144,7 +144,7 @@ class InterventionViewTestCase(BaseViewTestCase): # Add user to default group default_group = Group.objects.get(name=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 = [ self.index_url, @@ -190,7 +190,7 @@ class InterventionViewTestCase(BaseViewTestCase): # Add user to default group default_group = Group.objects.get(name=DEFAULT_GROUP) self.superuser.groups.set([default_group]) - self.intervention.share_with_list([]) + self.intervention.share_with_user_list([]) success_urls = [ self.index_url, @@ -236,7 +236,7 @@ class InterventionViewTestCase(BaseViewTestCase): # Add user to zb group zb_group = self.groups.get(name=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 = [ self.index_url, @@ -282,7 +282,7 @@ class InterventionViewTestCase(BaseViewTestCase): # Add user to zb group zb_group = self.groups.get(name=ZB_GROUP) self.superuser.groups.set([zb_group]) - self.intervention.share_with_list([]) + self.intervention.share_with_user_list([]) success_urls = [ self.index_url, @@ -328,7 +328,7 @@ class InterventionViewTestCase(BaseViewTestCase): # Add user to ets group ets_group = Group.objects.get(name=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 = [ self.index_url, @@ -374,7 +374,7 @@ class InterventionViewTestCase(BaseViewTestCase): # Add user to default group ets_group = Group.objects.get(name=ETS_GROUP) self.superuser.groups.set([ets_group]) - self.intervention.share_with_list([]) + self.intervention.share_with_user_list([]) success_urls = [ self.index_url, diff --git a/intervention/tests/test_workflow.py b/intervention/tests/test_workflow.py index 1a66245c..c5290503 100644 --- a/intervention/tests/test_workflow.py +++ b/intervention/tests/test_workflow.py @@ -30,7 +30,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase): super().setUp() # Recreate a new (bare minimum) intervention before each test self.intervention = self.create_dummy_intervention() - self.intervention.share_with(self.superuser) + self.intervention.share_with_user(self.superuser) def test_new(self): """ @@ -365,7 +365,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase): if self.eco_account.recorded is None: rec_action = UserActionLogEntry.get_recorded_action(self.superuser) 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() num_all_deducs = EcoAccountDeduction.objects.count() diff --git a/intervention/views.py b/intervention/views.py index 00440bb8..3004a79f 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -432,7 +432,7 @@ def share_view(request: HttpRequest, id: str, token: str): request, _("{} has been shared with you").format(intervention.identifier) ) - intervention.share_with(user) + intervention.share_with_user(user) return redirect("intervention:detail", id=id) else: messages.error( diff --git a/konova/models/object.py b/konova/models/object.py index 69a0a2e7..e6c27a66 100644 --- a/konova/models/object.py +++ b/konova/models/object.py @@ -378,6 +378,7 @@ class CheckableObjectMixin(models.Model): class ShareableObjectMixin(models.Model): # Users having access on this object 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( max_length=255, null=True, @@ -435,9 +436,36 @@ class ShareableObjectMixin(models.Model): 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 Args: @@ -449,7 +477,7 @@ class ShareableObjectMixin(models.Model): if not self.is_shared_with(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 Args: @@ -472,24 +500,32 @@ class ShareableObjectMixin(models.Model): from user.models import User 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)) + keep_accessing_users = form_data["users"] accessing_users = keep_accessing_users + new_accessing_users users = User.objects.filter( id__in=accessing_users ) removed_users = self.users.all().exclude( id__in=accessing_users - ).values("id") + ).values_list("id", flat=True) + removed_users = removed_users.union(removed_team_users) # Send mails - for user in removed_users: - celery_send_mail_shared_access_removed.delay(self.identifier, self.title, user["id"]) - for user in new_accessing_users: - celery_send_mail_shared_access_given.delay(self.identifier, self.title, user) + for user_id in removed_users: + celery_send_mail_shared_access_removed.delay(self.identifier, self.title, user_id) + for user_id in new_accessing_users: + celery_send_mail_shared_access_given.delay(self.identifier, self.title, user_id) # Set new shared users - self.share_with_list(users) + self.share_with_user_list(users) + self.share_with_team_list(accessing_teams) @property def shared_users(self) -> QuerySet: diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index ca93bc88..a20ac2da 100644 Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index d1da918b..aba79815 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ #: compensation/forms/modalForms.py:47 compensation/forms/modalForms.py:63 #: compensation/forms/modalForms.py:356 compensation/forms/modalForms.py:463 #: intervention/forms/forms.py:54 intervention/forms/forms.py:156 -#: intervention/forms/forms.py:168 intervention/forms/modalForms.py:127 -#: intervention/forms/modalForms.py:140 intervention/forms/modalForms.py:153 +#: intervention/forms/forms.py:168 intervention/forms/modalForms.py:148 +#: intervention/forms/modalForms.py:161 intervention/forms/modalForms.py:174 #: konova/filters/mixins.py:53 konova/filters/mixins.py:54 #: konova/filters/mixins.py:81 konova/filters/mixins.py:82 #: konova/filters/mixins.py:94 konova/filters/mixins.py:95 @@ -26,7 +26,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\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" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -64,7 +64,7 @@ msgstr "Verantwortliche Stelle" #: compensation/forms/forms.py:165 intervention/forms/forms.py:64 #: intervention/forms/forms.py:81 intervention/forms/forms.py:97 #: 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" msgstr "Auswählen..." @@ -221,7 +221,7 @@ msgstr "Abbuchungen" #: 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-before.html:36 -#: intervention/forms/modalForms.py:338 +#: intervention/forms/modalForms.py:359 msgid "Surface" msgstr "Fläche" @@ -284,8 +284,8 @@ msgid "Type" msgstr "Typ" #: analysis/templates/analysis/reports/includes/old_data/amount.html:24 -#: compensation/tables.py:89 intervention/forms/modalForms.py:349 -#: intervention/forms/modalForms.py:356 intervention/tables.py:88 +#: compensation/tables.py:89 intervention/forms/modalForms.py:370 +#: intervention/forms/modalForms.py:377 intervention/tables.py:88 #: intervention/templates/intervention/detail/view.html:19 #: konova/templates/konova/includes/quickstart/interventions.html:4 #: templates/navbars/navbar.html:22 @@ -295,7 +295,7 @@ msgstr "Eingriff" #: analysis/templates/analysis/reports/includes/old_data/amount.html:34 #: compensation/tables.py:266 #: 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 #: templates/navbars/navbar.html:34 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/deadlines.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/payments.html:34 #: intervention/templates/intervention/detail/includes/revocation.html:38 @@ -484,7 +484,7 @@ msgid "Due on which date" msgstr "Zahlung wird an diesem Datum erwartet" #: 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" msgstr "Zusätzlicher Kommentar, maximal {} Zeichen" @@ -512,7 +512,7 @@ msgstr "Zusatzbezeichnung" msgid "Select an additional biotope type" 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²" msgstr "" @@ -540,7 +540,7 @@ msgstr "Fristart wählen" #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:31 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:31 #: ema/templates/ema/detail/includes/deadlines.html:31 -#: intervention/forms/modalForms.py:126 +#: intervention/forms/modalForms.py:147 msgid "Date" msgstr "Datum" @@ -752,7 +752,7 @@ msgstr "Menge" #: intervention/templates/intervention/detail/includes/documents.html:39 #: intervention/templates/intervention/detail/includes/payments.html:39 #: 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" msgstr "Aktionen" @@ -1000,14 +1000,14 @@ msgstr "Zuletzt bearbeitet" #: compensation/templates/compensation/detail/compensation/view.html:100 #: 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 msgid "Shared with" msgstr "Freigegeben für" #: compensation/templates/compensation/detail/eco_account/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 msgid "Share" 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" #: 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" msgstr "Nutzer direkt hinzufügen" -#: intervention/forms/modalForms.py:43 +#: intervention/forms/modalForms.py:57 msgid "" "Multiple selection possible - You can only select users which do not already " "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 " "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" 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 {}" msgstr "Freigabe Einstellungen für {}" -#: intervention/forms/modalForms.py:128 +#: intervention/forms/modalForms.py:149 msgid "Date of revocation" msgstr "Datum des Widerspruchs" -#: intervention/forms/modalForms.py:139 +#: intervention/forms/modalForms.py:160 #: intervention/templates/intervention/detail/includes/revocation.html:35 msgid "Document" msgstr "Dokument" -#: intervention/forms/modalForms.py:142 +#: intervention/forms/modalForms.py:163 msgid "Must be smaller than 15 Mb" 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 msgid "Add revocation" msgstr "Widerspruch hinzufügen" -#: intervention/forms/modalForms.py:224 +#: intervention/forms/modalForms.py:245 msgid "Checked intervention data" msgstr "Eingriffsdaten geprüft" -#: intervention/forms/modalForms.py:230 +#: intervention/forms/modalForms.py:251 msgid "Checked compensations data and payments" msgstr "Kompensationen und Zahlungen geprüft" -#: intervention/forms/modalForms.py:239 +#: intervention/forms/modalForms.py:260 #: intervention/templates/intervention/detail/includes/controls.html:19 msgid "Run check" msgstr "Prüfung vornehmen" -#: intervention/forms/modalForms.py:240 konova/forms.py:514 +#: intervention/forms/modalForms.py:261 konova/forms.py:514 msgid "" "I, {} {}, confirm that all necessary control steps have been performed by " "myself." @@ -1383,23 +1395,23 @@ msgstr "" "Ich, {} {}, bestätige, dass die notwendigen Kontrollschritte durchgeführt " "wurden:" -#: intervention/forms/modalForms.py:324 +#: intervention/forms/modalForms.py:345 msgid "Only recorded accounts can be selected for deductions" 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" msgstr "Nur freigegebene Eingriffe können gewählt werden" -#: intervention/forms/modalForms.py:364 +#: intervention/forms/modalForms.py:385 msgid "New Deduction" 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" msgstr "Geben Sie die Informationen für eine neue Abbuchung ein." -#: intervention/forms/modalForms.py:408 +#: intervention/forms/modalForms.py:429 msgid "" "Eco-account {} is not recorded yet. You can only deduct from recorded " "accounts." @@ -1407,7 +1419,7 @@ msgstr "" "Ökokonto {} ist noch nicht verzeichnet. Abbuchungen können nur von " "verzeichneten Ökokonten erfolgen." -#: intervention/forms/modalForms.py:418 +#: intervention/forms/modalForms.py:439 msgid "" "The account {} has not enough surface for a deduction of {} m². There are " "only {} m² left" @@ -2273,7 +2285,7 @@ msgstr "* sind Pflichtfelder." msgid "New entry" 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" msgstr "Neu" @@ -2406,7 +2418,7 @@ msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!" msgid "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" msgstr "Beschreibung" @@ -2434,19 +2446,23 @@ msgstr "" "Sie werden standardmäßig der Administrator dieses Teams. Sie müssen sich " "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" msgstr "Administrator" -#: user/forms.py:231 +#: user/forms.py:250 msgid "Administrators manage team details and members" 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." 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" msgstr "Team bearbeiten" @@ -2466,7 +2482,7 @@ msgstr "Gelöscht" msgid "Show contact data" 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" msgstr "" @@ -2515,20 +2531,20 @@ msgstr "" msgid "Manage teams" 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 msgid "Teams" msgstr "" -#: user/templates/user/team/index.html:21 +#: user/templates/user/team/index.html:20 msgid "Add new team" msgstr "Neues Team hinzufügen" -#: user/templates/user/team/index.html:32 +#: user/templates/user/team/index.html:31 msgid "Members" msgstr "Mitglieder" -#: user/templates/user/team/index.html:55 +#: user/templates/user/team/index.html:54 msgid "Remove team" msgstr "Team entfernen" diff --git a/user/admin.py b/user/admin.py index 3e608617..1aeacee3 100644 --- a/user/admin.py +++ b/user/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from user.models import UserNotification, UserActionLogEntry, User +from user.models import UserNotification, UserActionLogEntry, User, Team 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(Team, TeamAdmin) # Outcommented for a cleaner admin backend on production #admin.site.register(UserNotification, UserNotificationAdmin) diff --git a/user/forms.py b/user/forms.py index 35c1e82e..01ec54b6 100644 --- a/user/forms.py +++ b/user/forms.py @@ -206,6 +206,25 @@ class NewTeamModalForm(BaseModalForm): self.action_url = reverse("user:team-new") 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): with transaction.atomic(): team = Team.objects.create( @@ -246,6 +265,22 @@ class EditTeamModalForm(NewTeamModalForm): 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): super_valid = super().is_valid() admin_valid = self.__is_admin_valid()