diff mbox series

[layerindex-web,6/7] layerindex: add Update Layer UI feature

Message ID bf57322ab19eba3bd93d789503e3f7b759ce9793.1703911977.git.tim.orling@konsulko.com
State New
Headers show
Series [layerindex-web,1/7] requirements.txt: bump all to latest | expand

Commit Message

Tim Orling Dec. 30, 2023, 4:57 a.m. UTC
* Add an "Update Layer" button to the layer detail view.
  - This allows a user that is a member of is_staff to trigger
    an update of the current layer (for the current branch)
* Add an "Update Layer" button to the reviewdetail view
  - This allows a user that is a member of is_staff and has
    publish_layer permissions to trigger an update attempt
    of the layer under review (even in the un-published state)
* The update is run as a task with Celery

NOTE:
  You must have the RABBITMQ_ and DATABASE_ credentials set
  correctly in the docker/settings.py file or set via
  environment variables or you will get authentication errors
  talking to layersdb or layersrabbit containers.

[YOCTO #12484]

layerindex/views.py: add update_layer_view
layerindex/urls.py: add update_layer_view
layerindex/urls_branch.py: add update_layer_view
templates/layerindex/reviewdetail.html: add Update Layer button
templates/layerindex/detail.html: add Update Layer button
templates/layerindex: add updatelayer.html

TODO:
  While the update is happening, the AJAX rendering of the
  update.log is showing the b'' characters and not adding
  any new lines. If you go back to the same task view
  afterwards, the log is rendered as expected.

TODO:
  After the update is completed, it would be nice to have a
  button to return you to the page from where you called the
  "Update Layer".

Signed-off-by: Tim Orling <tim.orling@konsulko.com>
---
 layerindex/urls.py                     |   2 +-
 layerindex/urls_branch.py              |   3 +-
 layerindex/views.py                    |  35 ++++++++
 templates/layerindex/detail.html       |   3 +
 templates/layerindex/reviewdetail.html |   3 +
 templates/layerindex/updatelayer.html  | 119 +++++++++++++++++++++++++
 6 files changed, 163 insertions(+), 2 deletions(-)
 create mode 100644 templates/layerindex/updatelayer.html
diff mbox series

Patch

diff --git a/layerindex/urls.py b/layerindex/urls.py
index cee3d2a..1fcd11d 100644
--- a/layerindex/urls.py
+++ b/layerindex/urls.py
@@ -16,7 +16,7 @@  from layerindex.views import LayerListView, LayerReviewListView, LayerReviewDeta
     ClassicRecipeSearchView, ClassicRecipeDetailView, ClassicRecipeStatsView, LayerUpdateDetailView, UpdateListView, \
     UpdateDetailView, StatsView, publish_view, LayerCheckListView, BBClassCheckListView, TaskStatusView, \
     ComparisonRecipeSelectView, ComparisonRecipeSelectDetailView, task_log_view, task_stop_view, email_test_view, \
-    BranchCompareView, RecipeDependenciesView
+    BranchCompareView, RecipeDependenciesView, update_layer_view
 from layerindex.models import LayerItem, Recipe, RecipeChangeset
 from rest_framework import routers
 from . import restviews
diff --git a/layerindex/urls_branch.py b/layerindex/urls_branch.py
index 6736f32..40cd915 100644
--- a/layerindex/urls_branch.py
+++ b/layerindex/urls_branch.py
@@ -8,7 +8,7 @@ 
 
 from django.views.defaults import page_not_found
 from django.urls import include, re_path, reverse_lazy
-from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, DistroSearchView, ClassSearchView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, RedirectParamsView, DuplicatesView, LayerUpdateDetailView, layer_export_recipes_csv_view, comparison_update_view
+from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, DistroSearchView, ClassSearchView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, RedirectParamsView, DuplicatesView, LayerUpdateDetailView, layer_export_recipes_csv_view, comparison_update_view, update_layer_view
 
 urlpatterns = [
     re_path(r'^$',
@@ -41,6 +41,7 @@  urlpatterns = [
             template_name='layerindex/classes.html'),
             name='class_search'),
     re_path(r'^edit/(?P<slug>[-\w]+)/$', edit_layer_view, {'template_name': 'layerindex/editlayer.html'}, name="edit_layer"),
+    re_path(r'^update/(?P<slug>[-\w]+)/$', update_layer_view, {'template_name': 'layerindex/updatelayer.html'}, name="update_layer"),
     re_path(r'^duplicates/$',
         DuplicatesView.as_view(
             template_name='layerindex/duplicates.html'),
diff --git a/layerindex/views.py b/layerindex/views.py
index 1a29dde..25c045e 100644
--- a/layerindex/views.py
+++ b/layerindex/views.py
@@ -121,6 +121,41 @@  def delete_layer_view(request, template_name, slug):
             'cancel_url': layeritem.get_absolute_url()
         })
 
+def update_layer_view(request, template_name, branch='master', slug=None):
+    if not (request.user.is_authenticated and request.user.is_staff):
+        raise PermissionDenied
+    return_url = None
+    branchobj = Branch.objects.filter(name=branch)[:1].get()
+    if slug:
+        # Existing Layer Update
+        layeritem = get_object_or_404(LayerItem, name=slug)
+        layerbranch = get_object_or_404(LayerBranch, layer=layeritem, branch=branchobj)
+        returnto = request.GET.get('returnto', 'layer_item')
+        if returnto:
+            if returnto == 'layer_review':
+                return_url = reverse_lazy(returnto, args=(layeritem.name,))
+            else:
+                return_url = reverse_lazy(returnto, args=(branch, layeritem.name))
+    else:
+        # Pre-Publish Layer Update attempt
+        layeritem = LayerItem()
+        layerbranch = LayerBranch(layer=layeritem, branch=branchobj)
+
+    from celery import uuid
+
+    cmd = 'layerindex/update.py --layer %s --branch %s;' % (layeritem.name, branch)
+
+    task_id = uuid()
+    # Create this here first, because inside the task we don't have all of the required info
+    update = Update(task_id=task_id)
+    update.started = datetime.now()
+    update.triggered_by = request.user
+    update.save()
+
+    res = tasks.run_update_command.apply_async((branch, cmd), task_id=task_id)
+
+    return HttpResponseRedirect(reverse_lazy('task_status', kwargs={'task_id': task_id}))
+
 def edit_layer_view(request, template_name, branch='master', slug=None):
     return_url = None
     branchobj = Branch.objects.filter(name=branch)[:1].get()
diff --git a/templates/layerindex/detail.html b/templates/layerindex/detail.html
index 12ce156..0fa8caf 100644
--- a/templates/layerindex/detail.html
+++ b/templates/layerindex/detail.html
@@ -38,6 +38,9 @@ 
                         {% endif %}
                         {% if user.is_authenticated %}
                             <span class="pull-right">
+                                {% if user.is_staff %}
+                                    <a href="{% url 'update_layer' url_branch layeritem.name %}" class="btn btn-info">Update layer</a>
+                                {% endif %}
                                 {% if perms.layerindex.publish_layer or useredit %}
                                     <a href="{% url 'edit_layer' url_branch layeritem.name %}" class="btn btn-default">Edit layer</a>
                                     {% if layeritem.layernote_set.count == 0 %}
diff --git a/templates/layerindex/reviewdetail.html b/templates/layerindex/reviewdetail.html
index 8baab7c..39501be 100644
--- a/templates/layerindex/reviewdetail.html
+++ b/templates/layerindex/reviewdetail.html
@@ -47,6 +47,9 @@ 
                                     <a href="{% url 'delete_layer' layeritem.name %}" class="btn btn-warning">Delete layer</a>
                                     <a href="{% url 'publish' layeritem.name %}" class="btn btn-primary">Publish layer</a>
                                 {% endif %}
+                                {% if user.is_staff %}
+                                    <a href="{% url 'update_layer' 'master' layeritem.name %}" class="btn btn-info">Update layer</a>
+                                {% endif %}
                             </span>
                         {% endif %}
                     </h1>
diff --git a/templates/layerindex/updatelayer.html b/templates/layerindex/updatelayer.html
new file mode 100644
index 0000000..799fb51
--- /dev/null
+++ b/templates/layerindex/updatelayer.html
@@ -0,0 +1,119 @@ 
+{% extends "base.html" %}
+{% load i18n %}
+{% load extrafilters %}
+
+{% comment %}
+
+  layerindex-web - update page
+
+  Copyright (C) 2016, 2018 Intel Corporation
+  Licensed under the MIT license, see COPYING.MIT for details
+
+{% endcomment %}
+
+<!--
+{% block title_append %} - {{ update.started }} {% endblock %}
+-->
+
+{% block content %}
+{% autoescape on %}
+
+        <ul class="breadcrumb">
+            <li><a href="{% url 'update_list' %}">Updates</a></li>
+            <li class="active">{{ update.started }}</li>
+        </ul>
+
+
+<h2>{{ update.started }} {% if update.reload %}(reload){% endif %}
+<span id="status-label" class="label {% if update.finished %}{% if update.retcode %}label-danger{% else %}label-success{% endif %}{% endif %} pull-right">{% if update.finished %}{% if update.retcode < 0 %}TERMINATED ({{ update.retcode }}){% elif update.retcode %}FAILED{% endif %}{% endif %}</span>
+</h2>
+
+{% if update.log %}
+    <pre>{{ update.log }}</pre>
+{% endif %}
+
+{% for layerupdate in layerupdates %}
+    <table class="table table-bordered">
+        <thead>
+            {% with layerbranch_exists=layerupdate.layerbranch_exists %}
+            <tr><td{% if layerupdate.errors > 0 or layerupdate.retcode != 0 %} class="error"{% elif layerupdate.warnings %} class="warning"{% endif %}>
+            {% if layerbranch_exists %}<a href="{% url 'layer_item' layerupdate.branch.name layerupdate.layer.name %}">{% endif %}<strong>{{ layerupdate.layer.name }} {{ layerupdate.branch.name }}</strong>{% if layerbranch_exists %}</a>{% endif %}
+            {% if layerupdate.vcs_before_rev != layerupdate.vcs_after_rev %}
+            <span class="pull-right">
+                {% if layerbranch_exists %}
+                {% with before_url=layerupdate.vcs_before_commit_url after_url=layerupdate.vcs_after_commit_url %}
+                {% if before_url %}<a href="{{ before_url }}">{% endif %}{{ layerupdate.vcs_before_rev|truncatesimple:10 }}{% if before_url %}</a>{% endif %} &rarr; {% if after_url %}<a href="{{ after_url }}">{% endif %}{{ layerupdate.vcs_after_rev|truncatesimple:10 }}{% if after_url %}</a>{% endif %}
+                {% endwith %}
+                {% else %}
+                {{ layerupdate.vcs_before_rev|truncatesimple:10 }} → {{ layerupdate.vcs_after_rev|truncatesimple:10 }}
+                {% endif %}
+            </span>
+            {% endif %}
+            </td></tr>
+            {% endwith %}
+        </thead>
+        <tbody>
+            {% if layerupdate.log %}
+            <tr><td class="td-pre">
+            <pre class="pre-scrollable pre-plain">{{ layerupdate.log }}</pre>
+            </td></tr>
+            {% endif %}
+        </tbody>
+    </table>
+{% endfor %}
+
+{% if not update.log and not layerupdates %}
+    <p>No messages or layer updates</p>
+{% endif %}
+
+{% if update.comparisonrecipeupdate_set.exists %}
+<h3>Updated comparison recipes</h3>
+<ul>
+{% for recipeupdate in update.comparisonrecipeupdate_set.all %}
+    <li><a href="{% url 'comparison_recipe' recipeupdate.recipe.id %}">{{ recipeupdate.recipe.pn }}</a> {% if recipeupdate.meta_updated and recipeupdate.link_updated %}(meta, link){% elif recipeupdate.link_updated %}(link){% elif recipeupdate.meta_updated %}(meta){% endif %}</li>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% endautoescape %}
+
+{% endblock %}
+{% if updates.count > 0 %}
+<div class="tab-pane" id="updates">
+    <nav class="navbar navbar-default">
+        <div class="container-fluid">
+            <div class="navbar-header">
+                <a class="navbar-brand">{{ layeritem.name }} updates</a>
+            </div>
+        </div>
+    </nav>
+
+    <table class="table table-bordered">
+        <thead>
+            <tr>
+                <th>Date/time</th>
+                <th>Errors</th>
+                <th>Warnings</th>
+            </tr>
+        </thead>
+        <tbody>
+            {% for update in updates %}
+                <tr>
+                    <td>
+                        {% if update.log %}
+                            <a href="{% url 'layerupdate' update.id %}">{{ update.started }}{% if update.update.reload %} (reload){% endif%}</a>
+                        {% else %}
+                            <span class="text-muted">{{ update.started }}{% if update.update.reload %} (reload){% endif%}</span>
+                        {% endif %}
+                    </td>
+                    <td>{% if update.errors %}<span class="badge badge-important">{{ update.errors }}</span>{% endif %}</td>
+                    <td>{% if update.warnings %}<span class="badge badge-warning">{{ update.warnings }}</span>{% endif %}</td>
+                </tr>
+            {% endfor %}
+        </tbody>
+    </table>
+</div>
+{% endif %}
+
+{% block scripts %}
+{% endblock %}