diff --git a/apps/main/admin.py b/apps/main/admin.py index 18496f8..28e3f16 100644 --- a/apps/main/admin.py +++ b/apps/main/admin.py @@ -1,10 +1,9 @@ from django.contrib import admin -from .models import Device, DeviceType, Experiment, Campaign, Location, Radar +from .models import Device, DeviceType, Experiment, Campaign, Location # Register your models here. admin.site.register(Campaign) admin.site.register(Experiment) admin.site.register(Device) admin.site.register(DeviceType) -admin.site.register(Location) -admin.site.register(Radar) \ No newline at end of file +admin.site.register(Location) \ No newline at end of file diff --git a/apps/main/forms.py b/apps/main/forms.py index c8276cb..7e611f0 100644 --- a/apps/main/forms.py +++ b/apps/main/forms.py @@ -1,9 +1,5 @@ from django import forms from django.utils.safestring import mark_safe -from datetime import datetime - -from apps.main.widgets import Filtering_ComboBox_Widget, Datepicker, HTMLrender,Filtering_ComboBox_Widget2 - from .models import DeviceType, Device, Experiment, Campaign, Configuration, Location @@ -38,6 +34,7 @@ class CampaignForm(forms.ModelForm): exclude = [''] class ExperimentForm(forms.ModelForm): + def __init__(self, *args, **kwargs): super(ExperimentForm, self).__init__(*args, **kwargs) self.fields['start_time'].widget = TimepickerWidget(self.fields['start_time'].widget.attrs) @@ -67,8 +64,17 @@ class ConfigurationForm(forms.ModelForm): class DeviceTypeForm(forms.Form): device_type = forms.ChoiceField(choices=add_empty_choice(DeviceType.objects.all().order_by('name').values_list('id', 'name'))) + +class UploadFileForm(forms.Form): + + file = forms.FileField() + +class DownloadFileForm(forms.Form): + + format = forms.ComboField() + class OperationForm(forms.Form): - today = datetime.today() +# today = datetime.today() # -----Campaigns from this month------ - campaign = forms.ChoiceField(choices=Campaign.objects.filter(start_date__month=today.month).filter(start_date__year=today.year).order_by('-start_date').values_list('id', 'name'), label="Campaign") + campaign = forms.ChoiceField(choices=Campaign.objects.all().order_by('-start_date').values_list('id', 'name')[:5], label="Campaign") \ No newline at end of file diff --git a/apps/main/models.py b/apps/main/models.py index ca347a7..ac9c19a 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -49,6 +49,18 @@ RADAR_STATES = ( ) # Create your models here. + +class Location(models.Model): + + name = models.CharField(max_length = 30) + description = models.TextField(blank=True, null=True) + + class Meta: + db_table = 'db_location' + + def __unicode__(self): + return u'%s' % self.name + class DeviceType(models.Model): name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'rc') @@ -62,8 +74,8 @@ class DeviceType(models.Model): class Device(models.Model): - device_type = models.ForeignKey(DeviceType) -# location = models.ForeignKey(Location) + device_type = models.ForeignKey(DeviceType, on_delete=models.CASCADE) + location = models.ForeignKey(Location, on_delete=models.CASCADE) name = models.CharField(max_length=40, default='') ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0') @@ -98,24 +110,27 @@ class Campaign(models.Model): def __unicode__(self): return u'%s' % (self.name) -class Radar(models.Model): - - name = models.CharField(max_length = 30) - campaign = models.ForeignKey(Campaign) - status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES) - - class Meta: - db_table = 'db_radar' - - def __unicode__(self): - return u'%s' % self.name +# class Radar(models.Model): +# +# # name = models.CharField(max_length = 30) +# experiment = models.ForeignKey('Experiment', on_delete=models.CASCADE) +# location = models.OneToOneField('Location', on_delete=models.CASCADE) +# status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES) +# +# class Meta: +# db_table = 'db_radar' +# +# def __unicode__(self): +# return u'%s' % self.location class Experiment(models.Model): template = models.BooleanField(default=False) - radar = models.ForeignKey(Radar) + campaign = models.ForeignKey('Campaign', null=True, blank=True, on_delete=models.CASCADE) + location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE) + name = models.CharField(max_length=40, default='') start_time = models.TimeField(default='00:00:00') end_time = models.TimeField(default='23:59:59') @@ -124,7 +139,7 @@ class Experiment(models.Model): db_table = 'db_experiments' def __unicode__(self): - return u'[%s]: %s' % (self.radar.name, self.name) + return u'%s' % (self.name) class Configuration(PolymorphicModel): @@ -132,8 +147,8 @@ class Configuration(PolymorphicModel): name = models.CharField(verbose_name="Configuration Name", max_length=40, default='') - experiment = models.ForeignKey(Experiment) - device = models.ForeignKey(Device) + experiment = models.ForeignKey('Experiment', null=True, blank=True, on_delete=models.CASCADE) + device = models.ForeignKey(Device, on_delete=models.CASCADE) type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES) @@ -142,14 +157,94 @@ class Configuration(PolymorphicModel): parameters = models.TextField(default='{}') + message = "" + class Meta: db_table = 'db_configurations' def __unicode__(self): - return u'[%s - %s]: %s' % (self.experiment.campaign.name, + return u'[%s - %s]: %s' % (self.experiment.name, self.experiment.name, self.device.name) + + def parms_to_dict(self): + + parameters = {} + + for key in self.__dict__.keys(): + parameters[key] = getattr(self, key) + + return parameters + + def dict_to_parms(self, parameters): + + if type(parameters) != type({}): + return + + for key in parameters.keys(): + setattr(self, key, parameters[key]) + + def export_to_file(self, format="json"): + + import json + content_type = 'application/json' + filename = '%s.json' %self.name + content = json.dumps(self.params_to_dict()) + + if format == 'text': + content_type = 'text/plain' + filename = '%s.%s' %(self.name, self.device.device_type.name) + content = self.params_to_text() + + if format == 'binary': + content_type = 'application/octet-stream' + filename = '%s.bin' %self.name + content = self.params_to_binary() + + fields = {'content_type':content_type, + 'filename':filename, + 'content':content + } + + return fields + + def import_from_file(self, filename): + + raise NotImplementedError, "This method should be implemented in each Configuration model" + + return {} + + def status_device(self): + + raise NotImplementedError, "This method should be implemented in each Configuration model" + + return None + + def stop_device(self): + + raise NotImplementedError, "This method should be implemented in each Configuration model" + + return None + + def start_device(self): + + raise NotImplementedError, "This method should be implemented in each Configuration model" + + return None + + def write_device(self, parms): + + raise NotImplementedError, "This method should be implemented in each Configuration model" + + return None + + def read_device(self): + + raise NotImplementedError, "This method should be implemented in each Configuration model" + + return None + def get_absolute_url(self): return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)]) @@ -157,24 +252,22 @@ class Configuration(PolymorphicModel): return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)]) def get_absolute_url_import(self): - return reverse('url_import_%s_conf' % self.device.device_type.name, args=[str(self.id)]) + return reverse('url_import_dev_conf', args=[str(self.id)]) def get_absolute_url_export(self): - return reverse('url_export_%s_conf' % self.device.device_type.name, args=[str(self.id)]) + return reverse('url_export_dev_conf', args=[str(self.id)]) def get_absolute_url_write(self): - return reverse('url_write_%s_conf' % self.device.device_type.name, args=[str(self.id)]) + return reverse('url_write_dev_conf', args=[str(self.id)]) def get_absolute_url_read(self): - return reverse('url_read_%s_conf' % self.device.device_type.name, args=[str(self.id)]) + return reverse('url_read_dev_conf', args=[str(self.id)]) -class Location(models.Model): - - name = models.CharField(max_length = 30) - description = models.TextField(blank=True, null=True) - - class Meta: - db_table = 'db_location' + def get_absolute_url_start(self): + return reverse('url_start_dev_conf', args=[str(self.id)]) - def __unicode__(self): - return u'%s' % self.name \ No newline at end of file + def get_absolute_url_stop(self): + return reverse('url_stop_dev_conf', args=[str(self.id)]) + + def get_absolute_url_status(self): + return reverse('url_status_dev_conf', args=[str(self.id)]) \ No newline at end of file diff --git a/apps/main/templates/dev_conf.html b/apps/main/templates/dev_conf.html index 64783ae..ef2cde7 100644 --- a/apps/main/templates/dev_conf.html +++ b/apps/main/templates/dev_conf.html @@ -10,10 +10,25 @@ {% block content %} + + Options + + + - + {% for key in dev_conf_keys %} @@ -24,13 +39,6 @@ {% endfor %}
Status{%if connected == True %} Connected {% else %} Disconnected {% endif %}{%if status %} {{status}} {% else %} Disconnected {% endif %}
- - - - - - - {% endblock %} {% block sidebar%} diff --git a/apps/main/templates/dev_conf_export.html b/apps/main/templates/dev_conf_export.html new file mode 100644 index 0000000..029ea49 --- /dev/null +++ b/apps/main/templates/dev_conf_export.html @@ -0,0 +1 @@ +{% extends "dev_conf_edit.html" %} \ No newline at end of file diff --git a/apps/main/templates/dev_conf_import.html b/apps/main/templates/dev_conf_import.html new file mode 100644 index 0000000..029ea49 --- /dev/null +++ b/apps/main/templates/dev_conf_import.html @@ -0,0 +1 @@ +{% extends "dev_conf_edit.html" %} \ No newline at end of file diff --git a/apps/main/templates/operation.html b/apps/main/templates/operation.html index 57f0f63..e288a18 100644 --- a/apps/main/templates/operation.html +++ b/apps/main/templates/operation.html @@ -23,17 +23,17 @@

+
- {% for radar in radars %} + {% for location in locations %}
-
+
- + {% for header in experiment_keys %} {% endfor%} + {% for item in experiments %} - {% for exs in item %} - - - {% for key in experiment_keys %} - {% if radar.name in exs.radar.name %} - - {% endif %} - {% endfor %} - {% endfor %} - + {% if location.name in item.location.name %} + + + {% for key in experiment_keys %} + + {% endfor %} + + {% endif %} {% endfor %}
#{{ header|title }}
{{ exs|attr:key }}
{{ forloop.counter }}{{ item|value:key }}
diff --git a/apps/main/urls.py b/apps/main/urls.py index 7b10d23..e5462a8 100644 --- a/apps/main/urls.py +++ b/apps/main/urls.py @@ -30,6 +30,14 @@ urlpatterns = ( url(r'^dev_conf/(?P-?\d+)/$', 'apps.main.views.dev_conf', name='url_dev_conf'), url(r'^dev_conf/(?P-?\d+)/edit/$', 'apps.main.views.dev_conf_edit', name='url_edit_dev_conf'), url(r'^dev_conf/(?P-?\d+)/delete/$', 'apps.main.views.dev_conf_delete', name='url_delete_dev_conf'), + + url(r'^dev_conf/(?P-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_dev_conf'), + url(r'^dev_conf/(?P-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_dev_conf'), + url(r'^dev_conf/(?P-?\d+)/import/$', 'apps.main.views.dev_conf_import', name='url_import_dev_conf'), + url(r'^dev_conf/(?P-?\d+)/export/$', 'apps.main.views.dev_conf_export', name='url_export_dev_conf'), + url(r'^dev_conf/(?P-?\d+)/start/$', 'apps.main.views.dev_conf_start', name='url_start_dev_conf'), + url(r'^dev_conf/(?P-?\d+)/stop/$', 'apps.main.views.dev_conf_stop', name='url_stop_dev_conf'), + url(r'^dev_conf/(?P-?\d+)/status/$', 'apps.main.views.dev_conf_status', name='url_status_dev_conf'), url(r'^operation/$', 'apps.main.views.operation', name='url_operation'), url(r'^operation/(?P-?\d+)/$', 'apps.main.views.operation', name='url_operation'), diff --git a/apps/main/views.py b/apps/main/views.py index 606e6c8..3e41dc4 100644 --- a/apps/main/views.py +++ b/apps/main/views.py @@ -1,9 +1,7 @@ from django.shortcuts import render, redirect, get_object_or_404, HttpResponse from django.contrib import messages -from datetime import datetime - -from .forms import CampaignForm, ExperimentForm, DeviceForm, ConfigurationForm, LocationForm, OperationForm +from .forms import CampaignForm, ExperimentForm, DeviceForm, ConfigurationForm, LocationForm, UploadFileForm, DownloadFileForm, OperationForm from apps.cgs.forms import CGSConfigurationForm from apps.jars.forms import JARSConfigurationForm from apps.usrp.forms import USRPConfigurationForm @@ -11,7 +9,7 @@ from apps.abs.forms import ABSConfigurationForm from apps.rc.forms import RCConfigurationForm from apps.dds.forms import DDSConfigurationForm -from .models import Campaign, Experiment, Device, Configuration, Location, Radar +from .models import Campaign, Experiment, Device, Configuration, Location from apps.cgs.models import CGSConfiguration from apps.jars.models import JARSConfiguration from apps.usrp.models import USRPConfiguration @@ -237,7 +235,8 @@ def campaigns(request): def campaign(request, id_camp): campaign = get_object_or_404(Campaign, pk=id_camp) - #experiments = Experiment.objects.filter(campaign=campaign) + experiments = Experiment.objects.filter(campaign=campaign) + form = CampaignForm(instance=campaign) kwargs = {} @@ -247,7 +246,7 @@ def campaign(request, id_camp): keys = ['id', 'name', 'start_time', 'end_time'] kwargs['experiment_keys'] = keys[1:] - #kwargs['experiments'] = experiments.values(*keys) + kwargs['experiments'] = experiments.values(*keys) kwargs['title'] = 'Campaign' kwargs['suptitle'] = 'Details' @@ -341,7 +340,7 @@ def experiment(request, id_exp): kwargs = {} - exp_keys = ['id', 'campaign', 'name', 'start_time', 'end_time'] + exp_keys = ['id', 'campaign', 'location', 'name', 'start_time', 'end_time'] conf_keys = ['id', 'device__name', 'device__device_type', 'device__ip_address', 'device__port_address'] conf_labels = ['id', 'device__name', 'device_type', 'ip_address', 'port_address'] @@ -517,37 +516,203 @@ def dev_conf_edit(request, id_conf): return render(request, 'dev_conf_edit.html', kwargs) -def dev_conf_read(request, id_conf): +def dev_conf_start(request, id_conf): + + conf = get_object_or_404(Configuration, pk=id_conf) + + DevConfModel = CONF_MODELS[conf.device.device_type.name] + + conf = DevConfModel.objects.get(pk=id_conf) + + if conf.start_device(): + messages.success(request, conf.message) + else: + messages.error(request, conf.message) + + return redirect(conf.get_absolute_url()) + +def dev_conf_stop(request, id_conf): conf = get_object_or_404(Configuration, pk=id_conf) - messages.error(request, "Read View not implemented yet") + DevConfModel = CONF_MODELS[conf.device.device_type.name] + + conf = DevConfModel.objects.get(pk=id_conf) + + if conf.stop_device(): + messages.success(request, conf.message) + else: + messages.error(request, conf.message) + + return redirect(conf.get_absolute_url()) + +def dev_conf_status(request, id_conf): + + conf = get_object_or_404(Configuration, pk=id_conf) + + DevConfModel = CONF_MODELS[conf.device.device_type.name] + + conf = DevConfModel.objects.get(pk=id_conf) + + if conf.status_device(): + messages.success(request, conf.message) + else: + messages.error(request, conf.message) - return redirect('url_dev_conf', id_conf=conf.id) + return redirect(conf.get_absolute_url()) + def dev_conf_write(request, id_conf): conf = get_object_or_404(Configuration, pk=id_conf) - messages.error(request, "Write View not implemented yet") + DevConfModel = CONF_MODELS[conf.device.device_type.name] + + conf = DevConfModel.objects.get(pk=id_conf) + + answer = conf.write_device() + + if answer: + messages.success(request, conf.message) + + conf.pk = None + conf.id = None + conf.type = 1 + conf.template = 0 + conf.save() + + else: + messages.error(request, conf.message) - return redirect('url_dev_conf', id_conf=conf.id) + return redirect(conf.get_absolute_url()) + +def dev_conf_read(request, id_conf): + + conf = get_object_or_404(Configuration, pk=id_conf) + + DevConfModel = CONF_MODELS[conf.device.device_type.name] + DevConfForm = CONF_FORMS[conf.device.device_type.name] + + conf = DevConfModel.objects.get(pk=id_conf) + + if request.method=='GET': + + parms = conf.read_device() + + if not parms: + messages.error(request, conf.message) + return redirect(conf.get_absolute_url()) + + form = DevConfForm(initial=parms, instance=conf) + + if request.method=='POST': + form = DevConfForm(request.POST, instance=conf) + + if form.is_valid(): + dev_model = form.save(commit=False) + + if dev_model.save(): + return redirect(conf.get_absolute_url()) + + messages.error(request, "Parameters could not be saved") + + kwargs = {} + kwargs['id_dev'] = conf.id + kwargs['form'] = form + kwargs['title'] = 'Device Configuration' + kwargs['suptitle'] = 'Parameters read from device' + kwargs['button'] = 'Save' + + ###### SIDEBAR ###### + kwargs.update(sidebar(conf)) + + return render(conf.get_absolute_url_edit()) def dev_conf_import(request, id_conf): conf = get_object_or_404(Configuration, pk=id_conf) - messages.error(request, "Import View not implemented yet") + DevConfModel = CONF_MODELS[conf.device.device_type.name] + DevConfForm = CONF_FORMS[conf.device.device_type.name] - return redirect('url_dev_conf', id_conf=conf.id) + conf = DevConfModel.objects.get(pk=id_conf) + + if request.method == 'GET': + file_form = UploadFileForm() + + if request.method == 'POST': + file_form = UploadFileForm(request.POST, request.FILES) + + if file_form.is_valid(): + + parms = conf.import_from_file(request.FILES['file']) + + if parms: + + messages.success(request, "Parameters imported from: '%s'." %request.FILES['file'].name) + + form = DevConfForm(initial=parms, instance=conf) + + kwargs = {} + kwargs['id_dev'] = conf.id + kwargs['form'] = form + kwargs['title'] = 'Device Configuration' + kwargs['suptitle'] = 'Parameters imported' + kwargs['button'] = 'Save' + kwargs['action'] = conf.get_absolute_url_edit() + kwargs['previous'] = conf.get_absolute_url() + + ###### SIDEBAR ###### + kwargs.update(sidebar(conf)) + + return render(request, '%s_conf_edit.html' %conf.device.device_type.name, kwargs) + + messages.error(request, "Could not import parameters from file") + + kwargs = {} + kwargs['id_dev'] = conf.id + kwargs['title'] = 'Device Configuration' + kwargs['form'] = file_form + kwargs['suptitle'] = 'Importing file' + kwargs['button'] = 'Import' + + kwargs.update(sidebar(conf)) + + return render(request, 'dev_conf_import.html', kwargs) def dev_conf_export(request, id_conf): conf = get_object_or_404(Configuration, pk=id_conf) - messages.error(request, "Export View not implemented yet") + DevConfModel = CONF_MODELS[conf.device.device_type.name] + + conf = DevConfModel.objects.get(pk=id_conf) + + if request.method == 'GET': + file_form = DownloadFileForm() + + if request.method == 'POST': + file_form = DownloadFileForm(request.POST) + + if file_form.is_valid(): + fields = conf.export_to_file(format = file_form.format) + + response = HttpResponse(content_type=fields['content_type']) + response['Content-Disposition'] = 'attachment; filename="%s"' %fields['filename'] + response.write(fields['content']) + + return response + + messages.error(request, "Could not export parameters") + + kwargs = {} + kwargs['id_dev'] = conf.id + kwargs['title'] = 'Device Configuration' + kwargs['form'] = file_form + kwargs['suptitle'] = 'Exporting file' + kwargs['button'] = 'Export' - return redirect('url_dev_conf', id_conf=conf.id) + return render(request, 'dev_conf_export.html', kwargs) def dev_conf_delete(request, id_conf): @@ -592,25 +757,27 @@ def sidebar(conf): def operation(request, id_camp=None): - today = datetime.today() - - if id_camp==None: - id_camp = Campaign.objects.filter(start_date__month=today.month).filter(start_date__year=today.year).order_by('-start_date')[0].id + if not id_camp: + campaigns = Campaign.objects.all().order_by('-start_date') + + if not campaigns: + return render(request, 'operation.html', {}) + id_camp = campaigns[0].id + + campaign = get_object_or_404(Campaign, pk = id_camp) + if request.method=='GET': - campaign = get_object_or_404(Campaign, pk = id_camp) - campaigns = Campaign.objects.filter(start_date__month=today.month).filter(start_date__year=today.year).order_by('-start_date') form = OperationForm(initial={'campaign': id_camp}) - if request.method=='POST': - campaign = get_object_or_404(Campaign, pk=request.POST['campaign']) - #id_camp = Campaign.objects.filter(start_date__month=today.month).filter(start_date__year=today.year).order_by('-start_date')[1].id - form = OperationForm(request.POST, initial={'campaign':campaign.name}) + if request.method=='POST': + form = OperationForm(request.POST, initial={'campaign':campaign.id}) + if form.is_valid(): return redirect('url_operation', id_camp=campaign.id) - radars = Radar.objects.filter(campaign = campaign) - experiments = [Experiment.objects.filter(radar=radar) for radar in radars] #zip(radars, [Experiment.objects.filter(radar=radar) for radar in radars]) + locations = Location.objects.filter(experiment__campaign = campaign) + experiments = Experiment.objects.filter(campaign=campaign) kwargs = {} #---Campaign @@ -621,11 +788,11 @@ def operation(request, id_camp=None): kwargs['experiment_keys'] = keys[1:] kwargs['experiments'] = experiments #---Radar - kwargs['radars'] = radars + kwargs['locations'] = locations #---Else - kwargs['title'] = 'Operation' + kwargs['title'] = 'Campaign' kwargs['suptitle'] = campaign.name kwargs['form'] = form - kwargs['button'] = '...' + kwargs['button'] = 'Apply' return render(request, 'operation.html', kwargs) \ No newline at end of file