Make it possible to filter social media fields per source
authorMagnus Hagander <magnus@hagander.net>
Thu, 16 May 2024 21:01:06 +0000 (23:01 +0200)
committerMagnus Hagander <magnus@hagander.net>
Thu, 16 May 2024 21:01:06 +0000 (23:01 +0200)
This allows a media provider to for exapmle say that it can only
register sponsor accounts, not speaker accounts. All existing
implementations support all kinds of registrations, but it's
infrastructure for the future.

postgresqleu/confreg/forms.py
postgresqleu/confreg/twitter.py
postgresqleu/confsponsor/backendforms.py
postgresqleu/confsponsor/forms.py
postgresqleu/confsponsor/views.py
postgresqleu/util/messaging/mastodon.py
postgresqleu/util/messaging/telegram.py
postgresqleu/util/messaging/twitter.py

index 19acf2addecf16a83baacaad90815ac067ba0964..da6b843b9eb57d153c302e576e1c2891e221b644 100644 (file)
@@ -490,18 +490,18 @@ class SpeakerProfileForm(forms.ModelForm):
 
         self.fields['photo512'].help_text = 'Photo will be rescaled to {}x{} pixels. We reserve the right to make minor edits to speaker photos if necessary'.format(*PRIMARY_SPEAKER_PHOTO_RESOLUTION)
 
-        for classname, social, impl in sorted(get_all_conference_social_media(), key=lambda x: x[1]):
+        for classname, social, impl in sorted(get_all_conference_social_media('speaker'), key=lambda x: x[1]):
             self.fields['social_{}'.format(social)] = forms.CharField(label="{} name".format(social.title()), max_length=250, required=False)
             self.fields['social_{}'.format(social)].initial = self.instance.attributes.get('social', {}).get(social, '')
 
     def clean(self):
         cleaned_data = super().clean()
 
-        for classname, social, impl in sorted(get_all_conference_social_media(), key=lambda x: x[1]):
+        for classname, social, impl in sorted(get_all_conference_social_media('speaker'), key=lambda x: x[1]):
             fn = 'social_{}'.format(social)
             if cleaned_data.get(fn, None):
                 try:
-                    cleaned_data[fn] = impl.clean_identifier_form_value(cleaned_data[fn])
+                    cleaned_data[fn] = impl.clean_identifier_form_value('speaker', cleaned_data[fn])
                 except ValidationError as v:
                     self.add_error(fn, v)
 
@@ -517,7 +517,7 @@ class SpeakerProfileForm(forms.ModelForm):
         if 'social' not in obj.attributes:
             obj.attributes['social'] = {}
 
-        for classname, social, impl in sorted(get_all_conference_social_media(), key=lambda x: x[1]):
+        for classname, social, impl in sorted(get_all_conference_social_media('speaker'), key=lambda x: x[1]):
             v = self.cleaned_data['social_{}'.format(social)]
             if v:
                 obj.attributes['social'][social] = v
index 244ab94d8c827762c0a7789c01509ec3013eec90..0cd72fbcbe066822e752c79d06c7ecf7def6ae96 100644 (file)
@@ -85,13 +85,13 @@ def render_multiprovider_tweet(conference, template, context):
     return versions
 
 
-def get_all_conference_social_media():
+def get_all_conference_social_media(whatfor):
     # When using .distinct() in django it randomly adds either "id" or "internalname" to the SQL
     # query and thus doesn't actually return distinct values. Rather than trying to debug
     # the horror that's an ORM, just run the query because queries are easy.
     for classname, in exec_to_list("SELECT DISTINCT classname FROM confreg_messagingprovider WHERE series_id IS NOT NULL"):
         c = get_messaging_class(classname)
-        if c.can_broadcast:
+        if c.can_broadcast and c.can_track_users_for(whatfor):
             yield (classname, c.typename.lower(), c)
 
 
index 67ba70a22d84ebd1a7e960581e53cdec1ff95b34..766043a15835e3c7281c467ce86b62151c61ed74 100644 (file)
@@ -54,10 +54,10 @@ class BackendSponsorForm(BackendForm):
 
     @property
     def nosave_fields(self):
-        return ['social_{}'.format(social) for classname, social, impl in get_all_conference_social_media()]
+        return ['social_{}'.format(social) for classname, social, impl in get_all_conference_social_media('sponsor')]
 
     def fix_fields(self):
-        for classname, social, impl in sorted(get_all_conference_social_media(), key=lambda x: x[1]):
+        for classname, social, impl in sorted(get_all_conference_social_media('sponsor'), key=lambda x: x[1]):
             fn = "social_{}".format(social)
             self.fields[fn] = django.forms.CharField(label="{} name".format(social.title()), max_length=250, required=False)
             self.fields[fn].initial = self.instance.social.get(social, '')
@@ -68,7 +68,7 @@ class BackendSponsorForm(BackendForm):
         self.update_protected_fields()
 
     def post_save(self):
-        for classname, social, impl in get_all_conference_social_media():
+        for classname, social, impl in get_all_conference_social_media('sponsor'):
             v = self.cleaned_data['social_{}'.format(social)]
             if v:
                 self.instance.social[social] = v
@@ -79,11 +79,11 @@ class BackendSponsorForm(BackendForm):
     def clean(self):
         cleaned_data = super().clean()
 
-        for classname, social, impl in get_all_conference_social_media():
+        for classname, social, impl in get_all_conference_social_media('sponsor'):
             fn = 'social_{}'.format(social)
             if cleaned_data.get(fn, None):
                 try:
-                    cleaned_data[fn] = impl.clean_identifier_form_value(cleaned_data[fn])
+                    cleaned_data[fn] = impl.clean_identifier_form_value('sponsor', cleaned_data[fn])
                 except ValidationError as v:
                     self.add_error(fn, v)
 
index 2738c86813d7a6f341cca9bee05f41384ab937f9..42f38a1c516abdeb397fd59163e6720527ec42f7 100644 (file)
@@ -47,7 +47,7 @@ class SponsorSignupForm(forms.Form):
 
         super(SponsorSignupForm, self).__init__(*args, **kwargs)
 
-        for classname, social, impl in sorted(get_all_conference_social_media(), key=lambda x: x[1]):
+        for classname, social, impl in sorted(get_all_conference_social_media('sponsor'), key=lambda x: x[1]):
             fn = "social_{}".format(social)
             self.fields[fn] = forms.CharField(label="Company {}".format(social.title()), max_length=250, required=False)
 
@@ -87,11 +87,11 @@ class SponsorSignupForm(forms.Form):
     def clean(self):
         cleaned_data = super(SponsorSignupForm, self).clean()
 
-        for classname, social, impl in get_all_conference_social_media():
+        for classname, social, impl in get_all_conference_social_media('sponsor'):
             fn = 'social_{}'.format(social)
             if cleaned_data.get(fn, None):
                 try:
-                    cleaned_data[fn] = impl.clean_identifier_form_value(cleaned_data[fn])
+                    cleaned_data[fn] = impl.clean_identifier_form_value('sponsor', cleaned_data[fn])
                 except ValidationError as v:
                     self.add_error(fn, v)
 
index 95122cc2bc8ed03513e8fda4c6221e72210789d6..a65cb080e22f391ab36df352c29159b3f697bfb4 100644 (file)
@@ -474,7 +474,12 @@ def sponsor_signup(request, confurlname, levelurlname):
                 if request.POST.get('contractchoice', '') not in ('0', '1') and not level.instantbuy:
                     return _render_contract_choices()
 
-                social = {social: form.cleaned_data['social_{}'.format(social)] for classname, social, impl in get_all_conference_social_media() if form.cleaned_data['social_{}'.format(social)]}
+                social = {
+                    social: form.cleaned_data['social_{}'.format(social)]
+                    for classname, social, impl
+                    in get_all_conference_social_media('sponsor')
+                    if form.cleaned_data['social_{}'.format(social)]
+                }
 
                 sponsor = Sponsor(conference=conference,
                                   signupat=timezone.now(),
index f8f6689d7d09e114e89a97c5c3518eaf7867a108..3904e8f78849a25e9d74b413485370f712362ff2 100644 (file)
@@ -116,13 +116,17 @@ class Mastodon(object):
 
     handle_regexp = re.compile(r'^@([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,})$', re.I)
 
+    @classmethod
+    def can_track_users_for(self, whatfor):
+        return True
+
     @classmethod
     def validate_baseurl(self, baseurl):
         if not OAuthApplication.objects.filter(name='mastodon', baseurl=baseurl).exists():
             return 'Global OAuth credentials for {} missing'.format(baseurl)
 
     @classmethod
-    def clean_identifier_form_value(self, value):
+    def clean_identifier_form_value(self, whatfor, value):
         if not self.handle_regexp.fullmatch(value):
             raise ValidationError("Invalid format of Mastodon username. Must use format @name@site.")
         return value
index 5de5c60c52ef67f99a43c3029bbb4fa38f3c16a6..6b705b1d51f831835758b81f22866d20157602e8 100644 (file)
@@ -121,12 +121,16 @@ class Telegram(object):
     direct_message_max_length = None
     typename = 'Telegram'
 
+    @classmethod
+    def can_track_users_for(self, whatfor):
+        return True
+
     @classmethod
     def validate_baseurl(self, baseurl):
         return None
 
     @classmethod
-    def clean_identifier_form_value(self, value):
+    def clean_identifier_form_value(self, whatfor, value):
         if not re.fullmatch('^[a-z0-9_]{5,}$', value, re.I):
             raise ValidationError("Invalid format of Telegram username")
         return value
index d3330a99b175530b51d06822bdcb21d582ce41bf..4bb91d87195e61253d007256951fd4ef7719ce97 100644 (file)
@@ -191,12 +191,16 @@ class Twitter(object):
     typename = 'Twitter'
     max_post_length = 280
 
+    @classmethod
+    def can_track_users_for(self, whatfor):
+        return True
+
     @classmethod
     def validate_baseurl(self, baseurl):
         return None
 
     @classmethod
-    def clean_identifier_form_value(self, value):
+    def clean_identifier_form_value(self, whatfor, value):
         # Always add the @ at the beginning. The validator forcibly strips it
         # so for backwards compatibility as long as that validator is used elsewhere,
         # we add it back here.