Skip to content

Commit

Permalink
Merge branch 'main' into rob-id-debug
Browse files Browse the repository at this point in the history
  • Loading branch information
caseyhans authored Dec 18, 2023
2 parents 4ae654a + 786bb4f commit 9f7cd16
Show file tree
Hide file tree
Showing 98 changed files with 3,739 additions and 848 deletions.
3 changes: 0 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
Health Assessment Workspace Collaborative
=========================================

.. image:: https://zenodo.org/badge/25273569.svg
:target: https://zenodo.org/badge/latestdoi/25273569

.. image:: https://readthedocs.org/projects/hawc/badge/
:target: https://hawc.readthedocs.io
:alt: Documentation Status
Expand Down
7 changes: 1 addition & 6 deletions compose/app/sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ manage clearsessions
manage collectstatic --noinput
manage migrate --noinput

if [[ $HAWC_LOAD_TEST_DB == "2" ]]; then
if [[ $HAWC_LOAD_TEST_DB == "1" ]]; then
echo "loading fixture database..."
manage load_test_db
elif [[ $HAWC_LOAD_TEST_DB == "1" ]]; then
echo "loading fixture database (if empty)..."
manage load_test_db --ifempty
else
echo "not modifying database..."
fi

# drop/rebuild materialized views
Expand Down
1 change: 1 addition & 0 deletions compose/example.env
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ HAWC_PM_CAN_MAKE_PUBLIC=True
HAWC_LOAD_TEST_DB=0
HAWC_FEATURE_FLAGS='{}'
HAWC_CSRF_TRUSTED_ORIGINS=https://hawc.com
WAGTAILADMIN_BASE_URL=https://hawc.com

# google tag manager
GTM_ID=GTM-0000000
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ For configurable parameters, we use environment variables which are loaded in th
- The "django" authentication provider means accounts can be created in hawc and passwords are managed in hawc
- The "external" authentication provider assumes an upstream server handles authentication and returns appropriate user metadata for integration via `/user/login/wam/`. If used, `hawc.apps.myuser.views.ExternalAuth.get_user_metadata` requires a custom implementation.
- `HAWC_LOGOUT_REDIRECT` [str, optional]. URL to redirect to after logout. Defaults to the homepage of hawc; this may need to be modified with some authentication providers.
- `HAWC_LOAD_TEST_DB` [0/1/2; default 0]. Load a test database with pre-populated fake data: always (2), if empty (1), or never (0; default). This setting is only used in staging and production django settings.
- `HAWC_LOAD_TEST_DB` [0/1; default 0]. Load a test database with pre-populated fake data (1), or never ( default). This setting is only used in staging and production django settings.

### Feature flags

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ A few major revisions were made to the compiled USWDS assets, most notably:

### Updating EPA.gov style

THere are multiple styles available when using HAWC; and the EPA style has to be updated periodically for the same look at feel as the EPA website. The following steps describe how to update HAWC styling with the EPA theme:
There are multiple styles available when using HAWC; and the EPA style has to be updated periodically for the same look at feel as the EPA website. The following steps describe how to update HAWC styling with the EPA theme:

1. In your browser, go to the [EPA Template](https://www.epa.gov/themes/epa_theme/pattern-lab/patterns/pages-standalone-template/pages-standalone-template.rendered.html) site. We recommend Firefox or Internet Explorer.
2. Right click the page and select "Save As" to download the page as an .html file.
Expand Down
1 change: 0 additions & 1 deletion docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ The Health Assessment Workspace Collaborative (HAWC) is a website designed to ca
The public website is currently available on <https://hawcproject.org>, though there are additional versions available in other locations, including private deployments.

[![Website](https://img.shields.io/website?url=https%3A%2F%2Fhawcproject.org)](https://hawcproject.org)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1414622.svg)](https://doi.org/10.5281/zenodo.1414622)
[![Github](https://img.shields.io/github/last-commit/shapiromatron/hawc.svg)](https://github.com/shapiromatron/hawc)
15 changes: 13 additions & 2 deletions frontend/lit/components/Reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,15 @@ class Reference extends Component {
</div>
);

if (data.searches.length) {
if (!expanded && data.searches.length) {
nodes.push(
<div
style={{minWidth: 85}}
className="d-flex dropdown flex-shrink-0"
key={h.randomString()}>
<a
className={`btn dropdown-toggle ${btn_size} outline-btn`}
title="HAWC Searches/Imports"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false">
Expand All @@ -90,7 +91,7 @@ class Reference extends Component {
</a>
<div className="dropdown-menu dropdown-menu-right">
{data.searches.map((d, i) => (
<a className="dropdown-item small" key={h.randomString()} href={d.url}>
<a className="dropdown-item small" key={d.url} href={d.url}>
{d.title}
</a>
))}
Expand Down Expand Up @@ -207,6 +208,16 @@ class Reference extends Component {
))}
</p>
) : null}
{expanded && data.searches.length > 0 ? (
<div>
<label>Searches/imports:&nbsp;</label>
{data.searches.map((d, i) => (
<a className="btn btn-light mr-1 mb-2" key={d.url} href={d.url}>
{d.title}
</a>
))}
</div>
) : null}
{showHr ? <hr className="my-4" /> : null}
</div>
);
Expand Down
20 changes: 19 additions & 1 deletion frontend/shared/utils/HAWCUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,12 @@ class HAWCUtils {
handleChange = () => {
const selector = `#detail-${$selectEl.val()}`,
clone = $insertItems.find(selector).clone();
$insertEl.fadeOut(() => $insertEl.html(clone).fadeIn());
$insertEl.fadeOut(() =>
$insertEl
.html(clone)
.trigger("select:change")
.fadeIn()
);
};
$selectEl.on("change", handleChange).trigger("change");
}
Expand All @@ -328,5 +333,18 @@ class HAWCUtils {
})
.trigger("change");
}

static addAnchorLinks(parent, selector) {
$(parent)
.find(selector)
.each(function(index) {
const id = $(this).attr("id");
if (id) {
$(this).append(
`<a href="#${id}" class="ml-2 anchor-link" title="Section link"><span class="fa fa-fw fa-chain"></span></a>`
);
}
});
}
}
export default HAWCUtils;
6 changes: 6 additions & 0 deletions hawc/apps/common/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ def diagnostic_cache(modeladmin, request, queryset):
modeladmin.message_user(request, message)


def clear_cache(modeladmin, request, queryset):
cache.clear()
message = "Cache cleared successfully"
modeladmin.message_user(request, message)


def diagnostic_email(modeladmin, request, queryset):
to_email = request.user.email
send_mail(
Expand Down
10 changes: 10 additions & 0 deletions hawc/apps/common/management/commands/dump_test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ def handle(self, *args, **options):

call_command("dumpdata", "sites", **shared_kwargs)
call_command("dumpdata", "contenttypes", **shared_kwargs)
call_command("dumpdata", "wagtailcore", **shared_kwargs)
call_command("dumpdata", "wagtailadmin", **shared_kwargs)
call_command("dumpdata", "wagtaildocs", **shared_kwargs)
call_command("dumpdata", "wagtailembeds", **shared_kwargs)
call_command("dumpdata", "wagtailforms", **shared_kwargs)
call_command("dumpdata", "wagtailimages", **shared_kwargs)
call_command("dumpdata", "wagtailredirects", **shared_kwargs)
call_command("dumpdata", "wagtailsearch", **shared_kwargs)
call_command("dumpdata", "wagtailusers", **shared_kwargs)
call_command("dumpdata", "myuser", **shared_kwargs)
call_command("dumpdata", "vocab", **shared_kwargs)
call_command(
Expand All @@ -40,6 +49,7 @@ def handle(self, *args, **options):
call_command("dumpdata", "invitro", **shared_kwargs)
call_command("dumpdata", "epimeta", **shared_kwargs)
call_command("dumpdata", "summary", **shared_kwargs)
call_command("dumpdata", "docs", **shared_kwargs)
call_command("dumpdata", "mgmt", **shared_kwargs)

Path(settings.TEST_DB_FIXTURE).parent.mkdir(exist_ok=True, parents=True)
Expand Down
78 changes: 49 additions & 29 deletions hawc/apps/common/management/commands/load_test_db.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import sys
from pathlib import Path

import pandas as pd
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.management import call_command
from django.core.management.base import BaseCommand, CommandError
from django.core.management.commands import migrate
from django.db.backends.base import creation
from django.test.utils import setup_databases

from hawc.apps.common.signals import ignore_signals

Expand All @@ -15,17 +18,23 @@ def load_iris_dataset() -> pd.DataFrame:
)


class DisableMigrations:
def __contains__(self, item: str) -> bool:
return True

def __getitem__(self, item: str) -> None:
return None


class MigrateSilentCommand(migrate.Command):
def handle(self, *args, **kwargs):
kwargs["verbosity"] = 0
return super().handle(*args, **kwargs)


class Command(BaseCommand):
help = """Load the test database from a fixture."""

def add_arguments(self, parser) -> None:
parser.add_argument(
"--ifempty",
action="store_true",
dest="ifempty",
help="Only flush/load if database is empty",
)

def write_media_files(self):
"""
Sync filesystem with database.
Expand All @@ -50,29 +59,40 @@ def write_media_files(self):
fn.parent.mkdir(parents=True, exist_ok=True)
df.to_excel(fn, index=False)

def setup_environment(self) -> None:
"""Disable migrations like pytest-django does, but outside of pytest-django."""
creation.TEST_DATABASE_PREFIX = ""
migrate.Command = MigrateSilentCommand
settings.MIGRATION_MODULES = DisableMigrations()
self.stdout.write(self.style.HTTP_INFO("Migrating database schema..."))
setup_databases(verbosity=0, interactive=False, keepdb=True)
self.stdout.write(self.style.HTTP_INFO("Loading database fixture..."))
call_command("loaddata", str(settings.TEST_DB_FIXTURE), verbosity=0)
settings.MIGRATION_MODULES = {}
self.stdout.write(self.style.HTTP_INFO("Writing migrations (fake)..."))
call_command("migrate", verbosity=0, fake=True)

def setup_test_environment(self) -> None:
"""Setup test environment within pytest environment."""
self.stdout.write(self.style.HTTP_INFO("Migrating database schema..."))
call_command("migrate", verbosity=0)
self.stdout.write(self.style.HTTP_INFO("Flushing data..."))
call_command("flush", verbosity=0, interactive=False)
self.stdout.write(self.style.HTTP_INFO("Loading database fixture..."))
call_command("loaddata", str(settings.TEST_DB_FIXTURE), verbosity=0)

def handle(self, *args, **options):
if not any(_ in settings.DATABASES["default"]["NAME"] for _ in ["fixture", "test"]):
db_name = settings.DATABASES["default"]["NAME"]
if not any(_ in db_name for _ in ["fixture", "test"]):
raise CommandError("Must be using a test database to execute.")

with ignore_signals():
self.stdout.write(self.style.HTTP_INFO("Migrating database schema..."))
call_command("migrate", verbosity=0)

if options["ifempty"] and get_user_model().objects.count() > 0:
message = "Migrations complete; fixture not loaded (db not empty)"
if "pytest" in sys.modules:
self.setup_test_environment()
else:
self.stdout.write(self.style.HTTP_INFO("Flushing data..."))
call_command("flush", verbosity=0, interactive=False)

self.stdout.write(self.style.HTTP_INFO("Loading database fixture..."))
call_command("loaddata", str(settings.TEST_DB_FIXTURE), verbosity=1)

self.stdout.write(self.style.HTTP_INFO("Loading database views..."))
call_command("recreate_views", verbosity=1)

self.stdout.write(self.style.HTTP_INFO("Creating files..."))
self.write_media_files()
self.setup_environment()

message = "Migrations complete; fixture (re)applied"
self.stdout.write(self.style.HTTP_INFO("Recreating database views..."))
call_command("recreate_views", verbosity=0)

self.stdout.write(self.style.SUCCESS(message))
self.stdout.write(self.style.HTTP_INFO("Creating files..."))
self.write_media_files()
16 changes: 14 additions & 2 deletions hawc/apps/common/signals.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from contextlib import contextmanager
from itertools import chain

from django.db.models.signals import m2m_changed, post_delete, post_save, pre_delete, pre_save
from django.db.models import signals as dsignals
from django.dispatch import Signal
from wagtail import signals as wts
from wagtail.admin import signals as wtas


@contextmanager
Expand All @@ -10,7 +14,15 @@ def ignore_signals():
Originally taken from: https://www.cameronmaske.com/muting-django-signals-with-a-pytest-fixture/
"""
signals = [pre_save, post_save, pre_delete, post_delete, m2m_changed]
signals = [
signal
for signal in chain(
dsignals.__dict__.values(),
wts.__dict__.values(),
wtas.__dict__.values(),
)
if isinstance(signal, Signal)
]
restore = {}
for signal in signals:
restore[signal] = signal.receivers
Expand Down
7 changes: 7 additions & 0 deletions hawc/apps/common/templates/common/analytics_plot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="card box-shadow">
<div class="card-body">
<h3 class="text-center">{{ title }}</h3>
<div>{% plotly plot event="htmx" resizable="True" %}</div>
<p class="text-muted text-center"> {{ caption }}</p>
</div>
</div>
20 changes: 20 additions & 0 deletions hawc/apps/common/templatetags/bs4.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from uuid import uuid4

from django import template
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from plotly.graph_objs._figure import Figure

Expand Down Expand Up @@ -47,6 +48,11 @@ def bs4_fullrow(text: str, tr_attrs: str = "") -> str:
)


@register.simple_tag()
def icon(name: str):
return format_html('<span class="fa fa-fw {} mr-1" aria-hidden="true"></span>', name)


@register.tag(name="alert")
def bs4_alert(parser, token):
args = token.contents.split()
Expand Down Expand Up @@ -124,3 +130,17 @@ def add_class(value, css_class):
else:
return mark_safe(string.replace(">", f' class="{css_class}">'))
return value


@register.simple_tag
def analytics_card(value, label):
return mark_safe(
f"""
<div class="card box-shadow">
<div class="card-body">
<h2 class="m-0 mt-1">{ value }</h2>
<p class="small">{ label }</p>
</div>
</div>
"""
)
Empty file added hawc/apps/docs/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions hawc/apps/docs/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class DocsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "hawc.apps.docs"
15 changes: 15 additions & 0 deletions hawc/apps/docs/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
RICH_TEXT_FEATURES = [
"anchor-identifier",
"h3",
"h4",
"h5",
"h6",
"bold",
"italic",
"link",
"ol",
"ul",
"hr",
"image",
"document-link",
]
Loading

0 comments on commit 9f7cd16

Please sign in to comment.