Dropzone initialized proof of concept, task api (still need to test)

pull/32/head
Piero Toffanin 2016-10-12 18:18:37 -04:00
rodzic c2e35d30d4
commit d25556ceae
10 zmienionych plików z 1864 dodań i 41 usunięć

Wyświetl plik

@ -1,8 +1,6 @@
from django.contrib import admin
from guardian.admin import GuardedModelAdmin
from .models import Project
from .models import Project, Task
class ProjectAdmin(GuardedModelAdmin):
pass
admin.site.register(Project, ProjectAdmin)
admin.site.register(Project, GuardedModelAdmin)
admin.site.register(Task, GuardedModelAdmin)

Wyświetl plik

@ -1,12 +1,13 @@
from django.contrib.auth.models import User
from rest_framework import serializers, viewsets, filters
from app import models, permissions
from guardian.shortcuts import get_objects_for_user
from rest_framework.response import Response
from rest_framework.decorators import detail_route
from app import models
from .tasks import TaskIDsSerializer, TaskSerializer
class ProjectSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField()
class ProjectSerializer(serializers.ModelSerializer):
owner = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
tasks = TaskIDsSerializer(many=True)
class Meta:
model = models.Project
@ -14,8 +15,20 @@ class ProjectSerializer(serializers.HyperlinkedModelSerializer):
class ProjectViewSet(viewsets.ModelViewSet):
"""
Projects the current user has access to.
Projects the current user has access to. Projects are the building blocks
of processing. Each project can have zero or more tasks associated with it.
Users can fine tune the permissions on projects, including whether users/groups have
access to view, add, change or delete them.<br/><br/>
- /api/projects/&lt;projectId&gt;/tasks : list all tasks belonging to a project<br/>
- /api/projects/&lt;projectId&gt;/tasks/&lt;taskId&gt; : get task details
"""
filter_fields = ('id', 'owner', 'name')
serializer_class = ProjectSerializer
queryset = models.Project.objects.all()
@detail_route(methods=['get'])
def tasks(self, request, pk=None):
tasks = self.get_object().tasks()
serializer = TaskSerializer(tasks, many=True)
return Response(serializer.data)

16
app/api/tasks.py 100644
Wyświetl plik

@ -0,0 +1,16 @@
from django.contrib.auth.models import User
from rest_framework import serializers, viewsets, filters
from app import models
from nodeodm.models import ProcessingNode
class TaskIDsSerializer(serializers.BaseSerializer):
def to_representation(self, obj):
return obj.id
class TaskSerializer(serializers.ModelSerializer):
project = serializers.PrimaryKeyRelatedField(queryset=models.Project.objects.all())
processing_node = serializers.PrimaryKeyRelatedField(queryset=ProcessingNode.objects.all())
class Meta:
model = models.Task

Wyświetl plik

@ -14,8 +14,8 @@ def boot():
if created:
logger.info("Created default group")
# Add default permissions (view_project, change_project, delete_task, etc.)
for permission in ('_project', '_task'):
# Add default permissions (view_project, change_project, delete_project, etc.)
for permission in ('_project'):
default_group.permissions.add(
*list(Permission.objects.filter(codename__endswith=permission))
)

Wyświetl plik

@ -25,6 +25,9 @@ class Project(models.Model):
def __str__(self):
return self.name
def tasks(self):
return Task.objects.filter(project=self);
class Meta:
permissions = (
('view_project', 'Can view project'),
@ -60,15 +63,15 @@ class Task(models.Model):
(50, 'CANCELED')
)
uuid = models.CharField(max_length=255, primary_key=True, help_text="Unique identifier of the task (as returned by OpenDroneMap's REST API)")
uuid = models.CharField(max_length=255, null=True, blank=True, unique=True, help_text="Unique identifier of the task (as returned by OpenDroneMap's REST API)")
project = models.ForeignKey(Project, on_delete=models.CASCADE, help_text="Project that this task belongs to")
name = models.CharField(max_length=255, help_text="A label for the task")
name = models.CharField(max_length=255, null=True, blank=True, help_text="A label for the task")
processing_time = models.IntegerField(default=-1, help_text="Number of milliseconds that elapsed since the beginning of this task (-1 indicates that no information is available)")
processing_node = models.ForeignKey(ProcessingNode, null=True, help_text="Processing node assigned to this task (or null if this task has not been associated yet)")
status = models.IntegerField(choices=STATUS_CODES, null=True, help_text="Current status of the task")
options = fields.JSONField(default=dict(), help_text="Options that are being used to process this task")
console_output = models.TextField(null=True, help_text="Console output of the OpenDroneMap's process")
ground_control_points = models.FileField(null=True, upload_to=gcp_directory_path, help_text="Optional Ground Control Points file to use for processing")
processing_node = models.ForeignKey(ProcessingNode, null=True, blank=True, help_text="Processing node assigned to this task (or null if this task has not been associated yet)")
status = models.IntegerField(choices=STATUS_CODES, null=True, blank=True, help_text="Current status of the task")
options = fields.JSONField(default=dict(), blank=True, help_text="Options that are being used to process this task")
console_output = models.TextField(null=True, blank=True, help_text="Console output of the OpenDroneMap's process")
ground_control_points = models.FileField(null=True, blank=True, upload_to=gcp_directory_path, help_text="Optional Ground Control Points file to use for processing")
# georeferenced_model
# orthophoto
# textured_model

Wyświetl plik

@ -34,7 +34,7 @@ class ProjectList extends React.Component {
error: `Could not load projects list: ${textStatus}`,
loading: false
});
})
});
}
componentWillUnmount(){

Wyświetl plik

@ -1,5 +1,7 @@
import React from 'react';
import ProjectListItemPanel from './ProjectListItemPanel';
import Dropzone from '../vendor/dropzone';
import $ from 'jquery';
class ProjectListItem extends React.Component {
constructor(props){
@ -8,10 +10,27 @@ class ProjectListItem extends React.Component {
this.state = {
showPanel: false
};
this.dropzoneInitialized = false;
this.togglePanel = this.togglePanel.bind(this);
}
initializeDropzone(domNode){
if (domNode != null && !this.dropzoneInitialized){
Dropzone.autoDiscover = false;
let dropzone = new Dropzone(domNode, {
url : '/api/upload'
});
dropzone.on("complete", function(file) {
console.log(file);
});
this.dropzoneInitialized = true;
}
}
togglePanel(){
this.setState({
showPanel: !this.state.showPanel
@ -43,6 +62,12 @@ class ProjectListItem extends React.Component {
{this.props.data.name}
</a>
<div className="dropzone" ref={domNode => this.initializeDropzone(domNode)}>
<div className="dz-default dz-message text-center">
<i className="fa fa-cloud-upload fa-4x"></i>
</div>
</div>
{this.state.showPanel ? <ProjectListItemPanel /> : ""}
</li>
);

Plik diff jest za duży Load Diff

Wyświetl plik

@ -21,22 +21,22 @@
<button class="btn btn-primary" onclick="location.href='{% url "admin:nodeodm_processingnode_add" %}';"><i class="fa fa-plus-circle"></i> {{ add_processing_node }}</button>
{% else %}
{% trans 'Upload Images' as upload_images %}
<p>
{% blocktrans %} To create a new project, press the "{{ upload_images }}" button. {% endblocktrans %}
</p>
<button class="btn btn-primary"><i class="glyphicon glyphicon-upload"></i> {{ upload_images }}</button>
<p>
<ul>
<li>{% trans 'Need at least 5 images' %}</li>
<li>{% trans 'Images must overlap by 60% or more' %}</li>
</ul>
</p>
{% endif %}
<!-- <h4>Projects</h4> -->
{% if no_tasks %}
{% trans 'Upload Images' as upload_images %}
<p>
{% blocktrans %} To create a map, press the "{{ upload_images }}" button. {% endblocktrans %}
</p>
<p>
<ul>
<li>{% trans 'You need at least 5 images' %}</li>
<li>{% trans 'Images must overlap by 60% or more' %}</li>
</ul>
</p>
{% endif %}
<div id="dashboard-app"></div>
{% render_bundle 'main' %}
<div id="dashboard-app"></div>
{% render_bundle 'main' %}
{% endif %}
{% endblock %}

Wyświetl plik

@ -1,7 +1,7 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from nodeodm.models import ProcessingNode
from .models import Project
from .models import Project, Task
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
@ -13,14 +13,15 @@ def index(request):
@login_required
def dashboard(request):
no_processingnodes = ProcessingNode.objects.count() == 0
no_tasks = Task.objects.filter(project__owner=request.user).count() == 0
# Create first project automatically
if Project.objects.filter(owner=request.user).count() == 0:
proj = Project(owner=request.user, name=_("First Project"))
proj.save()
Project.objects.create(owner=request.user, name=_("First Project"))
return render(request, 'app/dashboard.html', {'title': 'Dashboard',
'no_processingnodes': no_processingnodes})
'no_processingnodes': no_processingnodes,
'no_tasks': no_tasks})
@login_required
def processing_node(request, processing_node_id):