diff options
-rw-r--r-- | workshop_app/forms.py | 25 | ||||
-rw-r--r-- | workshop_app/models.py | 2 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/add_workshop_type.html | 50 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/base.html | 12 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/edit_workshop_type.html | 110 | ||||
-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 | 8 | ||||
-rw-r--r-- | workshop_app/views.py | 64 |
9 files changed, 291 insertions, 73 deletions
diff --git a/workshop_app/forms.py b/workshop_app/forms.py index 95b0ce1..46049f0 100644 --- a/workshop_app/forms.py +++ b/workshop_app/forms.py @@ -3,7 +3,8 @@ from string import punctuation, digits from django import forms from django.utils import timezone -from .models import (Profile, Workshop, department_choices, title, source, states, Comment) +from .models import (Profile, Workshop, Comment, department_choices, title, source, states, WorkshopType, + AttachmentFile) try: from string import letters @@ -192,3 +193,25 @@ class CommentsForm(forms.ModelForm): 'class': 'form-check-input', }) } + + +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 37f3a31..d690a7e 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/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 88ee1a1..398c38b 100644 --- a/workshop_app/templates/workshop_app/base.html +++ b/workshop_app/templates/workshop_app/base.html @@ -46,17 +46,17 @@ <a class="nav-link" href="{% url 'workshop_status_coordinator' %}">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="{% 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> @@ -92,9 +92,9 @@ {% endblock %} <div class="container-fluid" style="margin-bottom: 44px"> -{% block content %} - <h1>Base Template Content. Please override me</h1> -{% endblock %} + {% block content %} + <h1>Base Template Content. Please override me</h1> + {% endblock %} </div> </body> 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/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 eb101c3..f9c7877 100644 --- a/workshop_app/urls.py +++ b/workshop_app/urls.py @@ -29,10 +29,12 @@ urlpatterns = [ 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), - url(r'^workshop_types/$', views.workshop_type_list), url(r'^workshops/(?P<workshop_id>\d+)$', views.workshop_details, name='workshop_details'), url(r'^workshop_type_details/(?P<workshop_type_id>\d+)$', views.workshop_type_details, name='workshop_type_details'), url(r'^workshop_type_tnc/(?P<workshop_type_id>\d+)$', views.workshop_type_tnc, name='workshop_type_tnc'), - url(r'^view_profile/(?P<workshop_type_id>\d+)$', views.view_comment_profile, name='view_profile'), + 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'^view_profile/(?P<user_id>\d+)$', views.view_comment_profile, name='view_profile'), ] diff --git a/workshop_app/views.py b/workshop_app/views.py index eefb94e..3f24a2f 100644 --- a/workshop_app/views.py +++ b/workshop_app/views.py @@ -1,4 +1,5 @@ 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 @@ -16,12 +17,12 @@ from django.utils import timezone from .forms import ( UserRegistrationForm, UserLoginForm, - ProfileForm, WorkshopForm, CommentsForm + ProfileForm, WorkshopForm, CommentsForm, WorkshopTypeForm ) from .models import ( Profile, User, - Workshop, - WorkshopType, Comment + Workshop, Comment, + WorkshopType, AttachmentFile ) from .send_mails import send_email @@ -336,13 +337,41 @@ 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} @@ -350,6 +379,18 @@ def workshop_type_details(request, workshop_type_id): @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(): @@ -368,7 +409,6 @@ 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(page) @@ -403,6 +443,20 @@ def workshop_details(request, workshop_id): @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 coordinator profile """ user = request.user |