# -*- coding: UTF-8 -*-
# views.py
#
# Copyright (C) 2014 HES-SO//HEG Arc
#
# Author(s): Cédric Gaspoz <cedric.gaspoz@he-arc.ch>
#
# This file is part of MarMix.
#
# MarMix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# MarMix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MarMix. If not, see <http://www.gnu.org/licenses/>.
# Stdlib imports
from hashlib import sha256
import json
import logging
import io
import datetime
# Core Django imports
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib import messages
from django.shortcuts import render_to_response, get_object_or_404
from django.template.context import RequestContext
from django.http import Http404, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from django.http import Http404
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from django.forms.models import modelform_factory
from django.http import HttpResponseRedirect
# Third-party app imports
from rest_framework import permissions, viewsets
from xlsxwriter.workbook import Workbook
# MarMix imports
from .models import Simulation, Currency, Team
from .serializers import SimulationSerializer, CurrencySerializer, TeamSerializer
from .forms import TeamsSelectionForm, TeamJoinForm
from .tasks import initialize_simulation
from customers.models import Customer
from tickers.models import Ticker
from .permissions import IsOwnerOrReadOnly, IsAdminOrReadOnly
logger = logging.getLogger(__name__)
[docs]def remove_tz_from_date(date):
naive_date = datetime.datetime(date.year, date.month, date.day, date.hour, date.minute, date.second, date.microsecond)
return naive_date
[docs]class SimulationViewSet(viewsets.ModelViewSet):
queryset = Simulation.objects.all()
serializer_class = SimulationSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
[docs]class CurrencyViewSet(viewsets.ModelViewSet):
queryset = Currency.objects.all()
serializer_class = CurrencySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
[docs]class TeamViewSet(viewsets.ModelViewSet):
queryset = Team.objects.all()
serializer_class = TeamSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
[docs]class SimulationListView(ListView):
model = Simulation
[docs] def get_context_data(self, **kwargs):
context = super(SimulationListView, self).get_context_data(**kwargs)
#context['foo'] = "bar"
return context
[docs] def get_queryset(self):
if self.request.user.is_staff:
simulations = Simulation.objects.all()
else:
simulations = Simulation.objects.all().filter(user=self.request.user)
return simulations
[docs]class SimulationDetailView(DetailView):
model = Simulation
[docs] def get_context_data(self, **kwargs):
context = super(SimulationDetailView, self).get_context_data(**kwargs)
context['simulation_state'] = Simulation.SIMULATION_STATE_DICT
return context
[docs] def get_object(self, queryset=None):
if self.request.user.is_staff:
simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
else:
simulation = get_object_or_404(Simulation, user=self.request.user, pk=self.kwargs['pk'])
return simulation
[docs]class TeamsSelectionView(SuccessMessageMixin, FormView):
template_name = 'simulations/manage_teams_form.html'
form_class = TeamsSelectionForm
success_message = _("Participating teams were successfully updated")
[docs] def get_context_data(self, **kwargs):
context = super(TeamsSelectionView, self).get_context_data(**kwargs)
simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
context['simulation_id'] = simulation.id
return context
[docs] def get_success_url(self):
return reverse('simulations-detail-view', kwargs={'pk': self.kwargs['pk']})
[docs]class SimulationCreate(SuccessMessageMixin, CreateView):
model = Simulation
fields = ['code', 'simulation_type', 'capital', 'currency']
success_message = _("The simulation <b>%(code)s</b> was successfully created. You can start using it right now!")
[docs] def get_context_data(self, **kwargs):
context = super(SimulationCreate, self).get_context_data(**kwargs)
customer = get_object_or_404(Customer, pk=self.kwargs['customer_id'])
context['customer_id'] = customer.id
context['action'] = 'create'
return context
[docs] def get_success_url(self):
return reverse('simulations-detail-view', kwargs={'pk': self.object.pk})
[docs] def get_success_message(self, cleaned_data):
return self.success_message % {'code': self.object.code, }
[docs]class SimulationUpdate(SuccessMessageMixin, UpdateView):
model = Simulation
fields = ['code', 'simulation_type', 'capital', 'currency']
success_message = _("The simulation was successfully updated!")
[docs] def get_success_url(self):
return reverse('simulations-detail-view', kwargs={'pk': self.object.pk})
[docs] def get_context_data(self, **kwargs):
context = super(SimulationUpdate, self).get_context_data(**kwargs)
simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
context['simulation_id'] = simulation.id
context['action'] = 'update'
return context
[docs] def get_object(self, queryset=None):
if self.request.user.is_staff:
simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
else:
simulation = get_object_or_404(Simulation, user=self.request.user, pk=self.kwargs['pk'])
return simulation
[docs]class SimulationDelete(SuccessMessageMixin, DeleteView):
model = Simulation
success_url = reverse_lazy('simulations-list-view')
success_message = _("The simulation <b>%(code)s</b> was successfully deleted!")
[docs] def delete(self, request, *args, **kwargs):
simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
messages.success(self.request, self.success_message % {'code': simulation.code, })
return super(SimulationDelete, self).delete(request, *args, **kwargs)
[docs] def get_object(self, queryset=None):
if self.request.user.is_staff:
simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
else:
simulation = get_object_or_404(Simulation, user=self.request.user, pk=self.kwargs['pk'])
return simulation
[docs]class TeamJoinView(SuccessMessageMixin, FormView):
template_name = 'simulations/join_team_form.html'
form_class = TeamJoinForm
success_message = _("You were successfully added to the team <b>%(team_name)s</b>!")
team_name = ''
[docs] def get_success_url(self):
return reverse('users:detail', kwargs={"username": self.request.user.username})
[docs] def get_success_message(self, cleaned_data):
return self.success_message % {'team_name': self.team_name, }
[docs]class TeamDetailView(DetailView):
model = Team
[docs] def get_context_data(self, **kwargs):
context = super(TeamDetailView, self).get_context_data(**kwargs)
#context['foo'] = "bar"
return context
[docs] def get_object(self, queryset=None):
if self.request.user.is_staff:
team = get_object_or_404(Team, pk=self.kwargs['pk'])
else:
team = get_object_or_404(Team, users=self.request.user, pk=self.kwargs['pk'])
return team
[docs]def teams_export_xlsx(request, simulation_id=None, customer_id=None):
if simulation_id:
simulation = get_object_or_404(Simulation, pk=simulation_id)
teams = simulation.teams.all()
elif customer_id:
customer = get_object_or_404(Customer, pk=customer_id)
teams = Team.objects.all().filter(customer=customer)
else:
customers = Customer.objects.all().filter(users=request.user)
teams = Team.objects.all().filter(customer=customers)
output = io.BytesIO()
workbook = Workbook(output, {'in_memory': True})
worksheet = workbook.add_worksheet('Teams')
bold = workbook.add_format({'bold': True})
date_format = workbook.add_format({'num_format': 'yyyy-MM-dd'})
worksheet.write(0, 0, 'Team', bold)
worksheet.write(0, 1, 'Registration key', bold)
worksheet.write(0, 2, 'Type', bold)
worksheet.write(0, 3, '# Members', bold)
worksheet.write(0, 4, 'Locked', bold)
worksheet.write(0, 5, 'Created', bold)
worksheet.write(0, 6, 'Modified', bold)
worksheet.write(0, 7, 'Organization', bold)
row = 1
for team in teams:
worksheet.write(row, 0, team.name)
worksheet.write(row, 1, team.uuid)
worksheet.write(row, 2, team.get_team_type_display())
worksheet.write(row, 3, team.get_members)
worksheet.write(row, 4, team.locked)
worksheet.write(row, 5, remove_tz_from_date(team.created), date_format)
worksheet.write(row, 6, remove_tz_from_date(team.modified), date_format)
worksheet.write(row, 7, team.customer.name)
row += 1
workbook.close()
output.seek(0)
response = HttpResponse(output.read(), content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = "attachment; filename=marmix_teams.xlsx"
return response
[docs]class SimulationInitializeView(SuccessMessageMixin, UpdateView):
"""
Update/Create the simulation. It calls initialize_simulation after form validation.
"""
model = Ticker
fields = ['nb_companies', 'initial_value', 'fixed_interest_rate']
success_message = _("The simulation <b>%(code)s</b> was successfully initialized. You can play the simulation right now!")
simulation = None
[docs] def get_object(self, queryset=None):
self.simulation = get_object_or_404(Simulation, pk=self.kwargs['pk'])
try:
ticker = self.simulation.ticker
except Ticker.DoesNotExist:
ticker = Ticker(simulation=self.simulation)
ticker.save()
return ticker
[docs] def get_context_data(self, **kwargs):
context = super(SimulationInitializeView, self).get_context_data(**kwargs)
context['simulation_id'] = self.simulation.id
return context
[docs] def get_success_url(self):
return reverse('simulations-detail-view', kwargs={'pk': self.simulation.id})
[docs] def get_success_message(self, cleaned_data):
return self.success_message % {'code': self.object.simulation.code, }
[docs]def manage_simulation(request, simulation_id, next_state):
"""
Helper to change the current state of the simulation.
Available states are READY -> RUNNING <-> PAUSED -> FINISHED -> ARCHIVED.
:param request:
:param simulation_id:
:param next_state:
:return: HttpResponseRedirect
"""
simulation = get_object_or_404(Simulation, pk=simulation_id)
next_state = int(next_state)
if next_state == Simulation.RUNNING and simulation.state == Simulation.READY:
simulation.state = Simulation.RUNNING
elif next_state == Simulation.PAUSED and simulation.state == Simulation.RUNNING:
simulation.state = Simulation.PAUSED
elif next_state == Simulation.RUNNING and simulation.state == Simulation.PAUSED:
simulation.state = Simulation.RUNNING
elif next_state == Simulation.ARCHIVED and simulation.state == Simulation.FINISHED:
simulation.state = Simulation.ARCHIVED
simulation.save()
messages.info(request, 'The simulation is now <b>%s</b>' % simulation.get_state_display())
return HttpResponseRedirect(reverse('simulations-detail-view', args=[simulation.id]))