Add ability to supply sql via a file
authorKarl O. Pinc <kop@karlpinc.com>
Mon, 16 Sep 2024 04:17:55 +0000 (23:17 -0500)
committerKarl O. Pinc <kop@karlpinc.com>
Mon, 16 Sep 2024 04:17:55 +0000 (23:17 -0500)
src/pgwui_sql/templates/sql.mak
src/pgwui_sql/templates/sql_edit.mak
src/pgwui_sql/views/base.py
src/pgwui_sql/views/search_path_base.py
src/pgwui_sql/views/sql.py
tests/templates/test_templates.py

index b5bc5a46990c02751d2f1f25bdbd97df1771e2c6..7fccb25d9b740094aad84c953678c58b1096849e 100644 (file)
@@ -46,8 +46,9 @@
 </%block>
 
 <%block name="action_success">
-  <p><em class="success">No errors</em>,
-  from a file<em class="success">!</em>
+  <p><em class="success">No errors</em>${
+      f', from file ({filename})' if upload_sql else ''
+      }<em class="success">!</em>
   </p>
   % if sql:
        <ol>
index 7df2b008e783e6db77c867f14f5c0836d1c76b31..9537cf8a61519f4ca3c52c0c41ac95a7885b59a6 100644 (file)
           window.alert('Problem showing the search_path: ' + error);
           })
   };
+  function toggle_sql_used(elem) {
+    sql_text = document.getElementById('sql_id');
+    if (elem.checked) {
+      sql_text.style.backgroundColor = 'lightgrey';
+    } else {
+      sql_text.style.backgroundColor = '';
+    }
+  };
 </script>
 
 <%def name="sql_row(tab_index)">
       <tr>
         <%self.lib:td_label for_id="search_path_id">
-
           search_path<a
              href="https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH"
              target="_blank"
       </tr>
 </%def>
 
+<%def name="file_input_row(tab_index)">
+      <tr>
+        <%self.lib:td_label for_id="upload_sql_id">
+          Execute SQL from a file
+        </%self.lib:td_label>
+        <%self.lib:td_input tab_index="${tab_index}" clas="search_path_data">
+          <input name="upload_sql"
+                 tabindex="${tab_index.val}"
+                 id="upload_sql_id"
+                 type="checkbox"
+                 onchange="toggle_sql_used(this);"
+                 ${upload_sql}
+                 />
+        </%self.lib:td_input>
+        <td>
+          <input name="sql_file"
+                 tabindex="${tab_index.val}"
+                 type="file"
+                 />
+          <% tab_index.inc() %>
+        </td>
+      </tr>
+</%def>
+
 <%def name="table_rows(tab_index)">
   <%parent:table_rows tab_index="${tab_index}" args="tab_index">
     ## A blank table row for spacing
     <tr class="verticalgap"><td></td><td></td></tr>
     ${self.sql_row(tab_index)}
+    ${self.file_input_row(tab_index)}
   </%parent:table_rows>
 </%def>
 
index aa467420e889b28432d728e2561ae9cf5e15cfdd..ccf2f1f77fff2879f5d3406da54ba911da8d96fe 100644 (file)
 # <http://www.gnu.org/licenses/>.
 #
 
-from wtforms.fields import TextAreaField
 import attrs
 import pgwui_core.core
 import pgwui_core.forms
+import wtforms.fields
 
 
 @attrs.define(slots=False)
 class SQLInitialPost(pgwui_core.forms.UserInitialPost):
     sql = attrs.field(default='')
+    upload_sql = attrs.field(default=False)
+    sql_file = attrs.field(default=None)
 
 
 class SQLWTForm(pgwui_core.forms.AuthWTForm):
@@ -33,7 +35,11 @@ class SQLWTForm(pgwui_core.forms.AuthWTForm):
     # We don't actually use the labels, wanting the template to
     # look (and render) like html, but I'll define them anyway
     # just to keep my hand in.
-    sql = TextAreaField('SQL:', id='sql_id')
+    sql = wtforms.fields.TextAreaField('SQL:', id='sql_id')
+    upload_sql = wtforms.fields.BooleanField(
+        'Execute SQL from a file:', id='upload_sql_id')
+    sql_file = wtforms.fields.FileField(
+        'File of SQL statements')
 
 
 @attrs.define(slots=False)
@@ -45,6 +51,12 @@ class SQLForm(pgwui_core.forms.UploadFormBaseMixin,
     Attributes:
       uh      The UploadHandler instance using the form
     '''
+    sql = attrs.field(default='')
+    upload_sql = attrs.field(default=False)
+    sql_file = attrs.field(default=None)
+    sql_file_read = attrs.field(default=False)
+    filename = attrs.field(default=None)
+
     def read(self):
         '''
         Read form data from the client
@@ -54,7 +66,22 @@ class SQLForm(pgwui_core.forms.UploadFormBaseMixin,
         super().read()
 
         # Read our own data
-        if self._form.sql.data is None:
+        self['filename'] = ''
+        self['upload_sql'] = self._form.upload_sql.data
+        if self['upload_sql']:
+            self['sql_file_read'] = False  # Parent class breaks defaulting
+            post = self.uh.request.POST
+            self['sql'] = ''
+            if self['action']:
+                if self._form.sql_file.data != '':
+                    if hasattr(post['sql_file'], 'filename'):
+                        self['filename'] = post['sql_file'].filename
+                    if hasattr(post['sql_file'], 'file'):
+                        fh = post['sql_file'].file
+                        self['sql'] = fh.read().decode()
+                        fh.close()
+                        self['sql_file_read'] = True
+        elif self._form.sql.data is None:
             self['sql'] = ''
         else:
             self['sql'] = self._form.sql.data
index 0c319c98022146849170a7fc67c226c45d62eb6d..00cc0c375df02427ca4cf7c4654882307f555482 100644 (file)
@@ -23,6 +23,11 @@ import pgwui_core.forms
 import pgwui_sql.views.base
 import pgwui_sql.exceptions as sql_ex
 
+from pgwui_core.constants import (
+    CHECKED,
+    UNCHECKED,
+)
+
 
 @attrs.define(slots=False)
 class SQLEditForm(pgwui_sql.views.base.SQLForm):
@@ -31,6 +36,20 @@ class SQLEditForm(pgwui_sql.views.base.SQLForm):
     def read(self):
         super().read()
         self['action'] = 'u'
+        self['upload_sql'] = self._form.upload_sql.data
+
+    def write(self, result, errors):
+        '''
+        Return the dict Pyramid uses to render the form.
+        '''
+        response = super().write(result, errors)
+
+        if self['upload_sql']:
+            response['upload_sql'] = CHECKED
+        else:
+            response['upload_sql'] = UNCHECKED
+
+        return response
 
 
 # Utility functions
index 5ea033546e465c04f4ef91bae0beb4362c5b30f9..a7ab78aa6949f73b0edbbe23a1a3b25d138a5b97 100644 (file)
@@ -100,10 +100,29 @@ class SQLResultsHandler(pgwui_core.core.SessionDBHandler):
         '''
         response = super().write(result, errors)
         response['search_path'] = self.search_path
+        response['upload_sql'] = self.uf['upload_sql']
+        response['filename'] = self.uf['filename']
         response['report_success'] = (not response['errors']
                                       and self.uf['action'] != '')
         return response
 
+    def val_input(self):
+        '''
+        Validate input needed beyond that required to connect to the db.
+
+        Returns:
+          A list of Error instances
+        '''
+        uf = self.uf
+        errors = super().val_input()
+
+        if uf['upload_sql'] and not uf['sql_file_read']:
+            errors.append(sql_ex.NoFileError(
+                'No SQL supplied',
+                descr=('The execute sql from a file checkbox was'
+                       ' checked, but a file containing SQL was not chosen')))
+        return errors
+
     def get_data(self):
         '''Return no data.  Data is in lines and we have no lines.
         '''
index 6bb5e49709a8a976e850c759db04cb96b8b06b3f..68ac7e7ef387cc604a73979b755153ef758f2333 100644 (file)
@@ -46,6 +46,7 @@ stock_template_args = {
     'csrf_token': 'somecsrftoken',
     'sql': 'select 1;',
     'search_path': '"$user", somedb',
+    'upload_sql': True
 }
 
 # The templates to test