kopia lustrzana https://github.com/OpenDroneMap/WebODM
Plugin API refactoring, upload to public URL working, celery tasks from plugins
rodzic
78b6c41dd2
commit
a847edcd06
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.0.3 on 2018-07-26 21:46
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0020_plugindatum'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='plugindatum',
|
||||
name='user',
|
||||
field=models.ForeignKey(default=None, help_text='The user this setting belongs to. If NULL, the setting is global.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
|
@ -7,7 +7,7 @@ logger = logging.getLogger('app.logger')
|
|||
|
||||
class PluginDatum(models.Model):
|
||||
key = models.CharField(max_length=255, help_text="Setting key", db_index=True)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, help_text="The user this setting belongs to. If NULL, the setting is global.")
|
||||
user = models.ForeignKey(User, null=True, default=None, on_delete=models.CASCADE, help_text="The user this setting belongs to. If NULL, the setting is global.")
|
||||
int_value = models.IntegerField(blank=True, null=True, default=None, help_text="Integer value")
|
||||
float_value = models.FloatField(blank=True, null=True, default=None, help_text="Float value")
|
||||
bool_value = models.NullBooleanField(blank=True, null=True, default=None, help_text="Bool value")
|
||||
|
|
|
@ -3,3 +3,5 @@ from .plugin_base import PluginBase
|
|||
from .menu import Menu
|
||||
from .mount_point import MountPoint
|
||||
from .functions import *
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ def register_plugins():
|
|||
|
||||
with open(plugin.get_path('public/webpack.config.js'), 'w') as f:
|
||||
f.write(wpc_content)
|
||||
logger.info('Wrote public/webpack.config.js for {}'.format(plugin))
|
||||
else:
|
||||
logger.warning("Cannot generate webpack.config.js for {}, a path is missing: {}".format(plugin, ' '.join(build_paths)))
|
||||
|
||||
|
@ -115,6 +114,10 @@ def get_active_plugins():
|
|||
if os.path.basename(plugin_path) == 'test' and not settings.TESTING:
|
||||
continue
|
||||
|
||||
# Ignore .gitignore
|
||||
if os.path.basename(plugin_path) == '.gitignore':
|
||||
continue
|
||||
|
||||
if not os.path.isfile(manifest_path) or not os.path.isfile(pluginpy_path):
|
||||
logger.warning("Found invalid plugin in {}".format(plugin_path))
|
||||
continue
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from app.api.tasks import TaskNestedView as TaskView
|
|
@ -0,0 +1,5 @@
|
|||
from worker.celery import app
|
||||
# noinspection PyUnresolvedReferences
|
||||
from worker.tasks import execute_grass_script
|
||||
|
||||
task = app.task
|
|
@ -5,7 +5,7 @@ from rest_framework import serializers
|
|||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
from app.api.tasks import TaskNestedView
|
||||
from app.plugins.views import TaskView
|
||||
|
||||
from worker.tasks import execute_grass_script
|
||||
|
||||
|
@ -16,7 +16,7 @@ class GeoJSONSerializer(serializers.Serializer):
|
|||
area = serializers.JSONField(help_text="Polygon contour defining the volume area to compute")
|
||||
|
||||
|
||||
class TaskVolume(TaskNestedView):
|
||||
class TaskVolume(TaskView):
|
||||
def post(self, request, pk=None):
|
||||
task = self.get_and_check_task(request, pk)
|
||||
if task.dsm_extent is None:
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
from app.plugins import GlobalDataStore
|
||||
from app.plugins.views import TaskView
|
||||
from app.plugins.worker import task
|
||||
|
||||
import requests
|
||||
|
||||
ds = GlobalDataStore('openaerialmap')
|
||||
|
||||
|
||||
def get_key_for(task_id, key):
|
||||
return "task_{}_{}".format(str(task_id), key)
|
||||
|
||||
|
||||
def get_task_info(task_id):
|
||||
return ds.get_json(get_key_for(task_id, "info"), {
|
||||
'sharing': False,
|
||||
'shared': False,
|
||||
'error': ''
|
||||
})
|
||||
|
||||
def set_task_info(task_id, json):
|
||||
return ds.set_json(get_key_for(task_id, "info"), json)
|
||||
|
||||
|
||||
# TODO: task info cleanup when task is deleted via signal
|
||||
|
||||
|
||||
class ShareInfo(TaskView):
|
||||
def get(self, request, pk=None):
|
||||
task = self.get_and_check_task(request, pk)
|
||||
return Response(get_task_info(task.id), status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class Share(TaskView):
|
||||
def post(self, request, pk=None):
|
||||
task = self.get_and_check_task(request, pk)
|
||||
|
||||
upload_orthophoto_to_oam.delay(task.id, task.get_asset_download_path('orthophoto.tif'))
|
||||
|
||||
task_info = get_task_info(task.id)
|
||||
task_info['sharing'] = True
|
||||
set_task_info(task.id, task_info)
|
||||
|
||||
return Response(task_info, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@task
|
||||
def upload_orthophoto_to_oam(task_id, orthophoto_path):
|
||||
# Upload to temporary central location since
|
||||
# OAM requires a public URL and not all WebODM
|
||||
# instances are public
|
||||
|
||||
res = requests.post('https://www.webodm.org/oam/upload',
|
||||
files=[
|
||||
('file', ('orthophoto.tif', open(orthophoto_path, 'rb'), 'image/tiff')),
|
||||
]).json()
|
||||
|
||||
if 'url' in res:
|
||||
orthophoto_public_url = res['url']
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger('app.logger')
|
||||
|
||||
logger.info("UPLOADED TO " + orthophoto_public_url)
|
||||
else:
|
||||
task_info = get_task_info(task_id)
|
||||
task_info['sharing'] = False
|
||||
task_info['error'] = 'Could not upload orthophoto to intermediate location.'
|
||||
set_task_info(task_id, task_info)
|
|
@ -5,6 +5,9 @@ from app.plugins import PluginBase, Menu, MountPoint
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django import forms
|
||||
|
||||
from plugins.openaerialmap.api import ShareInfo, Share
|
||||
|
||||
|
||||
class TokenForm(forms.Form):
|
||||
token = forms.CharField(label='', required=False, max_length=1024, widget=forms.TextInput(attrs={'placeholder': 'Token'}))
|
||||
|
||||
|
@ -40,6 +43,12 @@ class Plugin(PluginBase):
|
|||
)
|
||||
]
|
||||
|
||||
def api_mount_points(self):
|
||||
return [
|
||||
MountPoint('task/(?P<pk>[^/.]+)/shareinfo', ShareInfo.as_view()),
|
||||
MountPoint('task/(?P<pk>[^/.]+)/share', Share.as_view())
|
||||
]
|
||||
|
||||
def home_view(self):
|
||||
@login_required
|
||||
def home(request):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import './ShareButton.scss';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import $ from 'jquery';
|
||||
|
||||
module.exports = class ShareButton extends React.Component{
|
||||
static defaultProps = {
|
||||
|
@ -17,8 +18,26 @@ module.exports = class ShareButton extends React.Component{
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true
|
||||
loading: true,
|
||||
shared: false,
|
||||
error: ''
|
||||
};
|
||||
|
||||
console.log("AH!");
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
const { task } = this.props;
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: `/api/plugins/openaerialmap/task/${task.id}/shareinfo`,
|
||||
contentType: "application/json"
|
||||
}).done(result => {
|
||||
this.setState({shared: result.shared, loading: false})
|
||||
}).fail(error => {
|
||||
this.setState({error, loading: false});
|
||||
});
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
|
@ -26,12 +45,15 @@ module.exports = class ShareButton extends React.Component{
|
|||
}
|
||||
|
||||
render(){
|
||||
const { loading, shared } = this.state;
|
||||
|
||||
return (<button
|
||||
onClick={this.handleClick}
|
||||
disabled={loading || shared}
|
||||
className="btn btn-sm btn-primary">
|
||||
{this.state.loading
|
||||
? <i className="fa fa-circle-o-notch fa-spin fa-fw"></i>
|
||||
: [<i className="oam-icon fa"></i>, "Share To OAM"]}
|
||||
{loading ?
|
||||
<i className="fa fa-circle-o-notch fa-spin fa-fw"></i> :
|
||||
[<i className="oam-icon fa"></i>, (shared ? "Shared To OAM" : " Share To OAM")]}
|
||||
</button>);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ import traceback
|
|||
|
||||
from celery.utils.log import get_task_logger
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import transaction
|
||||
from django.db.models import Count
|
||||
from django.db.models import Q
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue