From 524186b80172945413a1fb69f263bcf90372d2c6 Mon Sep 17 00:00:00 2001 From: bobbyvish Date: Mon, 8 Apr 2024 00:33:02 +0530 Subject: [PATCH] refactor: validation of all forms --- module_activity/api/urls.py | 1 + module_activity/api/views.py | 39 ++++++++ module_activity/views.py | 28 ++++-- module_auth/views.py | 1 + module_iam/forms.py | 4 + ...9_alter_appversion_device_type_and_more.py | 34 +++++++ module_iam/models.py | 8 +- .../base_structure/elements/sidebar.html | 4 +- .../layout/base_authentication_template.html | 1 + .../base_structure/layout/base_template.html | 1 + templates/module_activity/bowel_detail.html | 16 ++-- .../chronic_conditon_list.html | 16 +++- .../module_activity/intolerance_list.html | 16 +++- templates/module_activity/meal_detail.html | 16 ++-- .../module_activity/meal_symptom_details.html | 16 ++-- .../module_activity/medication_detail.html | 16 ++-- .../module_activity/past_treatment_list.html | 16 +++- templates/module_activity/symptoms_list.html | 16 +++- .../module_auth/password_reset_confirm.html | 50 +++++++++- templates/module_auth/user_add.html | 78 +++++++++++++++- templates/module_cms/faq_add.html | 35 ++++++- templates/module_cms/privacy_policy_edit.html | 28 ++++-- .../module_cms/terms_and_condition_edit.html | 23 +++-- .../module_iam/profile_details_edit.html | 93 ++++++++++++++++++- templates/module_support/contact_us.html | 2 +- 25 files changed, 475 insertions(+), 83 deletions(-) create mode 100644 module_iam/migrations/0009_alter_appversion_device_type_and_more.py diff --git a/module_activity/api/urls.py b/module_activity/api/urls.py index 5783cf9..4d16985 100644 --- a/module_activity/api/urls.py +++ b/module_activity/api/urls.py @@ -25,6 +25,7 @@ urlpatterns = [ path("meal-symptoms//", views.MealSymptomAPIView.as_view()), path("meal/", views.MealAPIView.as_view()), + path("meal/duplicate/", views.MealDuplicateAPIView.as_view()), path("meal/date/", views.MealDateAPIView.as_view()), path("meal//", views.MealAPIView.as_view()), diff --git a/module_activity/api/views.py b/module_activity/api/views.py index a87eb92..7979a8f 100644 --- a/module_activity/api/views.py +++ b/module_activity/api/views.py @@ -621,6 +621,45 @@ class MealAPIView(APIView): message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT ) + +class MealDuplicateAPIView(APIView): + authentication_classes = [JWTAuthentication] + permission_classes = [IsAuthenticated] + serializer_class = MealRecordSerializer + model = MealRecord + + def post(self, request): + meal_id = request.POST.get("id") + meal_time = request.POST.get("time") + try: + original_meal = self.model.objects.get(pk=meal_id) + except Exception as e: + return ApiResponse.error(message="Meal not found", errors=str(e)) + + instance = self.model( + principal=original_meal.principal, + date=original_meal.date, + time=meal_time, + meal_type=original_meal.meal_type + ) + + instance.save() + + for food_obj in original_meal.food_records.all(): + instance.food_records.add(food_obj) + + for beverage_obj in original_meal.beverage_records.all(): + instance.beverage_records.add(beverage_obj) + + for ingredient_obj in original_meal.food_ingredient_records.all(): + instance.food_ingredient_records.add(ingredient_obj) + + instance.save() + + serializer_obj = self.serializer_class(instance).data + + return ApiResponse.success(message=constants.SUCCESS, data=serializer_obj) + class FoodDataAPIView(APIView): authentication_classes = [] permission_classes = [] diff --git a/module_activity/views.py b/module_activity/views.py index 448b939..c05e18b 100644 --- a/module_activity/views.py +++ b/module_activity/views.py @@ -98,6 +98,11 @@ class BaseListJson(BaseDatatableView): model = Intolerance columns = ["id", "name", "duration", "active", "deleted"] order_columns = ["id", "name", "duration", "active", "deleted"] + FILTER_ICONTAINS = "icontains" + + def get_filter_method(self): + """Returns preferred filter method""" + return self.FILTER_ICONTAINS def get_initial_queryset(self): principal_id = self.kwargs.get("principal_id") @@ -105,12 +110,18 @@ class BaseListJson(BaseDatatableView): return self.model.objects.filter(principal=principal_id, deleted=deleted_flag) - def filter_queryset(self, qs): - search_value = self.request.GET.get("search[value]", None) - if search_value: - qs = qs.filter( - Q(name__icontains=search_value) | Q(duration__icontains=search_value) - ) + def ordering(self, qs): + print(f"request is {self.request.GET}") + order = self.request.GET.get('order[0][dir]', None) + if order: + column_index = int(self.request.GET.get('order[0][column]', None)) - 1 + order_column = self.order_columns[column_index] + print(f"order column is {order_column}") + if order == "asc": + qs = qs.order_by(order_column) + elif order == "desc": + qs = qs.order_by("-" + order_column) + return qs @@ -317,6 +328,11 @@ class MealListJsonView(BaseDatatableView): model = MealRecord columns = ["id", "date", "time", "meal_type"] order_columns = ["id", "date", "time", "meal_type"] + FILTER_ICONTAINS = "icontains" + + def get_filter_method(self): + """Returns preferred filter method""" + return self.FILTER_ICONTAINS def get_initial_queryset(self): principal_id = self.kwargs.get("principal_id") diff --git a/module_auth/views.py b/module_auth/views.py index daf902c..49ca854 100644 --- a/module_auth/views.py +++ b/module_auth/views.py @@ -249,6 +249,7 @@ class UserRecordView(permission.ResourcePermissionRequiredMixin, LoginRequiredMi recent_meal_symptom_records = MealSymptomRecord.objects.filter( principal=id ).order_by('-id')[:5] + return recent_meal_symptom_records def get(self, request, id): # Retrieve the IAmPrincipal instance diff --git a/module_iam/forms.py b/module_iam/forms.py index f171d74..391f80f 100644 --- a/module_iam/forms.py +++ b/module_iam/forms.py @@ -100,6 +100,7 @@ class IAmPrincipalForm(forms.ModelForm): if principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_ADMIN): instance.is_superuser = True elif principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_SUBADMIN): + instance.is_superuser = False instance.is_staff = True if commit: instance.save() @@ -221,6 +222,9 @@ class ProfileEditForm(forms.ModelForm): "gender", "phone_no" ] + labels = { + 'phone_no': 'Phone Number', # Map phone_no field to phone_number_label variable + } class IAmPrincipalResourceLinkForm(IAmPrincipalForm): diff --git a/module_iam/migrations/0009_alter_appversion_device_type_and_more.py b/module_iam/migrations/0009_alter_appversion_device_type_and_more.py new file mode 100644 index 0000000..e19a4db --- /dev/null +++ b/module_iam/migrations/0009_alter_appversion_device_type_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 5.0.2 on 2024-04-05 07:06 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('module_iam', '0008_appversion_device_type_alter_appversion_version'), + ] + + operations = [ + migrations.AlterField( + model_name='appversion', + name='device_type', + field=models.CharField(choices=[('apple', 'apple'), ('android', 'android')], max_length=10, verbose_name='Device Type (apple / android)'), + ), + migrations.AlterField( + model_name='appversion', + name='force_upgrade', + field=models.BooleanField(default=False, help_text='Indicates whether a force upgrade is needed for this app version.', verbose_name='Force Upgrade'), + ), + migrations.AlterField( + model_name='appversion', + name='recommend_upgrade', + field=models.BooleanField(default=False, help_text='Indicates whether a recommend upgrade is needed for this app version.', verbose_name='Recommend Upgrade'), + ), + migrations.AlterField( + model_name='appversion', + name='version', + field=models.CharField(max_length=5, validators=[django.core.validators.RegexValidator('^\\d+\\.\\d+\\.\\d+$')], verbose_name='Version'), + ), + ] diff --git a/module_iam/models.py b/module_iam/models.py index 497afc9..1b16eca 100644 --- a/module_iam/models.py +++ b/module_iam/models.py @@ -452,10 +452,10 @@ class AppVersion(models.Model): ('apple', 'apple'), ('android', 'android'), ] - device_type = models.CharField(max_length=10, choices=DEVICE_CHOICES) - version = models.CharField(max_length=10, validators=[RegexValidator(r'^\d+\.\d+$')]) - force_upgrade = models.BooleanField(default=False, help_text='Indicates whether a force upgrade is needed for this app version.') - recommend_upgrade = models.BooleanField(default=False, help_text='Indicates whether a recommend upgrade is needed for this app version.') + device_type = models.CharField(max_length=10, choices=DEVICE_CHOICES, verbose_name='Device Type (apple / android)') + version = models.CharField(max_length=5, validators=[RegexValidator(r'^\d+\.\d+\.\d+$')], verbose_name='Version') + force_upgrade = models.BooleanField(default=False, verbose_name='Force Upgrade', help_text='Indicates whether a force upgrade is needed for this app version.') + recommend_upgrade = models.BooleanField(default=False, verbose_name='Recommend Upgrade', help_text='Indicates whether a recommend upgrade is needed for this app version.') class Meta: db_table = "app_version" diff --git a/templates/base_structure/elements/sidebar.html b/templates/base_structure/elements/sidebar.html index 703f0fa..f813dfe 100644 --- a/templates/base_structure/elements/sidebar.html +++ b/templates/base_structure/elements/sidebar.html @@ -51,8 +51,8 @@ IAM Group
  • - IAM Role --> -
  • + IAM Role + --> {% endif %} diff --git a/templates/base_structure/layout/base_authentication_template.html b/templates/base_structure/layout/base_authentication_template.html index 9039d91..104831b 100644 --- a/templates/base_structure/layout/base_authentication_template.html +++ b/templates/base_structure/layout/base_authentication_template.html @@ -47,6 +47,7 @@ + diff --git a/templates/base_structure/layout/base_template.html b/templates/base_structure/layout/base_template.html index 083acce..b184c75 100644 --- a/templates/base_structure/layout/base_template.html +++ b/templates/base_structure/layout/base_template.html @@ -71,6 +71,7 @@ + diff --git a/templates/module_activity/bowel_detail.html b/templates/module_activity/bowel_detail.html index 89a803f..1d2d185 100644 --- a/templates/module_activity/bowel_detail.html +++ b/templates/module_activity/bowel_detail.html @@ -12,16 +12,12 @@
    -

    Bowel Details

    -
    -
    - {% comment %} {% endcomment %} - {% comment %} Add - Category {% endcomment %} - {% comment %} Add User {% endcomment %} + +

    + + arrow_back + Bowel Details

    +
    diff --git a/templates/module_activity/chronic_conditon_list.html b/templates/module_activity/chronic_conditon_list.html index 6d3ac20..8b161aa 100644 --- a/templates/module_activity/chronic_conditon_list.html +++ b/templates/module_activity/chronic_conditon_list.html @@ -38,8 +38,10 @@ + Sr no. # + aria-sort="ascending" style="width: 50.2656px;">Record Id User Symptoms <'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" + "<'table-responsive'tr>" + diff --git a/templates/module_activity/intolerance_list.html b/templates/module_activity/intolerance_list.html index 828834f..a92b17c 100644 --- a/templates/module_activity/intolerance_list.html +++ b/templates/module_activity/intolerance_list.html @@ -38,8 +38,10 @@ + Sr no # + aria-sort="ascending" style="width: 50.2656px;">Record Id User Intolerances <'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" + "<'table-responsive'tr>" + diff --git a/templates/module_activity/meal_detail.html b/templates/module_activity/meal_detail.html index 2ad0cc5..a617509 100644 --- a/templates/module_activity/meal_detail.html +++ b/templates/module_activity/meal_detail.html @@ -12,16 +12,12 @@
    -

    Meal Details

    -
    -
    - {% comment %} {% endcomment %} - {% comment %} Add - Category {% endcomment %} - {% comment %} Add User {% endcomment %} + +

    + + arrow_back + Meal Details

    +
    diff --git a/templates/module_activity/meal_symptom_details.html b/templates/module_activity/meal_symptom_details.html index cb0daa0..9a78b21 100644 --- a/templates/module_activity/meal_symptom_details.html +++ b/templates/module_activity/meal_symptom_details.html @@ -12,16 +12,12 @@
    -

    Meal Symptoms Details

    -
    -
    - {% comment %} {% endcomment %} - {% comment %} Add - Category {% endcomment %} - {% comment %} Add User {% endcomment %} + +

    + + arrow_back + Meal Symptoms Details

    +
    diff --git a/templates/module_activity/medication_detail.html b/templates/module_activity/medication_detail.html index 5168b57..e55fabd 100644 --- a/templates/module_activity/medication_detail.html +++ b/templates/module_activity/medication_detail.html @@ -12,16 +12,12 @@
    -

    Meal Details

    -
    -
    - {% comment %} {% endcomment %} - {% comment %} Add - Category {% endcomment %} - {% comment %} Add User {% endcomment %} + +

    + + arrow_back + Medication Details

    +
    diff --git a/templates/module_activity/past_treatment_list.html b/templates/module_activity/past_treatment_list.html index 415969d..dedbb33 100644 --- a/templates/module_activity/past_treatment_list.html +++ b/templates/module_activity/past_treatment_list.html @@ -39,8 +39,10 @@ + Sr no. # + aria-sort="ascending" style="width: 50.2656px;">Record Id User Past Treatment <'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" + "<'table-responsive'tr>" + diff --git a/templates/module_activity/symptoms_list.html b/templates/module_activity/symptoms_list.html index 0dec90c..2aeee2e 100644 --- a/templates/module_activity/symptoms_list.html +++ b/templates/module_activity/symptoms_list.html @@ -38,8 +38,10 @@ + Sr no # + aria-sort="ascending" style="width: 50.2656px;">Record Id User Symptoms <'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" + "<'table-responsive'tr>" + diff --git a/templates/module_auth/password_reset_confirm.html b/templates/module_auth/password_reset_confirm.html index 3e0c537..a65f64b 100644 --- a/templates/module_auth/password_reset_confirm.html +++ b/templates/module_auth/password_reset_confirm.html @@ -9,21 +9,21 @@
    {% if validlink %} -
    + {% csrf_token %}
    - {{ form.new_password1.errors }} + {{ form.new_password1.errors }}
    - {{ form.new_password2.errors }} + {{ form.new_password2.errors }}
    @@ -40,5 +40,49 @@ {% block javascript %} + + {% endblock %} diff --git a/templates/module_auth/user_add.html b/templates/module_auth/user_add.html index b6e84b2..e88760a 100644 --- a/templates/module_auth/user_add.html +++ b/templates/module_auth/user_add.html @@ -22,7 +22,7 @@
    -
    + {% csrf_token %} {% include 'base_structure/includes/dynamic_template_form.html' with form=form %}
    @@ -42,5 +42,81 @@ {% block javascript %} + {% endblock %} \ No newline at end of file diff --git a/templates/module_cms/faq_add.html b/templates/module_cms/faq_add.html index 8ba0fcb..a6c0879 100644 --- a/templates/module_cms/faq_add.html +++ b/templates/module_cms/faq_add.html @@ -24,7 +24,7 @@
    - + {% csrf_token %} {% include 'base_structure/includes/dynamic_template_form.html' with form=form %}
    @@ -47,6 +47,37 @@ {% endblock %} \ No newline at end of file diff --git a/templates/module_cms/privacy_policy_edit.html b/templates/module_cms/privacy_policy_edit.html index 7c51ebc..75c6120 100644 --- a/templates/module_cms/privacy_policy_edit.html +++ b/templates/module_cms/privacy_policy_edit.html @@ -3,8 +3,8 @@ {% block stylesheet %} - {% include "cdn_through_html/quill_cdn_css.html" %} - {{form.media}} +{% include "cdn_through_html/quill_cdn_css.html" %} +{{form.media}} {% endblock %} @@ -26,9 +26,10 @@
    - + {% csrf_token %} {% include 'base_structure/includes/dynamic_template_form.html' with form=form %} +
    @@ -48,11 +49,22 @@ {% include "cdn_through_html/quill_cdn_js.html" %} - - {% endblock %} \ No newline at end of file diff --git a/templates/module_cms/terms_and_condition_edit.html b/templates/module_cms/terms_and_condition_edit.html index 8477f6e..d983930 100644 --- a/templates/module_cms/terms_and_condition_edit.html +++ b/templates/module_cms/terms_and_condition_edit.html @@ -26,9 +26,10 @@
    - + {% csrf_token %} {% include 'base_structure/includes/dynamic_template_form.html' with form=form %} +
    @@ -48,11 +49,21 @@ {% include "cdn_through_html/quill_cdn_js.html" %} - - {% endblock %} \ No newline at end of file diff --git a/templates/module_iam/profile_details_edit.html b/templates/module_iam/profile_details_edit.html index d76df09..13a84e0 100644 --- a/templates/module_iam/profile_details_edit.html +++ b/templates/module_iam/profile_details_edit.html @@ -75,7 +75,7 @@
    --> -
    + {% csrf_token %} {% include 'base_structure/includes/dynamic_template_form.html' with form=form %}
    @@ -127,7 +127,96 @@ if (profilePhotoUrl) { // If the URL exists, add the profile photo to FilePond pond.addFile(profilePhotoUrl); -} + } + + $(document).ready(function() { + // Add custom validation method to check for special characters + $.validator.addMethod("noSpecialChars", function(value, element) { + return /^[a-zA-Z\s]*$/.test(value); // Allow only letters and whitespace + }, "Please enter only letters and spaces."); + + // Add custom validation method to check for starting with a letter + $.validator.addMethod("startsWithLetter", function(value, element) { + return /^[a-zA-Z]/.test(value); // Check if the value starts with a letter + }, "Please start with a letter."); + + // Initialize form validation + $("#profileEditForm").validate({ + rules: { + first_name: { + required: true, + minlength: 2, + maxlength:15, + noSpecialChars: true, + startsWithLetter: true + }, + last_name: { + required: true, + minlength: 2, + maxlength: 15, + noSpecialChars: true, + startsWithLetter: true + }, + date_of_birth: { + required: true, + date: true, + dateISO: true, // Check for ISO date format (YYYY-MM-DD) + pattern: /^\d{4}-\d{2}-\d{2}$/ // Custom pattern for YYYY-MM-DD format + }, + gender: { + required: true + }, + phone_no: { + required: true, + digits: true, + minlength: 10, + maxlength: 10 + } + }, + messages: { + first_name: { + required: "Please enter your first name.", + minlength: "First name must be at least 2 characters.", + maxlength: "First name must not exceed 15 characters.", + noSpecialChars: "Please enter only letters and spaces.", + startsWithLetter: "First name must start with a letter." + }, + last_name: { + required: "Please enter your last name.", + minlength: "Last name must be at least 2 characters.", + maxlength: "First name must not exceed 15 characters.", + noSpecialChars: "Please enter only letters and spaces.", + startsWithLetter: "Last name must start with a letter." + }, + date_of_birth: { + required: "Please enter your date of birth.", + date: "Please enter a valid date in the format YYYY-MM-DD.", + dateISO: "Please enter a valid date in the format YYYY-MM-DD.", + pattern: "Please enter a valid date in the format YYYY-MM-DD." + }, + gender: { + required: "Please select your gender." + }, + phone_no: { + required: "Please enter your phone number.", + digits: "Please enter only digits.", + minlength: "Phone number must be 10 digits long.", + maxlength: "Phone number must be 10 digits long." + } + }, + errorElement: 'div', + errorPlacement: function(error, element) { + error.addClass('invalid-feedback'); + $(element).closest('.form-group').append(error); + }, + highlight: function(element, errorClass, validClass) { + $(element).addClass('is-invalid').removeClass('is-valid'); + }, + unhighlight: function(element, errorClass, validClass) { + $(element).removeClass('is-invalid').addClass('is-valid'); + } + }); + }); {% endblock %} \ No newline at end of file diff --git a/templates/module_support/contact_us.html b/templates/module_support/contact_us.html index e51f764..2a2ae60 100644 --- a/templates/module_support/contact_us.html +++ b/templates/module_support/contact_us.html @@ -115,7 +115,7 @@ -
    +