diff options
-rw-r--r-- | statistics_app/templates/statistics_app/team_stats.html | 124 | ||||
-rw-r--r-- | statistics_app/urls.py | 5 | ||||
-rw-r--r-- | statistics_app/views.py | 26 | ||||
-rw-r--r-- | teams/__init__.py | 0 | ||||
-rw-r--r-- | teams/admin.py | 5 | ||||
-rw-r--r-- | teams/apps.py | 5 | ||||
-rw-r--r-- | teams/models.py | 9 | ||||
-rw-r--r-- | teams/tests.py | 3 | ||||
-rw-r--r-- | teams/views.py | 3 | ||||
-rw-r--r-- | workshop_app/templates/workshop_app/my_workshops.html | 68 | ||||
-rw-r--r-- | workshop_app/views.py | 58 | ||||
-rw-r--r-- | workshop_portal/settings.py | 1 |
12 files changed, 238 insertions, 69 deletions
diff --git a/statistics_app/templates/statistics_app/team_stats.html b/statistics_app/templates/statistics_app/team_stats.html new file mode 100644 index 0000000..4e3e870 --- /dev/null +++ b/statistics_app/templates/statistics_app/team_stats.html @@ -0,0 +1,124 @@ +{% extends 'workshop_app/base.html' %} + +{% block title %} + Workshop Statistics +{% endblock %} + + +{% block extra %} + + <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://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.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> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> + <!-- For Charts --> + + <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.bundle.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script> + + <!-- For Google GeoChart India Map --> + <script type='text/javascript' src='https://www.google.com/jsapi'></script> + +{% endblock %} + +{% block content %} + +<div class="container"> +<div class="row"> + <br> + <div class="col-md-12 "> + <br> + <canvas id="myChartPie" ></canvas> + <script> + var dynamic_pie_color = []; + var data = {{ workshop_data.data}}; + + var dynamicColors = function() { + var r = Math.floor(Math.random() * 255); + var g = Math.floor(Math.random() * 255); + var b = Math.floor(Math.random() * 255); + return "rgb(" + r + "," + g + "," + b + ")"; + }; + + + for (var i in data) { + dynamic_pie_color.push(dynamicColors()); + } + + var data = { + datasets: [{ + data: data, + label: 'My dataset', // for legend + backgroundColor: dynamic_pie_color, + }], + labels: [{% for label in workshop_data.labels %}"{{ label }}",{% endfor %}] + }; + + var pieOptions = { + events: false, + animation: { + duration: 500, + easing: "easeOutQuart", + onComplete: function () { + var ctx = this.chart.ctx; + ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily); + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + + this.data.datasets.forEach(function (dataset) { + + for (var i = 0; i < dataset.data.length; i++) { + var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model, + total = dataset._meta[Object.keys(dataset._meta)[0]].total, + mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2, + start_angle = model.startAngle, + end_angle = model.endAngle, + mid_angle = start_angle + (end_angle - start_angle)/2; + + var x = mid_radius * Math.cos(mid_angle); + var y = mid_radius * Math.sin(mid_angle); + + ctx.fillStyle = '#fff'; + if (i == 3){ // Darker text color for lighter background + ctx.fillStyle = '#444'; + } + + var val = dataset.data[i]; + var percent = String(Math.round(val/total*100)) + "%"; + + if(val != 0) { + ctx.fillText(dataset.data[i], model.x + x, model.y + y); + // Display percent in another line, line break doesn't work for fillText + ctx.fillText(percent, model.x + x, model.y + y + 15); + } + } + }); + } + } + }; + + var pieChartCanvas = $("#myChartPie"); + var pieChart = new Chart(pieChartCanvas, { + type: 'pie', // or doughnut + data: data, + options: pieOptions + }); + </script> + <style> + #visualization path { + stroke-width:1; /* control the countries borders width */ + stroke:white; /* choose a color for the border */ + } + </style> + <div id="visualization" style="width: 400px; height: 300px; display: block; margin: 0 auto;" ></div> + + </div> +</div> +</div> +<br> +{% endblock %} diff --git a/statistics_app/urls.py b/statistics_app/urls.py index 94b358e..9e0dbbf 100644 --- a/statistics_app/urls.py +++ b/statistics_app/urls.py @@ -2,12 +2,13 @@ from django.conf.urls import url from django.contrib import admin from statistics_app import views -import django - urlpatterns = [ url(r'^statistics/$', views.workshop_stats), url(r'^statistics/public_stats/$', views.workshop_public_stats), url(r'^statistics/profile_stats/$', views.profile_stats), + url(r'^statistics/v1/team_stats/$', views.team_stats), + # url(r'^statistics/v1/filter/$', views.team_stats), + url(r'^statistics/v1/all/$', views.all_stats), ] diff --git a/statistics_app/views.py b/statistics_app/views.py index 1507196..8c3a6f0 100644 --- a/statistics_app/views.py +++ b/statistics_app/views.py @@ -10,6 +10,8 @@ from workshop_app.models import ( BookedWorkshop, ProposeWorkshopDate, Testimonial ) +from teams.models import Team + from django.template.loader import get_template from django.template import RequestContext from datetime import datetime, date @@ -582,3 +584,27 @@ def profile_stats(request): else: logout(request) return render(request, "workshop_app/logout.html") + +@login_required +def team_stats(request, team_id): + user = request.user + team = Team.objects.get(team_id) + if user not in team.members.all(): + if user.groups.filter(name='instructor').count() > 0: + return redirect('/manage/') + return redirect('/book/') + + member_workshop_data = {} + for member in team.members.all(): + workshop_count = ProposeWorkshopDate.objects.filter(proposed_workshop_instructor=member.id).count() + if member_workshop_data.get('data'): + member_workshop_data['data'].append(workshop_count) + else: + member_workshop_data['data'] = [workshop_count] + if member_workshop_data.get('labels'): + member_workshop_data['labels'].append(member.user.username) + else: + member_workshop_data['labels'] = [member.user.username] + return render(request, 'statistics_app/team_stats.html', {'workshop_data': member_workshop_data}) + + diff --git a/teams/__init__.py b/teams/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/teams/__init__.py diff --git a/teams/admin.py b/teams/admin.py new file mode 100644 index 0000000..1653090 --- /dev/null +++ b/teams/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from teams.models import Team + +admin.site.register(Team) diff --git a/teams/apps.py b/teams/apps.py new file mode 100644 index 0000000..17954d6 --- /dev/null +++ b/teams/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class TeamsConfig(AppConfig): + name = 'teams' diff --git a/teams/models.py b/teams/models.py new file mode 100644 index 0000000..c82a92c --- /dev/null +++ b/teams/models.py @@ -0,0 +1,9 @@ +from django.db import models +from django.contrib.auth.models import User + +from workshop_app.models import Profile + +class Team(models.Model): + members = models.ManyToManyField(Profile) + creator = models.OneToOneField(User) + created_date = models.DateTimeField(auto_now=True)
\ No newline at end of file diff --git a/teams/tests.py b/teams/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/teams/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/teams/views.py b/teams/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/teams/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/workshop_app/templates/workshop_app/my_workshops.html b/workshop_app/templates/workshop_app/my_workshops.html index 846c11b..ba35757 100644 --- a/workshop_app/templates/workshop_app/my_workshops.html +++ b/workshop_app/templates/workshop_app/my_workshops.html @@ -119,12 +119,44 @@ {% block content %} -{% if workshop_occurences %} +{% if workshops %} <h3 align="center" style="color:#2952a2;">The status of your workshops </h3> <br> <!-- Pending View --> <div class="container"> + {% if request.user.profile.position == 'instructor'%} + <h3 align="center" style="color: #04a9cf;"><strong><u>Team Member Requests</u></strong></h3> + + <table class="table"> + <thead> + <tr> + <th>Coordinator Name</th> + <th>Team Member</th> + <th>Workshop Name</th> + <th>Workshop Day</th> + </tr> + </thead> + <tbody> + {% for workshop in team_workshops %} + <tr> + <td><a href="{{ URL_ROOT }}/view_comment_profile/{{ workshop.requested_workshop_coordinator.profile.user.id }}"> + {{ workshop.proposed_workshop_coordinator.get_full_name }}</a> + </td> + <td> + {{ workshop.proposed_workshop_instructor.get_full_name }} + </td> + <td> + {{ workshop.proposed_workshop_title }} + </td> + <td> + {{ workshop.proposed_workshop_date | date }} + </td> + </tr> + {% endfor %} + </tbody> + </table> + {% endif %} {% if request.user.profile.position == 'instructor' %} <h3 align="center" style="color: #04a9cf;"><strong><u>Requests for Me</u></strong></h3> {% else %} @@ -144,7 +176,7 @@ </tr> </thead> {% csrf_token %} - {% for workshop in workshop_occurences %} + {% for workshop in workshops %} <tbody> <tr> {% if workshop.status == 'Pending' and workshop.requested_workshop_instructor %} @@ -186,7 +218,7 @@ </tr> </thead> {% csrf_token %} - {% for workshop in workshop_occurences %} + {% for workshop in workshops %} <tbody> <tr> {% if workshop.status == 'ACCEPTED' and workshop.requested_workshop_title %} @@ -271,7 +303,7 @@ </tr> </thead> {% csrf_token %} - {% for workshop in workshop_occurences %} + {% for workshop in workshops %} <tbody> <tr> {% if workshop.status == 'Pending' and workshop.condition_one %} @@ -314,7 +346,7 @@ </tr> </thead> {% csrf_token %} - {% for workshop in workshop_occurences %} + {% for workshop in workshops %} <tbody> <tr> {% if workshop.status == 'DELETED' or workshop.status == 'REJECTED' %} @@ -335,32 +367,6 @@ </table> </div> -<!-- Page Navigation --> - <div class="container"> - <div class="Page-Nav" align="center"> - <nav aria-label="Page navigation"> - <ul class="pagination pagination-sm"> - <li class="page-item"> - {% if workshop_occurences.has_previous %} - <a class="page-link" tabindex="-1" - href="?page={{ workshop_occurences.previous_page_number }}">Previous</a> - {% endif %} - </li> - <li class="page-item"> - <span class="current"> - Page {{ workshop_occurences.number }} of {{ workshop_occurences.paginator.num_pages }} - </span> - </li> - <li class="page-item"> - {% if workshop_occurences.has_next %} - <a class="page-link" href="?page={{ workshop_occurences.next_page_number }}">Next - </a> - {% endif %} - </li> - </ul> - </nav> - </div> - </div> {% else %} {% if request.user.profile.position == 'instructor' %} diff --git a/workshop_app/views.py b/workshop_app/views.py index 961445a..772615b 100644 --- a/workshop_app/views.py +++ b/workshop_app/views.py @@ -10,6 +10,7 @@ from .models import ( BookedWorkshop, ProposeWorkshopDate, Testimonial, ProfileComments ) +from teams.models import Team from datetime import datetime, date from django.contrib.auth import login, logout, authenticate from django.contrib.auth.decorators import login_required @@ -658,38 +659,36 @@ def my_workshops(request): today = datetime.today().date() workshop_occurence_list = RequestedWorkshop.objects.filter( requested_workshop_instructor=user.id, - requested_workshop_date__gt=today, + requested_workshop_date__gte=today, ).order_by('-requested_workshop_date') - for w in workshop_occurence_list: - workshops.append(w) proposed_workshop = ProposeWorkshopDate.objects.filter( proposed_workshop_instructor=user.id, - proposed_workshop_date__gt=today, + proposed_workshop_date__gte=today, ).order_by('-proposed_workshop_date') - for p in proposed_workshop: - workshops.append(p) proposed_workshop_pending = ProposeWorkshopDate.objects.filter( status='Pending' ).order_by('-proposed_workshop_date') - for p in proposed_workshop_pending: - workshops.append(p) + workshops = list(workshop_occurence_list) + list(proposed_workshop) + list(proposed_workshop_pending) + + # team_members = list(set(user.profile.team_set.all().values_list('members', flat=True))) + teams = Team.objects.filter(members=user.profile) + team_workshops = [] + + if teams: + team_members = Profile.objects.filter(team__in=teams).exclude(id=user.profile.id).distinct() + team_member_ids = team_members.values_list('user__id') + team_workshops = ProposeWorkshopDate.objects.filter( + proposed_workshop_date__gte=today, + proposed_workshop_instructor_id__in=team_member_ids, + ) + print(team_workshops) - #Show upto 12 Workshops per page - paginator = Paginator(workshops, 12) - page = request.GET.get('page') - try: - workshop_occurences = paginator.page(page) - except PageNotAnInteger: - #If page is not an integer, deliver first page. - workshop_occurences = paginator.page(1) - except EmptyPage: - #If page is out of range(e.g 999999), deliver last page. - workshop_occurences = paginator.page(paginator.num_pages) return render(request, 'workshop_app/my_workshops.html', - { "workshop_occurences" :workshop_occurences, + { "workshops" :workshops, + "team_workshops": team_workshops, "today": today}) else: @@ -697,28 +696,15 @@ def my_workshops(request): workshop_occurence_list = RequestedWorkshop.objects.filter( requested_workshop_coordinator=user.id ).order_by('-requested_workshop_date') - for w in workshop_occurence_list: - workshops.append(w) proposed_workshop = ProposeWorkshopDate.objects.filter( proposed_workshop_coordinator=user.id ).order_by('-proposed_workshop_date') - for p in proposed_workshop: - workshops.append(p) - #Show upto 12 Workshops per page - paginator = Paginator(workshops, 12) - page = request.GET.get('page') - try: - workshop_occurences = paginator.page(page) - except PageNotAnInteger: - #If page is not an integer, deliver first page. - workshop_occurences = paginator.page(1) - except EmptyPage: - #If page is out of range(e.g 999999), deliver last page. - workshop_occurences = paginator.page(paginator.num_pages) + workshops = list(workshop_occurence_list) + list(proposed_workshop) + list(proposed_workshop_pending) + return render(request, 'workshop_app/my_workshops.html', - {"workshop_occurences": workshop_occurences}) + {"workshops": workshops}) else: return redirect('/login/') diff --git a/workshop_portal/settings.py b/workshop_portal/settings.py index e7f9adb..46dc9b7 100644 --- a/workshop_portal/settings.py +++ b/workshop_portal/settings.py @@ -48,6 +48,7 @@ INSTALLED_APPS = [ 'workshop_app', 'recurrence', 'statistics_app', + 'teams', ] MIDDLEWARE_CLASSES = [ |