diff options
author | pnshiralkar | 2020-05-19 01:25:30 +0530 |
---|---|---|
committer | pnshiralkar | 2020-05-19 01:25:30 +0530 |
commit | 9dad3388d07af45c885fbe5b713294a19d7d6b2e (patch) | |
tree | b2e9e26098fdd59c776b115b1ece95dcb83e0143 | |
parent | c23bbd34b4f31002c47ef6167144f104b74b5b71 (diff) | |
parent | 9487f85e6731147c4580c53383c24faae35ebd72 (diff) | |
download | workshop_booking-9dad3388d07af45c885fbe5b713294a19d7d6b2e.tar.gz workshop_booking-9dad3388d07af45c885fbe5b713294a19d7d6b2e.tar.bz2 workshop_booking-9dad3388d07af45c885fbe5b713294a19d7d6b2e.zip |
Merge branch 'revampv2' of https://github.com/FOSSEE/workshop_booking into cms
-rw-r--r-- | workshop_app/forms.py | 26 | ||||
-rw-r--r-- | workshop_app/models.py | 2 | ||||
-rw-r--r-- | workshop_app/static/workshop_app/js/datepicker.js | 50 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/add_workshop_type.html | 50 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/base.html | 10 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/edit_workshop_type.html | 110 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/my_workshops.html | 234 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/propose_workshop.html | 42 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/workshop_status_coordinator.html | 88 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/workshop_status_instructor.html | 139 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/workshop_type_details.html | 33 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/workshop_type_list.html | 60 | ||||
-rw-r--r-- | workshop_app/urls.py | 22 | ||||
-rw-r--r-- | workshop_app/views.py | 262 |
14 files changed, 719 insertions, 409 deletions
diff --git a/workshop_app/forms.py b/workshop_app/forms.py index 334bd4e..4bef28c 100644 --- a/workshop_app/forms.py +++ b/workshop_app/forms.py @@ -1,9 +1,11 @@ from string import punctuation, digits from django import forms +from django.forms import inlineformset_factory from django.utils import timezone -from .models import (Profile, Workshop, ProfileComments, department_choices, title, source, states) +from .models import (Profile, Workshop, ProfileComments, department_choices, title, source, states, WorkshopType, + AttachmentFile) try: from string import letters @@ -189,3 +191,25 @@ class ProfileCommentsForm(forms.ModelForm): widgets = { 'comments': forms.CharField(), } + + +class WorkshopTypeForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(WorkshopTypeForm, self).__init__(*args, **kwargs) + for field in self.visible_fields(): + field.field.widget.attrs['class'] = 'form-control' + field.field.widget.attrs['placeholder'] = field.label + field.field.widget.attrs['rows'] = 6 + + class Meta: + model = WorkshopType + exclude = [] + + +class AttachmentFileForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(AttachmentFileForm, self).__init__(*args, **kwargs) + + class Meta: + model = AttachmentFile + exclude = ['workshop_type'] diff --git a/workshop_app/models.py b/workshop_app/models.py index b35d9a7..b43600f 100644 --- a/workshop_app/models.py +++ b/workshop_app/models.py @@ -145,7 +145,7 @@ class WorkshopType(models.Model): class AttachmentFile(models.Model): - attachments = models.FileField(upload_to=attachments, blank=True, + attachments = models.FileField(upload_to=attachments, blank=False, help_text='Please upload workshop documents one by one, \ ie.workshop schedule, instructions etc. \ Please Note: Name of Schedule file should be similar to \ diff --git a/workshop_app/static/workshop_app/js/datepicker.js b/workshop_app/static/workshop_app/js/datepicker.js new file mode 100644 index 0000000..19f91d6 --- /dev/null +++ b/workshop_app/static/workshop_app/js/datepicker.js @@ -0,0 +1,50 @@ +//ToolTip popup function on-hover +$(document).ready(function () { + $('[data-toggle="popover"]').popover({ + placement: 'top', + trigger: 'hover' + }); + + $('[data-toggle="popinfo"]').popover({ + placement: 'top', + trigger: 'hover' + }); +}); + +// Change date modal +function changeDate(date) { + let previous_date = new Date(date); + let dateToday = new Date(); + let upto = new Date(); + + previous_date.setDate(previous_date.getDate() + 1); + upto.setFullYear(dateToday.getFullYear() + 1); + + let counter = date.split(" "); + const id = counter.slice(-1).pop(); + if (date[0] === 'P') { + counter = '.pDate' + id + $(counter).datepicker({ + changeMonth: true, + changeYear: true, + minDate: dateToday, + maxDate: upto, + dateFormat: "yy-mm-dd", + }); + $(".ui-dialog-content").dialog("close"); + $('.myDialogP' + id).dialog(); + + } else { + counter = '.rDate' + id; + $(counter).datepicker({ + changeMonth: true, + changeYear: true, + minDate: dateToday, + maxDate: upto, + dateFormat: "yy-mm-dd", + }); + $(".ui-dialog-content").dialog("close"); + $('.myDialogR' + id).dialog(); + + } +};
\ No newline at end of file diff --git a/workshop_app/templates/workshop_app/add_workshop_type.html b/workshop_app/templates/workshop_app/add_workshop_type.html new file mode 100644 index 0000000..ed28b03 --- /dev/null +++ b/workshop_app/templates/workshop_app/add_workshop_type.html @@ -0,0 +1,50 @@ +{% extends 'workshop_app/base.html' %} + +{% block title %} + Add new Workshop type +{% endblock %} + +{% block content %} + <div class="container"> + <h2 class="text-center m-2">New Workshop Type</h2> + <br> + <form method="post"> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Workshop Name :</div> + <div class="col text-left"> + <div class="row"><div class="col">{{ form.name }}</div></div> + <div class="row m-1 text-danger"><div class="col">{{ form.name.errors }}</div></div> + </div> + + </div> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Duration :</div> + <div class="col text-left"> + <div class="row"><div class="col">{{ form.duration }}</div></div> + <div class="row m-1 text-muted"><div class="col">{{ form.duration.help_text }}</div></div> + <div class="row m-1 text-danger"><div class="col">{{ form.duration.errors }}</div></div> + </div> + </div> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Description :</div> + <div class="col text-left"> + <div class="row"><div class="col">{{ form.description }}</div></div> + <div class="row m-1 text-danger"><div class="col">{{ form.description.errors }}</div></div> + </div> + </div> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Terms and Conditions :</div> + <div class="col text-left"> + <div class="row"><div class="col">{{ form.terms_and_conditions }}</div></div> + <div class="row m-1 text-danger"><div class="col">{{ form.terms_and_conditions.errors }}</div></div> + </div> + </div> + + <div class="row my-3"> + <div class="col-12"> + <button type="submit" class="btn btn-md btn-primary float-right m-3">Create</button> + </div> + </div> + </form> + </div> +{% endblock %}
\ No newline at end of file diff --git a/workshop_app/templates/workshop_app/base.html b/workshop_app/templates/workshop_app/base.html index c7a454e..ae404e7 100644 --- a/workshop_app/templates/workshop_app/base.html +++ b/workshop_app/templates/workshop_app/base.html @@ -43,20 +43,20 @@ <ul class="navbar-nav mr-auto"> {% if request.user.profile.position == 'coordinator' %} <li class="nav-item"> - <a class="nav-link" href="/my_workshops/">Workshop Status</a> + <a class="nav-link" href="{% url 'workshop_status_instructor' %}">Workshop Status</a> </li> <li class="nav-item"> - <a class="nav-link" href="/propose_workshop/">Propose Workshop</a> + <a class="nav-link" href="{% url 'propose_workshop' %}">Propose Workshop</a> </li> <li class="nav-item"> - <a class="nav-link" href="/workshop_types/">Workshop Types</a> + <a class="nav-link" href="{% url 'workshop_type_list' %}">Workshop Types</a> </li> {% elif request.user.profile.position == 'instructor' %} <li class="nav-item"> - <a class="nav-link" href="/my_workshops/">Workshop Status</a> + <a class="nav-link" href="{% url 'workshop_status_instructor' %}">Workshop Status</a> </li> <li class="nav-item"> - <a class="nav-link" href="/workshop_types/">Workshop Types</a> + <a class="nav-link" href="{% url 'workshop_type_list' %}">Workshop Types</a> </li> {% endif %} </ul> diff --git a/workshop_app/templates/workshop_app/edit_workshop_type.html b/workshop_app/templates/workshop_app/edit_workshop_type.html new file mode 100644 index 0000000..b756f39 --- /dev/null +++ b/workshop_app/templates/workshop_app/edit_workshop_type.html @@ -0,0 +1,110 @@ +{% extends 'workshop_app/base.html' %} + +{% block title %} + Add new Workshop type +{% endblock %} + +{% block extra-dependencies %} +{% endblock %} + +{% block extra-custom-scripts %} + + <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.formset/1.2.2/jquery.formset.js"></script> +{% endblock %} + +{% block content %} + <div class="container"> + <h2 class="text-center m-2">View / Edit Workshop Type</h2> + <br> + <form method="post" enctype="multipart/form-data"> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Workshop Name :</div> + <div class="col text-left"> + <div class="row"> + <div class="col">{{ form.name }}</div> + </div> + <div class="row m-1 text-danger"> + <div class="col">{{ form.name.errors }}</div> + </div> + </div> + + </div> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Duration :</div> + <div class="col text-left"> + <div class="row"> + <div class="col">{{ form.duration }}</div> + </div> + <div class="row m-1 text-muted"> + <div class="col">{{ form.duration.help_text }}</div> + </div> + <div class="row m-1 text-danger"> + <div class="col">{{ form.duration.errors }}</div> + </div> + </div> + </div> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Description :</div> + <div class="col text-left"> + <div class="row"> + <div class="col">{{ form.description }}</div> + </div> + <div class="row m-1 text-danger"> + <div class="col">{{ form.description.errors }}</div> + </div> + </div> + </div> + <div class="row my-3"> + <div class="col-3 font-weight-bold">Terms and Conditions :</div> + <div class="col text-left"> + <div class="row"> + <div class="col">{{ form.terms_and_conditions }}</div> + </div> + <div class="row m-1 text-danger"> + <div class="col">{{ form.terms_and_conditions.errors }}</div> + </div> + </div> + </div> + + <h2 class="text-center m-2">Attachments</h2> + {{ form_file.management_form }} + {{ form_file.non_form_errors }} + {% for form in form_file %} + <div class="inline {{ form_file.prefix }} my-4"> + <div class="row"> + <div class="col-11"> + {% for field in form %} + <div class="col-6">{{ field }}</div> + {% endfor %} + </div> + {% if form.id.value %} + <div class="col-1"> + <a href="{% url 'delete_attachment_file' form.id.value %}"><button class="btn btn-md btn-danger float-right" type="button">Delete</button></a> + </div> + {% endif %} + </div> + + </div> + <hr> + {% endfor %} + <div class="row my-3"> + <div class="col-12"> + <button type="submit" class="btn btn-md btn-primary float-right m-3">Save</button> + </div> + </div> + </form> + </div> + <br><br><br><br> + <script type="text/javascript"> + $(function () { + $(".inline.{{ form_file.prefix }}").formset({ + prefix: "{{ form_file.prefix }}", // The form prefix for your django formset + addCssClass: "btn btn-md btn-primary bordered inline-form-add", // CSS class applied to the add link + deleteCssClass: "hidden", // CSS class applied to the delete link + addText: 'Add another attachment', // Text for the add link + deleteText: '', + formCssClass: 'inline-form' // CSS class applied to each form in a formset + }) + }); + </script> +{% endblock %}
\ No newline at end of file diff --git a/workshop_app/templates/workshop_app/my_workshops.html b/workshop_app/templates/workshop_app/my_workshops.html deleted file mode 100644 index b6e3731..0000000 --- a/workshop_app/templates/workshop_app/my_workshops.html +++ /dev/null @@ -1,234 +0,0 @@ -{% extends "workshop_app/base.html" %} - -{% block title %} - Workshop Status -{% endblock %} - -{% block extra-dependencies %} - <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> - <script src="https://code.jquery.com/jquery-1.12.4.js"></script> - <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> -{% endblock %} -{% block extra-custom-scripts %} - <script> - //ToolTip popup function on-hover - $(document).ready(function () { - $('[data-toggle="popover"]').popover({ - placement: 'top', - trigger: 'hover' - }); - }); - - //ToolTip popup function on-hover - $(document).ready(function () { - $('[data-toggle="popinfo"]').popover({ - placement: 'top', - trigger: 'hover' - }); - }); - - // Change date modal - function changeDate(date) { - var previous_date = new Date(date); - var dateToday = new Date(); - var upto = new Date(); - - previous_date.setDate(previous_date.getDate() + 1); - upto.setFullYear(dateToday.getFullYear() + 1); - - if (date[0] == 'P') { - var counter = date.split(" "); - var id = counter.slice(-1).pop(); - counter = '.pDate' + id - $(counter).datepicker({ - changeMonth: true, - changeYear: true, - minDate: dateToday, - maxDate: upto, - dateFormat: "yy-mm-dd", - }); - $(".ui-dialog-content").dialog("close"); - $('.myDialogP' + id).dialog(); - - } else { - var counter = date.split(" "); - var id = counter.slice(-1).pop(); - counter = '.rDate' + id; - $(counter).datepicker({ - changeMonth: true, - changeYear: true, - minDate: dateToday, - maxDate: upto, - dateFormat: "yy-mm-dd", - }); - $(".ui-dialog-content").dialog("close"); - $('.myDialogR' + id).dialog(); - - } - }; - - </script> -{% endblock %} - - -{% block content %} - {% if workshops %} - <h3 align="center" style="color:#2952a2;">The status of your workshops </h3> - <br> - - <!-- Accepted View --> - <br> - <div class="container"> - <h3 align="center" style="color: #04a9cf;"><strong>Workshops Accepted</strong></h3> - <table class="table table-striped"> - <thead> - <tr> - {% if request.user.profile.position == 'instructor' %} - <th>Coordinator Name</th> - <th>Institute</th> - {% else %} - <th>Instructor Name</th> - {% endif %} - <th>Workshop Name</th> - <th>Workshop Day</th> - <th>Status</th> - </tr> - </thead> - {% csrf_token %} - {% for workshop in workshops %} - <tbody> - <tr> - {% if workshop.status == 1 and workshop.workshop_type %} - {% if request.user.profile.position == 'instructor' %} - <td> - <a href="{{ URL_ROOT }}/view_profile/{{ workshop.coordinator.profile.user.id }}"> - {{ workshop.coordinator.get_full_name }}</a></td> - <td>{{ workshop.coordinator.profile.institute }}</td> - {% else %} - <td>{{ workshop.instructor.get_full_name }}</td> - {% endif %} - <td>{{ workshop.workshop_type |capfirst }}</td> - {% if workshop.date > today %} - <td>{{ workshop.date | date }} - <span class="material-icons" style="cursor:pointer;" data-toggle="popinfo" - title="Note" - data-content="Click here to change date" - class="datepicker" - onclick="changeDate('R,{{ workshop.date| safe }}, {{ forloop.counter }}')">event</span> - <div class="myDialogR{{ forloop.counter }}" style="display: none;" - title="Select New Date"> - <form method="post"> - <input type="text" name="new_date" class="rDate{{ forloop.counter }}"/><br> - <input type="hidden" name="action" value="change_date"> - <input type="hidden" name="workshop_id" value="{{ workshop.id }}"> - <input type="hidden" name="cid" value="{{ workshop.coordinator.id }}"> - {% csrf_token %} - <button class="btn btn-primary btn-xs" type="submit">Save</button> - </form> - </div> - </td> - {% else %} - <td>{{ workshop.date | date }}</td> - {% endif %} - <td><span class="badge badge-success">{{ workshop.get_status }}</span></td> - {% endif %} - </tr> - </tbody> - - {% endfor %} - - </table> - </div> - - - <!-- Proposed View --> - <br> - <div class="container"> - - {% if request.user.profile.position == 'instructor' %} - <h3 align="center" style="color: #04a9cf;"><strong>Workshops Proposed By Coordinators</strong> - </h3> - {% else %} - <h3 align="center" style="color: #04a9cf;"><strong>Workshops Proposed By Me</strong></h3> - {% endif %} - <table class="table table-striped"> - <thead> - <tr> - {% if request.user.profile.position == 'instructor' %} - <th>Coordinator Name</th> - <th>Institute</th> - {% else %} - - {% endif %} - <th>Workshop Name</th> - <th>Workshop Day</th> - <th>Status</th> - {% if request.user.profile.position == 'instructor' %} - <th>Action</th> - {% endif %} - </tr> - </thead> - {% csrf_token %} - {% for workshop in workshops %} - <tbody> - <tr> - {% if workshop.status == 0 and workshop.tnc_accepted %} - {% if request.user.profile.position == 'instructor' %} - - <td> - <a href="{{ URL_ROOT }}/view_comment_profile/{{ workshop.coordinator.profile.user.id }}"> - {{ workshop.coordinator.get_full_name }}</a></td> - <td>{{ workshop.coordinator.profile.institute }}</td> - {% endif %} - <td>{{ workshop.workshop_type }}</td> - <td>{{ workshop.date | date }}</td> - - <td><span class="badge badge-warning">{{ workshop.get_status }}</span></td> - {% if request.user.profile.position == 'instructor' and workshop.status == 0 %} - <td> - <form method="post"> - <input type="hidden" name="action" value="accept"> - <input type="hidden" name="workshop_id" value="{{ workshop.id }}"> - {% csrf_token %} - <button class="btn btn-primary btn-sm" id="book-btn" data-toggle="popover" - title="Please Note" - data-content="Once Accepted you can't Reject, you have to personally contact the Coordinator if the workshop is to be cancelled"> - Accept - </button> - </form> - </td> - {% endif %} - {% endif %} - </tr> - </tbody> - - {% endfor %} - </table> - </div> - - - - {% else %} - {% if request.user.profile.position == 'instructor' %} - <div class="container"> - <div class="jumbotron"> - <h1>Welcome {{ user.first_name }}</h1> - <p>Your workshop related information will be shown here, Please navigate to <b>Workshop list</b> and - depending upon - your expertise and availability create a workshop by going to - <b>Create Workshop</b>.</p> - </div> - </div> - {% else %} - <div class="container"> - <div class="jumbotron"> - <h1>Welcome {{ user.first_name }}</h1> - <p>Information Related to your workshops will be shown here, you can also - propose a Workshop as per your available date in <strong>Workshops > Propose a Workshop - tab</strong> .</p> - </div> - </div> - {% endif %} - {% endif %} - -{% endblock %} diff --git a/workshop_app/templates/workshop_app/propose_workshop.html b/workshop_app/templates/workshop_app/propose_workshop.html index 678d11e..5ebc435 100644 --- a/workshop_app/templates/workshop_app/propose_workshop.html +++ b/workshop_app/templates/workshop_app/propose_workshop.html @@ -26,6 +26,20 @@ maxDate: upto, beforeShowDay: $.datepicker.noWeekends, }); + + + $('#disp_tnc').click(function (e) { + e.preventDefault() + if ($('#id_workshop_type').val() === '') + $('.modal-body').html("<p class='text-danger'>Please select a workshop_type first!</p>") + else + $.ajax({ + url: '/workshop_type_tnc/' + $('#id_workshop_type').val(), + success: function (data) { + $('.modal-body').html(data.tnc) + } + }) + }) }); </script> {% endblock %} @@ -36,6 +50,10 @@ .errorlist { color: red; } + + .modal-open .modal{ + overflow-y: hidden; + } </style> <div class="container" align="center"> @@ -59,7 +77,9 @@ <br> {{ form.date }} <br> - {{ form.tnc_accepted }} I accept the <a href="/tnc">terms and conditions</a> + {{ form.tnc_accepted }} I accept the <a href="#" id="disp_tnc" data-toggle="modal" + data-target="#exampleModalCenter">terms and + conditions</a> <br> {% if form.errors %} <br> @@ -78,4 +98,24 @@ <br> </div> + <!-- Modal --> + <div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" + aria-labelledby="exampleModalCenterTitle" aria-hidden="true"> + <div class="modal-dialog modal-dialog-centered" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="exampleModalLongTitle">Terms and Conditions</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> {% endblock %}
\ No newline at end of file diff --git a/workshop_app/templates/workshop_app/workshop_status_coordinator.html b/workshop_app/templates/workshop_app/workshop_status_coordinator.html new file mode 100644 index 0000000..00e28b3 --- /dev/null +++ b/workshop_app/templates/workshop_app/workshop_status_coordinator.html @@ -0,0 +1,88 @@ +{% extends "workshop_app/base.html" %} + +{% block title %} + My Workshops +{% endblock %} + +{% block extra-custom-scripts %} +<style > + .table-heading{ + color: #04a9cf; + } + </style> +{% endblock %} + +{% block content %} + {% if not workshops %} + <div class="container"> + <div class="jumbotron"> + <h1>Welcome {{ user.first_name }}</h1> + <p>Information Related to your workshops will be shown here, you can also + propose a Workshop as per your available date in <strong>Propose Workshop tab</strong> .</p> + </div> + </div> + {% else %} + <h3 class="text-center">The status of your workshops </h3> + <br> + + <!-- Accepted View --> + + <br> + <div class="container"> + <h3 class="text-center table-heading"><strong>Workshops Accepted</strong></h3> + <table class="table table-striped"> + <thead> + <tr> + <th>Instructor Name</th> + <th>Workshop Name</th> + <th>Workshop Day</th> + <th>Status</th> + </tr> + </thead> + + {% for workshop in workshops %} + <tbody> + <tr> + {% if workshop.status %} + <td>{{ workshop.instructor.get_full_name }}</td> + <td>{{ workshop.workshop_type |capfirst }}</td> + <td>{{ workshop.date | date }}</td> + <td><span class="badge badge-success">{{ workshop.get_status }}</span></td> + {% endif %} + </tr> + </tbody> + {% endfor %} + + </table> + </div> + + <!-- Proposed View --> + + <br> + <div class="container"> + <h3 class="text-center table-heading"><strong>Workshops Proposed By Me</strong></h3> + <table class="table table-striped"> + <thead> + <tr> + <th>Workshop Name</th> + <th>Workshop Day</th> + <th>Status</th> + </tr> + </thead> + {% for workshop in workshops %} + <tbody> + <tr> + {% if not workshop.status and workshop.tnc_accepted %} + <td>{{ workshop.workshop_type }}</td> + <td>{{ workshop.date | date }}</td> + <td><span class="badge badge-warning">{{ workshop.get_status }}</span></td> + {% endif %} + </tr> + </tbody> + + {% endfor %} + </table> + </div> + {% endif %} + +{% endblock %} diff --git a/workshop_app/templates/workshop_app/workshop_status_instructor.html b/workshop_app/templates/workshop_app/workshop_status_instructor.html new file mode 100644 index 0000000..ef64a70 --- /dev/null +++ b/workshop_app/templates/workshop_app/workshop_status_instructor.html @@ -0,0 +1,139 @@ +{% extends "workshop_app/base.html" %} + +{% block title %} + Workshop Status +{% endblock %} + +{% block extra-dependencies %} + <style > + .table-heading{ + color: #04a9cf; + } + </style> + <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> + <script src="https://code.jquery.com/jquery-1.12.4.js"></script> + <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> +{% endblock %} +{% block extra-custom-scripts %} + {% load static %} + <script src="{% static 'workshop_app/js/datepicker.js' %}"></script> +{% endblock %} + + +{% block content %} + {% if not workshops %} + <div class="container"> + <div class="jumbotron"> + <h1>Welcome {{ user.first_name }}</h1> + <p>Your workshop related information will be shown here, Please navigate to <b>Workshop list</b> and + depending upon + your expertise and availability create a workshop by going to + <b>Create Workshop</b>.</p> + </div> + </div> + {% else %} + <h3 class="text-center">The status of your workshops </h3> + <br> + + <!-- Accepted View --> + <br> + <div class="container"> + <h3 align="center" class="table-heading"><strong>Workshops Accepted</strong></h3> + <table class="table table-striped"> + <thead> + <tr> + <th>Coordinator Name</th> + <th>Institute</th> + <th>Workshop Name</th> + <th>Workshop Day</th> + <th>Status</th> + </tr> + </thead> + {% for workshop in workshops %} + <tbody> + <tr> + {% if workshop.status %} + <td> + <a href="{% url 'view_profile' workshop.coordinator.profile.user.id %}"> + {{ workshop.coordinator.get_full_name }}</a> + </td> + <td>{{ workshop.coordinator.profile.institute }}</td> + <td>{{ workshop.workshop_type |capfirst }}</td> + <td>{{ workshop.date | date }} + + {% if workshop.date > today %} + <span class="material-icons datepicker btn" + data-toggle="popinfo" + title="Note" + data-content="Click here to change date" + onclick="changeDate('R,{{ workshop.date| safe }}, {{ forloop.counter }}')">event</span> + <div class="myDialogR{{ forloop.counter }}" style="display: none;" + title="Select New Date"> + <form method="post" action="{% url 'change_workshop_date' workshop.id %}"> + <input type="text" placeholder="New date" name="new_date" + class="rDate{{ forloop.counter }}"/><br> + {% csrf_token %} + <button class="btn btn-primary btn-xs" type="submit">Save</button> + </form> + </div> + {% endif %} + </td> + <td><span class="badge badge-success">{{ workshop.get_status }}</span></td> + {% endif %} + </tr> + </tbody> + + {% endfor %} + + </table> + </div> + + + <!-- Proposed View --> + <br> + <div class="container"> + <h3 class="text-center table-heading"><strong>Workshops Proposed By Coordinators</strong> + </h3> + <table class="table table-striped"> + <thead> + <tr> + <th>Coordinator Name</th> + <th>Institute</th> + <th>Workshop Name</th> + <th>Workshop Day</th> + <th>Status</th> + <th>Action</th> + </tr> + </thead> + {% csrf_token %} + {% for workshop in workshops %} + <tbody> + <tr> + {% if not workshop.status and workshop.tnc_accepted %} + <td> + <a href="{% url 'view_profile' workshop.coordinator.profile.user.id %}"> + {{ workshop.coordinator.get_full_name }}</a> + </td> + <td>{{ workshop.coordinator.profile.institute }}</td> + <td>{{ workshop.workshop_type }}</td> + <td>{{ workshop.date | date }}</td> + <td><span class="badge badge-warning">{{ workshop.get_status }}</span></td> + <td> + <a href="{% url 'accept_workshop' workshop.id %}"> + <button class="btn btn-primary btn-sm" id="book-btn" data-toggle="popover" + title="Please Note" + data-content="Once Accepted you can't Reject, you have to personally contact the Coordinator if the workshop is to be cancelled"> + Accept + </button> + </a> + </td> + {% endif %} + </tr> + </tbody> + + {% endfor %} + </table> + </div> + {% endif %} + +{% endblock %} diff --git a/workshop_app/templates/workshop_app/workshop_type_details.html b/workshop_app/templates/workshop_app/workshop_type_details.html index b8d6559..298d976 100644 --- a/workshop_app/templates/workshop_app/workshop_type_details.html +++ b/workshop_app/templates/workshop_app/workshop_type_details.html @@ -1,23 +1,40 @@ - {% extends 'workshop_app/base.html' %} {% block title %} - View Workshop details + View Workshop details {% endblock %} {% block extra %} - <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> --> + <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> --> - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> - <script src="{{URL_ROOT}}/static/workshop_app/js/bootstrap-3.3.7.min.js"></script> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> + <script src="{{ URL_ROOT }}/static/workshop_app/js/bootstrap-3.3.7.min.js"></script> {% endblock %} {% block content %} - <div class="container"> - {{ workshop_type.description | safe }} - </div> + <div class="container"> + <h2 class="text-center m-3">Workshop Details</h2> + <table class="table table-hover"> + <tr class="d-flex"> + <th class="col-3">Workshop Name :</th> + <td class="col">{{ workshop_type.name }}</td> + </tr> + <tr class="d-flex"> + <th class="col-3">Duration :</th> + <td class="col">{{ workshop_type.duration }}</td> + </tr> + <tr class="d-flex"> + <th class="col-3">Description :</th> + <td class="col">{{ workshop_type.description }}</td> + </tr> + <tr class="d-flex"> + <th class="col-3">Terms and Conditions :</th> + <td class="col">{{ workshop_type.terms_and_conditions }}</td> + </tr> + </table> + </div> {% endblock %} diff --git a/workshop_app/templates/workshop_app/workshop_type_list.html b/workshop_app/templates/workshop_app/workshop_type_list.html index 0531864..a3d9c6e 100644 --- a/workshop_app/templates/workshop_app/workshop_type_list.html +++ b/workshop_app/templates/workshop_app/workshop_type_list.html @@ -4,55 +4,16 @@ View List of available Workshops {% endblock %} -{% block extra %} - - <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> --> - <style> - /* The Modal (background) */ - .modal { - display: none; /* Hidden by default */ - position: fixed; /* Stay in place */ - z-index: 1; /* Sit on top */ - padding-top: 100px; /* Location of the box */ - left: 0; - top: 0; - width: 100%; /* Full width */ - height: 100%; /* Full height */ - overflow: auto; /* Enable scroll if needed */ - background-color: rgb(0,0,0); /* Fallback color */ - background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ - } - - /* Modal Content */ - .modal-content { - background-color: #fefefe; - margin: auto; - padding: 20px; - border: 1px solid #888; - width: 80%; - } - - /* The Close Button */ - .close { - color: #aaaaaa; - float: right; - font-size: 28px; - font-weight: bold; - } - .close:hover, - .close:focus { - color: #000; - text-decoration: none; - cursor: pointer; - } - </style> - - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> - <script src="{{URL_ROOT}}/static/workshop_app/js/bootstrap-3.3.7.min.js"></script> - {% endblock %} - {% block content %} - + <div class="container"> + <h2 class="text-center">Workshop Types</h2> + <br> + {% if request.user.profile.position == 'instructor' %} + <a href="{% url 'add_workshop_type' %}"> + <button class="btn btn-md btn-primary float-right mb-3 mx-4">Add Workshop Type</button> + </a> + <br> + {% endif %} <div class="container"> <table class="table table-hover"> <thead> @@ -60,6 +21,7 @@ <th>id</th> <th>Workshop Name</th> <th>Workshop Duration</th> + <th>Action</th> </tr> </thead> @@ -119,5 +81,5 @@ </nav> </div> </div> - +</div> {% endblock %} diff --git a/workshop_app/urls.py b/workshop_app/urls.py index 84ab2fe..b8f1a68 100644 --- a/workshop_app/urls.py +++ b/workshop_app/urls.py @@ -16,10 +16,6 @@ Including another URLconf from django.conf.urls import url from workshop_app import views -js_info_dict = { - 'packages': ('recurrence', ), -} - urlpatterns = [ url(r'^register/$', views.user_register), url(r'^activate_user/(?P<key>.+)$', views.activate_user), @@ -28,9 +24,15 @@ urlpatterns = [ url(r'^logout/$', views.user_logout), url(r'^view_profile/$', views.view_profile), url(r'^edit_profile/$', views.edit_profile), - url(r'^my_workshops/$', views.my_workshops), - url(r'^propose_workshop/$', views.propose_workshop), - url(r'^workshop_types/$', views.workshop_type_list), - url(r'^workshop_type_details/([1-9][0-9]*)$', views.workshop_type_details), - url(r'^view_profile/([1-9][0-9]*)$', views.view_comment_profile), - ] + url(r'^workshop_status$', views.workshop_status_coordinator, name='workshop_status_coordinator'), + url(r'^dashboard$', views.workshop_status_instructor, name='workshop_status_instructor'), + url(r'^accept_workshop/(?P<workshop_id>\d+)', views.accept_workshop, name='accept_workshop'), + url(r'^change_workshop_date/(?P<workshop_id>\d+)$', views.change_workshop_date, name='change_workshop_date'), + url(r'^propose_workshop/$', views.propose_workshop, name='propose_workshop'), + url(r'^add_workshop_type$', views.add_workshop_type, name='add_workshop_type'), + url(r'^delete_attachment_file/(?P<file_id>\d+)$', views.delete_attachment_file, name='delete_attachment_file'), + url(r'^workshop_types/$', views.workshop_type_list, name='workshop_type_list'), + url(r'^workshop_type_details/(?P<workshop_type_id>\d+)$', views.workshop_type_details, name='workshop_type_details'), + url(r'^view_profile/(?P<user_id>\d+)$', views.view_comment_profile, name='view_profile'), + url(r'^workshop_type_tnc/(?P<workshop_type_id>\d+)$', views.workshop_type_tnc, name='workshop_type_tnc'), +] diff --git a/workshop_app/views.py b/workshop_app/views.py index 5d0525c..05ebf94 100644 --- a/workshop_app/views.py +++ b/workshop_app/views.py @@ -1,3 +1,8 @@ +from django.db.models import Q +from django.forms import inlineformset_factory, model_to_dict +from django.http import JsonResponse, Http404 +from django.urls import reverse + try: from StringIO import StringIO as string_io except ImportError: @@ -6,18 +11,18 @@ from datetime import datetime from django.contrib.auth import login, logout, authenticate from django.contrib.auth.decorators import login_required -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.core.paginator import Paginator from django.shortcuts import render, redirect from django.utils import timezone from .forms import ( UserRegistrationForm, UserLoginForm, - ProfileForm, WorkshopForm + ProfileForm, WorkshopForm, WorkshopTypeForm ) from .models import ( Profile, User, Workshop, - WorkshopType + WorkshopType, AttachmentFile ) from .send_mails import send_email @@ -42,8 +47,8 @@ def is_instructor(user): def get_landing_page(user): # For now, landing pages of both instructor and coordinator are same if is_instructor(user): - return '/my_workshops/' - return '/my_workshops/' + return reverse('workshop_status_instructor') + return reverse('workshop_status_coordinator') # View functions @@ -150,7 +155,7 @@ def user_register(request): ) else: if request.user.is_authenticated and is_email_checked(request.user): - return redirect('/my_workshops/') + return redirect(get_landing_page(request.user)) elif request.user.is_authenticated: return render(request, 'workshop_app/activation.html') form = UserRegistrationForm() @@ -195,102 +200,96 @@ def edit_profile(request): # Workshop views @login_required -def my_workshops(request): +def workshop_status_coordinator(request): + """ Workshops proposed by Coordinator """ user = request.user + if is_instructor(user): + return redirect(get_landing_page(user)) + workshops = Workshop.objects.filter( + coordinator=user.id + ).order_by('-date') + return render(request, 'workshop_app/workshop_status_coordinator.html', + {"workshops": workshops}) - if user.is_authenticated: - # View for instructor - if is_instructor(user): - if request.method == 'POST': - client_data = request.POST - action = request.POST.get('action') - if action == 'accept': - workshop = Workshop.objects.get(id=client_data.get('workshop_id')) - # Change Status of the selected workshop - workshop.status = 1 - workshop.instructor = user - workshop.save() - # Parameters for emails - coordinator_email = workshop.coordinator.email - coordinator_name = workshop.coordinator.profile.user.get_full_name() - coordinator_phone = workshop.coordinator.profile.phone_number - coordinator_institute = workshop.coordinator.profile.institute - instructor_phone = request.user.profile.phone_number - workshop_title = workshop.workshop_type.name - workshop_date = str(workshop.date) - - # For Instructor - send_email(request, call_on='Booking Confirmed', - user_position='instructor', - workshop_date=workshop_date, - workshop_title=workshop_title, - user_name=str(coordinator_name), - other_email=coordinator_email, - phone_number=coordinator_phone, - institute=coordinator_institute - ) - - # For Coordinator - send_email(request, call_on='Booking Confirmed', - workshop_date=workshop_date, - workshop_title=workshop_title, - other_email=coordinator_email, - phone_number=instructor_phone - ) - - elif action == 'change_date': - cid = client_data.get('cid') - new_workshop_date = datetime.strptime(client_data.get('new_date'), "%Y-%m-%d") - coordinator_email = User.objects.get(id=cid) - today = datetime.today() - if today > new_workshop_date: - # Invalid date - pass - else: - workshop = Workshop.objects.filter(id=client_data.get('workshop_id')) - workshop_date = workshop.first().date - workshop.update(date=new_workshop_date) - - # For Instructor - send_email(request, call_on='Change Date', - user_position='instructor', - workshop_date=str(workshop_date), - new_workshop_date=str(new_workshop_date.date()) - ) - # For Coordinator - send_email(request, call_on='Change Date', - new_workshop_date=str(new_workshop_date.date()), - workshop_date=str(workshop_date), - other_email=coordinator_email.email - ) +@login_required +def workshop_status_instructor(request): + """ Workshops to accept and accepted by Instructor """ + user = request.user + if not is_instructor(user): + return redirect(get_landing_page(user)) + today = timezone.now().date() + workshops = Workshop.objects.filter(Q( + instructor=user.id, + date__gte=today, + ) | Q(status=0)).order_by('-date') - today = timezone.now() - proposed_workshop = Workshop.objects.filter( - instructor=user.id, - date__gte=today, - ).order_by('-date') + return render(request, 'workshop_app/workshop_status_instructor.html', + {"workshops": workshops, + "today": today}) - proposed_workshop_pending = Workshop.objects.filter( - status=0 - ).order_by('-date') - workshops = list(proposed_workshop) + list(proposed_workshop_pending) +@login_required +def accept_workshop(request, workshop_id): + user = request.user + if not is_instructor(user): + return redirect(get_landing_page(user)) + workshop = Workshop.objects.get(id=workshop_id) + # Change Status of the selected workshop + workshop.status = 1 + workshop.instructor = user + workshop.save() + + coordinator_profile = workshop.coordinator.profile + + # For Instructor + send_email(request, call_on='Booking Confirmed', + user_position='instructor', + workshop_date=str(workshop.date), + workshop_title=workshop.workshop_type.name, + user_name=str(coordinator_profile.user.get_full_name()), + other_email=workshop.coordinator.email, + phone_number=coordinator_profile.phone_number, + institute=coordinator_profile.institute + ) + + # For Coordinator + send_email(request, call_on='Booking Confirmed', + workshop_date=str(workshop.date), + workshop_title=workshop.workshop_type.name, + other_email=workshop.coordinator.email, + phone_number=request.user.profile.phone_number + ) + return redirect(reverse('workshop_status_instructor')) - return render(request, 'workshop_app/my_workshops.html', - {"workshops": workshops, - "today": today}) - # Coordinator view - else: - workshops = Workshop.objects.filter( - coordinator=user.id - ).order_by('-date') - return render(request, 'workshop_app/my_workshops.html', - {"workshops": workshops}) - # Not logged in view - else: - return redirect('/login/') +@login_required +def change_workshop_date(request, workshop_id): + user = request.user + if not is_instructor(user): + return redirect(get_landing_page(user)) + if request.method == 'POST': + new_workshop_date = datetime.strptime(request.POST.get('new_date'), "%Y-%m-%d") + today = datetime.today() + if today <= new_workshop_date: + workshop = Workshop.objects.filter(id=workshop_id) + workshop_date = workshop.first().date + workshop.update(date=new_workshop_date) + + # For Instructor + send_email(request, call_on='Change Date', + user_position='instructor', + workshop_date=str(workshop_date), + new_workshop_date=str(new_workshop_date.date()) + ) + + # For Coordinator + send_email(request, call_on='Change Date', + new_workshop_date=str(new_workshop_date.date()), + workshop_date=str(workshop_date), + other_email=workshop.first().coordinator.email + ) + return redirect(reverse('workshop_status_instructor')) # TODO: Show terms n conditions of selected ws type @@ -316,7 +315,7 @@ def propose_workshop(request): workshop_type=form_data.workshop_type, coordinator=form_data.coordinator ).exists(): - return redirect('/my_workshops/') + return redirect(get_landing_page(user)) else: form_data.save() instructors = Profile.objects.filter(position='instructor') @@ -330,7 +329,7 @@ def propose_workshop(request): phone_number=user.profile.phone_number, institute=user.profile.institute ) - return redirect('/my_workshops/') + return redirect(get_landing_page(user)) # GET request return render( request, 'workshop_app/propose_workshop.html', @@ -338,19 +337,69 @@ def propose_workshop(request): ) +@login_required def workshop_type_details(request, workshop_type_id): """Gives the types of workshop details """ user = request.user if user.is_superuser: return redirect("/admin") - workshop_type = WorkshopType.objects.get(id=workshop_type_id) + workshop_type = WorkshopType.objects.filter(id=workshop_type_id) + if workshop_type.exists(): + workshop_type = workshop_type.first() + else: + return redirect(reverse('workshop_type_list')) + + qs = AttachmentFile.objects.filter(workshop_type=workshop_type) + AttachmentFileFormSet = inlineformset_factory(WorkshopType, AttachmentFile, fields=['attachments'], + can_delete=False, extra=(qs.count() + 1)) + + if is_instructor(user): + if request.method == 'POST': + form = WorkshopTypeForm(request.POST, instance=workshop_type) + form_file = AttachmentFileFormSet(request.POST, request.FILES, instance=form.instance) + if form.is_valid(): + form_data = form.save() + for file in form_file: + if file.is_valid() and file.clean() and file.clean()['attachments']: + if file.cleaned_data['id']: + file.cleaned_data['id'].delete() + file.save() + return redirect(reverse('workshop_type_details', args=[form_data.id])) + else: + form = WorkshopTypeForm(instance=workshop_type) + form_file = AttachmentFileFormSet() + for subform, data in zip(form_file, qs): + subform.initial = model_to_dict(data) + return render(request, 'workshop_app/edit_workshop_type.html', {'form': form, 'form_file': form_file}) return render( request, 'workshop_app/workshop_type_details.html', {'workshop_type': workshop_type} ) +@login_required +def delete_attachment_file(request, file_id): + if not is_instructor(request.user): + return redirect(get_landing_page(request.user)) + file = AttachmentFile.objects.filter(id=file_id) + if file.exists(): + file = file.first() + file.delete() + return redirect(reverse('workshop_type_details', args=[file.workshop_type.id])) + return redirect(reverse('workshop_type_list')) + + +@login_required +def workshop_type_tnc(request, workshop_type_id): + workshop_type = WorkshopType.objects.filter(id=workshop_type_id) + if workshop_type.exists(): + workshop_type = workshop_type.first() + return JsonResponse({'tnc': workshop_type.terms_and_conditions}) + else: + raise Http404 + + def workshop_type_list(request): """Gives the details for types of workshops.""" user = request.user @@ -360,16 +409,29 @@ def workshop_type_list(request): workshop_types = WorkshopType.objects.all() paginator = Paginator(workshop_types, 12) # Show upto 12 workshops per page - page = request.GET.get('page') - workshop_type = paginator.get_page(paginator.num_pages) + workshop_type = paginator.get_page(page) return render(request, 'workshop_app/workshop_type_list.html', {'workshop_type': workshop_type}) @login_required +def add_workshop_type(request): + if not is_instructor(request.user): + return redirect(get_landing_page(request.user)) + if request.method == 'POST': + form = WorkshopTypeForm(request.POST) + if form.is_valid(): + form_data = form.save() + return redirect(reverse('workshop_type_details', args=[form_data.id])) + else: + form = WorkshopTypeForm + return render(request, 'workshop_app/add_workshop_type.html', {'form': form}) + + +@login_required def view_comment_profile(request, user_id): - """instructor can view/post comments on coordinator profile """ + """Instructor can view coordinator profile """ user = request.user if is_instructor(user) and is_email_checked(user): coordinator_profile = Profile.objects.get(user_id=user_id) |