diff --git a/intervention/forms.py b/intervention/forms.py index 98bfb7ff..8f03e927 100644 --- a/intervention/forms.py +++ b/intervention/forms.py @@ -15,7 +15,7 @@ from django.urls import reverse from django.utils.translation import gettext_lazy as _ from intervention.models import Intervention -from konova.forms import BaseForm +from konova.forms import BaseForm, BaseModalForm from konova.models import Document from konova.settings import DEFAULT_LAT, DEFAULT_LON, DEFAULT_ZOOM from organisation.models import Organisation @@ -220,6 +220,42 @@ class OpenInterventionForm(EditInterventionForm): self.disable_form_field(field) +class ShareInterventionForm(BaseModalForm): + url = forms.CharField( + label=_("Share link"), + label_suffix="", + disabled=True, + required=False, + widget=forms.TextInput( + attrs={ + "style": "width:100%", + } + ) + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.form_title = _("Share") + self.form_caption = _("Send this link to users who you want to have writing access on the data.") + self.template = "modal/modal_form.html" + self.render_submit = False + + # Make sure an access_token is set + if self.instance.access_token is None: + self.instance.generate_access_token() + + self.share_link = self.request.build_absolute_uri( + reverse("intervention:share", args=(self.instance.id, self.instance.access_token,)) + ) + self.initialize_form_field( + "url", + self.share_link + ) + + def save(self): + i = 0 + + class DummyFilterInput(forms.HiddenInput): """ A dummy input widget diff --git a/intervention/models.py b/intervention/models.py index 67fd83a4..81981bba 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -13,6 +13,7 @@ from django.utils.timezone import now from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_IDENTIFIER_TEMPLATE from konova.models import BaseObject, Geometry, UuidModel +from konova.utils import generators from konova.utils.generators import generate_random_string from organisation.models import Organisation from user.models import UserActionLogEntry @@ -92,6 +93,12 @@ class Intervention(BaseObject): # Users having access on this object users = models.ManyToManyField(User) + access_token = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Used for sharing access", + ) def __str__(self): return "{} ({})".format(self.identifier, self.title) @@ -139,6 +146,40 @@ class Intervention(BaseObject): _str = "{}{}{}".format(curr_month, curr_year, rand_str) return INTERVENTION_IDENTIFIER_TEMPLATE.format(_str) + def generate_access_token(self, make_unique: bool = False, rec_depth: int = 5): + """ Creates a new access token for the intervention + + Tokens are not used for identification of a table row. The share logic checks the intervention id as well + as the given token. Therefore two different interventions can hold the same access_token without problems. + For (possible) future changes to the share logic, the make_unique parameter may be used for checking whether + the access_token is already used in any intervention. If so, tokens will be generated as long as a free token + can be found. + + Args: + make_unique (bool): Perform check on uniqueness over all intervention entries + rec_depth (int): How many tries for generating a free random token (only if make_unique) + + Returns: + + """ + # Make sure we won't end up in an infinite loop of trying to generate access_tokens + rec_depth = rec_depth - 1 + if rec_depth < 0 and make_unique: + raise RuntimeError( + "Access token generating for {} does not seem to find a free random token! Aborted!".format(self.id) + ) + + # Create random token + token = generators.generate_random_string(15) + token_used_in = Intervention.objects.filter(access_token=token) + # Make sure the token is not used anywhere as access_token, yet. + # Make use of QuerySet lazy method for checking if it exists or not. + if token_used_in and make_unique: + self.generate_access_token(make_unique, rec_depth) + else: + self.access_token = token + self.save() + def save(self, *args, **kwargs): if self.identifier is None or len(self.identifier) == 0: # Create new identifier diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index 7354bca1..ae4006a1 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -24,11 +24,9 @@ {% if has_access %} - - - + + {% endif %} \ No newline at end of file