Repository: liqd/a4-opin

Issue:
improvements for orga info in dashboard
Some issues with how texts and info on organizations are edited (see https://opin.me/de/dashboard/opin-examples/)
- [x] The title of the page should be “Edit your organisation information“ instead of “Edit a project”
- [x] The label of the submit button of the form should be changed to “Save changes“
- [x] The info underneath the upload fields should read “You’re image will be uploaded/removed once you click “save changes” at the end of this page.” instead of  “Please hit the post button to save your changes.”
- [x] Currently,there is a 400 chars limit in the dashboard for texts that are entered for an organization. This should be changed to 1000 chars
- [x] The fields for the organization texts “Description”, “Description how” and “Description why” should be changed to the order of how they are shown on the organization page : Why; How; Descr.
- [x] The fields for the organization texts “Description”, “Description how” and “Description why” should be textareas that have a standard height of 4 lines of text
- [x] Rename the fields for orga texts: “Description” should be renamed to “More info about the organisation / Short text for organisation overview” 
- [x] The preview of the uploaded orga logo should be smaller (max 250px width) and (nice to have) it should be floated to the left of the logo upload form field
- [x] The menu item in the dashboard nav for this page should be called “Organisation information“ instead of “Organisations”
- [x] The label “Image” should be changed to “Header Image”
- [x] There should be an info box underneath the image upload fields that informs on the required file format, max. file size and dimensions of the image; could be maybe combined with the save changes button info (see above)
- [x] The “Title”label for the form field should be renamed to “Title of the organization”



Discussion:
@rittermo I changed the text for the image upload to 'You’re image will be uploaded/removed once you save your changes at the end of this page.' because this text is shown underneath all image uploads (also in other forms) and we don't the text on the button,

@rittermo 'Organisation information' is a bit too long, so I just changed it to 'Information'. I think as it is in the 'Organisations settings' it should be ok. 


Resolving patch:
diff --git a/euth/contrib/widgets.py b/euth/contrib/widgets.py
--- a/euth/contrib/widgets.py
+++ b/euth/contrib/widgets.py
@@ -9,13 +9,16 @@
 
 
 class ImageInputWidget(widgets.ClearableFileInput):
+
     """
     A project-specific improved version of the clearable file upload.
 
     Allows to upload and delete uploaded files. It doesn't passing attributes
     using the positional `attrs` argument and hard codes css files.
     """
+
     def render(self, name, value, attrs=None):
+
         substitutions = {
             'name': name,
             'filename': '',
@@ -23,7 +26,8 @@ def render(self, name, value, attrs=None):
                 'Select a picture from your local folder.'
             ),
             'post_note': ugettext(
-                'Please hit the post button to save your changes.'
+                'You’re image will be uploaded/removed '
+                'once you save your changes at the end of this page.'
             ),
             'upload_title': ugettext('Upload a picture'),
             'clear_title': ugettext('Remove the picture'),
@@ -52,7 +56,8 @@ def render(self, name, value, attrs=None):
             substitutions['url'] = conditional_escape(value.url)
             substitutions['filename'] = basename(value.name)
             snippets['img'] = (
-                '<img src="{url}" class="img-responsive" alt="" />'
+                '<div class="form-{name}"><img src="{url}"'
+                ' class="img-responsive" alt="" /></div>'
             )
 
             if not self.is_required:
@@ -82,6 +87,8 @@ def render(self, name, value, attrs=None):
                 {file_input}
                 {alert}
                 {checkbox}
+            </div>
+            <div class="col-sm-3 col-md-4">
                 {img}
             </div>
         </div>
@@ -91,6 +98,7 @@ def render(self, name, value, attrs=None):
 
 
 class DateTimeInput(widgets.DateTimeInput):
+
     class Media:
         js = (staticfiles_storage.url('flatpickr.min.js'),
               'js/dateTimeInput.js')
diff --git a/euth/dashboard/forms.py b/euth/dashboard/forms.py
--- a/euth/dashboard/forms.py
+++ b/euth/dashboard/forms.py
@@ -5,6 +5,7 @@
 from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.forms import modelformset_factory
+from django.utils.translation import ugettext as _
 
 from euth.contrib import widgets
 from euth.memberships import models as member_models
@@ -18,6 +19,7 @@
 
 
 class ProfileForm(forms.ModelForm):
+
     class Meta:
         model = user_models.User
         fields = ['avatar', 'username']
@@ -62,6 +64,7 @@ def clean_emails(self):
 
 
 class ProjectForm(forms.ModelForm):
+
     class Meta:
         model = project_models.Project
         fields = ['image', 'name', 'description', 'information', 'is_public',
@@ -76,6 +79,7 @@ def save(self, commit=True):
 
 
 class PhaseForm(forms.ModelForm):
+
     class Meta:
         model = phase_models.Phase
         exclude = ('module', 'type')
@@ -215,12 +219,23 @@ def save(self, commit=True):
 
 
 class OrganisationForm(forms.ModelForm):
+
     """
     Special form that allows editing of all translated fields.
     """
 
-    translated_fields = ['title', 'description',
-                         'description_how', 'description_why']
+    translated_fields = [('title', forms.CharField(
+        help_text=_(
+            'The title of '
+            'your organisation'))),
+        ('description_why', forms.CharField(
+            widget=forms.Textarea)),
+        ('description_how', forms.CharField(
+            widget=forms.Textarea)),
+        ('description', forms.CharField(
+            widget=forms.Textarea, help_text=_(
+                'More info about the organisation / '
+                'Short text for organisation overview')))]
     languages = [lang_code for lang_code, lang in settings.LANGUAGES]
 
     class Meta:
@@ -233,6 +248,17 @@ class Meta:
             'image': widgets.ImageInputWidget(),
             'logo': widgets.ImageInputWidget(),
         }
+        labels = {
+            'image': _('Header Image'),
+        }
+        help_texts = {
+            'image': _("Your image should be at least 1300px wide and "
+                       "600px high. Supported formats are %s."
+                       % ", ".join(settings.ALLOWED_UPLOAD_IMAGES)),
+            'logo': _("Your image should be at least 200px wide and "
+                      "200px high. Supported formats are %s."
+                      % ", ".join(settings.ALLOWED_UPLOAD_IMAGES))
+        }
 
     def _get_identifier(self, language, fieldname):
         return '{}__{}'.format(language, fieldname)
@@ -242,13 +268,17 @@ def __init__(self, *args, **kwargs):
 
         # inject additional form fields for translated model fields
         for lang_code in self.languages:
-            for fieldname in self.translated_fields:
+            for name, translated_field in self.translated_fields:
                 self.instance.set_current_language(lang_code)
-                label = fieldname.replace('_', ' ').capitalize()
-                identifier = self._get_identifier(lang_code, fieldname)
-                initial = self.instance.safe_translation_getter(fieldname)
-                field = forms.CharField(label=label, max_length=400,
-                                        required=False, initial=initial)
+                label = name.replace('_', ' ').capitalize()
+                identifier = self._get_identifier(
+                    lang_code, name)
+                initial = self.instance.safe_translation_getter(
+                    name)
+                field = translated_field
+                field.label = label
+                field.required = False
+                field.initial = initial
                 self.fields[identifier] = field
 
     def translated(self):
@@ -289,8 +319,8 @@ def save(self, commit=True):
                 if lang_code in self.data:
                     instance.set_current_language(lang_code)
                     for fieldname in self.translated_fields:
-                        identifier = '{}__{}'.format(lang_code, fieldname)
-                        setattr(instance, fieldname,
+                        identifier = '{}__{}'.format(lang_code, fieldname[0])
+                        setattr(instance, fieldname[0],
                                 self.cleaned_data.get(identifier))
                     instance.save()
         return instance
@@ -299,7 +329,7 @@ def clean(self):
         for lang_code in self.languages:
             if lang_code in self.data:
                 for fieldname in self.translated_fields:
-                    identifier = self._get_identifier(lang_code, fieldname)
+                    identifier = self._get_identifier(lang_code, fieldname[0])
                     data = self.cleaned_data
                     if identifier not in data or not data[identifier]:
                         msg = 'This field is required'


Test patch: