Repository: akrherz/iem
Pull request #1180: Omnibus
Author: login: akrherz
Created: 2025-03-23T21:31:51Z | Merged: 2025-03-23T22:07:41Z



Diff:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c471cec58d..14602f2647 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,11 +2,11 @@ ci:
   autoupdate_schedule: quarterly
 repos:
   - repo: https://github.com/pre-commit/mirrors-eslint
-    rev: 'v9.22.0'
+    rev: 'v9.23.0'
     hooks:
       - id: eslint
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: "v0.11.1"
+    rev: "v0.11.2"
     hooks:
       - id: ruff
         args: [--fix, --exit-non-zero-on-fix]
diff --git a/htdocs/current/camrad.php b/htdocs/current/camrad.php
index ec477ef19a..9ee7aeb400 100644
--- a/htdocs/current/camrad.php
+++ b/htdocs/current/camrad.php
@@ -86,12 +86,14 @@
 $c0->__set("status", MS_ON);
 $db_ts = $ts->format("Y-m-d H:i");
 $year = $ts->format("Y");
-$c0->__set("data", "geom from "
-    . " (select significance, phenomena, geom, random() as oid from sbw "
-    . " WHERE vtec_year = $year and polygon_end > '$db_ts' and "
-    ." polygon_begin <= '$db_ts' and issue <= '$db_ts' "
-    . " and significance = 'W' ORDER by phenomena ASC) as foo "
-    . " using unique oid using SRID=4326");
+$c0->__set("data", <<<EOM
+    geom from (
+    select significance, phenomena, geom, random() as oid from sbw
+    WHERE vtec_year = $year and polygon_end > '$db_ts' and
+    polygon_begin <= '$db_ts' and issue <= '$db_ts'
+    and significance = 'W' ORDER by phenomena ASC) as foo
+    using unique oid using SRID=4326
+EOM);
 
 $radar = $map->getLayerByName("nexrad_n0q");
 $radar->__set("status", MS_ON);
diff --git a/htdocs/current/severe.phtml b/htdocs/current/severe.phtml
index 11505e27b2..a59152873d 100644
--- a/htdocs/current/severe.phtml
+++ b/htdocs/current/severe.phtml
@@ -94,12 +94,10 @@ events.</li>
 <li><a href="/raccoon/">IEM Raccoon</a>
   <br />Generate Microsoft Powerpoint overviews of storm based warnings.</li>
 
-
 <li><a href="/vtec/search.php">Search by County/Zone or Point</a>
   <br />Find archived warnings by searching for a county or zone.  You can
   also search for storm based warnings by a point.</li>
 
-
 <li><a href="/GIS/apps/rview/watch.phtml">Storm Prediction Center (SPC) Watches since 1997.</a>
  <br />Maps of SPC issued watches and initial RADAR (since 1997) at watch issuance.</li>
 
diff --git a/htdocs/current/uscrn.phtml b/htdocs/current/uscrn.phtml
index 8b544fda0d..e3d7cd32b9 100644
--- a/htdocs/current/uscrn.phtml
+++ b/htdocs/current/uscrn.phtml
@@ -149,8 +149,7 @@ station.</p>
 <tr>
   <th>
  <a href="{$uri}tmpf">Air</a>
- (<a href="{$uri}max_tmpf">Hi</a> /
- <a href="{$uri}min_tmpf">Lo</a>)
+ (<a href="{$uri}max_tmpf">Hi</a> / <a href="{$uri}min_tmpf">Lo</a>)
 </th>
   <th><a href="{$uri}dwpf">Dewp</a></th>
   <th><a href="{$uri}feel">Feels Like</a></th>
@@ -159,7 +158,7 @@ station.</p>
   <th><a href="{$uri}peak">Gust</a>
     @ <a href="{$uri}peak_ts">Time</a></th>
 </tr></thead>
-<tbody>  
+<tbody>
 {$table}
 </tbody>
 </table>
diff --git a/htdocs/current/webcam-static.js b/htdocs/current/webcam-static.js
index 47e2d70678..a9719ebd3e 100644
--- a/htdocs/current/webcam-static.js
+++ b/htdocs/current/webcam-static.js
@@ -22,12 +22,12 @@ Ext.onReady(() => {
     });
 
     Ext.override(Date, {
-        toUTC: function () {
+        toUTC: function () {  // this
             // Convert the date to the UTC date
             return Ext.Date.add(this, Ext.Date.MINUTE, this.getTimezoneOffset());
         },
 
-        fromUTC: function () {
+        fromUTC: function () {  // this
             // Convert the date from the UTC date
             return Ext.Date.add(this, Ext.Date.MINUTE, -this.getTimezoneOffset());
         }
@@ -75,9 +75,9 @@ Ext.onReady(() => {
             data.push({
                 boxLabel: Number(record.get("cid").substr(5, 3)) + " " + record.get("name"),
                 name: record.get("cid"),
-                checked: checked,
+                checked,
                 listeners: {
-                    change: (cb, isChecked) => {
+                    change(cb, isChecked) {
                         const id = cb.getName();
                         if (!imagestore.isLoaded) { return; }
 
@@ -125,7 +125,7 @@ Ext.onReady(() => {
         '</tpl>',
         '<div class="x-clear"></div>',
         {
-            shouldShow: (cid) => {
+            shouldShow(cid) {
                 return (disableStore.find('cid', cid) === -1);
             }
         }
@@ -155,7 +155,7 @@ Ext.onReady(() => {
             tbar: [{
                 xtype: 'button',
                 text: 'All Off',
-                handler: () => {
+                handler() {
                     Ext.getCmp("camselector").items.each((i) => {
                         i.setValue(false);
                     });
@@ -163,7 +163,7 @@ Ext.onReady(() => {
             }, {
                 xtype: 'button',
                 text: 'All On',
-                handler: () => {
+                handler()  {
                     Ext.getCmp("camselector").items.each((i) => {
                         i.setValue(true);
                     });
@@ -180,12 +180,12 @@ Ext.onReady(() => {
                 autoHeight: true,
                 overItemCls: 'x-view-over',
                 emptyText: "No Images Loaded or Selected for Display",
-                tpl: tpl
+                tpl
             }],
             tbar: [{
                 xtype: 'button',
                 text: 'Help',
-                handler: () => {
+                handler() {
                     helpWin.show();
                 }
             }, {
@@ -241,11 +241,11 @@ Ext.onReady(() => {
                         imagestore.reload({
                             add: false,
                             params: {
-                                'ts': ts,
+                                ts,
                                 'network': Ext.getCmp("networkSelect").getValue()
                             }
                         });
-                        window.location.href = "#" + Ext.getCmp("networkSelect").getValue() + "-" + ts;
+                        window.location.href = `#${Ext.getCmp("networkSelect").getValue()}-${ts}`;
                     }
                 }
 
@@ -334,7 +334,7 @@ Ext.onReady(() => {
 
 
     const task = {
-        run: function () {
+        run() {
             if (imagestore.data.length > 0 && Ext.getCmp("timemode") &&
                 Ext.getCmp("timemode").realtime) {
                 imagestore.reload({
diff --git a/htdocs/js/maptable.js b/htdocs/js/maptable.js
index e565ff7737..1e7dee7ad4 100644
--- a/htdocs/js/maptable.js
+++ b/htdocs/js/maptable.js
@@ -41,7 +41,7 @@ function get_style(color, text) {
             font: '14px Calibri,sans-serif',
             text,
             fill: new ol.style.Fill({
-                color: color,
+                color,
                 width: 1
             }),
             stroke: new ol.style.Stroke({
diff --git a/htdocs/projects/iembot/twitter.php b/htdocs/projects/iembot/twitter.php
index 1931024f35..ca92037bf6 100644
--- a/htdocs/projects/iembot/twitter.php
+++ b/htdocs/projects/iembot/twitter.php
@@ -40,7 +40,7 @@
     "iembot_twitter_subs(user_id, screen_name, channel) VALUES ($1, $2, $3)");
 $st_delsub = iem_pg_prepare($pgconn, "DELETE from " .
     "iembot_twitter_subs WHERE user_id = $1 and channel = $2");
-$st_deletesubs = pg_prepare(
+$st_deletesubs = iem_pg_prepare(
     $pgconn,
     "DELETE from iembot_twitter_subs where user_id = $1",
 );
diff --git a/include/cow_worker.php b/include/cow_worker.php
index 4abf9f4ea1..974442f820 100644
--- a/include/cow_worker.php
+++ b/include/cow_worker.php
@@ -9,7 +9,7 @@ function printLSR($lsr, $verified = FALSE)
         "x" => "Debris Flow", "q" => "Snow Squall",
         "F" => "Flash Flood", "T" => "Tornado", "D" => "Tstm Wnd Dmg",
         "H" => "Hail", "G" => "Wind Gust", "W" => "Waterspout",
-        "M" => "Marine Tstm Wnd", "2" => "Dust Storm"
+        "M" => "Marine Tstm Wnd", "2" => "Dust Storm", "h" => "Marine Hail",
     );
     $background = ($lsr["warned"] == False) ? "#f00" : "#0f0";
     if (is_null($lsr["leadtime"])) {
diff --git a/scripts/dbutil/sync_stations.py b/scripts/dbutil/sync_stations.py
index cf2c83b205..09a037eb6c 100644
--- a/scripts/dbutil/sync_stations.py
+++ b/scripts/dbutil/sync_stations.py
@@ -74,7 +74,7 @@ def sync(df, dbname):
             ugc_zone = %(ugc_zone)s, id = %(id)s, ncdc81 = %(ncdc81)s,
             ncei91 = %(ncei91)s,
             temp24_hour = %(temp24_hour)s, precip24_hour = %(precip24_hour)s,
-            wigos = %(wigos)s
+            wigos = %(wigos)s, synop = %(synop)s
             WHERE iemid = %(iemid)s
        """,
             prow,
@@ -106,8 +106,8 @@ def main():
             index_col="iemid",
         )
     df["iemid"] = df.index.values
-    # fix dtype for two columns
-    for col in ["temp24_hour", "precip24_hour", "remote_id"]:
+    # fix dtype
+    for col in ["temp24_hour", "precip24_hour", "remote_id", "synop"]:
         df[col] = df[col].astype("Int64")
     for sub in subscribers:
         sync(df, sub)


Reviews:
user: login: gemini-code-assist[bot]
body: ## Code Review
The pull request includes several changes across different files, mainly focusing on code formatting, minor logic adjustments, and some documentation updates. Overall, the changes seem reasonable, but a closer look is necessary to ensure correctness and maintainability.

### Summary of Findings
* **Inconsistent use of shorthand array syntax**: In `htdocs/current/webcam-static.js`, the shorthand syntax for array creation is used inconsistently. While it's used for `checked`, it's not used for `ts` in the same file. Maintaining consistency improves readability.
* **Potential SQL injection vulnerability**: In `htdocs/current/camrad.php`, the SQL query is constructed using string concatenation. While the variables are formatted, there's no explicit escaping, which could lead to a SQL injection vulnerability if the formatted values contain malicious characters. Consider using parameterized queries for better security.
* **Missing error handling**: In `include/database.inc.php`, the `iem_pg_prepare` function dies if `pg_prepare` fails. While this might be acceptable for development, it's not ideal for production. Consider adding more robust error handling, such as logging the error and returning a specific error code or exception.

### Merge Readiness
The pull request contains a mix of minor formatting changes and some potential issues that need to be addressed. Before merging, the SQL injection vulnerability in `htdocs/current/camrad.php` should be addressed, and the error handling in `include/database.inc.php` should be improved. The inconsistent use of shorthand array syntax in `htdocs/current/webcam-static.js` should also be fixed. I am unable to approve this pull request, and recommend that others review and approve this code before merging. Given the presence of a potential SQL injection vulnerability, I recommend that the pull request not be merged until this is addressed (at a minimum).
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-03-23T21:32:06Z

Review comments:
diff_hunk: @@ -86,12 +86,14 @@
 $c0->__set("status", MS_ON);
 $db_ts = $ts->format("Y-m-d H:i");
 $year = $ts->format("Y");
-$c0->__set("data", "geom from "
-    . " (select significance, phenomena, geom, random() as oid from sbw "
-    . " WHERE vtec_year = $year and polygon_end > '$db_ts' and "
-    ." polygon_begin <= '$db_ts' and issue <= '$db_ts' "
-    . " and significance = 'W' ORDER by phenomena ASC) as foo "
-    . " using unique oid using SRID=4326");
+$c0->__set("data", <<<EOM
+    geom from (
+    select significance, phenomena, geom, random() as oid from sbw
+    WHERE vtec_year = $year and polygon_end > '$db_ts' and
+    polygon_begin <= '$db_ts' and issue <= '$db_ts'
+    and significance = 'W' ORDER by phenomena ASC) as foo
path: htdocs/current/camrad.php
user: login: gemini-code-assist[bot]
body: ![critical](https://img.shields.io/badge/priority-critical-red)

The SQL query is constructed using string concatenation. While the variables are formatted, there's no explicit escaping, which could lead to a SQL injection vulnerability if the formatted values contain malicious characters. Consider using parameterized queries for better security. This is a critical issue that needs to be addressed before merging.

```php
$sql = "SELECT significance, phenomena, geom, random() as oid from sbw 
    WHERE vtec_year = $1 and polygon_end > $2 and
    polygon_begin <= $3 and issue <= $4
    and significance = 'W' ORDER by phenomena ASC";
$rs = pg_prepare($conn, 'sbw_query', $sql);
$result = pg_execute($conn, 'sbw_query', array($year, $db_ts, $db_ts, $db_ts));

$c0->__set("data", "geom from (select * from sbw_query) as foo using unique oid using SRID=4326");
```
created_at: 2025-03-23T21:32:06Z
author_association: NONE
diff_hunk: @@ -241,11 +241,11 @@ Ext.onReady(() => {
                         imagestore.reload({
                             add: false,
                             params: {
-                                'ts': ts,
+                                ts,
path: htdocs/current/webcam-static.js
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

Inconsistent use of shorthand property syntax. `ts: ts` is verbose, while `network` is concise. For consistency, use the shorthand syntax.

```javascript
                                ts,
                                'network': Ext.getCmp("networkSelect").getValue()
```
created_at: 2025-03-23T21:32:06Z
author_association: NONE
diff_hunk: @@ -74,7 +74,7 @@ def sync(df, dbname):
             ugc_zone = %(ugc_zone)s, id = %(id)s, ncdc81 = %(ncdc81)s,
             ncei91 = %(ncei91)s,
             temp24_hour = %(temp24_hour)s, precip24_hour = %(precip24_hour)s,
-            wigos = %(wigos)s
+            wigos = %(wigos)s, synop = %(synop)s
path: scripts/dbutil/sync_stations.py
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

Adding `synop` to the update statement. Ensure that this column exists in the target database schema. If it doesn't, this change will cause an error.

```suggestion
            temp24_hour = %(temp24_hour)s, precip24_hour = %(precip24_hour)s,
            wigos = %(wigos)s, synop = %(synop)s
```
created_at: 2025-03-23T21:32:06Z
author_association: NONE

PR comments:
user: login: deepsource-io[bot]
created_at: 2025-03-23T21:32:05Z
body: <div><p>Here's the code health analysis summary for commits <code>8bb7a41..4e8c0de</code>. <a href="https://app.deepsource.com/gh/akrherz/iem/run/e06241d6-f016-4875-a426-e846632f781c/">View details on DeepSource</a>&nbsp;↗.</p><h3>Analysis Summary</h3><table><thead><tr><th>Analyzer</th><th>Status</th><th>Summary</th><th>Link</th></tr></thead><tbody><tr><td><img src="https://static.deepsource.com/analyzer_logos/shell.svg" alt="DeepSource Shell Logo" width="16px" height="16px"/><strong>Shell</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td></td><td><a href="https://app.deepsource.com/gh/akrherz/iem/run/e06241d6-f016-4875-a426-e846632f781c/shell/">View Check</a>&nbsp;↗</td></tr><tr><td><img src="https://static.deepsource.com/analyzer_logos/javascript.svg" alt="DeepSource JavaScript Logo" width="16px" height="16px"/><strong>JavaScript</strong></td><td><span>❌&nbsp;</span><span>Failure</span></td><td><div>❗ 12 occurences introduced</div></td><td><a href="https://app.deepsource.com/gh/akrherz/iem/run/e06241d6-f016-4875-a426-e846632f781c/javascript/">View Check</a>&nbsp;↗</td></tr><tr><td><img src="https://static.deepsource.com/analyzer_logos/python.svg" alt="DeepSource Python Logo" width="16px" height="16px"/><strong>Python</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td></td><td><a href="https://app.deepsource.com/gh/akrherz/iem/run/e06241d6-f016-4875-a426-e846632f781c/python/">View Check</a>&nbsp;↗</td></tr><tr><td><img src="https://static.deepsource.com/analyzer_logos/php.svg" alt="DeepSource PHP Logo" width="16px" height="16px"/><strong>PHP</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td></td><td><a href="https://app.deepsource.com/gh/akrherz/iem/run/e06241d6-f016-4875-a426-e846632f781c/php/">View Check</a>&nbsp;↗</td></tr></tbody></table><hr/><blockquote><div>💡 If you’re a repository administrator, you can configure the quality gates from the <a href="https://app.deepsource.com/gh/akrherz/iem/settings/reporting">settings</a>.</div></blockquote></div>

author_association: NONE
user: login: codecov-commenter
created_at: 2025-03-23T21:48:17Z
body: ## [Codecov](https://app.codecov.io/gh/akrherz/iem/pull/1180?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=akrherz) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 88.99%. Comparing base [(`8bb7a41`)](https://app.codecov.io/gh/akrherz/iem/commit/8bb7a414aecd2b558bf88b534cd11defdd1984db?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=akrherz) to head [(`4e8c0de`)](https://app.codecov.io/gh/akrherz/iem/commit/4e8c0ded99dfaf223899ac4b8b7c810434b2702c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=akrherz).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #1180   +/-   ##
=======================================
  Coverage   88.99%   88.99%           
=======================================
  Files         411      411           
  Lines       31435    31435           
=======================================
  Hits        27975    27975           
  Misses       3460     3460           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/akrherz/iem/pull/1180?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=akrherz).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=akrherz).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE