summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPalaparthy Adityachandra2020-08-15 11:43:46 +0530
committerGitHub2020-08-15 11:43:46 +0530
commitf8972ccd73c598cf0b0f20f13b4b8cf2179719e3 (patch)
tree47ad199e95c7b11ee4752c23a4cc04155872b580
parentf4ce8c9e3f20d0d4c873bfb8b0dd4d83ac0b8a58 (diff)
parent7d750d0559d4ff027900e58609cce842f07795b9 (diff)
downloadworkshop_booking-f8972ccd73c598cf0b0f20f13b4b8cf2179719e3.tar.gz
workshop_booking-f8972ccd73c598cf0b0f20f13b4b8cf2179719e3.tar.bz2
workshop_booking-f8972ccd73c598cf0b0f20f13b4b8cf2179719e3.zip
Merge pull request #158 from FOSSEE/fix_stats
Fix statistics app
-rw-r--r--requirements.txt3
-rw-r--r--statistics_app/forms.py49
-rw-r--r--statistics_app/templates/statistics_app/paginator.html34
-rw-r--r--statistics_app/templates/statistics_app/team_stats.html152
-rw-r--r--statistics_app/templates/statistics_app/workshop_public_stats.html470
-rw-r--r--statistics_app/urls.py12
-rw-r--r--statistics_app/views.py638
-rw-r--r--teams/models.py9
-rw-r--r--workshop_app/admin.py45
-rw-r--r--workshop_app/models.py36
-rw-r--r--workshop_app/static/workshop_app/css/base.css3
-rw-r--r--workshop_app/templates/workshop_app/base.html22
-rw-r--r--workshop_portal/settings.py2
-rw-r--r--workshop_portal/urls.py1
14 files changed, 446 insertions, 1030 deletions
diff --git a/requirements.txt b/requirements.txt
index 622c429..cc9dfd7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,4 +2,5 @@ Django==3.0.7
coverage
pyaml
django-recurrence
-python-decouple==3.3 \ No newline at end of file
+python-decouple==3.3
+pandas
diff --git a/statistics_app/forms.py b/statistics_app/forms.py
new file mode 100644
index 0000000..16d79c8
--- /dev/null
+++ b/statistics_app/forms.py
@@ -0,0 +1,49 @@
+# Django imports
+from django import forms
+
+# Local Imports
+from workshop_app.models import states, WorkshopType
+
+
+class FilterForm(forms.Form):
+ from_date = forms.DateField(
+ widget=forms.DateInput(
+ attrs={'type': 'date', 'class': 'form-control'}
+ )
+ )
+ to_date = forms.DateField(
+ widget=forms.DateInput(
+ attrs={'type': 'date', 'class': 'form-control'}
+ )
+ )
+ workshop_type = forms.ModelChoiceField(
+ queryset=WorkshopType.objects.all(), required=False,
+ widget=forms.Select(attrs={'class': 'form-control'})
+ )
+ state = forms.ChoiceField(
+ choices=states, required=False,
+ widget=forms.Select(attrs={'class': 'form-control'})
+ )
+ show_workshops = forms.BooleanField(
+ help_text="Show my workshops only", required=False,
+ )
+ sort = forms.ChoiceField(
+ choices=(("date", "Oldest"), ("-date", "Latest")),
+ help_text="Sort by",
+ widget=forms.Select(attrs={'class': 'form-control'})
+ )
+ def __init__(self, *args, **kwargs):
+ start = kwargs.pop("start") if "start" in kwargs else None
+ end = kwargs.pop("end") if "end" in kwargs else None
+ selected_state = kwargs.pop("state") if "state" in kwargs else None
+ selected_type = kwargs.pop("type") if "type" in kwargs else None
+ show_workshops = (kwargs.pop("show_workshops")
+ if "show_workshops" in kwargs else None)
+ sort = kwargs.pop("sort") if "sort" in kwargs else None
+ super(FilterForm, self).__init__(*args, **kwargs)
+ self.fields["from_date"].initial = start
+ self.fields["to_date"].initial = end
+ self.fields["state"].initial = selected_state
+ self.fields["workshop_type"].initial = selected_type
+ self.fields["show_workshops"].initial = show_workshops
+ self.fields["sort"].initial = sort
diff --git a/statistics_app/templates/statistics_app/paginator.html b/statistics_app/templates/statistics_app/paginator.html
new file mode 100644
index 0000000..9f0840a
--- /dev/null
+++ b/statistics_app/templates/statistics_app/paginator.html
@@ -0,0 +1,34 @@
+<ul class="pagination pagination">
+ {% if objects.has_previous %}
+ <li class="page-item">
+ <a class="page-link" href="?page=1{% if request.GET.from_date %}&from_date={{ request.GET.from_date }}{% endif %}{% if request.GET.to_date %}&to_date={{ request.GET.to_date }}{% endif %}{% if request.GET.state %}&state={{ request.GET.state }}{% endif %}{% if request.GET.workshop_type %}&workshop_type={{ request.GET.workshop_type }}{% endif %}{% if request.GET.show_workshops %}&show_workshops={{ request.GET.show_workshops }}{% endif %}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}
+ " aria-label="Previous">
+ <span aria-hidden="true">
+ <i class="fa fa-angle-double-left"></i>
+ </span>
+ <span class="sr-only">begin</span>
+ </a>
+ </li>
+ {% endif %}
+
+ {% for n in objects.paginator.page_range %}
+ {% if objects.number == n %}
+ <li class="page-item active">
+ <span class="page-link">{{ n }}<span class="sr-only">(current)</span></span>
+ </li>
+ {% elif n > objects.number|add:'-5' and n < objects.number|add:'5' %}
+ <li class="page-item"><a class="page-link" href="?page={{ n }}{% if request.GET.from_date %}&from_date={{ request.GET.from_date }}{% endif %}{% if request.GET.to_date %}&to_date={{ request.GET.to_date }}{% endif %}{% if request.GET.state %}&state={{ request.GET.state }}{% endif %}{% if request.GET.workshop_type %}&workshop_type={{ request.GET.workshop_type }}{% endif %}{% if request.GET.show_workshops %}&show_workshops={{ request.GET.show_workshops }}{% endif %}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}">{{ n }}</a></li>
+ {% endif %}
+ {% endfor %}
+
+ {% if objects.has_next %}
+ <li class="page-item">
+ <a class="page-link" href="?page={{ objects.paginator.num_pages }}{% if request.GET.from_date %}&from_date={{ request.GET.from_date }}{% endif %}{% if request.GET.to_date %}&to_date={{ request.GET.to_date }}{% endif %}{% if request.GET.state %}&state={{ request.GET.state }}{% endif %}{% if request.GET.workshop_type %}&workshop_type={{ request.GET.workshop_type }}{% endif %}{% if request.GET.show_workshops %}&show_workshops={{ request.GET.show_workshops }}{% endif %}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}" aria-label="Next">
+ <span aria-hidden="true">
+ <i class="fa fa-angle-double-right"></i>
+ </span>
+ <span class="sr-only">end</span>
+ </a>
+ </li>
+ {% endif %}
+</ul> \ No newline at end of file
diff --git a/statistics_app/templates/statistics_app/team_stats.html b/statistics_app/templates/statistics_app/team_stats.html
index 4e3e870..0342f61 100644
--- a/statistics_app/templates/statistics_app/team_stats.html
+++ b/statistics_app/templates/statistics_app/team_stats.html
@@ -4,121 +4,45 @@
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 class="container-fluid">
+ <div class="row">
+ <div class="col-md-2">
+ <ul class="nav nav-pills list-group">
+ {% for team in all_teams %}
+ <li class="nav-item">
+ <a href="{% url 'statistics_app:team' team.id %}" class="nav-link list-group-item">
+ Team {{forloop.counter}}
+ </a>
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ <div class="col-md-8">
+ <br>
+ <canvas id="myChart"></canvas>
+ </div>
+ </div>
</div>
-<br>
+<script>
+ var ctx = document.getElementById('myChart').getContext('2d');
+ var chart = new Chart(ctx, {
+ // The type of chart we want to create
+ type: 'bar',
+
+ // The data for our dataset
+ data: {
+ labels: {{team_labels|safe}},
+ datasets: [{
+ data: {{ws_count|safe}},
+ label: "Team Members Workshops",
+ backgroundColor: 'rgb(255, 99, 132)',
+ borderColor: 'rgb(255, 99, 132)',
+ }]
+ },
+ // Configuration options go here
+ options: {}
+ });
+</script>
{% endblock %}
diff --git a/statistics_app/templates/statistics_app/workshop_public_stats.html b/statistics_app/templates/statistics_app/workshop_public_stats.html
index a42f818..ad55858 100644
--- a/statistics_app/templates/statistics_app/workshop_public_stats.html
+++ b/statistics_app/templates/statistics_app/workshop_public_stats.html
@@ -1,346 +1,140 @@
{% extends 'workshop_app/base.html' %}
-{% block title %}
- Open 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="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>
-
-<script>
- var dateToday = new Date();
- var upto = new Date();
-
- dateToday.setDate(dateToday.getDate() - 1);
- upto.setFullYear(dateToday.getFullYear() + 1);
-
- $( function() {
- from = $( "#from" )
- .datepicker({
- defaultDate: "+1w",
- changeMonth: true,
- changeYear: true,
- showButtonPanel: true,
- maxDate: dateToday,
- dateFormat: "yy-mm-dd"
- })
- .on( "change", function() {
- to.datepicker( "option", "minDate", getDate( this ) );
- }),
- to = $( "#to" ).datepicker({
- defaultDate: "+1w",
- changeMonth: true,
- changeYear: true,
- showButtonPanel: true,
- minDate: dateToday,
- maxDate: upto,
- dateFormat: "yy-mm-dd"
- })
- .on( "change", function() {
- from.datepicker( "option", "maxDate", getDate( this ) );
- });
-
- function getDate( element ) {
- var date;
- try {
- date = $.datepicker.parseDate( dateFormat, element.value );
- } catch( error ) {
- date = null;
- }
- return date;
- }
- } );
-
- </script>
-
-{% endblock %}
+{% block title %} Statistics {% endblock %}
{% block content %}
+<div class="container-fluid">
+ <div class="row">
+ <div class="col-md-3">
+ <form method="GET">
+ <div class="card">
+ <div class="card-header">
+ <div class="row">
+ <div class="col-md-8">
+ <h3><u>Filters</u></h3>
+ </div>
+ <div class="col-md-4">
+ <a href="{% url 'statistics_app:public' %}" class="btn btn-outline-info">
+ <i class="fa fa-times"></i>&nbsp;Clear
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="card-body">
+ <div>From date: {{form.from_date}}</div>
+ <div>To date: {{form.to_date}}</div>
+ <div>Workshop: {{form.workshop_type}}</div>
+ <div>State: {{form.state}}</div>
+ <div>{{form.sort.help_text}}: {{form.sort}}</div>
+ {% if request.user.is_authenticated %}
+ <div>{{form.show_workshops.help_text}}: {{form.show_workshops}}</div>
+ {% endif %}
+ <br>
+ <div class="row justify-content-center">
+ <div class="col-md-4">
+ <button type="submit" class="btn btn-success">
+ <i class="fa fa-eye"></i>&nbsp;View
+ </button>
+ </div>
+ <div class="col-md-6">
+ <button type="submit" class="btn btn-info" name="download" value="download">
+ <i class="fa fa-download"></i>&nbsp;Download
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ <div class="col">
+ <div class="row">
+ <div class="col-md-6">
+ {% include "statistics_app/paginator.html" %}
+ </div>
+ <div class="col-md-3">
+ <button class="btn btn-info" id="state_graph">
+ <i class="fa fa-bar-chart"></i>&nbsp;State chart
+ </button>
+ </div>
+ <div class="col-md-3">
+ <button class="btn btn-info" id="type_graph">
+ <i class="fa fa-bar-chart"></i>&nbsp;Workshops chart
+ </button>
+ </div>
+ </div>
+ <table class="table table-responsive-sm">
+ <thead>
+ <tr>
+ <th>Sr No.</th>
+ <th>Coordinator Name</th>
+ <th>Institute Name</th>
+ <th>Instructor Name</th>
+ <th>Workshop Name</th>
+ <th>Workshop Date</th>
+ </tr>
+ </thead>
+ {% csrf_token %}
+ {% for workshop in objects %}
+ <tbody>
+ <tr>
+ <td>{{ forloop.counter0|add:objects.start_index}}</td>
+ <td>{{ workshop.coordinator.get_full_name | capfirst }}</td>
+ <td>{{ workshop.coordinator.profile.institute | capfirst }}</td>
+ <td>{{ workshop.instructor.get_full_name | capfirst }}</td>
+ <td>{{ workshop.workshop_type.name }}</td>
+ <td>{{ workshop.date | date}}</td>
+ </tr>
+ </tbody>
+ {% endfor %}
+ </table>
+ {% include "statistics_app/paginator.html" %}
+ </div>
+ </div>
+</div>
-<div class="container">
- <div class="row">
- <div class="col-md-4" align="left" >
- <fieldset data-mini="true">
- <label for="radio-2">Overall Count</label>
- <input type="radio" name="radio-1" id="radio-2" value="OWC">
- <label for="radio-3">India Map</label>
- <input type="radio" name="radio-1" id="radio-3" value="MOIN">
- </fieldset>
- </div>
-
- <div class="col-md-8">
- <form method="POST" >
- {% csrf_token %}
- <div class="form-group">
- <label>state: </label>
- <select name="states">
- <option value="all">ALL</option>
- <option value="IN-AP">Andhra Pradesh</option>
- <option value="IN-AR">Arunachal Pradesh</option
- <option value="IN-AS">Assam</option>
- <option value="IN-BR">Bihar</option>
- <option value="IN-CT">Chhattisgarh</option>
- <option value="IN-GA">Goa</option>
- <option value="IN-GJ">Gujarat</option>
- <option value="IN-HR">Haryana</option>
- <option value="IN-HP">Himachal Pradesh</option>
- <option value="IN-JK">Jammu and Kashmir</option>
- <option value="IN-JH">Jharkhand</option>
- <option value="IN-KA">Karnataka</option>
- <option value="IN-KL">Kerala</option>
- <option value="IN-MP">Madhya Pradesh</option>
- <option value="IN-MH">Maharashtra</option>
- <option value="IN-MN">Manipur</option>
- <option value="IN-ML">Meghalaya</option>
- <option value="IN-MZ">Mizoram</option>
- <option value="IN-NL">Nagaland</option>
- <option value="IN-OR">Odisha</option>
- <option value="IN-PB">Punjab</option>
- <option value="IN-RJ">Rajasthan</option>
- <option value="IN-SK">Sikkim</option>
- <option value="IN-TN">Tamil Nadu</option>
- <option value="IN-TG">Telangana</option>
- <option value="IN-TR">Tripura</option>
- <option value="IN-UT">Uttarakhand</option>
- <option value="IN-UP">Uttar Pradesh</option>
- <option value="IN-WB">West Bengal</option>
- <option value="IN-AN">Andaman and Nicobar Islands</option>
- <option value="IN-CH">Chandigarh</option>
- <option value="IN-DN">Dadra and Nagar Haveli</option>
- <option value="IN-DD">Daman and Diu</option>
- <option value="IN-DL">Delhi</option>
- <option value="IN-LD">Lakshadweep</option>
- <option value="IN-PY">Puducherry</option>
- </select>
- <label>WorkshopType: </label>
- <select name="workshoptype_name">
- {% for workshop in workshoptype_list %}
- <option value={{ workshop.id }}> {{ workshop }} </option>
- {% endfor %}
- </select>
- &nbsp;
- <br>
- <label for="from">From</label>
- <input type="text" id="from" name="from">
- <label for="to">to</label>
- <input type="text" id="to" name="to">
- <button class="btn btn-info btn-sm" type="submit" name="View" value="View">View</button>
- </div>
- </form>
-
- {% if messages %}
- <ul class="messages">
- {% for message in messages %}
- <div class="alert alert-{{ message.tags }}">
- <li {% if message.tags %} class="{{ message.tags }}"{% endif %}> {{ message }}
- </li>
- </div>
- {% endfor %}
- </ul>
- {% endif %}
-
- </div>
- <br>
- <table class="table table-hover">
- <thead>
- <tr>
- <th>Coordinator Name</th>
- <th>Institute Name</th>
- <th>Instructor Name</th>
- <th>Workshop Name</th>
- <th>Workshop Date</th>
- <th>Initiated By</th>
- </tr>
- </thead>
- {% csrf_token %}
- {% for workshop in workshop_list %}
- {% if workshop.proposed_workshop_date %}
- <tbody>
- <tr>
- <td>{{ workshop.proposed_workshop_coordinator.get_full_name | capfirst }}</td>
- <td>{{ workshop.proposed_workshop_coordinator.profile.institute | capfirst }}</td>
- <td>{{ workshop.proposed_workshop_instructor.get_full_name }}</td>
- <td>{{ workshop.proposed_workshop_title.workshoptype_name }}</td>
- <td>{{ workshop.proposed_workshop_date | date}}</td>
- <td>Coordinator</td>
- </tr>
- </tbody>
- {% else %}
- <tbody>
- <tr>
- <td>{{ workshop.requested_workshop_coordinator.get_full_name | capfirst }}</td>
- <td>{{ workshop.requested_workshop_coordinator.profile.institute | capfirst }}</td>
- <td>{{ workshop.requested_workshop_instructor.get_full_name }}</td>
- <td>{{ workshop.requested_workshop_title.workshoptype_name }}</td>
- <td>{{ workshop.requested_workshop_date | date}}</td>
- <td>Instructor</td>
- </tr>
- </tbody>
- {% endif %}
- {% endfor %}
- </table>
-
- <!-- 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_list.has_previous %}
- <a class="page-link" tabindex="-1"
- href="?page={{ workshop_list.previous_page_number }}">Previous</a>
- {% endif %}
- </li>
- <li class="page-item">
- <span class="current">
- Page {{ workshop_list.number }} of {{ workshop_list.paginator.num_pages }}
- </span>
- </li>
- <li class="page-item">
- {% if workshop_list.has_next %}
- <a class="page-link" href="?page={{ workshop_list.next_page_number }}">Next
- </a>
- {% endif %}
- </li>
- </ul>
- </nav>
- </div>
- </div>
- </div>
-
-<div class="row">
- <br>
- <div class="col-md-12 ">
- <br>
- <canvas id="myChartPie" ></canvas>
- <script>
- $( function() {
- $( "fieldset" ).controlgroup();
- });
-
- var ctx1 = document.getElementById("myChartPie").getContext('2d');
- var myChart;
-
- $('input[type=radio]').change(function() {
- if (this.value == 'OWC') { //Overall Workshop Count
- if(myChart){
- myChart.destroy();
- }
-
- var dWidth = $(window).width() * 0.9;
- var dHeight = $(window).height() * 0.9;
-
- $( "#myChartPie" ).dialog({
- resizable: false,
- draggable: true,
- title: 'Pie Chart',
- closeOnEscape: true,
- stack: true,
- zIndex: 10000,
- width: dWidth,
- height: dHeight,
- modal: true
- });
-
- document.getElementById("visualization").style.visibility='hidden';
- myChart = new Chart(ctx1, {
- type: 'pie',
- data: {
- labels : {{ workshoptype_count.0 | safe}},
- datasets: [{
- data: {{ workshoptype_count.1 }},
- //Add more color scheme if workshop number increases
- backgroundColor: [
- 'rgba(153, 102, 255, 1)',
- 'rgba(191, 191, 1, 1)',
- 'rgba(75, 192, 192, 1)',
- 'rgba(153, 102, 255, 1)'
- ]
- }]
- },
- options: {
- responsive: true
- }
- });
- }
-
- else if (this.value == 'MOIN') {
- if(myChart){
- myChart.destroy();
- }
-
- var dWidth = $(window).width() * 0.9;
- var dHeight = $(window).height() * 0.9;
-
- $( "#visualization" ).dialog({
- resizable: false,
- draggable: true,
- title: 'State wise(Map of India)',
- closeOnEscape: true,
- stack: true,
- zIndex: 10000,
- width: dWidth,
- height: dHeight,
- modal: true
- });
-
- document.getElementById("visualization").style.visibility='visible';
- function drawVisualization() {
- var data = google.visualization.arrayToDataTable(
- {{ india_map | safe }}
- );
-
- var opts = {
- region: 'IN',
- domain: 'IN',
- displayMode: 'regions',
- resolution: 'provinces',
- datalessRegionColor: 'transparent',
- colorAxis: {colors: ['#e6e6e6','#ff8b3e']},
-
-
- };
+<!-- The Modal -->
+<div id="dialog" title="Workshops Statistics">
+ <canvas id="myChart"></canvas>
+</div>
- var geochart = new google.visualization.GeoChart(
- document.getElementById('visualization'));
- geochart.draw(data, opts);
- };
- if(google) {
- google.load('visualization', '1.0', {
- packages: ['geochart'],
- callback: function() {
- // do stuff, if you wan't - it doesn't matter, because the page isn't blank!
- drawVisualization();
- }
- })
- }
- }
- });
- </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>
+<script type="text/javascript">
+ var state_labels = {{ws_states|safe}};
+ var state_data = {{ws_count|safe}};
+ var type_labels = {{ws_type|safe}};
+ var type_data = {{ws_type_count|safe}};
+ var chart;
+ $("#state_graph").on("click", function() {
+ show_graph(state_labels, state_data, "State wise workshops");
+ });
+ $("#type_graph").on("click", function() {
+ show_graph(type_labels, type_data, "Type wise workshops");
+ });
+
+ function show_graph(labels, data, graph_name, chart_name) {
+ var ctx = document.getElementById('myChart').getContext('2d');
+ if(chart) chart.destroy();
+ chart = new Chart(ctx, {
+ // The type of chart we want to create
+ type: 'bar',
+
+ // The data for our dataset
+ data: {
+ labels: labels,
+ datasets: [{
+ data: data,
+ label: graph_name,
+ backgroundColor: 'rgb(255, 99, 132)',
+ borderColor: 'rgb(255, 99, 132)',
+ }]
+ },
+ // Configuration options go here
+ options: {}
+ });
+ $("#dialog").dialog({
+ width: 900,
+ height: 500
+ });
+ }
+</script>
- </div>
-</div>
-</div>
-<br>
{% endblock %}
diff --git a/statistics_app/urls.py b/statistics_app/urls.py
index 8950e37..05d7ac9 100644
--- a/statistics_app/urls.py
+++ b/statistics_app/urls.py
@@ -1,12 +1,10 @@
-
-from django.conf.urls import url
-from django.contrib import admin
+from django.urls import path
from statistics_app import views
+app_name = "statistics_app"
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),
+ path('public', views.workshop_public_stats, name="public"),
+ path('team', views.team_stats, name="team"),
+ path('team/<int:team_id>', views.team_stats, name="team"),
]
diff --git a/statistics_app/views.py b/statistics_app/views.py
index 784f30d..3c9fcae 100644
--- a/statistics_app/views.py
+++ b/statistics_app/views.py
@@ -1,569 +1,129 @@
-from workshop_app.forms import (
- UserRegistrationForm, UserLoginForm,
- ProfileForm, CreateWorkshop,
- ProposeWorkshopDateForm
-)
-from workshop_app.models import (
- Profile, User,
- has_profile, Workshop,
- WorkshopType, RequestedWorkshop,
- BookedWorkshop, ProposeWorkshopDate,
- Testimonial
-)
-from teams.models import Team
+# Python Imports
+import datetime as dt
+import pandas as pd
+# Django Imports
from django.template.loader import get_template
from django.template import RequestContext
-from datetime import datetime, date
-from django.contrib.auth import login, logout, authenticate
+from django.contrib import messages
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.db import IntegrityError
+from django.urls import reverse
from django.utils import timezone
-from django.http import HttpResponse, HttpResponseRedirect
-from django.conf import settings
-from os import listdir, path, sep
-from zipfile import ZipFile
-from django.contrib import messages
-from operator import itemgetter
-import datetime as dt
-import csv
-try:
- from StringIO import StringIO as string_io
-except ImportError:
- from io import BytesIO as string_io
-
+from django.http import HttpResponse
-# Create your views here.
-def check_workshop_type(x):
- try:
- y = datetime.strftime(x.proposed_workshop_date, '%d-%m-%Y')
- except BaseException:
- y = datetime.strftime(x.requested_workshop_date, '%d-%m-%Y')
- return y
+# Local Imports
+from workshop_app.models import (
+ Profile, User, has_profile, Workshop, WorkshopType, Testimonial,
+ states
+)
+from teams.models import Team
+from .forms import FilterForm
def is_instructor(user):
'''Check if the user is having instructor rights'''
- return True if user.groups.filter(name='instructor').count() > 0 else False
+ return user.groups.filter(name='instructor').exists()
def is_email_checked(user):
if hasattr(user, 'profile'):
- return True if user.profile.is_email_verified else False
+ return user.profile.is_email_verified
else:
return False
-def pie_chart():
- '''This function gives Data for drawring Pie Chart'''
-
- # Count Total Number of workshops for each type
- workshop_titles = WorkshopType.objects.all()
- workshoptype_dict = {}
- for title in workshop_titles:
- workshoptype_dict[title] = 0
-
- for title in workshoptype_dict.keys():
- workshoptype_dict[title] += RequestedWorkshop.objects.filter(
- requested_workshop_title=title,
- status='ACCEPTED').count()
- workshoptype_dict[title] += ProposeWorkshopDate.objects.filter(
- proposed_workshop_title=title,
- status='ACCEPTED').count()
-
- # For Pie Chart
- workshoptype_num = [count for count in workshoptype_dict.values()]
- workshoptype_title = [str(title) for title in workshoptype_dict.keys()]
-
- workshoptype_count = [workshoptype_title, workshoptype_num]
- del workshoptype_title, workshoptype_num
-
- return workshoptype_count
-
-
-def india_map():
- '''This function returns count of workshops based on states in India.'''
-
- states = [
- ['Code', 'State', 'Number'],
- ["IN-AP", "Andhra Pradesh", 0],
- ["IN-AR", "Arunachal Pradesh", 0],
- ["IN-AS", "Assam", 0],
- ["IN-BR", "Bihar", 0],
- ["IN-CT", "Chhattisgarh", 0],
- ["IN-GA", "Goa", 0],
- ["IN-GJ", "Gujarat", 0],
- ["IN-HR", "Haryana", 0],
- ["IN-HP", "Himachal Pradesh", 0],
- ["IN-JK", "Jammu and Kashmir", 0],
- ["IN-JH", "Jharkhand", 0],
- ["IN-KA", "Karnataka", 0],
- ["IN-KL", "Kerala", 0],
- ["IN-MP", "Madhya Pradesh", 0],
- ["IN-MH", "Maharashtra", 0],
- ["IN-MN", "Manipur", 0],
- ["IN-ML", "Meghalaya", 0],
- ["IN-MZ", "Mizoram", 0],
- ["IN-NL", "Nagaland", 0],
- ["IN-OR", "Odisha", 0],
- ["IN-PB", "Punjab", 0],
- ["IN-RJ", "Rajasthan", 0],
- ["IN-SK", "Sikkim", 0],
- ["IN-TN", "Tamil Nadu", 0],
- ["IN-TG", "Telangana", 0],
- ["IN-TR", "Tripura", 0],
- ["IN-UT", "Uttarakhand", 0],
- ["IN-UP", "Uttar Pradesh", 0],
- ["IN-WB", "West Bengal", 0],
- ["IN-AN", "Andaman and Nicobar Islands", 0],
- ["IN-CH", "Chandigarh", 0],
- ["IN-DN", "Dadra and Nagar Haveli", 0],
- ["IN-DD", "Daman and Diu", 0],
- ["IN-DL", "Delhi", 0],
- ["IN-LD", "Lakshadweep", 0],
- ["IN-PY", "Puducherry", 0]
- ]
- workshop_state = []
- requestedWorkshops = RequestedWorkshop.objects.filter(status='ACCEPTED')
- proposedWorkshops = ProposeWorkshopDate.objects.filter(status='ACCEPTED')
- for workshop in requestedWorkshops:
- for s in states:
- if s[0] == workshop.requested_workshop_coordinator.profile.state:
- s[2] += 1
-
- for workshop in proposedWorkshops:
- for s in states:
- if s[0] == workshop.proposed_workshop_coordinator.profile.state:
- s[2] += 1
-
- return states
-
-
-
-def monthly_accepted_chart():
- '''This function returns workshops accepted for each month
- in the current year'''
- today = datetime.now()
- upto = today + dt.timedelta(days=15)
-
- workshop_count = [0] * 12
- for x in range(12):
- workshop_count[x] += RequestedWorkshop.objects.filter(
- requested_workshop_date__year=str(today.year),
- requested_workshop_date__month=str(x + 1),
- status='ACCEPTED').count()
- workshop_count[x] += ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__year=str(today.year),
- proposed_workshop_date__month=str(x + 1),
- status='ACCEPTED').count()
-
- return workshop_count
-
-
-@login_required
-def workshop_stats(request):
- user = request.user
- today = datetime.now()
- upto = today + dt.timedelta(days=15)
-
- #For Monthly Chart
- workshop_count = monthly_accepted_chart()
-
- # For Pie Chart
- workshoptype_count = pie_chart()
-
- # For India Map
- states = india_map()
- # For Data Downloading and Viewing
- if request.method == 'POST':
- try:
- from_dates = request.POST.get('from')
- to_dates = request.POST.get('to')
-
- # Fetches Accepted workshops which were proposed by Coordinators
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__range=(from_dates, to_dates),
- status='ACCEPTED'
- )
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- requested_workshop_date__range=(from_dates, to_dates),
- status='ACCEPTED'
- )
-
- upcoming_workshops = []
-
- for workshop in proposed_workshops:
- upcoming_workshops.append(workshop)
-
- for workshop in requested_workshops:
- upcoming_workshops.append(workshop)
-
- upcoming_workshops = sorted(upcoming_workshops,
- key=lambda x: check_workshop_type(x))
-
- download = request.POST.get('Download')
- if download:
- response = HttpResponse(content_type='text/csv')
-
- response['Content-Disposition'] = 'attachment;\
- filename="records_from_{0}_to_{1}.csv"'.format(
- from_dates, to_dates
- )
-
- writer = csv.writer(response)
- header = [
- 'coordinator name',
- 'instructor name',
- 'workshop',
- 'date',
- 'status',
- 'institute name',
- 'state'
- ]
-
- writer.writerow(header)
-
- for workshop in upcoming_workshops:
- try:
- row = [
- workshop.proposed_workshop_coordinator,
- workshop.proposed_workshop_instructor,
- workshop.proposed_workshop_title,
- workshop.proposed_workshop_date,
- workshop.status,
- workshop.proposed_workshop_coordinator.profile.institute,
- str(workshop.proposed_workshop_coordinator.profile.state)
- ]
-
- except BaseException:
- row = [
- workshop.requested_workshop_coordinator,
- workshop.requested_workshop_instructor,
- workshop.requested_workshop_title,
- workshop.requested_workshop_date,
- workshop.status,
- workshop.requested_workshop_coordinator.profile.institute,
- str(workshop.requested_workshop_coordinator.profile.state)
- ]
-
- writer.writerow(row)
- return response
- else:
- return render(request,
- 'statistics_app/workshop_stats.html',
- {"upcoming_workshops": upcoming_workshops,
- "show_workshop_stats": settings.SHOW_WORKSHOP_STATS,
- "workshop_count": workshop_count,
- "workshoptype_count": workshoptype_count,
- "india_map": states})
- except BaseException:
- messages.info(request, 'Please enter Valid Dates')
-
- if is_instructor(user) and is_email_checked(user):
- try:
- # Fetches Accepted workshops which were proposed by Coordinators
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__range=(today, upto),
- status='ACCEPTED'
- )
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- requested_workshop_date__range=(today, upto),
- status='ACCEPTED'
- )
-
- upcoming_workshops = []
- for workshop in proposed_workshops:
- upcoming_workshops.append(workshop)
-
- for workshop in requested_workshops:
- upcoming_workshops.append(workshop)
-
- upcoming_workshops = sorted(upcoming_workshops,
- key=lambda x: check_workshop_type(x))
-
- except BaseException:
- upcoming_workshops = []
-
- paginator = Paginator(upcoming_workshops, 12)
-
- page = request.GET.get('page')
- try:
- upcoming_workshops = paginator.page(page)
- except PageNotAnInteger:
- # If page is not an integer, deliver first page.
- upcoming_workshops = paginator.page(1)
- except EmptyPage:
- # If page is out of range(e.g 999999), deliver last page.
- upcoming_workshops = paginator.page(paginator.num_pages)
-
- return render(request, 'statistics_app/workshop_stats.html',
- {
- "upcoming_workshops": upcoming_workshops,
- "show_workshop_stats": settings.SHOW_WORKSHOP_STATS,
- "workshop_count": workshop_count,
- "workshoptype_count": workshoptype_count,
- "india_map": states
- })
- else:
- return redirect('/statistics/public_stats/')
-
-
def workshop_public_stats(request):
user = request.user
- today = datetime.now()
- upto = today + dt.timedelta(days=15)
-
- #For Pie Chart
- workshoptype_count = pie_chart()
-
- # For India Map
- states = india_map()
-
- # Select By WorkshopType
- workshoptype_list = list(WorkshopType.objects.all())
- workshoptype_list.append('all')
-
- # For Data Viewing
- if request.method == 'POST':
- workshop_list = []
-
- try:
- from_dates = request.POST.get('from')
- to_dates = request.POST.get('to')
- selected_state = request.POST.get('states')
- selected_workshoptype = request.POST.get('workshoptype_name')
- if selected_state == 'all':
- # If dates not passed
- if len(from_dates) == 0 and len(to_dates) == 0:
- from_dates = '2017-01-01'
- to_dates = upto
- # If SelectedWorkshopType is 'All'
- if len(selected_workshoptype) == 0:
- # Fetches Accepted workshops which were proposed by
- # Coordinators
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__range=(from_dates, to_dates),
- status='ACCEPTED'
- )
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- requested_workshop_date__range=(from_dates, to_dates),
- status='ACCEPTED'
- )
-
- else:
- # Fetches Accepted workshops which were proposed by
- # Coordinators
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__range=(from_dates, to_dates),
- status='ACCEPTED', proposed_workshop_title_id=int(selected_workshoptype)
- )
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- requested_workshop_date__range=(from_dates, to_dates),
- status='ACCEPTED', requested_workshop_title_id=int(selected_workshoptype)
- )
-
- for workshop in proposed_workshops:
- workshop_list.append(workshop)
-
- for workshop in requested_workshops:
- workshop_list.append(workshop)
-
- else:
- # If dates not passed
- if len(from_dates) == 0 and len(to_dates) == 0:
- from_dates = '2017-01-01'
- to_dates = upto
-
- # Get list of coordinators
- coordinators_state_wise = Profile.objects.filter(
- state=selected_state)
-
- if len(selected_workshoptype) == 0:
- # Traverse through list of coordinators and append
- # workshop_list
- for coordinator in coordinators_state_wise:
- # Fetches Accepted workshops which were proposed by
- # Coordinators
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__range=(
- from_dates,
- to_dates),
- status='ACCEPTED',
- proposed_workshop_coordinator=coordinator.user_id)
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- requested_workshop_date__range=(
- from_dates,
- to_dates),
- status='ACCEPTED',
- requested_workshop_coordinator=coordinator.user_id)
-
- for workshop in proposed_workshops:
- workshop_list.append(workshop)
-
- for workshop in requested_workshops:
- workshop_list.append(workshop)
-
- else:
- # Traverse through list of coordinators and append
- # workshop_list
- for coordinator in coordinators_state_wise:
- # Fetches Accepted workshops which were proposed by
- # Coordinators
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- proposed_workshop_date__range=(
- from_dates,
- to_dates),
- status='ACCEPTED', proposed_workshop_title_id=int(selected_workshoptype),
- proposed_workshop_coordinator=coordinator.user_id)
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- requested_workshop_date__range=(
- from_dates,
- to_dates),
- status='ACCEPTED', requested_workshop_title_id=int(selected_workshoptype),
- requested_workshop_coordinator=coordinator.user_id)
-
- for workshop in proposed_workshops:
- workshop_list.append(workshop)
-
- for workshop in requested_workshops:
- workshop_list.append(workshop)
-
- return render(request,
- 'statistics_app/workshop_public_stats.html',
- {
- "workshoptype_list": workshoptype_list[::-1],
- "workshop_list": workshop_list,
- "workshoptype_count": workshoptype_count,
- "india_map": states})
-
- except BaseException:
- messages.info(request, 'Please enter Valid Dates')
-
+ form = FilterForm()
+ from_date = request.GET.get('from_date')
+ to_date = request.GET.get('to_date')
+ state = request.GET.get('state')
+ workshoptype = request.GET.get('workshop_type')
+ show_workshops = request.GET.get('show_workshops')
+ sort = request.GET.get('sort')
+ download = request.GET.get('download')
+
+ if from_date and to_date:
+ form = FilterForm(
+ start=from_date, end=to_date, state=state, type=workshoptype,
+ show_workshops=show_workshops, sort=sort
+ )
+ workshops = Workshop.objects.filter(
+ date__range=(from_date, to_date), status=1
+ ).order_by(sort)
+ if state:
+ workshops = workshops.filter(coordinator__profile__state=state)
+ if workshoptype:
+ workshops = workshops.filter(workshop_type_id=workshoptype)
else:
- '''Default Data'''
- workshop_list = []
-
- proposed_workshops = ProposeWorkshopDate.objects.filter(
- status='ACCEPTED')
-
- # Fetches Accepted workshops which were Accepted by
- # Instructors based on their Availability
- requested_workshops = RequestedWorkshop.objects.filter(
- status='ACCEPTED')
-
- for workshop in proposed_workshops:
- workshop_list.append(workshop)
-
- for workshop in requested_workshops:
- workshop_list.append(workshop)
-
-
- return render(request,
- 'statistics_app/workshop_public_stats.html',
- {
- "workshoptype_list": workshoptype_list[::-1],
- "workshoptype_count": workshoptype_count,
- "workshop_list": workshop_list,
- "india_map": states})
+ today = timezone.now()
+ upto = today + dt.timedelta(days=15)
+ workshops = Workshop.objects.filter(
+ date__range=(today, upto), status=1
+ ).order_by("date")
+ if show_workshops:
+ if is_instructor(user):
+ workshops = workshops.filter(instructor_id=user.id)
+ else:
+ workshops = workshops.filter(coordinator_id=user.id)
+ if download:
+ data = workshops.values(
+ "workshop_type__name", "coordinator__first_name",
+ "coordinator__last_name", "instructor__first_name",
+ "instructor__last_name", "coordinator__profile__state",
+ "date", "status"
+ )
+ df = pd.DataFrame(data)
+ if not df.empty:
+ df.status.replace(
+ [0, 1, 2], ['Pending', 'Success', 'Reject'], inplace=True
+ )
+ codes, states = list(zip(*states))
+ df.coordinator__profile__state.replace(codes, states, inplace=True)
+ response = HttpResponse(content_type='text/csv')
+ response['Content-Disposition'] = f'attachment; filename=statistics.csv'
+ output_file = df.to_csv(response, index=False)
+ return response
+ else:
+ messages.add_message(request, messages.WARNING, "No data found")
+ ws_states, ws_count = Workshop.objects.get_workshops_by_state(workshops)
+ ws_type, ws_type_count = Workshop.objects.get_workshops_by_type(workshops)
+ paginator = Paginator(workshops, 30)
+ page = request.GET.get('page')
+ workshops = paginator.get_page(page)
+ context = {"form": form, "objects": workshops, "ws_states": ws_states,
+ "ws_count": ws_count, "ws_type": ws_type,
+ "ws_type_count": ws_type_count}
+ return render(
+ request, 'statistics_app/workshop_public_stats.html', context
+ )
@login_required
-def profile_stats(request):
+def team_stats(request, team_id=None):
user = request.user
- if is_instructor(user) and is_email_checked(user):
- profiles = Profile.objects.all()
-
- rworkshops = RequestedWorkshop.objects.filter(status='ACCEPTED')
- pworkshops = ProposeWorkshopDate.objects.filter(status='ACCEPTED')
-
- iprofile = Profile.objects.filter(position='instructor')
- cprofile = Profile.objects.filter(position='coordinator')
-
- instructor_profile = []
- coordinator_profile = []
-
- for p in iprofile:
- instructor_profile.append({"profile": p,
- "count": 0
- })
-
-
- for p in cprofile:
- coordinator_profile.append({"profile": p,
- "count": 0
- })
-
- for p in instructor_profile:
- p['count'] += RequestedWorkshop.objects.filter(
- requested_workshop_instructor_id=p['profile'].user.id,
- status='ACCEPTED').count()
-
- p['count'] += ProposeWorkshopDate.objects.filter(
- proposed_workshop_instructor_id=p['profile'].user.id,
- status='ACCEPTED').count()
-
- for p in coordinator_profile:
- p['count'] += RequestedWorkshop.objects.filter(
- requested_workshop_coordinator_id=p['profile'].user.id,
- status='ACCEPTED').count()
-
- p['count'] += ProposeWorkshopDate.objects.filter(
- proposed_workshop_coordinator_id=p['profile'].user.id,
- status='ACCEPTED').count()
-
- #Sorting
- coordinator_profile = sorted(coordinator_profile,
- key=lambda k:k['count'], reverse=True)
- instructor_profile = sorted(instructor_profile,
- key=lambda k:k['count'], reverse=True)
-
- return render(request, "statistics_app/profile_stats.html",
- {
- "instructor_data": instructor_profile,
- "coordinator_data": coordinator_profile,
- })
+ teams = Team.objects.all()
+ if team_id:
+ team = teams.get(id=team_id)
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/')
+ team = teams.first()
+ if not team.members.filter(user_id=user.id).exists():
+ messages.add_message(
+ request, messages.INFO, "You are not added to the team"
+ )
+ return redirect(reverse("workshop_app:index"))
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})
+ workshop_count = Workshop.objects.filter(
+ instructor_id=member.user.id).count()
+ member_workshop_data[member.user.get_full_name()] = workshop_count
+ team_labels = list(member_workshop_data.keys())
+ ws_count = list(member_workshop_data.values())
+ return render(
+ request, 'statistics_app/team_stats.html',
+ {'team_labels': team_labels, "ws_count": ws_count, 'all_teams': teams,
+ 'team_id': team.id}
+ )
diff --git a/teams/models.py b/teams/models.py
index b0f6fe4..ed91f73 100644
--- a/teams/models.py
+++ b/teams/models.py
@@ -4,6 +4,9 @@ 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, on_delete=models.CASCADE)
- created_date = models.DateTimeField(auto_now=True) \ No newline at end of file
+ members = models.ManyToManyField(Profile)
+ creator = models.OneToOneField(User, on_delete=models.CASCADE)
+ created_date = models.DateTimeField(auto_now=True)
+
+ def __str__(self):
+ return f"Team created by {self.creator.get_full_name()}"
diff --git a/workshop_app/admin.py b/workshop_app/admin.py
index 988351f..d236c39 100644
--- a/workshop_app/admin.py
+++ b/workshop_app/admin.py
@@ -1,4 +1,4 @@
-import csv
+import pandas as pd
from django.contrib import admin
from django.http import HttpResponse
@@ -23,21 +23,15 @@ class ProfileAdmin(admin.ModelAdmin):
actions = ['download_csv']
def download_csv(self, request, queryset):
- openfile = string_io()
+ data = queryset.values(
+ "title", "user__first_name", "user__last_name",
+ "user__email", "institute", "location", "department",
+ "phone_number"
+ )
+ df = pd.DataFrame(data)
response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment;filename=profile_data.csv'
- writer = csv.writer(response)
- writer.writerow(['email_id', 'title', 'username', 'first_name', 'last_name',
- 'institute', 'location', 'department',
- 'phone_number', 'position'])
- for q in queryset:
- writer.writerow([q.user.email, q.title, q.user, q.user.first_name,
- q.user.last_name, q.institute,
- q.location, q.department, q.phone_number,
- q.position])
-
- openfile.seek(0)
- response.write(openfile.read())
+ response['Content-Disposition'] = f'attachment; filename=profile.csv'
+ output_file = df.to_csv(response, index=False)
return response
download_csv.short_description = "Download CSV file for selected stats."
@@ -49,17 +43,18 @@ class WorkshopAdmin(admin.ModelAdmin):
actions = ['download_csv']
def download_csv(self, request, queryset):
- openfile = string_io()
+ data = queryset.values(
+ "workshop_type__name", "date", "coordinator__first_name",
+ "coordinator__last_name", "instructor__first_name",
+ "instructor__last_name", "status"
+ )
+ df = pd.DataFrame(data)
+ df.status.replace(
+ [0, 1, 2], ['Pending', 'Success', 'Reject'], inplace=True
+ )
response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment;filename=workshop_data.csv'
- writer = csv.writer(response)
- writer.writerow(['workshop_type', 'date', 'instructor', 'coordinator', 'status'])
-
- for q in queryset:
- writer.writerow([q.title, q.date, q.instructor, q.coordinator, q.status])
-
- openfile.seek(0)
- response.write(openfile.read())
+ response['Content-Disposition'] = f'attachment; filename=workshops.csv'
+ output_file = df.to_csv(response, index=False)
return response
download_csv.short_description = "Download CSV file for selected stats."
diff --git a/workshop_app/models.py b/workshop_app/models.py
index 62d10b5..48856fd 100644
--- a/workshop_app/models.py
+++ b/workshop_app/models.py
@@ -1,5 +1,6 @@
import os
import uuid
+import pandas as pd
from django.contrib.auth.models import User
from django.core.validators import RegexValidator
@@ -44,6 +45,7 @@ source = (
)
states = (
+ ("", "---------"),
("IN-AP", "Andhra Pradesh"),
("IN-AR", "Arunachal Pradesh"),
("IN-AS", "Assam"),
@@ -85,7 +87,7 @@ states = (
def has_profile(user):
""" check if user has profile """
- return True if hasattr(user, 'profile') else False
+ return hasattr(user, 'profile')
def attachments(instance, filename):
@@ -155,6 +157,34 @@ class AttachmentFile(models.Model):
workshop_type = models.ForeignKey(WorkshopType, on_delete=models.CASCADE)
+class WorkshopManager(models.Manager):
+
+ def get_workshops_by_state(self, workshops):
+ w = workshops.values_list("coordinator__profile__state", flat=True)
+ states_map = dict(states)
+ df = pd.DataFrame(w)
+ data_states, data_counts = [], []
+ if not df.empty:
+ grouped_data = df.value_counts().to_dict()
+ for state, count in grouped_data.items():
+ state_name = state[0]
+ data_states.append(states_map[state_name])
+ data_counts.append(count)
+ return data_states, data_counts
+
+ def get_workshops_by_type(self, workshops):
+ w = workshops.values_list("workshop_type__name", flat=True)
+ df = pd.DataFrame(w)
+ data_wstypes, data_counts = [], []
+ if not df.empty:
+ grouped_data = df.value_counts().to_dict()
+ for ws, count in grouped_data.items():
+ ws_name = ws[0]
+ data_wstypes.append(ws_name)
+ data_counts.append(count)
+ return data_wstypes, data_counts
+
+
class Workshop(models.Model):
"""
Contains details of workshops
@@ -179,6 +209,8 @@ class Workshop(models.Model):
help_text="I accept the terms and conditions"
)
+ objects = WorkshopManager()
+
def __str__(self):
return f"{self.workshop_type} on {self.date} by {self.coordinator}"
@@ -187,6 +219,8 @@ class Workshop(models.Model):
return choice.get(self.status)
+
+
class Testimonial(models.Model):
"""
Contains Testimonals of Workshops
diff --git a/workshop_app/static/workshop_app/css/base.css b/workshop_app/static/workshop_app/css/base.css
index 31f8da5..e8dd4ed 100644
--- a/workshop_app/static/workshop_app/css/base.css
+++ b/workshop_app/static/workshop_app/css/base.css
@@ -2,7 +2,7 @@
* Footer Styles
*/
.navbar {
- z-index: 1000;
+ z-index: 1000;
}
.footer {
position: fixed;
@@ -11,6 +11,7 @@
background-color: #61615F;
color: white;
text-align: center;
+ z-index: 100;
}
.base-content {
padding-top: 5em;
diff --git a/workshop_app/templates/workshop_app/base.html b/workshop_app/templates/workshop_app/base.html
index 7535f6a..ba968ba 100644
--- a/workshop_app/templates/workshop_app/base.html
+++ b/workshop_app/templates/workshop_app/base.html
@@ -14,6 +14,8 @@
<script src="{% static 'workshop_app/js/bootstrap.min.js' %}"></script>
<script src="{% static 'workshop_app/js/popper.min.js' %}"></script>
<script src="{% static 'workshop_app/js/toastr.min.js' %}"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
{% block extra-dependencies %}
@@ -24,6 +26,7 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="{% static 'workshop_app/css/base.css' %}" type="text/css"/>
<link rel="stylesheet" href="{% static 'workshop_app/css/font-awesome.css' %}" type="text/css"/>
+ <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
{% block extra-custom-scripts %}
{% endblock %}
@@ -43,8 +46,27 @@
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
+ <ul class="navbar-nav">
+ <li class="nav-item">
+ <a class="nav-link text-white" href="/">
+ Home
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link text-white" href="{% url 'statistics_app:public' %}">
+ Workshop Statistics
+ </a>
+ </li>
+ </ul>
{% if user.is_authenticated %}
<ul class="navbar-nav mr-auto">
+ {% if request.user|has_group:"instructor" %}
+ <li class="nav-item">
+ <a class="nav-link text-white" href="{% url 'statistics_app:team' %}">
+ Team Statistics
+ </a>
+ </li>
+ {% endif %}
<li class="nav-item">
<a class="nav-link text-white" href="{% url 'workshop_app:workshop_status_instructor' %}">
Workshop Status
diff --git a/workshop_portal/settings.py b/workshop_portal/settings.py
index 78f0358..67f7f12 100644
--- a/workshop_portal/settings.py
+++ b/workshop_portal/settings.py
@@ -134,7 +134,7 @@ STATIC_URL = '/static/'
STATIC_ROOT = 'workshop_app/static/'
-LOGIN_URL = '/login/'
+LOGIN_URL = '/workshop/login/'
MEDIA_URL = '/data/'
diff --git a/workshop_portal/urls.py b/workshop_portal/urls.py
index 45f1407..59a7431 100644
--- a/workshop_portal/urls.py
+++ b/workshop_portal/urls.py
@@ -26,6 +26,7 @@ urlpatterns = [
url(r'^workshop/', include('workshop_app.urls')),
url(r'^reset/', include('django.contrib.auth.urls')),
url(r'^page/', include('cms.urls')),
+ url(r'^statistics/', include('statistics_app.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)