Added settings page

pull/1122/head
Luca Di Leo 2022-01-05 06:49:33 -08:00
rodzic a9a474ad46
commit 32863c7b33
5 zmienionych plików z 169 dodań i 178 usunięć

Wyświetl plik

@ -14,124 +14,125 @@ from rest_framework import status
#from .platform_helper import get_all_platforms, get_platform_by_name #from .platform_helper import get_all_platforms, get_platform_by_name
class ImportFolderTaskView(TaskView): # class ImportFolderTaskView(TaskView):
def post(self, request, project_pk=None, pk=None): # def post(self, request, project_pk=None, pk=None):
task = self.get_and_check_task(request, pk) # task = self.get_and_check_task(request, pk)
# Read form data # Read form data
folder_url = request.data.get('selectedFolderUrl', None) # folder_url = request.data.get('selectedFolderUrl', None)
platform_name = request.data.get('platform', None) # platform_name = request.data.get('platform', None)
# Make sure both values are set # # Make sure both values are set
if folder_url == None or platform_name == None: # if folder_url == None or platform_name == None:
return Response({'error': 'Folder URL and platform name must be set.'}, status=status.HTTP_400_BAD_REQUEST) # return Response({'error': 'Folder URL and platform name must be set.'}, status=status.HTTP_400_BAD_REQUEST)
# Fetch the platform by name # # Fetch the platform by name
platform = get_platform_by_name(platform_name) # platform = get_platform_by_name(platform_name)
# Make sure that the platform actually exists # # Make sure that the platform actually exists
if platform == None: # if platform == None:
return Response({'error': 'Failed to find a platform with the name \'{}\''.format(platform_name)}, status=status.HTTP_400_BAD_REQUEST) # return Response({'error': 'Failed to find a platform with the name \'{}\''.format(platform_name)}, status=status.HTTP_400_BAD_REQUEST)
# Verify that the folder url is valid # # Verify that the folder url is valid
if platform.verify_folder_url(folder_url) == None: # if platform.verify_folder_url(folder_url) == None:
return Response({'error': 'Invalid URL'}, status=status.HTTP_400_BAD_REQUEST) # return Response({'error': 'Invalid URL'}, status=status.HTTP_400_BAD_REQUEST)
# Get the files from the folder # # Get the files from the folder
files = platform.import_from_folder(folder_url) # files = platform.import_from_folder(folder_url)
# Update the task with the new information # # Update the task with the new information
task.console_output += "Importing {} images...\n".format(len(files)) # task.console_output += "Importing {} images...\n".format(len(files))
task.images_count = len(files) # task.images_count = len(files)
task.pending_action = pending_actions.IMPORT # task.pending_action = pending_actions.IMPORT
task.save() # task.save()
# Associate the folder url with the project and task # # Associate the folder url with the project and task
combined_id = "{}_{}".format(project_pk, pk) # combined_id = "{}_{}".format(project_pk, pk)
get_current_plugin().get_global_data_store().set_string(combined_id, folder_url) # get_current_plugin().get_global_data_store().set_string(combined_id, folder_url)
# Start importing the files in the background # # Start importing the files in the background
serialized = [file.serialize() for file in files] # serialized = [file.serialize() for file in files]
run_function_async(import_files, task.id, serialized) # run_function_async(import_files, task.id, serialized)
return Response({}, status=status.HTTP_200_OK) # return Response({}, status=status.HTTP_200_OK)
class CheckUrlTaskView(TaskView): # class CheckUrlTaskView(TaskView):
def get(self, request, project_pk=None, pk=None): # def get(self, request, project_pk=None, pk=None):
# Assert that task exists # # Assert that task exists
self.get_and_check_task(request, pk) # self.get_and_check_task(request, pk)
# Check if there is an imported url associated with the project and task # # Check if there is an imported url associated with the project and task
combined_id = "{}_{}".format(project_pk, pk) # combined_id = "{}_{}".format(project_pk, pk)
folder_url = get_current_plugin().get_global_data_store().get_string(combined_id, default = None) # folder_url = get_current_plugin().get_global_data_store().get_string(combined_id, default = None)
if folder_url == None: # if folder_url == None:
return Response({}, status=status.HTTP_200_OK) # return Response({}, status=status.HTTP_200_OK)
else: # else:
return Response({'folder_url': folder_url}, status=status.HTTP_200_OK) # return Response({'folder_url': folder_url}, status=status.HTTP_200_OK)
class PlatformsVerifyTaskView(TaskView): # class PlatformsVerifyTaskView(TaskView):
def get(self, request, platform_name): # def get(self, request, platform_name):
# Read the form data # # Read the form data
folder_url = request.GET.get('folderUrl', None) # folder_url = request.GET.get('folderUrl', None)
# Fetch the platform by name # # Fetch the platform by name
platform = get_platform_by_name(platform_name) # platform = get_platform_by_name(platform_name)
# Make sure that the platform actually exists # # Make sure that the platform actually exists
if platform == None: # if platform == None:
return Response({'error': 'Failed to find a platform with the name \'{}\''.format(platform_name)}, status=status.HTTP_400_BAD_REQUEST) # return Response({'error': 'Failed to find a platform with the name \'{}\''.format(platform_name)}, status=status.HTTP_400_BAD_REQUEST)
# Verify that the folder url is valid # # Verify that the folder url is valid
folder = platform.verify_folder_url(folder_url) # folder = platform.verify_folder_url(folder_url)
if folder == None: # if folder == None:
return Response({'error': 'Invalid URL'}, status=status.HTTP_400_BAD_REQUEST) # return Response({'error': 'Invalid URL'}, status=status.HTTP_400_BAD_REQUEST)
# Return the folder # # Return the folder
return Response({'folder': folder.serialize()}, status=status.HTTP_200_OK) # return Response({'folder': folder.serialize()}, status=status.HTTP_200_OK)
class PlatformsTaskView(TaskView): # # class PlatformsTaskView(TaskView):
def get(self, request): # # def get(self, request):
# Fetch and return all platforms # # # Fetch and return all platforms
platforms = get_all_platforms() # # platforms = get_all_platforms()
return Response({'platforms': [platform.serialize(user = request.user) for platform in platforms]}, status=status.HTTP_200_OK) # # return Response({'platforms': [platform.serialize(user = request.user) for platform in platforms]}, status=status.HTTP_200_OK)
def import_files(task_id, files): # def import_files(task_id, files):
import requests # import requests
from app import models # from app import models
from app.plugins import logger # from app.plugins import logger
def download_file(task, file): # def download_file(task, file):
path = task.task_path(file['name']) # path = task.task_path(file['name'])
download_stream = requests.get(file['url'], stream=True, timeout=60) # download_stream = requests.get(file['url'], stream=True, timeout=60)
with open(path, 'wb') as fd: # with open(path, 'wb') as fd:
for chunk in download_stream.iter_content(4096): # for chunk in download_stream.iter_content(4096):
fd.write(chunk) # fd.write(chunk)
models.ImageUpload.objects.create(task=task, image=path) # models.ImageUpload.objects.create(task=task, image=path)
logger.info("Will import {} files".format(len(files))) # logger.info("Will import {} files".format(len(files)))
task = models.Task.objects.get(pk=task_id) # task = models.Task.objects.get(pk=task_id)
task.create_task_directories() # task.create_task_directories()
task.save() # task.save()
try: # try:
downloaded_total = 0 # downloaded_total = 0
for file in files: # for file in files:
download_file(task, file) # download_file(task, file)
task.check_if_canceled() # task.check_if_canceled()
models.Task.objects.filter(pk=task.id).update(upload_progress=(float(downloaded_total) / float(len(files)))) # models.Task.objects.filter(pk=task.id).update(upload_progress=(float(downloaded_total) / float(len(files))))
downloaded_total += 1 # downloaded_total += 1
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: # except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
raise NodeServerError(e) # raise NodeServerError(e)
task.refresh_from_db() # task.refresh_from_db()
task.pending_action = None # task.pending_action = None
task.processing_time = 0 # task.processing_time = 0
task.partial = False # task.partial = False
task.save() # task.save()

Wyświetl plik

@ -10,57 +10,16 @@ from app.plugins import logger
#from .platform_helper import get_all_extended_platforms #from .platform_helper import get_all_extended_platforms
""" class DynamicForm(forms.Form): # def LoadButtonsView(plugin):
"""This dynamic form will go through all the extended platforms, and retrieve their fields""" # def view(request):
def __init__(self, *args, **kwargs):
ds = kwargs.pop('data_store')
super(DynamicForm, self).__init__(*args, **kwargs)
extended_platforms = get_all_extended_platforms()
for platform in extended_platforms:
for form_field in platform.get_form_fields():
django_field = form_field.get_django_field(ds)
django_field.group = platform.name
self.fields[form_field.field_id] = django_field
"""
def HomeView(plugin):
@login_required
def view(request):
""" ds = plugin.get_user_data_store(request.user)
# if this is a POST request we need to process the form data # return render(
if request.method == "POST": # request,
form = DynamicForm(request.POST, data_store = ds) # plugin.template_path("load_buttons.js"),
if form.is_valid(): # {
extended_platforms = get_all_extended_platforms() # "api_url": "/api" + plugin.public_url("").rstrip("/"),
for platform in extended_platforms: # },
for form_field in platform.get_form_fields(): # content_type="text/javascript",
form_field.save_value(ds, form) # )
messages.success(request, "Configuration updated successfuly!")
else:
form = DynamicForm(data_store = ds) """
return render( # return view
request,
plugin.template_path("app.html"),
{"title": "DroneDB"},
)
return view
def LoadButtonsView(plugin):
def view(request):
return render(
request,
plugin.template_path("load_buttons.js"),
{
"api_url": "/api" + plugin.public_url("").rstrip("/"),
},
content_type="text/javascript",
)
return view

Wyświetl plik

@ -0,0 +1,13 @@
{
"name": "DroneDB",
"webodmMinVersion": "1.1.2",
"description": "Integrate WebODM with DroneDB: import images and export results",
"version": "0.0.1",
"author": "Luca Di Leo",
"email": "ldileo@digipa.it",
"repository": "https://github.com/OpenDroneMap/WebODM",
"tags": ["ddb", "DroneDB", "cloud"],
"homepage": "https://github.com/OpenDroneMap/WebODM",
"experimental": true,
"deprecated": false
}

Wyświetl plik

@ -1,25 +1,33 @@
from app.plugins import PluginBase, Menu, MountPoint, logger from app.plugins import PluginBase, Menu, MountPoint, logger
from .api_views import PlatformsTaskView, PlatformsVerifyTaskView, ImportFolderTaskView, CheckUrlTaskView #from .api_views import PlatformsTaskView, PlatformsVerifyTaskView, ImportFolderTaskView, CheckUrlTaskView
from .app_views import HomeView, LoadButtonsView #from .app_views import HomeView, LoadButtonsView
#from .platform_helper import get_all_extended_platforms #from .platform_helper import get_all_extended_platforms
from django.contrib import messages
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django import forms
class SettingsForm(forms.Form):
registry_url = forms.CharField(label='Registry Url', required=False, max_length=1024, widget=forms.TextInput(attrs={'placeholder': 'Registry Url'}))
username = forms.CharField(label='Username', required=False, max_length=1024, widget=forms.TextInput(attrs={'placeholder': 'Username'}))
password = forms.CharField(label='Password', required=False, max_length=1024, widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
class Plugin(PluginBase): class Plugin(PluginBase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def main_menu(self): def main_menu(self):
return [Menu("DroneDB", self.public_url(""), "fa-cloud-download-alt fa fa-fw")] return [Menu("DroneDB", self.public_url(""), "fas fa-cloud fa-fw")]
def include_js_files(self): #def include_js_files(self):
return ["load_buttons.js"] # return ["load_buttons.js"]
def include_css_files(self): #def include_css_files(self):
return ["build/ImportView.css", "build/TaskView.css"] # return ["build/ImportView.css", "build/TaskView.css"]
def build_jsx_components(self): #def build_jsx_components(self):
return ["ImportView.jsx", "TaskView.jsx"] # return ["ImportView.jsx", "TaskView.jsx"]
""" def api_mount_points(self): """ def api_mount_points(self):
#api_views = [api_view for platform in get_all_extended_platforms() for api_view in platform.get_api_views()] #api_views = [api_view for platform in get_all_extended_platforms() for api_view in platform.get_api_views()]
@ -33,8 +41,33 @@ class Plugin(PluginBase):
MountPoint("platforms", PlatformsTaskView.as_view()), MountPoint("platforms", PlatformsTaskView.as_view()),
] """ ] """
def HomeView(self):
@login_required
def home(request):
ds = self.get_user_data_store(request.user)
# if this is a POST request we need to process the form data
if request.method == 'POST':
form = SettingsForm(request.POST)
if form.is_valid():
ds.set_string('registry_url', form.cleaned_data['registry_url'])
ds.set_string('username', form.cleaned_data['username'])
ds.set_string('password', form.cleaned_data['password'])
messages.success(request, 'Settings updated.')
form = SettingsForm(initial={'username': ds.get_string('username', default=""),
'password': ds.get_string('password', default=""),
'registry_url': ds.get_string('registry_url', default="https://hub.dronedb.app")})
return render(request, self.template_path("app.html"), {
'title': 'DroneDB',
'form': form
})
return home
def app_mount_points(self): def app_mount_points(self):
return [ return [
MountPoint("$", HomeView(self)), MountPoint("$", self.HomeView()),
MountPoint("load_buttons.js$", LoadButtonsView(self)), #MountPoint("load_buttons.js$", LoadButtonsView(self)),
] ]

Wyświetl plik

@ -1,31 +1,16 @@
{% extends "app/plugins/templates/base.html" %} {% extends "app/plugins/templates/base.html" %}
{% load bootstrap_extras %} {% load bootstrap_extras %}
{% block content %} {% block content %}
<h3>Welcome to Cloud Import!</h3> <h3>Welcome to DroneDB!</h3>
<h5><strong>Instructions</strong></h5> <h5><strong>Instructions</strong></h5>
On this screen, you will be able to configure everything that is necessary for your different platforms.<BR/> On this screen, you can provide the registry url and credentials to access DroneDB
You might need to set up a server URL, an authentication token or something else. If so, this is the place! <br/>
<BR/> <br/>
<BR/> <form action="" method="post" class="oam-form oam-token-form">
<h3>Platforms</h3> <h4>Settings</h4>
<form action="" method="post" class="oam-form">
{% csrf_token %} {% csrf_token %}
{% regroup form by field.group as field_groups %} {% include "app/plugins/templates/form.html" %}
{% for field_group in field_groups %} <button type="submit" class="btn btn-primary"><i class="fa fa-save fa-fw"></i> Save Configuration</i></button>
<h4><strong>{{field_group.grouper}}</strong></h4>
{% for field in field_group.list %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label for="{{ field.id_for_label }}" class="control-label">{{ field.label }}</label>
{{ field|with_class:'form-control' }}
{% if field.errors %}
<span class='text-danger'>{{ field.errors|join:'<br />' }}</span>
{% elif field.help_text %}
<span class="help-block ">{{ field.help_text }}</span>
{% endif %}
</div>
{% endfor %}
{% endfor %}
<button type="submit" class="btn btn-primary"><i class="fa fa-save fa-fw"></i> Save Configuration</button>
</form> </form>
{% endblock %} {% endblock %}