You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2022/05/10 21:30:42 UTC

[airavata-django-portal] branch AIRAVATA-3562 updated (793b8f39 -> 5c2aed33)

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a change to branch AIRAVATA-3562
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git


    from 793b8f39 AIRAVATA-3565 Other field for single and multi choice fields
     new 6d761044 AIRAVATA-3565 Add validation to extended user profile editor
     new 9a68c808 AIRAVATA-3565 Adding required column to ExtendedUserProfileField
     new 49ebb76c AIRAVATA-3565 Support for optional extended user profile fields
     new 5c2aed33 AIRAVATA-3565 Combining both forms into one

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../js/models/ExtendedUserProfileField.js          |  1 +
 .../0016_extendeduserprofilefield_required.py      | 18 ++++++++
 django_airavata/apps/auth/models.py                |  1 +
 django_airavata/apps/auth/serializers.py           |  3 +-
 .../js/components/ExtendedUserProfileEditor.vue    | 10 +++-
 .../ExtendedUserProfileMultiChoiceFieldEditor.vue  | 42 +++++++++++++++++
 .../ExtendedUserProfileSingleChoiceFieldEditor.vue | 53 +++++++++++++++++++++-
 .../ExtendedUserProfileTextFieldEditor.vue         | 24 +++++++++-
 ...ExtendedUserProfileUserAgreementFieldEditor.vue | 39 +++++++++++++++-
 .../js/components/UserProfileEditor.vue            | 11 +----
 .../js/containers/UserProfileContainer.vue         | 47 +++++++++++++------
 .../js/store/modules/extendedUserProfile.js        |  2 +-
 .../static/common/js/errors/vuelidateHelpers.js    | 14 ++++++
 13 files changed, 235 insertions(+), 30 deletions(-)
 create mode 100644 django_airavata/apps/auth/migrations/0016_extendeduserprofilefield_required.py


[airavata-django-portal] 01/04: AIRAVATA-3565 Add validation to extended user profile editor

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3562
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 6d761044053c67f0000b00a5aedda025585f8d61
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue May 10 16:12:44 2022 -0400

    AIRAVATA-3565 Add validation to extended user profile editor
---
 .../js/components/ExtendedUserProfileEditor.vue    |  6 +++
 .../ExtendedUserProfileMultiChoiceFieldEditor.vue  | 39 +++++++++++++++++
 .../ExtendedUserProfileSingleChoiceFieldEditor.vue | 50 +++++++++++++++++++++-
 .../ExtendedUserProfileTextFieldEditor.vue         | 21 ++++++++-
 ...ExtendedUserProfileUserAgreementFieldEditor.vue | 30 ++++++++++++-
 .../js/store/modules/extendedUserProfile.js        |  2 +-
 .../static/common/js/errors/vuelidateHelpers.js    | 14 ++++++
 7 files changed, 158 insertions(+), 4 deletions(-)

diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
index b224fba2..1f6bcdf8 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
@@ -2,6 +2,7 @@
   <b-card>
     <template v-for="extendedUserProfileField in extendedUserProfileFields">
       <component
+        ref="extendedUserProfileFieldComponents"
         :key="extendedUserProfileField.id"
         :is="getEditor(extendedUserProfileField)"
         :extended-user-profile-field="extendedUserProfileField"
@@ -19,6 +20,11 @@ import ExtendedUserProfileUserAgreementFieldEditor from "./ExtendedUserProfileUs
 export default {
   computed: {
     ...mapGetters("extendedUserProfile", ["extendedUserProfileFields"]),
+    valid() {
+      return this.$refs.extendedUserProfileFieldComponents.every(
+        (c) => c.valid
+      );
+    },
   },
   methods: {
     getEditor(extendedUserProfileField) {
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
index db45cbb9..8edc55b6 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
@@ -5,25 +5,39 @@
       :options="options"
       stacked
       @change="onChange"
+      :state="validateStateErrorOnly($v.value)"
     >
       <b-form-checkbox :value="otherOptionValue"
         >Other (please specify)</b-form-checkbox
       >
+
+      <b-form-invalid-feedback :state="validateState($v.value)"
+        >This field is required.</b-form-invalid-feedback
+      >
     </b-form-checkbox-group>
     <b-form-input
       class="mt-2"
       v-if="showOther"
       v-model="other"
       placeholder="Please specify"
+      :state="validateState($v.other)"
+      @input="onInput"
     />
+    <b-form-invalid-feedback :state="validateState($v.other)"
+      >Please specify a value for 'Other'.</b-form-invalid-feedback
+    >
   </extended-user-profile-field-editor>
 </template>
 
 <script>
 import { mapGetters, mapMutations } from "vuex";
+import { validationMixin } from "vuelidate";
+import { required } from "vuelidate/lib/validators";
+import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 const OTHER_OPTION = new Object(); // sentinel value
 export default {
+  mixins: [validationMixin],
   components: { ExtendedUserProfileFieldEditor },
   props: ["extendedUserProfileField"],
   data() {
@@ -52,6 +66,7 @@ export default {
           value: values,
           id: this.extendedUserProfileField.id,
         });
+        this.$v.value.$touch();
       },
     },
     other: {
@@ -63,6 +78,7 @@ export default {
           value,
           id: this.extendedUserProfileField.id,
         });
+        this.$v.other.$touch();
       },
     },
     showOther() {
@@ -82,6 +98,21 @@ export default {
     otherOptionValue() {
       return OTHER_OPTION;
     },
+    valid() {
+      return !this.$v.$invalid;
+    },
+  },
+  validations() {
+    const validations = {
+      value: {
+        required,
+      },
+      other: {},
+    };
+    if (this.showOther) {
+      validations.other = { required };
+    }
+    return validations;
   },
   methods: {
     ...mapMutations("extendedUserProfile", [
@@ -94,6 +125,14 @@ export default {
         this.other = "";
       }
     },
+    onInput() {
+      // Handle case where initially there is an other value. If the user
+      // deletes the other value, then we still want to keep the other text box
+      // until the user unchecks the other option.
+      this.otherOptionSelected = true;
+    },
+    validateState: errors.vuelidateHelpers.validateState,
+    validateStateErrorOnly: errors.vuelidateHelpers.validateStateErrorOnly,
   },
 };
 </script>
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
index 524fee70..0324b753 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
@@ -1,25 +1,48 @@
 <template>
   <extended-user-profile-field-editor v-bind="$props">
-    <b-form-select v-model="value" :options="options" @change="onChange">
+    <b-form-select
+      v-model="value"
+      :options="options"
+      @change="onChange"
+      :state="validateStateErrorOnly($v.value)"
+    >
+      <template #first>
+        <b-form-select-option :value="null" disabled
+          >-- Please select an option --</b-form-select-option
+        >
+      </template>
+
       <b-form-select-option :value="otherOptionValue"
         >Other (please specify)</b-form-select-option
       >
     </b-form-select>
+    <b-form-invalid-feedback :state="validateState($v.value)"
+      >This field is required.</b-form-invalid-feedback
+    >
     <b-form-input
       class="mt-2"
       v-if="showOther"
       v-model="other"
       placeholder="Please specify"
+      :state="validateState($v.other)"
+      @input="onInput"
     />
+    <b-form-invalid-feedback :state="validateState($v.other)"
+      >Please specify a value for 'Other'.</b-form-invalid-feedback
+    >
   </extended-user-profile-field-editor>
 </template>
 
 <script>
 import { mapGetters, mapMutations } from "vuex";
+import { validationMixin } from "vuelidate";
+import { required } from "vuelidate/lib/validators";
+import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 const OTHER_OPTION = new Object(); // sentinel value
 
 export default {
+  mixins: [validationMixin],
   components: { ExtendedUserProfileFieldEditor },
   props: ["extendedUserProfileField"],
   data() {
@@ -46,6 +69,7 @@ export default {
             value,
             id: this.extendedUserProfileField.id,
           });
+          this.$v.value.$touch();
         }
       },
     },
@@ -58,6 +82,7 @@ export default {
           value,
           id: this.extendedUserProfileField.id,
         });
+        this.$v.other.$touch();
       },
     },
     showOther() {
@@ -78,6 +103,21 @@ export default {
     otherOptionValue() {
       return OTHER_OPTION;
     },
+    valid() {
+      return !this.$v.$invalid;
+    },
+  },
+  validations() {
+    const validations = {
+      value: {},
+      other: {},
+    };
+    if (this.showOther) {
+      validations.other = { required };
+    } else {
+      validations.value = { required };
+    }
+    return validations;
   },
   methods: {
     ...mapMutations("extendedUserProfile", [
@@ -87,6 +127,14 @@ export default {
     onChange(value) {
       this.otherOptionSelected = value === this.otherOptionValue;
     },
+    onInput() {
+      // Handle case where initially there is an other value. If the user
+      // deletes the other value, then we still want to keep the other text box
+      // until the user unchecks the other option.
+      this.otherOptionSelected = true;
+    },
+    validateState: errors.vuelidateHelpers.validateState,
+    validateStateErrorOnly: errors.vuelidateHelpers.validateStateErrorOnly,
   },
 };
 </script>
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
index c9a96488..284ac65d 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
@@ -1,13 +1,20 @@
 <template>
   <extended-user-profile-field-editor v-bind="$props">
-    <b-form-input v-model="value" />
+    <b-form-input v-model="value" :state="validateState($v.value)" />
+    <b-form-invalid-feedback :state="validateState($v.value)"
+      >This field is required.</b-form-invalid-feedback
+    >
   </extended-user-profile-field-editor>
 </template>
 
 <script>
 import { mapGetters, mapMutations } from "vuex";
+import { validationMixin } from "vuelidate";
+import { required } from "vuelidate/lib/validators";
+import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 export default {
+  mixins: [validationMixin],
   components: { ExtendedUserProfileFieldEditor },
   props: ["extendedUserProfileField"],
   computed: {
@@ -18,11 +25,23 @@ export default {
       },
       set(value) {
         this.setTextValue({ value, id: this.extendedUserProfileField.id });
+        this.$v.$touch();
       },
     },
+    valid() {
+      return !this.$v.$invalid;
+    },
+  },
+  validations() {
+    return {
+      value: {
+        required,
+      },
+    };
   },
   methods: {
     ...mapMutations("extendedUserProfile", ["setTextValue"]),
+    validateState: errors.vuelidateHelpers.validateState,
   },
 };
 </script>
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
index f21965be..9d1c6ffa 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
@@ -1,15 +1,29 @@
 <template>
   <extended-user-profile-field-editor v-bind="$props">
-    <b-form-checkbox v-model="value" :unchecked-value="false">
+    <b-form-checkbox
+      v-model="value"
+      :unchecked-value="false"
+      :value="true"
+      :state="validateStateErrorOnly($v.value)"
+    >
       {{ extendedUserProfileField.checkbox_label }}
     </b-form-checkbox>
+    <b-form-invalid-feedback :state="validateState($v.value)"
+      >This field is required.</b-form-invalid-feedback
+    >
   </extended-user-profile-field-editor>
 </template>
 
 <script>
 import { mapGetters, mapMutations } from "vuex";
+import { validationMixin } from "vuelidate";
+import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
+
+const mustBeTrue = (value) => value === true;
+
 export default {
+  mixins: [validationMixin],
   components: { ExtendedUserProfileFieldEditor },
   props: ["extendedUserProfileField"],
   computed: {
@@ -23,11 +37,25 @@ export default {
           value,
           id: this.extendedUserProfileField.id,
         });
+        this.$v.value.$touch();
       },
     },
+    valid() {
+      return !this.$v.$invalid;
+    },
+  },
+  validations() {
+    const validations = {
+      value: {
+        mustBeTrue,
+      },
+    };
+    return validations;
   },
   methods: {
     ...mapMutations("extendedUserProfile", ["setUserAgreementValue"]),
+    validateState: errors.vuelidateHelpers.validateState,
+    validateStateErrorOnly: errors.vuelidateHelpers.validateStateErrorOnly,
   },
 };
 </script>
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js b/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js
index d2163890..6e264490 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js
@@ -50,7 +50,7 @@ const getters = {
     const value = state.extendedUserProfileValues.find(
       (v) => v.ext_user_profile_field === id
     );
-    return value && value.agreement_value;
+    return value ? value.agreement_value : false;
   },
 };
 
diff --git a/django_airavata/static/common/js/errors/vuelidateHelpers.js b/django_airavata/static/common/js/errors/vuelidateHelpers.js
index 3f431834..1332e77d 100644
--- a/django_airavata/static/common/js/errors/vuelidateHelpers.js
+++ b/django_airavata/static/common/js/errors/vuelidateHelpers.js
@@ -2,3 +2,17 @@ export function validateState(validation) {
   const { $dirty, $error } = validation;
   return $dirty ? !$error : null;
 }
+
+/**
+ * Return false if there is a validation error, null otherwise.
+ *
+ * This is just like validateState except it doesn't return true when valid
+ * which is useful if you only want to show invalid feedback.
+ *
+ * @param {*} validation
+ * @returns
+ */
+export function validateStateErrorOnly(validation) {
+  const { $dirty, $error } = validation;
+  return $dirty && $error ? false : null;
+}


[airavata-django-portal] 04/04: AIRAVATA-3565 Combining both forms into one

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3562
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 5c2aed337dbba7302f214c5c2991b56bb121e520
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue May 10 17:30:34 2022 -0400

    AIRAVATA-3565 Combining both forms into one
---
 .../js/components/ExtendedUserProfileEditor.vue    |  4 +-
 .../js/components/UserProfileEditor.vue            | 11 +----
 .../js/containers/UserProfileContainer.vue         | 47 +++++++++++++++-------
 3 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
index 1f6bcdf8..d1a6df0d 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
@@ -1,5 +1,5 @@
 <template>
-  <b-card>
+  <div>
     <template v-for="extendedUserProfileField in extendedUserProfileFields">
       <component
         ref="extendedUserProfileFieldComponents"
@@ -8,7 +8,7 @@
         :extended-user-profile-field="extendedUserProfileField"
       />
     </template>
-  </b-card>
+  </div>
 </template>
 
 <script>
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue
index 68f423e8..bbac76ab 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue
@@ -1,5 +1,5 @@
 <template>
-  <b-card v-if="user">
+  <div v-if="user">
     <b-form-group
       label="Username"
       :disabled="true"
@@ -40,14 +40,7 @@
         ></b-alert
       >
     </b-form-group>
-    <!-- TODO: move save button up to container -->
-    <b-button
-      variant="primary"
-      @click="save"
-      :disabled="$v.$invalid || disabled"
-      >Save</b-button
-    >
-  </b-card>
+  </div>
 </template>
 
 <script>
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue
index 3955c151..86fbb395 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue
@@ -16,16 +16,22 @@
     <b-alert v-else-if="user && !user.complete" show>
       >Please complete your user profile before continuing.</b-alert
     >
-    <user-profile-editor
-      ref="userProfileEditor"
-      @save="onSave"
-      @resend-email-verification="handleResendEmailVerification"
-    />
-    <!-- TODO: include both forms in the same card -->
-    <!-- include extended-user-profile-editor if there are extendedUserProfileFields -->
-    <extended-user-profile-editor
-      v-if="extendedUserProfileFields && extendedUserProfileFields.length > 0"
-    />
+    <b-card>
+      <user-profile-editor
+        ref="userProfileEditor"
+        @save="onSave"
+        @resend-email-verification="handleResendEmailVerification"
+      />
+      <!-- include extended-user-profile-editor if there are extendedUserProfileFields -->
+      <template
+        v-if="extendedUserProfileFields && extendedUserProfileFields.length > 0"
+      >
+        <hr />
+        <extended-user-profile-editor ref="extendedUserProfileEditor" />
+      </template>
+
+      <b-button variant="primary" @click="onSave">Save</b-button>
+    </b-card>
     <b-link
       v-if="user && user.complete"
       class="text-muted small"
@@ -64,7 +70,9 @@ export default {
     }
   },
   data() {
-    return {};
+    return {
+      invalidForm: false,
+    };
   },
   computed: {
     ...mapGetters("userProfile", ["user"]),
@@ -83,10 +91,12 @@ export default {
       "saveExtendedUserProfileValues",
     ]),
     async onSave() {
-      // TODO: only save if both standard and extended user profiles are valid
-      this.saveExtendedUserProfileValues();
-      if (this.$refs.userProfileEditor.valid) {
+      if (
+        this.$refs.userProfileEditor.valid &&
+        this.$refs.extendedUserProfileEditor.valid
+      ) {
         await this.updateUser();
+        await this.saveExtendedUserProfileValues();
         notifications.NotificationList.add(
           new notifications.Notification({
             type: "SUCCESS",
@@ -94,6 +104,15 @@ export default {
             duration: 5,
           })
         );
+      } else {
+        // TODO: make sure to highlight which fields are invalid
+        notifications.NotificationList.add(
+          new notifications.Notification({
+            type: "WARNING",
+            message: "The form is invalid. Please fix and try again.",
+            duration: 5,
+          })
+        );
       }
     },
     async handleResendEmailVerification() {


[airavata-django-portal] 03/04: AIRAVATA-3565 Support for optional extended user profile fields

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3562
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 49ebb76c7ccaaf23e38bd57e803381bb56d608be
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue May 10 16:47:21 2022 -0400

    AIRAVATA-3565 Support for optional extended user profile fields
---
 .../js/models/ExtendedUserProfileField.js                 |  1 +
 .../ExtendedUserProfileMultiChoiceFieldEditor.vue         |  9 ++++++---
 .../ExtendedUserProfileSingleChoiceFieldEditor.vue        |  9 ++++++---
 .../js/components/ExtendedUserProfileTextFieldEditor.vue  |  7 +++++--
 .../ExtendedUserProfileUserAgreementFieldEditor.vue       | 15 ++++++++++++---
 5 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js
index 8b719db1..2eec7ac8 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js
@@ -30,6 +30,7 @@ const FIELDS = [
     type: ExtendedUserProfileFieldChoice,
   },
   "other",
+  "required",
 ];
 
 export default class ExtendedUserProfileField extends BaseModel {
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
index 8edc55b6..ff02eea7 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
@@ -32,7 +32,7 @@
 <script>
 import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
-import { required } from "vuelidate/lib/validators";
+import { requiredIf } from "vuelidate/lib/validators";
 import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 const OTHER_OPTION = new Object(); // sentinel value
@@ -101,16 +101,19 @@ export default {
     valid() {
       return !this.$v.$invalid;
     },
+    required() {
+      return this.extendedUserProfileField.required;
+    },
   },
   validations() {
     const validations = {
       value: {
-        required,
+        required: requiredIf("required"),
       },
       other: {},
     };
     if (this.showOther) {
-      validations.other = { required };
+      validations.other = { required: requiredIf("required") };
     }
     return validations;
   },
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
index 0324b753..40872081 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
@@ -36,7 +36,7 @@
 <script>
 import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
-import { required } from "vuelidate/lib/validators";
+import { requiredIf } from "vuelidate/lib/validators";
 import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 const OTHER_OPTION = new Object(); // sentinel value
@@ -106,6 +106,9 @@ export default {
     valid() {
       return !this.$v.$invalid;
     },
+    required() {
+      return this.extendedUserProfileField.required;
+    },
   },
   validations() {
     const validations = {
@@ -113,9 +116,9 @@ export default {
       other: {},
     };
     if (this.showOther) {
-      validations.other = { required };
+      validations.other = { required: requiredIf("required") };
     } else {
-      validations.value = { required };
+      validations.value = { required: requiredIf("required") };
     }
     return validations;
   },
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
index 284ac65d..37b451d7 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
@@ -10,7 +10,7 @@
 <script>
 import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
-import { required } from "vuelidate/lib/validators";
+import { requiredIf } from "vuelidate/lib/validators";
 import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 export default {
@@ -31,11 +31,14 @@ export default {
     valid() {
       return !this.$v.$invalid;
     },
+    required() {
+      return this.extendedUserProfileField.required;
+    },
   },
   validations() {
     return {
       value: {
-        required,
+        required: requiredIf("required"),
       },
     };
   },
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
index 9d1c6ffa..487d6b09 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
@@ -20,8 +20,6 @@ import { validationMixin } from "vuelidate";
 import { errors } from "django-airavata-common-ui";
 import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
 
-const mustBeTrue = (value) => value === true;
-
 export default {
   mixins: [validationMixin],
   components: { ExtendedUserProfileFieldEditor },
@@ -43,17 +41,28 @@ export default {
     valid() {
       return !this.$v.$invalid;
     },
+    required() {
+      return this.extendedUserProfileField.required;
+    },
   },
   validations() {
     const validations = {
       value: {
-        mustBeTrue,
+        mustBeTrue: this.mustBeTrue,
       },
     };
     return validations;
   },
   methods: {
     ...mapMutations("extendedUserProfile", ["setUserAgreementValue"]),
+    mustBeTrue(value) {
+      if (this.required) {
+        return value === true;
+      } else {
+        // If not required, always valid
+        return true;
+      }
+    },
     validateState: errors.vuelidateHelpers.validateState,
     validateStateErrorOnly: errors.vuelidateHelpers.validateStateErrorOnly,
   },


[airavata-django-portal] 02/04: AIRAVATA-3565 Adding required column to ExtendedUserProfileField

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3562
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 9a68c8082042d03062e0eccfddd48e1b86e3f5e6
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue May 10 16:19:56 2022 -0400

    AIRAVATA-3565 Adding required column to ExtendedUserProfileField
---
 .../0016_extendeduserprofilefield_required.py          | 18 ++++++++++++++++++
 django_airavata/apps/auth/models.py                    |  1 +
 django_airavata/apps/auth/serializers.py               |  3 ++-
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/django_airavata/apps/auth/migrations/0016_extendeduserprofilefield_required.py b/django_airavata/apps/auth/migrations/0016_extendeduserprofilefield_required.py
new file mode 100644
index 00000000..4c6dd6f1
--- /dev/null
+++ b/django_airavata/apps/auth/migrations/0016_extendeduserprofilefield_required.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.11 on 2022-05-10 20:14
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('django_airavata_auth', '0015_auto_20220329_1708'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='extendeduserprofilefield',
+            name='required',
+            field=models.BooleanField(default=True),
+        ),
+    ]
diff --git a/django_airavata/apps/auth/models.py b/django_airavata/apps/auth/models.py
index b465fd4e..8d7cbb41 100644
--- a/django_airavata/apps/auth/models.py
+++ b/django_airavata/apps/auth/models.py
@@ -158,6 +158,7 @@ class ExtendedUserProfileField(models.Model):
     created_date = models.DateTimeField(auto_now_add=True)
     updated_date = models.DateTimeField(auto_now=True)
     deleted = models.BooleanField(default=False)
+    required = models.BooleanField(default=True)
 
     def __str__(self) -> str:
         return f"{self.name} ({self.id})"
diff --git a/django_airavata/apps/auth/serializers.py b/django_airavata/apps/auth/serializers.py
index 7d3a61dc..1b752362 100644
--- a/django_airavata/apps/auth/serializers.py
+++ b/django_airavata/apps/auth/serializers.py
@@ -125,7 +125,7 @@ class ExtendedUserProfileFieldSerializer(serializers.ModelSerializer):
     class Meta:
         model = models.ExtendedUserProfileField
         fields = ['id', 'name', 'help_text', 'order', 'created_date',
-                  'updated_date', 'field_type', 'other', 'choices', 'checkbox_label', 'links']
+                  'updated_date', 'field_type', 'other', 'choices', 'checkbox_label', 'links', 'required']
         read_only_fields = ('created_date', 'updated_date')
 
     def to_representation(self, instance):
@@ -175,6 +175,7 @@ class ExtendedUserProfileFieldSerializer(serializers.ModelSerializer):
         instance.name = validated_data['name']
         instance.help_text = validated_data['help_text']
         instance.order = validated_data['order']
+        instance.required = validated_data.get('required', instance.required)
         # logger.debug(f"instance.field_type={instance.field_type}, validated_data={validated_data}")
         if instance.field_type == 'single_choice':
             instance.single_choice.other = validated_data.get('other', instance.single_choice.other)