kopia lustrzana https://github.com/OpenDroneMap/WebODM
Added processingnode API, UI improvements
rodzic
6036e613f6
commit
75c83ff03b
|
@ -0,0 +1,24 @@
|
|||
from rest_framework import serializers, viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.decorators import permission_classes
|
||||
from rest_framework.permissions import DjangoModelPermissions
|
||||
from rest_framework.filters import DjangoFilterBackend
|
||||
from nodeodm.models import ProcessingNode
|
||||
|
||||
class ProcessingNodeSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ProcessingNode
|
||||
|
||||
|
||||
class ProcessingNodeViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
Processing nodes available. Processing nodes are associated with
|
||||
zero or more tasks and take care of processing input images.
|
||||
"""
|
||||
|
||||
# Don't need a "view node" permission. If you are logged-in, you can view nodes.
|
||||
permission_classes = (DjangoModelPermissions, )
|
||||
filter_backends = (DjangoFilterBackend, )
|
||||
pagination_class = None
|
||||
serializer_class = ProcessingNodeSerializer
|
||||
queryset = ProcessingNode.objects.all()
|
|
@ -1,7 +1,6 @@
|
|||
from django.contrib.auth.models import User
|
||||
from rest_framework import serializers, viewsets, filters
|
||||
from rest_framework import serializers, viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.decorators import detail_route
|
||||
from app import models
|
||||
from .tasks import TaskIDsSerializer, TaskSerializer
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
from django.conf.urls import url, include
|
||||
from .projects import ProjectViewSet
|
||||
from .tasks import TaskViewSet
|
||||
from .processingnodes import ProcessingNodeViewSet
|
||||
from rest_framework_nested import routers
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'projects', ProjectViewSet)
|
||||
router.register(r'processingnodes', ProcessingNodeViewSet)
|
||||
|
||||
tasks_router = routers.NestedSimpleRouter(router, r'projects', lookup='project')
|
||||
tasks_router.register(r'tasks', TaskViewSet, base_name='projects-tasks')
|
||||
|
|
|
@ -35,7 +35,7 @@ class EditTaskPanel extends React.Component {
|
|||
return (
|
||||
<div className="edit-task-panel">
|
||||
<form className="form-horizontal">
|
||||
<p>Your images are being uploaded. In the meanwhile, set these additional options:</p>
|
||||
<p>Your images are being uploaded. In the meanwhile, check these additional options:</p>
|
||||
<div className="form-group">
|
||||
<label className="col-sm-2 control-label">Name</label>
|
||||
<div className="col-sm-10">
|
||||
|
|
|
@ -169,6 +169,8 @@ class ProjectListItem extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.showPanel ? <ProjectListItemPanel /> : ""}
|
||||
|
||||
{this.state.upload.uploading ? <UploadProgressBar {...this.state.upload}/> : ""}
|
||||
|
||||
{this.state.upload.error !== "" ?
|
||||
|
@ -180,7 +182,6 @@ class ProjectListItem extends React.Component {
|
|||
|
||||
<EditTaskPanel className={!this.state.upload.showEditTask ? "hide" : ""} />
|
||||
|
||||
{this.state.showPanel ? <ProjectListItemPanel /> : ""}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -257,7 +257,7 @@
|
|||
</ul>
|
||||
<!-- /.nav-second-level -->
|
||||
</li>
|
||||
{% if user.is_superuser %}
|
||||
{% if user.is_staff %}
|
||||
<li>
|
||||
<a href="/admin/"><i class="fa fa-gears fa-fw"></i> {% trans 'Administration' %}</a>
|
||||
</li>
|
||||
|
|
|
@ -3,6 +3,7 @@ from rest_framework.test import APIClient
|
|||
from rest_framework import status
|
||||
|
||||
from app.models import Project, Task
|
||||
from nodeodm.models import ProcessingNode
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class TestApi(BootTestCase):
|
||||
|
@ -98,4 +99,57 @@ class TestApi(BootTestCase):
|
|||
|
||||
# Cannot access task details for a task that doesn't exist
|
||||
res = client.get('/api/projects/{}/tasks/999/'.format(project.id, other_task.id))
|
||||
self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND)
|
||||
self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
def test_processingnodes(self):
|
||||
client = APIClient()
|
||||
|
||||
pnode = ProcessingNode.objects.create(
|
||||
hostname="localhost",
|
||||
port=999
|
||||
)
|
||||
|
||||
# Cannot list processing nodes as guest
|
||||
res = client.get('/api/processingnodes/')
|
||||
self.assertEqual(res.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
res = client.get('/api/processingnodes/{}/'.format(pnode.id))
|
||||
self.assertEqual(res.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
client.login(username="testuser", password="test1234")
|
||||
|
||||
# Can list processing nodes as normal user
|
||||
res = client.get('/api/processingnodes/')
|
||||
self.assertEqual(res.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(len(res.data) == 1)
|
||||
self.assertTrue(res.data[0]["hostname"] == "localhost")
|
||||
|
||||
# Can get single processing node as normal user
|
||||
res = client.get('/api/processingnodes/{}/'.format(pnode.id))
|
||||
self.assertEqual(res.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(res.data["hostname"] == "localhost")
|
||||
|
||||
# Cannot delete a processing node as normal user
|
||||
res = client.delete('/api/processingnodes/{}/'.format(pnode.id))
|
||||
self.assertTrue(res.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# Cannot create a processing node as normal user
|
||||
res = client.post('/api/processingnodes/', {'hostname': 'localhost', 'port':'1000'})
|
||||
self.assertTrue(res.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
client.login(username="testsuperuser", password="test1234")
|
||||
|
||||
# Can delete a processing node as super user
|
||||
res = client.delete('/api/processingnodes/{}/'.format(pnode.id))
|
||||
self.assertTrue(res.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Can create a processing node as super user
|
||||
res = client.post('/api/processingnodes/', {'hostname': 'localhost', 'port':'1000'})
|
||||
self.assertTrue(res.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Verify node has been created
|
||||
res = client.get('/api/processingnodes/')
|
||||
self.assertEqual(res.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(len(res.data) == 1)
|
||||
self.assertTrue(res.data[0]["port"] == 1000)
|
|
@ -9,7 +9,7 @@ import json
|
|||
class ProcessingNode(models.Model):
|
||||
hostname = models.CharField(max_length=255, help_text="Hostname where the node is located (can be an internal hostname as well)")
|
||||
port = models.PositiveIntegerField(help_text="Port that connects to the node's API")
|
||||
api_version = models.CharField(max_length=32, help_text="API version used by the node")
|
||||
api_version = models.CharField(max_length=32, null=True, help_text="API version used by the node")
|
||||
last_refreshed = models.DateTimeField(null=True, help_text="When was the information about this node last retrieved?")
|
||||
queue_count = models.PositiveIntegerField(default=0, help_text="Number of tasks currently being processed by this node (as reported by the node itself)")
|
||||
available_options = fields.JSONField(default=dict(), help_text="Description of the options that can be used for processing")
|
||||
|
|
Ładowanie…
Reference in New Issue