From 2d7435314672c2f4653f600edadae1d4c0b02406 Mon Sep 17 00:00:00 2001
From: Stefano Alberto Russo <stefano.russo@gmail.com>
Date: Mon, 15 Nov 2021 18:12:38 +0100
Subject: [PATCH] Moved from Text to Page models, in order to allow building a
 mini-website inside the platform to provide help and informations.

---
 .../webapp/code/rosetta/core_app/admin.py     |  4 +-
 .../management/commands/core_app_populate.py  | 83 ++++++++++++++-----
 .../migrations/0019_auto_20211115_1547.py     | 23 +++++
 .../webapp/code/rosetta/core_app/models.py    | 12 +--
 .../rosetta/core_app/templates/account.html   |  2 +-
 .../core_app/templates/add_profile_conf.html  |  2 +-
 .../core_app/templates/add_software.html      |  2 +-
 .../rosetta/core_app/templates/computing.html |  2 +-
 .../rosetta/core_app/templates/error.html     |  4 +-
 .../rosetta/core_app/templates/header.html    |  6 +-
 .../code/rosetta/core_app/templates/main.html | 10 +--
 .../rosetta/core_app/templates/new_task.html  |  2 +-
 .../code/rosetta/core_app/templates/page.html | 28 +++++++
 .../rosetta/core_app/templates/register.html  |  2 +-
 .../rosetta/core_app/templates/software.html  |  2 +-
 .../rosetta/core_app/templates/storage.html   |  2 +-
 .../rosetta/core_app/templates/success.html   |  4 +-
 .../rosetta/core_app/templates/task_log.html  |  2 +-
 .../rosetta/core_app/templates/tasks.html     |  2 +-
 .../webapp/code/rosetta/core_app/views.py     | 35 ++++++--
 services/webapp/code/rosetta/urls.py          |  2 +
 21 files changed, 173 insertions(+), 58 deletions(-)
 create mode 100644 services/webapp/code/rosetta/core_app/migrations/0019_auto_20211115_1547.py
 create mode 100644 services/webapp/code/rosetta/core_app/templates/page.html

diff --git a/services/webapp/code/rosetta/core_app/admin.py b/services/webapp/code/rosetta/core_app/admin.py
index c22b65d..b69c3b2 100644
--- a/services/webapp/code/rosetta/core_app/admin.py
+++ b/services/webapp/code/rosetta/core_app/admin.py
@@ -1,6 +1,6 @@
 from django.contrib import admin
 
-from .models import Profile, LoginToken, Task, Container, Computing, Storage, KeyPair, Text
+from .models import Profile, LoginToken, Task, Container, Computing, Storage, KeyPair, Page
 
 admin.site.register(Profile)
 admin.site.register(LoginToken)
@@ -9,4 +9,4 @@ admin.site.register(Container)
 admin.site.register(Computing)
 admin.site.register(Storage)
 admin.site.register(KeyPair)
-admin.site.register(Text)
+admin.site.register(Page)
diff --git a/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py b/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py
index 9a11444..0b3d3ec 100644
--- a/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py
+++ b/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py
@@ -1,6 +1,6 @@
 from django.core.management.base import BaseCommand
 from django.contrib.auth.models import User
-from ...models import Profile, Container, Computing, Storage, KeyPair, Text
+from ...models import Profile, Container, Computing, Storage, KeyPair, Page
 
 class Command(BaseCommand):
     help = 'Adds the admin superuser with \'a\' password.'
@@ -62,29 +62,70 @@ class Command(BaseCommand):
                   
 
         #=====================
-        #  Default home text
+        #  Default home page
         #=====================
-        default_home_text_content = '''
-<div class="span8 offset2" style="margin: 30px auto; max-width:800px">
-  Welcome to Rosetta!
-  <br/><br/>
-  This is the default home text loaded after populating the platform with the default/demo data.
-  To change it, head to the <a href="/admin">admin</a> page and edit the <code>Text</code> model.
-  <br/><br/>
-  The default installation provides a test user register with email <code>testuser@rosetta.platform</code>
-  and password <code>testpass</code>, which you can use to login on the menu on the rightand give Rosetta
-  a try immediately. If you run with the default docker-compose file (i.e. you just run 
-  <code>rosetta/setup</code>), then you will also have a few demo computing resources you can play with
-  out-of-the-box, including a small Slurm cluster. Otherwise, you will need to setup your own computing
-  resources either platform-wide or as user.
-</div>
+        default_home_page_content = '''
+<header id="top" class="header">
+    <div style="display:table-row">
+        <div class="text-vertical-center">
+            <h1>&nbsp;&nbsp;Rosetta <img src="/static/img/emoji_u1f6f0.png" style="height:84px; width:64px; padding-bottom:20px"></h1>
+            <h2 style="margin-top:10px; margin-left:25px; margin-right:25px; font-weight:100; line-height: 30px;"><i>A container-centric Science Platform<br></i></h2>
+        </div>
+    </div>   
+    <div class="container">
+        <div class="dashboard">
+            <div class="span8 offset2" style="margin: 30px auto; max-width:800px">
+                Welcome to Rosetta!
+                <br/><br/>
+                This is the default main page content loaded after populating the platform with the default/demo data.
+                To change it, head to the <a href="/admin">admin</a> section and edit the <code>Page</code> model with id "main".
+                <br/><br/>
+                A test user with admin rights registered with email <code>testuser@rosetta.platform</code> and password 
+                <code>testpass</code> has been created as well, which you can use to login on the menu on the right and give Rosetta
+                immediately a try. If you run with the default docker-compose file (i.e. you just run <code>rosetta/setup</code>),
+                then you will also have a few demo computing and storage resources (beside the internal engine) already available
+                and that you can play with, including a small Slurm cluster. Otherwise, you will need to setup your own ones
+                from the <a href="/admin">admin</a> section.
+                <br />
+                <br />
+                You can also create custom pages and access them under <code>/pages/page_id</code> should you need to provide
+                your users informations about the platform and its storage and computing resources. For example, see this
+                demo extra <a href="/pages/help">help page</a>. 
+            </div>
+        </div>
+    </div>          
+</header>
 '''
-        home_text = Text.objects.filter(id='home')
-        if home_text:
-            print('Not creating default home text as already present')
+        home_page = Page.objects.filter(id='main')
+        if home_page:
+            print('Not creating default main page content as already present')
         else:
-            print('Creating default home text...')
-            Text.objects.create(id='home', content=default_home_text_content)
+            print('Creating default main page content...')
+            Page.objects.create(id='main', content=default_home_page_content)
+
+        extra_help_page_content = '''
+<h1>Help!</h1>
+<hr>
+<p>
+This is a demo extra page (a help page, in this case). Here you could for example provide the instructions on how to set up SSH-based 
+computing resources using user keys, or who to contact to join a specific group to access its software and computing resources.
+</p>
+
+<p>
+In general, the part of the URL following the <code>/pages/</code> path is parsed as the page id, 
+so that if a page with that id exists in the database, its content will show up here.
+You can use this system for creating a mini-website inside the platform 
+to provide help, news and informations on your deployment. Or you can just ignore the whole thing and leave a plain logo in the main page. 
+</p>
+'''
+
+        extra_help_page = Page.objects.filter(id='help')
+        if home_page:
+            print('Not creating extra help page content as already present')
+        else:
+            print('Creating extra help page content...')
+            Page.objects.create(id='help', content=extra_help_page_content)
+
 
 
         #===================== 
diff --git a/services/webapp/code/rosetta/core_app/migrations/0019_auto_20211115_1547.py b/services/webapp/code/rosetta/core_app/migrations/0019_auto_20211115_1547.py
new file mode 100644
index 0000000..49feeee
--- /dev/null
+++ b/services/webapp/code/rosetta/core_app/migrations/0019_auto_20211115_1547.py
@@ -0,0 +1,23 @@
+# Generated by Django 2.2.1 on 2021-11-15 15:47
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core_app', '0018_delete_computinguserconf'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Page',
+            fields=[
+                ('id', models.CharField(max_length=16, primary_key=True, serialize=False, verbose_name='Page id')),
+                ('content', models.TextField(blank=True, null=True, verbose_name='Page content')),
+            ],
+        ),
+        migrations.DeleteModel(
+            name='Text',
+        ),
+    ]
diff --git a/services/webapp/code/rosetta/core_app/models.py b/services/webapp/code/rosetta/core_app/models.py
index 0640726..01685d4 100644
--- a/services/webapp/code/rosetta/core_app/models.py
+++ b/services/webapp/code/rosetta/core_app/models.py
@@ -391,17 +391,17 @@ class KeyPair(models.Model):
 
 
 #=========================
-#  Texts 
+#  Page 
 #=========================
 
-class Text(models.Model):
-    '''A model to store some text contents for the platform, like the home page text'''
+class Page(models.Model):
+    '''A model to store pages for the platform, as custom a custom home page'''
 
-    id = models.CharField('Text id', max_length=16, primary_key=True)
-    content = models.TextField('Text content', blank=True, null=True)
+    id = models.CharField('Page id', max_length=16, primary_key=True)
+    content = models.TextField('Page content', blank=True, null=True)
 
     def __str__(self):
-        return str('Text with id "{}"'.format(self.id))
+        return str('Page "{}"'.format(self.id))
 
 
 
diff --git a/services/webapp/code/rosetta/core_app/templates/account.html b/services/webapp/code/rosetta/core_app/templates/account.html
index 42c52ea..2ca2d5a 100644
--- a/services/webapp/code/rosetta/core_app/templates/account.html
+++ b/services/webapp/code/rosetta/core_app/templates/account.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html b/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html
index 1b1369a..8f1135a 100644
--- a/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html
+++ b/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/add_software.html b/services/webapp/code/rosetta/core_app/templates/add_software.html
index 300d486..668480d 100644
--- a/services/webapp/code/rosetta/core_app/templates/add_software.html
+++ b/services/webapp/code/rosetta/core_app/templates/add_software.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/computing.html b/services/webapp/code/rosetta/core_app/templates/computing.html
index 0edbc23..b9991ea 100644
--- a/services/webapp/code/rosetta/core_app/templates/computing.html
+++ b/services/webapp/code/rosetta/core_app/templates/computing.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/error.html b/services/webapp/code/rosetta/core_app/templates/error.html
index 106404a..b31a70c 100644
--- a/services/webapp/code/rosetta/core_app/templates/error.html
+++ b/services/webapp/code/rosetta/core_app/templates/error.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
@@ -13,11 +13,9 @@
       <br/>
       <br/><br/>
       <div class='centerbox-error-outer'> 
-        <a href="/main"> 
           <span class='centerbox-error-inner'>     
           {{data.error}}
           </span>
-        </a>
       </div>
 
       <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/header.html b/services/webapp/code/rosetta/core_app/templates/header.html
index 46dc332..8e26792 100644
--- a/services/webapp/code/rosetta/core_app/templates/header.html
+++ b/services/webapp/code/rosetta/core_app/templates/header.html
@@ -12,8 +12,12 @@
     {% if refresh %}
     <meta http-equiv="refresh" content="{{refresh}}" >
     {% endif %}
-
+    
+    {% if title %}
+    <title>Rosetta - {{ title }}</title>
+    {% else %}
     <title>Rosetta</title>
+    {% endif %}
 
     <!-- Bootstrap Core CSS -->
     <link href="/static/css/bootstrap-3.3.5.min.css" rel="stylesheet">
diff --git a/services/webapp/code/rosetta/core_app/templates/main.html b/services/webapp/code/rosetta/core_app/templates/main.html
index e91e4bf..eb1a989 100644
--- a/services/webapp/code/rosetta/core_app/templates/main.html
+++ b/services/webapp/code/rosetta/core_app/templates/main.html
@@ -2,7 +2,9 @@
 {% include "header.html" %}
 {% include "navigation.html"%}
 
-    <!-- Header -->
+    {% if data.page.content %}
+    {{ data.page.content | safe }}
+    {% else %}
     <header id="top" class="header">
         <div style="display:table-row">
             <div class="text-vertical-center">
@@ -13,19 +15,17 @@
         
         <div class="container">
             <div class="dashboard">
-                {% if data.home_text %}
-                {{ data.home_text | safe }}
-                {% else %}
                 <div class="span8 offset2" style="margin: 30px auto; max-width:800px">
                 <br/>
                 Welcome to Rosetta!
                 <br/><br/>
                 This is an empty installation. To load some demo data, run <code>rosetta/populate</code>.
                 </div>
-                {% endif %}
+                
             </div>
         </div>          
     </header>
+    {% endif %}
 
 {% include "footer.html" %}
 
diff --git a/services/webapp/code/rosetta/core_app/templates/new_task.html b/services/webapp/code/rosetta/core_app/templates/new_task.html
index fb6cd69..23db343 100644
--- a/services/webapp/code/rosetta/core_app/templates/new_task.html
+++ b/services/webapp/code/rosetta/core_app/templates/new_task.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/page.html b/services/webapp/code/rosetta/core_app/templates/page.html
new file mode 100644
index 0000000..9055a94
--- /dev/null
+++ b/services/webapp/code/rosetta/core_app/templates/page.html
@@ -0,0 +1,28 @@
+{% load static %} 
+{% include "header.html" with title=data.page.title %}
+{% include "navigation.html"%}
+
+<br/>
+<br/>
+
+<div class="container">
+  <div class="dashboard">
+    <div class="span8 offset2">
+      <!-- <h1>Example title</h1>
+      <hr> -->
+      {{ data.page.content | safe }}
+      
+    </div>
+  </div>
+</div>
+
+
+
+
+
+
+
+{% include "footer.html" %}
+
+
+
diff --git a/services/webapp/code/rosetta/core_app/templates/register.html b/services/webapp/code/rosetta/core_app/templates/register.html
index 8a7ca29..f1439a9 100644
--- a/services/webapp/code/rosetta/core_app/templates/register.html
+++ b/services/webapp/code/rosetta/core_app/templates/register.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/software.html b/services/webapp/code/rosetta/core_app/templates/software.html
index 86fef6b..8be03d0 100644
--- a/services/webapp/code/rosetta/core_app/templates/software.html
+++ b/services/webapp/code/rosetta/core_app/templates/software.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/storage.html b/services/webapp/code/rosetta/core_app/templates/storage.html
index 9b29c54..43b0c78 100644
--- a/services/webapp/code/rosetta/core_app/templates/storage.html
+++ b/services/webapp/code/rosetta/core_app/templates/storage.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/success.html b/services/webapp/code/rosetta/core_app/templates/success.html
index bb1991c..7cc06a0 100644
--- a/services/webapp/code/rosetta/core_app/templates/success.html
+++ b/services/webapp/code/rosetta/core_app/templates/success.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
@@ -12,11 +12,9 @@
       <hr>
       <br/>
       <div class='centerbox-success-outer'> 
-        <a href="/main"> 
           <span class='centerbox-success-inner'>     
           {{data.success}}
           </span>
-        </a>
       </div>
       
       
diff --git a/services/webapp/code/rosetta/core_app/templates/task_log.html b/services/webapp/code/rosetta/core_app/templates/task_log.html
index 2a842cb..994c254 100644
--- a/services/webapp/code/rosetta/core_app/templates/task_log.html
+++ b/services/webapp/code/rosetta/core_app/templates/task_log.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" with refresh=data.refresh %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/templates/tasks.html b/services/webapp/code/rosetta/core_app/templates/tasks.html
index fa9b554..67cec11 100644
--- a/services/webapp/code/rosetta/core_app/templates/tasks.html
+++ b/services/webapp/code/rosetta/core_app/templates/tasks.html
@@ -1,6 +1,6 @@
 {% load static %} 
 {% include "header.html" %}
-{% include "navigation.html" with main_path='/main/' %}
+{% include "navigation.html" %}
 
 <br/>
 <br/>
diff --git a/services/webapp/code/rosetta/core_app/views.py b/services/webapp/code/rosetta/core_app/views.py
index 352648d..1904a01 100644
--- a/services/webapp/code/rosetta/core_app/views.py
+++ b/services/webapp/code/rosetta/core_app/views.py
@@ -5,11 +5,11 @@ import subprocess
 from django.conf import settings
 from django.shortcuts import render
 from django.contrib.auth import authenticate, login, logout
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
 from django.contrib.auth.models import User
 from django.shortcuts import redirect
 from django.db.models import Q
-from .models import Profile, LoginToken, Task, TaskStatuses, Container, Computing, KeyPair, Text
+from .models import Profile, LoginToken, Task, TaskStatuses, Container, Computing, KeyPair, Page
 from .utils import send_email, format_exception, timezonize, os_shell, booleanize, debug_param, get_task_tunnel_host, get_task_proxy_host, random_username, setup_tunnel_and_proxy, finalize_user_creation
 from .decorators import public_view, private_view
 from .exceptions import ErrorMessage
@@ -23,6 +23,10 @@ logger = logging.getLogger(__name__)
 _task_cache = {}
 
 
+#====================
+#  Page views
+#====================
+
 @public_view
 def login_view(request):
 
@@ -186,19 +190,36 @@ def entrypoint(request):
 @public_view
 def main_view(request):
 
-    # Set data & render
+    # Init data
     data = {}
     
-    # Get homepage text if any
+    # Get custom home page if any
     try:
-        text = Text.objects.get(id='home')
-        data['home_text'] = text.content
-    except Text.DoesNotExist:
+        page = Page.objects.get(id='main')
+        data['page'] = page
+    except Page.DoesNotExist:
         pass
 
     return render(request, 'main.html', {'data': data})
 
 
+@public_view
+def page_view(request, page_id):
+
+    # Init data
+    data = {}
+    
+    # Get the page
+    try:
+        page = Page.objects.get(id=page_id)
+        data['page'] = page
+    except Page.DoesNotExist:
+        return HttpResponseNotFound('Page not found')
+
+    return render(request, 'page.html', {'data': data})
+
+
+
 #====================
 # Account view
 #====================
diff --git a/services/webapp/code/rosetta/urls.py b/services/webapp/code/rosetta/urls.py
index 1015d6f..88b14fd 100644
--- a/services/webapp/code/rosetta/urls.py
+++ b/services/webapp/code/rosetta/urls.py
@@ -45,6 +45,8 @@ urlpatterns = [
     path('login/', core_app_views.login_view),
     path('logout/', core_app_views.logout_view),
     url(r'^register/$', core_app_views.register_view),
+    url(r'^pages/(?P<page_id>\w{0,36})/$', core_app_views.page_view),
+
     
     # Software    
     url(r'^software/$', core_app_views.software),
-- 
GitLab